diff --git a/.clang-format b/.clang-format new file mode 100644 index 00000000..3715edfd --- /dev/null +++ b/.clang-format @@ -0,0 +1,6 @@ +BasedOnStyle: LLVM +IndentWidth: 4 +UseTab: Never +ColumnLimit: 100 +AllowShortFunctionsOnASingleLine: Inline +SortIncludes: false diff --git a/.travis.yml b/.travis.yml index c6962212..c1aaedba 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,13 +1,24 @@ language: node_js +os: linux +dist: trusty node_js: - - "5.7.0" + - "8.9.4" +before_install: + - export CHROME_BIN=chromium-browser + - export DISPLAY=:99.0 + - sh -e /etc/init.d/xvfb start script: - - "node node_modules/pxt-core/built/pxt.js travis" - - "node node_modules/pxt-core/built/pxt.js testdir tests" + - "node node_modules/pxt-core/built/pxt.js travis" +# - "(cd libs/lang-test0; node ../../node_modules/pxt-core/built/pxt.js run)" +# - "(cd libs/lang-test1; node ../../node_modules/pxt-core/built/pxt.js run)" +# - "(cd libs/lang-test0; node ../../node_modules/pxt-core/built/pxt.js test)" +# - "(cd libs/lang-test1; node ../../node_modules/pxt-core/built/pxt.js test)" +# - "node node_modules/pxt-core/built/pxt.js testdir tests" +# - "(cd libs/hello; node ../../node_modules/pxt-core/built/pxt.js testconv http://az851932.vo.msecnd.net/files/td-converter-tests-v1.json)" sudo: false notifications: email: - - kindscript@microsoft.com + - touchdevelop-build@microsoft.com cache: directories: - node_modules diff --git a/THIRD-PARTY-NOTICES.txt b/THIRD-PARTY-NOTICES.txt new file mode 100644 index 00000000..2f11c769 --- /dev/null +++ b/THIRD-PARTY-NOTICES.txt @@ -0,0 +1,229 @@ +/*!----------------- PXT ThirdPartyNotices ------------------------------------------------------- + +PXT uses third party material from the projects listed below. +The original copyright notice and the license under which Microsoft +received such third party material are set forth below. Microsoft +reserves all other rights not expressly granted, whether by +implication, estoppel or otherwise. + +In the event that we accidentally failed to list a required notice, please +bring it to our attention. Post an issue or email us: + + abchatra@microsoft.com + +--------------------------------------------- +Third Party Code Components +--------------------------------------------- + +Some code derived (as noted) from + +https://github.com/bbcmicrobit/micropython + +The MIT License (MIT) + +Copyright (c) 2013-2016 The MicroPython-on-micro:bit Developers, as listed +in the accompanying AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +----------------- google/blockly ------------------- + +Sounds under sim/public/blockly/media from Google Blockly. + + +Copyright 2013 Google Inc + + Apache License + Version 2.0, January 2011 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + +--------------------------------------------- \ No newline at end of file diff --git a/clients/chrome/README.md b/clients/chrome/README.md deleted file mode 100644 index b3261250..00000000 --- a/clients/chrome/README.md +++ /dev/null @@ -1,26 +0,0 @@ -# microbit-chrome -Prototype chrome addon that exposes the micro:bit's serial output to webpages. -* watch the [demo video](https://vimeo.com/146207766) - -# Installation -See [developer.chrome.com](https://developer.chrome.com/extensions/getstarted#unpacked) -for instructions on how to install the local version into your chrome browser. - -# Requirements -* Chrome 48 or later. - -# Sample page -The `demo.html` webpage goes along with the -https://github.com/Microsoft/microbit-touchdevelop/blob/master/examples/tcs34725.cpp -program. Run `http-server` from this directory, then visit -http://localhost:8080/demo.html -(keep in mind that pages served from `file://` cannot open ports). - -# Building - -Open a command prompt and run the following commands. - -```` -npm install -typings update -```` \ No newline at end of file diff --git a/clients/chrome/background.js b/clients/chrome/background.js deleted file mode 100644 index 1a73f494..00000000 --- a/clients/chrome/background.js +++ /dev/null @@ -1,67 +0,0 @@ -var connections = []; -// A list of "ports", i.e. connected clients (such as web pages). Multiple web -// pages can connect to our service: they all receive the same data. -var ports = []; -function byPath(path) { - return connections.filter(function (x) { return x.path == path; }); -} -function byId(id) { - return connections.filter(function (x) { return x.id == id; }); -} -function onReceive(data, id) { - if (ports.length == 0) - return; - var view = new DataView(data); - var decoder = new TextDecoder("utf-8"); - var decodedString = decoder.decode(view); - ports.forEach(function (port) { return port.postMessage({ - type: "serial", - data: decodedString, - id: id - }); }); -} -function findNewDevices() { - chrome.serial.getDevices(function (serialPorts) { - serialPorts.forEach(function (serialPort) { - if (byPath(serialPort.path).length == 0 && - serialPort.displayName == "mbed Serial Port") { - chrome.serial.connect(serialPort.path, { bitrate: 115200 }, function (info) { - // In case the [connect] operation takes more than five seconds... - if (info && byPath(serialPort.path).length == 0) - connections.push({ - id: info.connectionId, - path: serialPort.path - }); - }); - } - }); - }); -} -function main() { - // Register new clients in the [ports] global variable. - chrome.runtime.onConnectExternal.addListener(function (port) { - if (/^(micro:bit|touchdevelop|yelm|pxt|codemicrobit|codethemicrobit|pxt.microbit.org)$/.test(port.name)) { - ports.push(port); - port.onDisconnect.addListener(function () { - ports = ports.filter(function (x) { return x != port; }); - }); - } - }); - // When receiving data for one of the connections that we're tracking, forward - // it to all connected clients. - chrome.serial.onReceive.addListener(function (info) { - if (byId(info.connectionId).length > 0) - onReceive(info.data, info.connectionId); - }); - // When it looks like we've been disconnected, drop the corresponding - // connection object from the [connections] global variable. - chrome.serial.onReceiveError.addListener(function (info) { - if (info.error == "system_error" || info.error == "disconnected" || info.error == "device_lost") - connections = connections.filter(function (x) { return x.id != info.connectionId; }); - }); - // Probe serial connections at regular intervals. In case we find an mbed port - // we haven't yet connected to, connect to it. - setInterval(findNewDevices, 5000); - findNewDevices(); -} -document.addEventListener("DOMContentLoaded", main); diff --git a/clients/chrome/background.ts b/clients/chrome/background.ts deleted file mode 100644 index 049889f7..00000000 --- a/clients/chrome/background.ts +++ /dev/null @@ -1,92 +0,0 @@ -// A list of: { -// id: number; -// path: string; -// } where [id] is the [connectionId] (internal to Chrome) and [path] is the -// OS' name for the device (e.g. "COM4"). -interface Connection { - id: string; - path: string; -} -let connections: Connection[] = []; - -// A list of "ports", i.e. connected clients (such as web pages). Multiple web -// pages can connect to our service: they all receive the same data. -let ports = []; - -interface Message { - type: string; - data: string; - id: string; -} - -function byPath(path: string): Connection[] { - return connections.filter((x) => x.path == path); -} - -function byId(id: string): Connection[] { - return connections.filter((x) => x.id == id); -} - -function onReceive(data, id: string) { - if (ports.length == 0) return; - - let view = new DataView(data); - let decoder = new TextDecoder("utf-8"); - let decodedString = decoder.decode(view); - ports.forEach(port => port.postMessage({ - type: "serial", - data: decodedString, - id: id, - })); -} - -function findNewDevices() { - chrome.serial.getDevices(function (serialPorts) { - serialPorts.forEach(function (serialPort) { - if (byPath(serialPort.path).length == 0 && - serialPort.displayName == "mbed Serial Port") { - chrome.serial.connect(serialPort.path, { bitrate: 115200 }, function (info) { - // In case the [connect] operation takes more than five seconds... - if (info && byPath(serialPort.path).length == 0) - connections.push({ - id: info.connectionId, - path: serialPort.path - }); - }); - } - }); - }); -} - -function main() { - // Register new clients in the [ports] global variable. - chrome.runtime.onConnectExternal.addListener(function (port) { - if (/^(micro:bit|touchdevelop|yelm|pxt|codemicrobit|codethemicrobit|pxt.microbit.org)$/.test(port.name)) { - ports.push(port); - port.onDisconnect.addListener(function () { - ports = ports.filter(function (x) { return x != port }); - }); - } - }); - - // When receiving data for one of the connections that we're tracking, forward - // it to all connected clients. - chrome.serial.onReceive.addListener(function (info) { - if (byId(info.connectionId).length > 0) - onReceive(info.data, info.connectionId); - }); - - // When it looks like we've been disconnected, drop the corresponding - // connection object from the [connections] global variable. - chrome.serial.onReceiveError.addListener(function (info) { - if (info.error == "system_error" || info.error == "disconnected" || info.error == "device_lost") - connections = connections.filter((x) => x.id != info.connectionId); - }); - - // Probe serial connections at regular intervals. In case we find an mbed port - // we haven't yet connected to, connect to it. - setInterval(findNewDevices, 5000); - findNewDevices(); -} - -document.addEventListener("DOMContentLoaded", main); diff --git a/clients/chrome/logo128.png b/clients/chrome/logo128.png deleted file mode 100644 index 02027906..00000000 Binary files a/clients/chrome/logo128.png and /dev/null differ diff --git a/clients/chrome/logo48.png b/clients/chrome/logo48.png deleted file mode 100644 index 02027906..00000000 Binary files a/clients/chrome/logo48.png and /dev/null differ diff --git a/clients/chrome/manifest.json b/clients/chrome/manifest.json deleted file mode 100644 index fa61c001..00000000 --- a/clients/chrome/manifest.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "app": { - "background": { - "scripts": [ "background.js" ] - } - }, - - "manifest_version": 2, - "name": "pxt.microbit.org", - "version": "0.7.0", - "author": "Microsoft Corporation", - "short_name": "pxt.microbit.org", - - "description": "Extension for https://pxt.microbit.org.", - "homepage_url": "https://pxt.microbit.org", - "offline_enabled": "true", - "icons": { - "48": "logo48.png", - "128": "logo128.png" - }, - - "permissions": [ - "serial", - "usb" - ], - - "externally_connectable": { - "matches": [ "*://localhost/*", "https://pxt.microbit.org/*", "https://*.microbit.org/*" ] - } -} diff --git a/clients/chrome/screenshot.png b/clients/chrome/screenshot.png deleted file mode 100644 index c6f4b56b..00000000 Binary files a/clients/chrome/screenshot.png and /dev/null differ diff --git a/clients/chrome/tsconfig.json b/clients/chrome/tsconfig.json deleted file mode 100644 index ffa98b79..00000000 --- a/clients/chrome/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "compiler-options": { - "target": "ES5", - "module": "amd", - "sourceMap": false - } - } \ No newline at end of file diff --git a/clients/electron/.gitignore b/clients/electron/.gitignore deleted file mode 100644 index ccedfdac..00000000 --- a/clients/electron/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -node_modules -projects \ No newline at end of file diff --git a/clients/electron/README.md b/clients/electron/README.md deleted file mode 100644 index f0aae8bb..00000000 --- a/clients/electron/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# PXT micro:bit Electron app - -A very basic wrapper around the web app. To install, copy the contents of this -directory to somewhere outside the main `pxt-microbit` repository. Then run `npm -install && npm start`. diff --git a/clients/electron/index.html b/clients/electron/index.html deleted file mode 100644 index 260b1839..00000000 --- a/clients/electron/index.html +++ /dev/null @@ -1,15 +0,0 @@ - - - - - code the micro:bit - - - - - - diff --git a/clients/electron/main.js b/clients/electron/main.js deleted file mode 100644 index 58bba12e..00000000 --- a/clients/electron/main.js +++ /dev/null @@ -1,39 +0,0 @@ -const {app, BrowserWindow, Menu} = require('electron') -const pxt = require('pxt-core') -const path = require('path') - -let win - -const cliPath = path.join(process.cwd(), "node_modules/pxt-microbit") - -function startServerAndCreateWindow() { - pxt.mainCli(cliPath, ["serve", "-no-browser"]) - createWindow() -} - -function createWindow () { - win = new BrowserWindow({ - width: 800, - height: 600, - title: "code the micro:bit" - }) - Menu.setApplicationMenu(null) - win.loadURL(`file://${__dirname}/index.html#local_token=${pxt.globalConfig.localToken}`) - win.on('closed', () => { - win = null - }) -} - -app.on('ready', startServerAndCreateWindow) - -app.on('window-all-closed', () => { - if (process.platform !== 'darwin') { - app.quit() - } -}) - -app.on('activate', () => { - if (win === null) { - createWindow() - } -}) diff --git a/clients/electron/package.json b/clients/electron/package.json deleted file mode 100644 index f9633774..00000000 --- a/clients/electron/package.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name" : "code-the-microbit", - "version" : "1.0.0", - "description": "Blocks / Javascript editor", - "author": "Microsoft", - "main" : "main.js", - "scripts": { - "start": "node_modules/.bin/electron ." - }, - "devDependencies": { - "electron": "*", - "pxt-microbit": "*" - } -} diff --git a/clients/macuploader/Graphics/appicon.sketch b/clients/macuploader/Graphics/appicon.sketch deleted file mode 100644 index 480cb417..00000000 Binary files a/clients/macuploader/Graphics/appicon.sketch and /dev/null differ diff --git a/clients/macuploader/Graphics/export.png b/clients/macuploader/Graphics/export.png index b5083be0..7bc58c2e 100644 Binary files a/clients/macuploader/Graphics/export.png and b/clients/macuploader/Graphics/export.png differ diff --git a/clients/macuploader/Graphics/menubar.sketch b/clients/macuploader/Graphics/menubar.sketch deleted file mode 100644 index 55ed3814..00000000 Binary files a/clients/macuploader/Graphics/menubar.sketch and /dev/null differ diff --git a/clients/macuploader/Microbit Uploader/AppDelegate.m b/clients/macuploader/Microbit Uploader/AppDelegate.m index 3f07a9ed..ae0d64e1 100644 --- a/clients/macuploader/Microbit Uploader/AppDelegate.m +++ b/clients/macuploader/Microbit Uploader/AppDelegate.m @@ -124,7 +124,7 @@ } - (void)launchEditor:(id)sender { - [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"https://pxt.microbit.org/"]]; + [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"https://makecode.microbit.org/"]]; } @end diff --git a/clients/macuploader/README.md b/clients/macuploader/README.md index de3205f4..69316e82 100644 --- a/clients/macuploader/README.md +++ b/clients/macuploader/README.md @@ -1,12 +1,12 @@ -# micro:bit uploader for OS X +# @boardname@ uploader for OS X ![](Microbit Uploader/Assets.xcassets/AppIcon.appiconset/icon_256x256.png) This project is a clone of the [Windows -uploader](https://pxt.microbit.org/uploader), but for OS X. Once launched, +uploader](https://makecode.microbit.org/uploader), but for OS X. Once launched, the app runs in your menu bar and will automatically deploy any HEX files to -your `micro:bit`. Like the Windows version, it is compatible with any browser -that can run [pxt.microbit.org](http://pxt.microbit.org). +your `@boardname@`. Like the Windows version, it is compatible with any browser +that can run @homeurl@. ## Install the built version diff --git a/clients/winuploader/Microbit.Uploader/MainForm.cs b/clients/winuploader/Microbit.Uploader/MainForm.cs index 11eecb33..09126c9b 100644 --- a/clients/winuploader/Microbit.Uploader/MainForm.cs +++ b/clients/winuploader/Microbit.Uploader/MainForm.cs @@ -32,7 +32,7 @@ namespace Microsoft.MicroBit private void openEditor() { // lanch editor - try { Process.Start("https://pxt.microbit.org#uploader"); } catch (Exception) { } + try { Process.Start("https://makecode.microbit.org#uploader"); } catch (Exception) { } } private void initializeFileWatch() @@ -236,7 +236,7 @@ namespace Microsoft.MicroBit { try { - Process.Start("https://pxt.microbit.org/uploader"); + Process.Start("https://makecode.microbit.org/uploader"); } catch (IOException) { } } diff --git a/docfiles/indexhead.html b/docfiles/indexhead.html new file mode 100644 index 00000000..88409052 --- /dev/null +++ b/docfiles/indexhead.html @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/about.md b/docs/about.md deleted file mode 100644 index fe60433d..00000000 --- a/docs/about.md +++ /dev/null @@ -1,5 +0,0 @@ -![](/static/mb/device/pano.jpg) - -# About - -Read more at https://calliope.cc . \ No newline at end of file diff --git a/docs/beta-ref.json b/docs/beta-ref.json index 58f715cc..7322453d 100644 --- a/docs/beta-ref.json +++ b/docs/beta-ref.json @@ -1,3 +1,3 @@ { - "appref": "v" + "appref": "v2" } diff --git a/docs/blocks.md b/docs/blocks.md deleted file mode 100644 index 9d291c18..00000000 --- a/docs/blocks.md +++ /dev/null @@ -1,14 +0,0 @@ -# Blocks language - -### @description Langugage constructs for the Block editor. - -```namespaces -for (let i = 0;i<5;++i) {} -if (true){} -let x = 0; -Math.random(5); -``` - -## See Also - -[logic](/blocks/logic), [loops](/blocks/loops), [math](/blocks/math), [variables](/blocks/variables) \ No newline at end of file diff --git a/docs/blocks/logic.md b/docs/blocks/logic.md deleted file mode 100644 index 2ff4f982..00000000 --- a/docs/blocks/logic.md +++ /dev/null @@ -1,9 +0,0 @@ -# Logic - -```cards -if(true) {} -true; -true && false; -!true; -1 != 0; -``` diff --git a/docs/blocks/logic/boolean.md b/docs/blocks/logic/boolean.md deleted file mode 100644 index 15df1b5f..00000000 --- a/docs/blocks/logic/boolean.md +++ /dev/null @@ -1,102 +0,0 @@ -# Boolean - -true or false. - -A Boolean has one of two possible values: `true`; `false`. Boolean (logical) operators (*and*, *or*, *not*) take Boolean inputs and yields a Boolean value. Comparison operators on other types ([numbers](/reference/types/number), [strings](/reference/types/string) yields a Boolean value. - -The following blocks represent the true and false Boolean values, which can be plugged in anywhere a Boolean value is expected: - -```blocks -true; -false; -``` - -The next three blocks represent the three Boolean (logic) operators: - -```blocks -true && false; -true || false; -!true; -``` - -The next six blocks represent comparison operators that yield a Boolean value. Most comparisons you will do involve [numbers](/reference/types/number): - -```blocks -42 == 0; -42 != 0; -42 < 0; -42 > 0; -42 <= 0; -42 >= 0; -``` - -Boolean values and operators are often used with an [if](/blocks/logic/if) or [while](/blocks/loops/while) statement to determine which code will execute next. For example: - -### Functions that return a Boolean - -Some functions return a Boolean value, which you can store in a Boolean variable. For example, the following code gets the on/off state of `point (1, 2)` and stores this in the Boolean variable named `on`. Then the code clears the screen if `on` is `true`: - -### Boolean operators - -Boolean operators take Boolean inputs and evaluate to a Boolean output: - -### Conjunction: `A and B` - -`A and B` evaluates to `true` if-and-only-if both A and B are true: - -```blocks -false && false == false; -false && true == false; -true && false == false; -true && true == true; -``` - -### Disjunction: `A or B` - -`A or B` evaluates to `true` if-and-only-if either A is true or B is true: - -```blocks -false || false == false; -false || true == true; -true || false == true; -true || true == true; -``` - -### Negation: `not A` - -`not A` evaluates to the opposite (negation) of A: - -```blocks -!false == true; -!true == false; -``` - -### Example - -This example turns on LED `3 , 3`, if LEDs `1 , 1` and `2 , 2` are both on: - -```blocks -if (led.point(1,1) && led.point(2,2)) { - led.plot(3,3) -} -``` - -### Comparisons of numbers and strings - -When you compare two Numbers, you get a Boolean value, such as the comparison `x < 5` in the code below: - -```blocks -let x = Math.random(5) -if(x < 5) { - basic.showString("low"); -} else { - basic.showString("high"); -} -``` - -See the documentation on [Numbers](/reference/types/number) for more information on comparing two Numbers. You can also [compare strings](/reference/types/string-functions) using the `equals` function. - -### See also - -[if](/blocks/logic/if), [while](/blocks/loops/while), [number](/reference/types/number) - diff --git a/docs/blocks/logic/if.md b/docs/blocks/logic/if.md deleted file mode 100644 index d8755a88..00000000 --- a/docs/blocks/logic/if.md +++ /dev/null @@ -1,28 +0,0 @@ -# If - -### @parent blocks/language - - -Conditionally run code depending on whether a [Boolean](/blocks/logic/boolean) condition is true or false. - -```blocks -if(true) { -} -``` - -Click on the dark blue gear icon (see above) to add an *else* or *if* to the current block. - -### Example: adjusting screen brightness - -```blocks -if(input.lightLevel()<100){ - led.setBrightness(255); -} -``` - -If the [light level](/reference/input/light-level) is `< 100`, this code sets the brightness to `255`: - -### See also - -[while loop](/blocks/loops/while), [for](/blocks/loops/for), [boolean](/blocks/logic/boolean) - diff --git a/docs/blocks/loops.md b/docs/blocks/loops.md deleted file mode 100644 index a27c249e..00000000 --- a/docs/blocks/loops.md +++ /dev/null @@ -1,7 +0,0 @@ -# Loops - -```cards -for(let i = 0;i<5;i++) {} -while(true) {} -basic.forever(() => {}); -``` diff --git a/docs/blocks/loops/for.md b/docs/blocks/loops/for.md deleted file mode 100644 index 67fb7c00..00000000 --- a/docs/blocks/loops/for.md +++ /dev/null @@ -1,20 +0,0 @@ -# For - -### @parent blocks/language - -Run part of the program the number of times you say. - -### Example: Count to 4 - -This program will show the numbers 0, 1, 2, 3, and 4 one after another on the LED screen. - -```blocks -for(let i = 0; i < 5; ++i) { -basic.showNumber(i) -} -``` - -### See also - -[repeat](/blocks/loops/repeat), [while](/blocks/loops/while), [if](/blocks/logic/if), [show number](/reference/basic/show-number) - diff --git a/docs/blocks/loops/repeat.md b/docs/blocks/loops/repeat.md deleted file mode 100644 index a76c052f..00000000 --- a/docs/blocks/loops/repeat.md +++ /dev/null @@ -1,12 +0,0 @@ -# Repeat - -Run part of the program the number of times you say. - -### Block Editor - -![](/static/mb/blocks/contents-0.png) - -### See also - -[for](/blocks/loops/for), [while](/blocks/loops/while), [if](/blocks/logic/if), [show number](/reference/basic/show-number) - diff --git a/docs/blocks/loops/while.md b/docs/blocks/loops/while.md deleted file mode 100644 index 8f2c3b10..00000000 --- a/docs/blocks/loops/while.md +++ /dev/null @@ -1,29 +0,0 @@ -# While - -Repeat code while a [Boolean](/blocks/logic/boolean) `condition` is true. - -```blocks -while(true) { -} -``` - -The while loop has a *condition* that evaluates to a [Boolean](/blocks/logic/boolean) value. After the `do` keyword, add the code that you want to run while the `condition` is `true`. The while loop concludes with `end while`. - -The condition is tested before any code runs. Which means that if the condition is false, the code inside the loop doesn't execute. - -### Example: diagonal line - -The following example uses a while loop to make a diagonal line on the LED screen (points `0, 0`, `1, 1`, `2, 2`, `3, 3`, `4, 4`). - -```blocks -let index = 4; -while(index >= 0) { - led.plot(index, index); - index--; -} -``` - -### See also - -[on button pressed](/reference/input/on-button-pressed), [for](/blocks/loops/for), [if](/blocks/logic/if), [forever](/reference/basic/forever) - diff --git a/docs/blocks/math.md b/docs/blocks/math.md deleted file mode 100644 index 5d519004..00000000 --- a/docs/blocks/math.md +++ /dev/null @@ -1,36 +0,0 @@ -# Math - -### [Numeric](/reference/types/number) values: 0, 1, 2, ... - -```block -0; -1; -2; -``` - -### Arithmetic binary operation (+, -, *, /) - -```block -0+1; -0-1; -1*2; -3/4; -``` - -### Absolute value - -```block -Math.abs(-5); -``` - -### Minimum/maximum of two values - -```block -Math.min(0, 1); -``` - -### Random value - -```block -Math.random(5); -``` diff --git a/docs/blocks/variables.md b/docs/blocks/variables.md deleted file mode 100644 index 8009c744..00000000 --- a/docs/blocks/variables.md +++ /dev/null @@ -1,21 +0,0 @@ -# Variables - -[Assign](/blocks/variables/assign) (set) a variable's value - -```blocks -let x = 0; -``` - -Get a variable's value - -```blocks -let x = 0; -x; -``` - -[Change](/blocks/variables/change-var) a variable's value - -```blocks -let x = 0; -x+=1; -``` diff --git a/docs/blocks/variables/assign.md b/docs/blocks/variables/assign.md deleted file mode 100644 index 11375c09..00000000 --- a/docs/blocks/variables/assign.md +++ /dev/null @@ -1,36 +0,0 @@ -# Assignment Operator - -Use an equals sign to make a [variable](/blocks/variables/var) store the [number](/reference/types/number) -or [string](/reference/types/string) you say. - -When you use the equals sign to store something in a variable, the equals sign is called -an *assignment operator*, and what you store is called a *value*. - -### Storing numbers in variables - -This program makes the variable `item` equal `5` and then shows it on the [LED screen](/device/screen). - -````blocks -let item = 5 -basic.showNumber(item) -```` - -### Storing strings in variables - -This program makes the variable `name` equal `Joe` and then shows it on the [LED screen](/device/screen). - -````blocks -let name = "Joe" -basic.showString(name); -```` - -### Notes - -You can use the assignment operator with variables of -every [type](/reference/types). A *type* is which kind of thing -a variable can store, like a number or string. - -### See also - -[variable](/blocks/variables/var), [types](/reference/types) - diff --git a/docs/blocks/variables/change-var.md b/docs/blocks/variables/change-var.md deleted file mode 100644 index 8b79b4cd..00000000 --- a/docs/blocks/variables/change-var.md +++ /dev/null @@ -1,40 +0,0 @@ -# Change Value - -Set the value for local and global variables. - -### @parent blocks/change-value - -Change the value of a variable - -```blocks -let x = 0 -x += 1 -``` - -### Declare a variable - -Use the assignment operator to set the value of a [variable](/blocks/variables/var). Change the value of a variable from 0 to 1 using the change item block. Like this: - -```blocks -let x = 0 -x += 1 -``` - -### Example - -Use the assignment operator to set the value of a [variable](/blocks/variables/var). Change the value of a variable from 0 to 1 using the change item block. Then display the new value of the variable on the LED screen. Like this: - -```blocks -let x = 0; -x += 1; -basic.showNumber(x); -``` - -### Notes - -* You can use the assignment operator with variables of each of the supported [types](/reference/types). - -### See also - -[variable](/blocks/variables/var), [types](/reference/types) - diff --git a/docs/blocks/variables/var.md b/docs/blocks/variables/var.md deleted file mode 100644 index 443489b8..00000000 --- a/docs/blocks/variables/var.md +++ /dev/null @@ -1,87 +0,0 @@ -# Local Variables - -How to define and use local variables. - -### @parent language - -A variable is a place where you can store and retrieve data. Variables have a name, a [type](/reference/types), and value: - -* *name* is how you'll refer to the variable -* *type* refers to the kind of data a variable can store -* *value* refers to what's stored in the variable - -### Var statement - -Use the Block Editor variable statement to create a variable -and the [assignment operator](/blocks/variables/assign) -to store something in the variable. - -For example, this code stores the number `2` in the `x` variable: - -```blocks -let x = 2; -``` -Here's how to define a variable in the Block Editor: - -1. Click `variables`. - -2. Change the default variable name if you like. - -3. Drag a block type on the right-side of the [assignment operator](/blocks/variables/assign) and click the down arrow to change the variable name. - -A variable is created for the number returned by the [brightness](/reference/led/brightness) function. - -```blocks -let b = led.brightness(); -``` - -### Using variables - -Once you've defined a variable, just use the variable's name whenever you need what's stored in the variable. For example, the following code shows the value stored in `counter` on the LED screen: - -```blocks -let counter = 1; -basic.showNumber(counter); -``` - -To change the contents of a variable use the assignment operator. The following code sets `counter` to 1 and then increments `counter` by 10: - -```blocks -let counter = 1; -counter = counter + 10; -basic.showNumber(counter); -``` - -### Why use variables? - -If you want to remember and modify data, you'll need a variable. -A counter is a great example: - -```blocks -let counter = 0; -input.onButtonPressed(Button.A, () => { - counter = counter + 1; - basic.showNumber(counter); -}); -``` - -### Local variables - -Local variables exist only within the function or block of code where they're defined. For example: - -```blocks -// x does NOT exist here. -if (led.brightness() > 128) { - // x exists here - let x = 0; -} -``` - -#### Notes - -* You can use the default variable names if you'd like, however, it's best to use descriptive variable names. To change a variable name in the editor, select the down arrow next to the variable and then click "new variable". - -### See also - -[types](/reference/types), [assignment operator](/blocks/variables/assign) - diff --git a/docs/browsers.md b/docs/browsers.md deleted file mode 100644 index c8bece92..00000000 --- a/docs/browsers.md +++ /dev/null @@ -1,103 +0,0 @@ -# Unsupported configuration - -Your browser is currently not supported. The following configurations are supported: - -## Windows - -You need one of these browsers running on Windows 7, Windows 8, Windows 8.1, or -Windows 10: - -* Internet Explorer 11 -* Microsoft Edge -* Google Chrome -* Mozilla Firefox - -## Mac - -You need one of these browsers running on OS X 10.9 Mavericks, OS X 10.10 -Yosemite, OS X 10.11 El Capitan, or macOS 10.12 Sierra: - -* Safari -* Google Chrome -* Mozilla Firefox - -## Linux - -If you're using a Raspberry Pi, please see [the documentation -here](/raspberry-pi). - -You need to be running a Linux distribution recent enough to run the most recent -version of one of the following: - -* Google Chrome, or Chromium -* Mozilla Firefox, Iceweasel, or Seamonkey - -## How to check your OS or browser - -### Windows - -* Click on the Start menu -* Type 'System' -* Click on the app called 'System' -* The version of Windows you are using will be displayed: - -![](/static/configurations/windows-version.png) - -### Mac - -* Click on the Apple icon in the top left -* Click on 'About this Mac' -* This window will be displayed: - -![](/static/configurations/osx-version.png) - -### Internet Explorer - -* Click on the Settings icon in the top right -* Click 'About Internet Explorer' -* This window will be displayed: - -![](/static/configurations/ie-version.png) - -### Edge - -Edge automatically updates, so you should always be using the latest version - -* Click on the menu icon in the top right (three dots) -* Scroll to the bottom -* Information similar to the following will be displayed: - -![](/static/configurations/edge-version.png) - -### Google Chrome - -Google Chrome automatically updates, so you should always be using the latest version - -* Click on the menu icon in the top right (three dots) -* Click Help, and About Google Chrome -* Information similar to the following will be displayed: - -![](/static/configurations/chrome-version.png) - -### Firefox - -Firefox automatically updates, so you should always be using the latest version - -* Click on the menu icon in the top right (three horizontal lines) -* Click the question mark icon (help button) -* Click 'About Firefox' - -![](/static/configurations/firefox-version.png) - -### Safari - -Safari updates when your operating system updates, so if you are using the -latest version of OS X then you'll be using the latest version of Safari. - -* Click on the Safari menu in the top left -* Click 'About Safari' - -![](/static/configurations/safari-version.png) - -IT administrators should check which browser versions are supported -[here](/browsers/technical). diff --git a/docs/browsers/linux.md b/docs/browsers/linux.md deleted file mode 100644 index 87218dda..00000000 --- a/docs/browsers/linux.md +++ /dev/null @@ -1,16 +0,0 @@ -# Recommended browser for Linux - -As you are using Linux, it is recommended that you use [Mozilla -Firefox][firefox] or [Google Chrome][chrome]. - -Please see [here][technical] for technical information on which browsers are -supported, or [here][versions] to check which version you are using. - -[edge]: https://www.microsoft.com/en-us/windows/microsoft-edge -[ie]: https://www.microsoft.com/en-us/download/internet-explorer.aspx -[firefox]: https://www.mozilla.org/en-US/firefox/new/ -[chrome]: https://www.google.com/chrome/ -[opera]: https://www.opera.com -[safari]: http://www.apple.com/safari/ -[technical]: /browsers/technical -[versions]: /browsers diff --git a/docs/browsers/mac.md b/docs/browsers/mac.md deleted file mode 100644 index c1cb98fc..00000000 --- a/docs/browsers/mac.md +++ /dev/null @@ -1,16 +0,0 @@ -# Recommended browser for Mac - -As you are using a Mac, it is recommended that you use [Safari][]. Alternatively, -[Google Chrome][chrome] and [Mozilla Firefox][firefox] are also supported. - -Please see [here][technical] for technical information on which browsers are -supported, or [here][versions] to check which version you are using. - -[edge]: https://www.microsoft.com/en-us/windows/microsoft-edge -[ie]: https://www.microsoft.com/en-us/download/internet-explorer.aspx -[firefox]: https://www.mozilla.org/en-US/firefox/new/ -[chrome]: https://www.google.com/chrome/ -[opera]: https://www.opera.com -[safari]: http://www.apple.com/safari/ -[technical]: /browsers/technical -[versions]: /browsers diff --git a/docs/browsers/technical.md b/docs/browsers/technical.md deleted file mode 100644 index adc4dbe4..00000000 --- a/docs/browsers/technical.md +++ /dev/null @@ -1,36 +0,0 @@ -# Technical information about browser support - -[pxt.microbit.org][] requires that you use a recent version of a modern -browser, such as Microsoft Edge, Google Chrome, Mozilla Firefox, Safari, Opera, -or IE11. This is because the editor uses modern web technologies such as [web -workers][] to enable compiling [TypeScript][] in the browser, or the using the -same [Monaco][] editor that powers [Visual Studio Code][]. - -[pxt.microbit.org]: https://pxt.microbit.org -[web workers]: http://www.w3.org/TR/workers/ -[typescript]: http://www.typescriptlang.org -[monaco]: https://microsoft.github.io/monaco-editor/ -[visual studio code]: http://code.visualstudio.com - -Most modern browsers automatically update themselves, but in some environments -such as schools these automatic updates are disabled for security. **We -strongly recommend that you use the most recent version of any of these -browsers**, but if you can't then you must use at least: - -| Browser | Minimum version | Release date | Windows | Mac | -| ----------------- | --------------- | -------------- | ----------- | ---------- | -| Edge | 12 | March 2015 | Windows 10+ | N/A | -| Internet Explorer | 11 | October 2013 | Windows 7+ | N/A | -| Mozilla Firefox | 31 ESR | July 2014 | Windows XP+ | OS X 10.6+ | -| Google Chrome | 38 | October 2014 | Windows XP+ | OS X 10.6+ | -| Safari | 9 | September 2015 | N/A | OS X 10.9+ | -| Opera | 21 | May 2014 | Windows 7+ | OS X 10.9+ | - - -Please see our information for which browsers are recommended for [Windows][], -[Mac][], [Linux][], or [Raspberry Pi][]. - -[Windows]: /browsers/windows -[Mac]: /browsers/mac -[Linux]: /browsers/linux -[Raspberry Pi]: /raspberry-pi diff --git a/docs/browsers/windows.md b/docs/browsers/windows.md deleted file mode 100644 index 6996a04a..00000000 --- a/docs/browsers/windows.md +++ /dev/null @@ -1,18 +0,0 @@ -# Recommended browser for Windows - -We recommend [Microsoft Edge][edge] if you are running Windows 10, but users on -Windows 7 or higher can use [Internet Explorer 11][ie] or recent versions of -[Mozilla Firefox][firefox], [Google Chrome][chrome], or [Opera][opera]. - - -Please see [here][technical] for technical information on which browsers are -supported, or [here][versions] to check which version you are using. - -[edge]: https://www.microsoft.com/en-us/windows/microsoft-edge -[ie]: https://www.microsoft.com/en-us/download/internet-explorer.aspx -[firefox]: https://www.mozilla.org/en-US/firefox/new/ -[chrome]: https://www.google.com/chrome/ -[opera]: https://www.opera.com -[safari]: http://www.apple.com/safari/ -[technical]: /browsers/technical -[versions]: /browsers diff --git a/docs/calliope/examples.md b/docs/calliope/examples.md new file mode 100644 index 00000000..c5bb910e --- /dev/null +++ b/docs/calliope/examples.md @@ -0,0 +1,17 @@ +# Projects + +Here are some cool tutorials to get you started with your @boardname@! + +## Basic + +```codecard +[ +{ + "name": "Radio Bridge", + "description": "Send radio messages to editor", + "url": "/projects/radio-bridge", + "imageUrl": "/static/mb/projects/radio-bridge.png", + "cardType": "example" +} +] +``` \ No newline at end of file diff --git a/docs/calliope/experiment/remoteCar.jpg b/docs/calliope/experiment/remoteCar.jpg new file mode 100644 index 00000000..b5d3b5bf Binary files /dev/null and b/docs/calliope/experiment/remoteCar.jpg differ diff --git a/docs/calliope/experiment/remoteCar_L.jpg b/docs/calliope/experiment/remoteCar_L.jpg new file mode 100644 index 00000000..c16fc17e Binary files /dev/null and b/docs/calliope/experiment/remoteCar_L.jpg differ diff --git a/docs/calliope/firststeps.md b/docs/calliope/firststeps.md new file mode 100644 index 00000000..33529b6f --- /dev/null +++ b/docs/calliope/firststeps.md @@ -0,0 +1,110 @@ +# Projects + +Here are some cool tutorials to get you started with your @boardname@! + +## Basic + +```codecard +[ + { + "name": "Get Ready", + "url":"/calliope/firststeps/firstSteps", + "description": "Find out how to start working with the Calliope mini", + "imageUrl": "/docs/calliope/firststeps/connecting.jpg", + "largeImageUrl": "/docs/calliope/firststeps/firstSteps.jpg", + "cardType": "tutorial", + "label": "Never seen a mini? Start Here!", + "labelClass": "green small ribbon" +}, +{ + "name": "The 5x5 LED matrix", + "url":"/calliope/firststeps/5x5LED", + "description": "Learn how to create and show images, numbers or letters on the LED matrix", + "imageUrl": "/docs/calliope/firststeps/5x5LED.jpg", + "largeImageUrl": "/docs/calliope/firststeps/5x5LED_L.jpg", + "cardType": "tutorial", + "label": "New? Start Here!", + "labelClass": "yellow small ribbon" +}, +{ + "name": "Radio", + "url":"/calliope/firststeps/Radio", + "description": "Find out how to use the radion function and how to send messages from one Calliope mini to another one", + "imageUrl": "/docs/calliope/firststeps/Radio.jpg", + "largeImageUrl": "/docs/calliope/firststeps/Radio_L.jpg", + "cardType": "tutorial", + "label": "", + "labelClass": "orange small ribbon" +}, +{ + "name": "Loops", + "url":"/calliope/firststeps/Loops", + "description": "Loops are important to be able to execute program instructions multiple times", + "imageUrl": "/docs/calliope/firststeps/Loops.jpg", + "largeImageUrl": "/docs/calliope/firststeps/Loops_L.jpg", + "cardType": "tutorial", + "label": "", + "labelClass": "green small ribbon" +}, +{ + "name": "Mathematics", + "url":"/calliope/firststeps/Mathematics", + "description": "The Calliope mini can become your little math helper", + "imageUrl": "/docs/calliope/firststeps/Mathematics.jpg", + "largeImageUrl": "/docs/calliope/firststeps/Mathematics_L.jpg", + "cardType": "tutorial", + "label": "", + "labelClass": "green small ribbon" +}, +{ + "name": "Inputs", + "url":"/calliope/firststeps/Inputs", + "description": "Use conditions for different actions", + "imageUrl": "/docs/calliope/firststeps/Inputs.jpg", + "largeImageUrl": "/docs/calliope/firststeps/Inputs_L.jpg", + "cardType": "tutorial", + "label": "", + "labelClass": "green small ribbon" +}, +{ + "name": "Sensors", + "url":"/calliope/firststeps/Sensors", + "description": "Measure temperature, light and orientation", + "imageUrl": "/docs/calliope/firststeps/Sensors.jpg", + "largeImageUrl": "/docs/calliope/firststeps/Sensors_L.jpg", + "cardType": "tutorial", + "label": "", + "labelClass": "green small ribbon" +}, +{ + "name": "Output", + "url":"/calliope/firststeps/Output", + "description": "Audio, light and motion", + "imageUrl": "/docs/calliope/firststeps/Output.jpg", + "largeImageUrl": "/docs/calliope/firststeps/Output_L.jpg", + "cardType": "tutorial", + "label": "", + "labelClass": "green small ribbon" +}, +{ + "name": "Decisions", + "url":"/calliope/firststeps/Decisions", + "description": "If..., then it happens... or it happens...", + "imageUrl": "/docs/calliope/firststeps/Decisions.jpg", + "largeImageUrl": "/docs/calliope/firststeps/Decisions_L.jpg", + "cardType": "tutorial", + "label": "", + "labelClass": "green small ribbon" +}, +{ + "name": "Variables", + "url":"/calliope/firststeps/Variables", + "description": "A variable is not a static value, it’s what you determine it to be.", + "imageUrl": "/docs/calliope/firststeps/Variables.jpg", + "largeImageUrl": "/docs/calliope/firststeps/Variables_L.jpg", + "cardType": "tutorial", + "label": "", + "labelClass": "green small ribbon" +} +] +``` \ No newline at end of file diff --git a/docs/calliope/firststeps/5x5LED.jpg b/docs/calliope/firststeps/5x5LED.jpg new file mode 100644 index 00000000..e8c1811a Binary files /dev/null and b/docs/calliope/firststeps/5x5LED.jpg differ diff --git a/docs/calliope/firststeps/5x5LED.md b/docs/calliope/firststeps/5x5LED.md new file mode 100644 index 00000000..8c11ff11 --- /dev/null +++ b/docs/calliope/firststeps/5x5LED.md @@ -0,0 +1,58 @@ +# ERSTE SCHRITTE: The 5X5 LED MATRIX + +## Introduction @unplugged + +Amongst other things, the Calliope mini comes with 25 red LEDs that can be turned on and off individually. If, for example, you wanted to display your name, you could program individual LEDs to light up in sequence so as to display the letters of your name one after the other. As this would be rather complex, you can also enter the character string into a text field and the Calliope Mini will light up the necessary LEDs in the correct order for you. + +## Step 1 @fullscreen + + +### DISPLAYING A CHARACTER STRING +To show your chosen sting of characters on the LED matrix, select the show string block from the Basic menu. Next, drag and attach this block to the Start block in the main screen. The text contained within the inverted commas will now be displayed on the Calliope mini when the program is started. + +```blocks +basic.showString("hi!") +``` + +## Step 2 @fullscreen + +### DISPLAYING NUMBERS +If you’d prefer to show a number instead of text, replace the text block in the main screen with the show number block from the Basic menu. + +```blocks +basic.showNumber(0) +``` + +## Step 3 @fullscreen + +### DISPLAYING IMAGES +To display a heart, a smiley or even a duck on your Calliope mini, Choose the show iconn block from the Basic menu and select any number of different images by simply clicking on the picture in the block. + +```blocks +basic.showIcon(IconNames.Heart) +``` + +## Step 4 @fullscreen + +You can also create your very own images: +Just select this block from the Basic menu and click in the boxes to create your very own image. + +```blocks +basic.showLeds(` + . . . . . + . . . . . + . . . . . + . . . . . + . . . . . + `) +``` + +## Step 4 @fullscreen + +Wenn du keine Pause zwischen 2 Bildern festlegst, zeigt der Calliope mini das erste Bild null Sekunden lang, also gar nicht. Den Warte ms Block findest du im Menü Kontrolle. + +```blocks +basic.showIcon(IconNames.Heart) +basic.pause(100) +basic.showIcon(IconNames.Yes) +``` \ No newline at end of file diff --git a/docs/calliope/firststeps/5x5LED_L.jpg b/docs/calliope/firststeps/5x5LED_L.jpg new file mode 100644 index 00000000..d1418c5d Binary files /dev/null and b/docs/calliope/firststeps/5x5LED_L.jpg differ diff --git a/docs/calliope/firststeps/Decisions.jpg b/docs/calliope/firststeps/Decisions.jpg new file mode 100644 index 00000000..f9fffcc8 Binary files /dev/null and b/docs/calliope/firststeps/Decisions.jpg differ diff --git a/docs/calliope/firststeps/Decisions.md b/docs/calliope/firststeps/Decisions.md new file mode 100644 index 00000000..4f725d1f --- /dev/null +++ b/docs/calliope/firststeps/Decisions.md @@ -0,0 +1,23 @@ +# ERSTE SCHRITTE: DAS 5X5 LED RASTER + +## Introduction @unplugged + +Options within a program can be made dependent not only on inputs, but also on other conditions. For example, you can create an oracle that randomly shows a sad or a happy smiley: + +## Step 1 @fullscreen + +### If – then do relationship +The actions below the "then“ are only executed if the condition before is fulfilled. +In this case, the heart will not be visible on the LED grid, as the decision variable is not equal to 1. You can find the if…then block in the Logic section. + +## Step 2 @fullscreen + +### And on we go +After the if…then block the program continues in any case, no matter whether the condition was fulfilled before or not. + +## Step 3 @fullscreen + +### If – then – else +If you expand the if…then block, the first if condition is checked first, if it is not fulfilled the second if condition is checked. Only those actions are triggered for which the associated condition is fulfilled. + +Click on the + on the bottom of the block to unfold the if…then block. The probability to display either a happy or a sad smiley on the LED grid is 50/50. \ No newline at end of file diff --git a/docs/calliope/firststeps/Decisions_L.jpg b/docs/calliope/firststeps/Decisions_L.jpg new file mode 100644 index 00000000..9e27aa63 Binary files /dev/null and b/docs/calliope/firststeps/Decisions_L.jpg differ diff --git a/docs/calliope/firststeps/Inputs.jpg b/docs/calliope/firststeps/Inputs.jpg new file mode 100644 index 00000000..e1fa5b7d Binary files /dev/null and b/docs/calliope/firststeps/Inputs.jpg differ diff --git a/docs/calliope/firststeps/Inputs.md b/docs/calliope/firststeps/Inputs.md new file mode 100644 index 00000000..0ad9255d --- /dev/null +++ b/docs/calliope/firststeps/Inputs.md @@ -0,0 +1,32 @@ +# FIRST STEPS: INPUTS + +## Introduction @unplugged + +So far all the programmed text, numbers and images have been displayed on the LED matrix immediately after being loaded onto the Calliope mini. However, if you would prefer to have an event take place after a specific input, you need to use the one of the main blocks from the Input section. In this case we are using the "on button A pressed“ block. By using this block, the Calliope mini will wait until your chosen condition is met before anything is displaying. + +## Step 1 @fullscreen + +### Buttons +The Calliope mini has two input buttons: Button A (in red) and Button B (in blue). When one of the buttons is pressed, the circuit is completed. +By using the "on button A pressed“ block from Input, you can display your output as soon as button A has been pressed. + +## Step 2 @fullscreen + +### Shake +You can request the position and movement of the Calliope mini and run an action once a change of the values has been detected. +Use the "on shake“ block from the Input section. Add an "show string Hi!" block from the Basic section and change the content of the string.Your text will be displayed when you shake the Calliope mini. The gesture can be changed by using the dropdown menu to choose the condition. + +## Step 3 @fullscreen + +### Pins +The Calliope mini has five rounded corners: -, +, 0 , 1, 2, and 3. If you place one finger on the – corner and another finger on one of the numbered corners, a small electrical current will flow through your body and back to the Calliope mini, thus closing the electrical circuit. + +Use the „on pin Pin0 pressed" block from Input. Use the "show string Hi!" block from the basic section. +Your text will be displayed when pin – and pin 0 are both pressed at the same time. + +## Step 4 @fullscreen + +### Various input +You can program the Calliope mini to respond to more than one input. There are two possible ways of doing this: +You can use indiviual events separated from each other with different actions to run after that condition is met. +Nevertheless, you can also use an "if" or "while" condition (from the Logic and Loops sections) and wait for your inputs to be met. \ No newline at end of file diff --git a/docs/calliope/firststeps/Inputs_L.jpg b/docs/calliope/firststeps/Inputs_L.jpg new file mode 100644 index 00000000..afe6e3b3 Binary files /dev/null and b/docs/calliope/firststeps/Inputs_L.jpg differ diff --git a/docs/calliope/firststeps/Loops.jpg b/docs/calliope/firststeps/Loops.jpg new file mode 100644 index 00000000..0a0f3fa1 Binary files /dev/null and b/docs/calliope/firststeps/Loops.jpg differ diff --git a/docs/calliope/firststeps/Loops.md b/docs/calliope/firststeps/Loops.md new file mode 100644 index 00000000..2ea6c349 --- /dev/null +++ b/docs/calliope/firststeps/Loops.md @@ -0,0 +1,18 @@ +# FIRST STEPS: LOOPS + +## Introduction @unplugged + +As you may have noticed in previous exercises, your program was executed only once by Calliope mini. To change this, you can use loops. Use an infinite loop so that the text runs over the LED grid of your Calliope mini infinitely often. + +## Step 1 @fullscreen + +### Infinite loop +The simplest way is to use a foverever block, from the basic section. +Everything inside will be repeated forever. + +## Step 2 @fullscreen + +Of course, you can also specify how often something should be repeated: + +### Repeat block +Use the „on start“ block or any other block that usually initiates a one time cycle. Take the "Repeat 4 times" block from the Loops section and enter the desired number in the number field. Whatever task is within this block will be executed for the number of times you entered within the “Repeat …“ number. \ No newline at end of file diff --git a/docs/calliope/firststeps/Loops_L.jpg b/docs/calliope/firststeps/Loops_L.jpg new file mode 100644 index 00000000..aaafe16f Binary files /dev/null and b/docs/calliope/firststeps/Loops_L.jpg differ diff --git a/docs/calliope/firststeps/Mathematics.jpg b/docs/calliope/firststeps/Mathematics.jpg new file mode 100644 index 00000000..28555272 Binary files /dev/null and b/docs/calliope/firststeps/Mathematics.jpg differ diff --git a/docs/calliope/firststeps/Mathematics.md b/docs/calliope/firststeps/Mathematics.md new file mode 100644 index 00000000..199aaf23 --- /dev/null +++ b/docs/calliope/firststeps/Mathematics.md @@ -0,0 +1,17 @@ +# FIRST STEPS: MATHEMATICS + +## Introduction @unplugged + +Calliope mini offers you the possibility to use different mathematical operations. You can calculate numbers, create random numbers and save your results in variables. + +## Step 1 @fullscreen + +### Calculation of numbers +The Calliope mini is able to perform the 4 basic arithmetic operations addition, subtraction, multiplication and division out of the box: + +You can find the required block in the menu Math. From the block's drop-down list you can choose between the four basic arithmetic operations and the exponentiation. To see the result of your calculation, you have to put the block inside a „show number" block from the Basic section. The Calliope mini displays the result of your calculation on the LED grid. + +## Step 2 @fullscreen + +### Random numbers +You can have Calliope mini create a random number: You can find the corresponding block in the menu Math ("pick random 0 to 10"). By changing the two numbers within the block, you determine how small or how large the random number is allowed to become. \ No newline at end of file diff --git a/docs/calliope/firststeps/Mathematics_L.jpg b/docs/calliope/firststeps/Mathematics_L.jpg new file mode 100644 index 00000000..200a530a Binary files /dev/null and b/docs/calliope/firststeps/Mathematics_L.jpg differ diff --git a/docs/calliope/firststeps/Output.jpg b/docs/calliope/firststeps/Output.jpg new file mode 100644 index 00000000..e2e89602 Binary files /dev/null and b/docs/calliope/firststeps/Output.jpg differ diff --git a/docs/calliope/firststeps/Output.md b/docs/calliope/firststeps/Output.md new file mode 100644 index 00000000..a18779cb --- /dev/null +++ b/docs/calliope/firststeps/Output.md @@ -0,0 +1,23 @@ +# ERSTE SCHRITTE: DAS 5X5 LED RASTER + +## Introduction @unplugged + +As well as the red LED matrix the Calliope mini also has a built-in loudspeaker (or piezo speaker to be more precise) that allows you to play different tones and an LED with which you can display a huge variety of different colours. + +## Step 1 @fullscreen + +### The RGB-LED +The white square under the LED matrix is the RGB-LED. Itworks in exactly the same way as watercolours do. Within this LED there are three smaller LEDs: one red, one green and one blue. When you select a colour in your programming environment, the Calliope mini will automatically display this colour by mixing the three base colours together, + +Within the Basic section you select the "set led to red“ block and + +## Step 2 @fullscreen + +### Light sensor +The light is measured by the LED matrix. You can select the light sensor by dragging the block from the Input section into the number block. With this block you can change the colour you want to display. Simply click on the red tap and choose another colour from the menu. +To turn the LED off, you can use the "turn build-in led off“ block or put the value "0“ on the name of the color. + +## Step 3 @fullscreen + +### The speaker +You can play individual notes or music pieces. Simply open the Music section and drag the "play tone 262 Hz for 1 beat“ and chance the value of the tone to see how you can adjust the height of the note. \ No newline at end of file diff --git a/docs/calliope/firststeps/Output_L.jpg b/docs/calliope/firststeps/Output_L.jpg new file mode 100644 index 00000000..cdb39714 Binary files /dev/null and b/docs/calliope/firststeps/Output_L.jpg differ diff --git a/docs/calliope/firststeps/Radio.jpg b/docs/calliope/firststeps/Radio.jpg new file mode 100644 index 00000000..7badc11b Binary files /dev/null and b/docs/calliope/firststeps/Radio.jpg differ diff --git a/docs/calliope/firststeps/Radio.md b/docs/calliope/firststeps/Radio.md new file mode 100644 index 00000000..f7a6991b --- /dev/null +++ b/docs/calliope/firststeps/Radio.md @@ -0,0 +1,25 @@ +# FIRST STEPS: RADIO + +## Introduction @unplugged + +There is a Radio module built into the Calliope Mini. This allows for several Calliope mini to communicate with each other and transmit information. To try this out yourself, you will need at least two Calliope mini. + + +## Step 1 @fullscreen + +### Allocating a channel +Firstly you must decide on a channel to use. Only those Calliope mini that are using the same channel will be able to exchange messages with each other. A Calliope mini will not be able to transmit or receive over several channels at the same time. To be able to send information, you must open the radio block and use the radio set group block. +Please ensure that the channel number you select is between 0 and 255. + +## Step 2 @fullscreen + +### Sending a message +To send a message you should select the "radio send string“ block. Now you can enter the string that will be sent on the channel. + +## Step 3 @fullscreen + +###Receive a message +Set the same channel as on the sending Calliope mini one. +Use the "on radio received receivedString“ block to look for data. +Include the "show string receivedString“ inside. +Let’s try with two (or more) Calliope mini! \ No newline at end of file diff --git a/docs/calliope/firststeps/Radio_L.jpg b/docs/calliope/firststeps/Radio_L.jpg new file mode 100644 index 00000000..a4bf4d78 Binary files /dev/null and b/docs/calliope/firststeps/Radio_L.jpg differ diff --git a/docs/calliope/firststeps/Sensors.jpg b/docs/calliope/firststeps/Sensors.jpg new file mode 100644 index 00000000..5c54b723 Binary files /dev/null and b/docs/calliope/firststeps/Sensors.jpg differ diff --git a/docs/calliope/firststeps/Sensors.md b/docs/calliope/firststeps/Sensors.md new file mode 100644 index 00000000..18bcc570 --- /dev/null +++ b/docs/calliope/firststeps/Sensors.md @@ -0,0 +1,30 @@ +# ERSTE SCHRITTE: DAS 5X5 LED RASTER + +## Introduction @unplugged + +The Calliope mini is equipped with a number of sensors: It has a temperature sensor, a light sensor, a compass as well as a microphone. + +## Step 1 @fullscreen + +### Displaying sensor data +In order to display data from your sensors on the Calliope mini’s LED matrix, you need to select a sensor (value). To do so go to the Basic section and select the "show number 0“ block. Within the number you can now change the "0“ to the value of a sensor. + +## Step 2 @fullscreen + +### Acceleration sensor +You can select the acceleration values by dragging the block from the Input section and place it on top of the "0“ (which will disappear). + +## Step 3 @fullscreen + +### Light sensor +The light is measured by the LED matrix. You can select the light sensor by dragging the block from the Input section into the number block. + +## Step 4 @fullscreen + +### Compass +The built in magnetometer allows the Calliope mini to tell in which direction it is facing. This sensor will provide a value between 0 and 360 degrees. The compass will need to be calibrated before use. Follow the instructions on the Calliope mini and tilt it in a circular fashion to display a complete circle. You can start using it by dragging the block from the Input section into the number block. + +## Step 4 @fullscreen + +### Temperature sensor +You can select the temperature sensor by dragging the block from the Input section into the number block. \ No newline at end of file diff --git a/docs/calliope/firststeps/Sensors_L.jpg b/docs/calliope/firststeps/Sensors_L.jpg new file mode 100644 index 00000000..29d19201 Binary files /dev/null and b/docs/calliope/firststeps/Sensors_L.jpg differ diff --git a/docs/calliope/firststeps/Variables.jpg b/docs/calliope/firststeps/Variables.jpg new file mode 100644 index 00000000..c0dbbc8b Binary files /dev/null and b/docs/calliope/firststeps/Variables.jpg differ diff --git a/docs/calliope/firststeps/Variables.md b/docs/calliope/firststeps/Variables.md new file mode 100644 index 00000000..373c4624 --- /dev/null +++ b/docs/calliope/firststeps/Variables.md @@ -0,0 +1,20 @@ +# ERSTE SCHRITTE: DAS 5X5 LED RASTER + +## Introduction @unplugged + +As in a football match, where the number of goals scored during the match can change, the value of a variable can also change during a running program. + +By clicking on the Variables section and then on the "Make a variable…“ button within this section you will generate a new variable. Now you can determine the name. + +## Step 1 @fullscreen + +By clicking on the Variables section and then on the "Make a variable…“ button within this section you will generate a new variable. Now you can determine the name. + +## Step 2 @fullscreen + +You can find a separate block for each variable, which you can use to display its value on the LED grid of Calliope mini by selecting the "show number 0“ block and use the "set variable to 0“ block from the Variables section and add this on a line before. if you change this number, the number on the grid will change accordingly. + +## Step 3 @fullscreen + +### Count your score +By combining what you have learned so far, you can program a simple score counter: When button A is pressed, the number of goals variable is increased by one numerical value and then displayed. Have a try! \ No newline at end of file diff --git a/docs/calliope/firststeps/Variables_L.jpg b/docs/calliope/firststeps/Variables_L.jpg new file mode 100644 index 00000000..0ea69185 Binary files /dev/null and b/docs/calliope/firststeps/Variables_L.jpg differ diff --git a/docs/calliope/firststeps/connecting.jpg b/docs/calliope/firststeps/connecting.jpg new file mode 100644 index 00000000..9ea754eb Binary files /dev/null and b/docs/calliope/firststeps/connecting.jpg differ diff --git a/docs/calliope/firststeps/firstSteps.jpg b/docs/calliope/firststeps/firstSteps.jpg new file mode 100644 index 00000000..b0c6276d Binary files /dev/null and b/docs/calliope/firststeps/firstSteps.jpg differ diff --git a/docs/calliope/firststeps/firstSteps.md b/docs/calliope/firststeps/firstSteps.md new file mode 100644 index 00000000..111f8ff0 --- /dev/null +++ b/docs/calliope/firststeps/firstSteps.md @@ -0,0 +1,61 @@ +# First Steps + +## Introduction @unplugged + +### 1) Connecting + +Connect your mini to your computer via a micro USB cable or Bluetooth. Macs, PCs, Chromebooks, Linux systems, Smartphones and Tablets are supported. + +Your Calliope mini will show up on your computer as a drive called 'MINI'. + +Open your favourite browser and head to our website and select Editor in the main navigation. + +For example drag and drop some blocks and try your program on the Simulator within the editor. + +Click the Download button in the editor. This will download a 'hex' file, which is a compact format of your program that your mini can read. Once the file has been downloaded, just copy it to your Calliope mini just like copying a file to a USB stick. + +![Connecting Image](/docs/calliope/firststeps/connecting.jpg) + + +## Introduction @unplugged + +### 2) Power it Up + +The Calliope mini requires a power source to work. You can either connect your Calliope mini directly to a computer using a Micro USB cable or you can power it using a battery pack. +Here are the instructions on how to connect the battery pack to your Calliope mini: + +The supplied battery pack requires two AAA batteries. + +Carefully insert the small white plastic connector from the battery pack into the board’s battery socket. + +Be careful to insure that the ridge on the plug is facing upwards. + +If the plug slides easily into the socket then you are attaching it correctly. Otherwise, turn the plug round and re-insert it into the socket. Slide it to "on“ and your Calliope mini is powered by the batteries. + +![Powering Image](/docs/calliope/firststeps/powerItUp.png) + + +## Introduction @unplugged + +### 3) Play! + +You can now play arround or try some of our other guided first-steps tutorials... + +[Learn how to write your name on the LED-Matrix](#tutorial:/calliope/firststeps/5x5LED) + +[Play with colors and sound](#tutorial:/calliope/firststeps/Output) + +[See how to Controll your mini with the buttons and pins](#tutorial:/calliope/firststeps/Inputs) + + +## Step 1 + +Play! + +You can now play arround or try some of our other guided first-steps tutorials... + +[Learn how to write your name on the LED-Matrix](#tutorial:/calliope/firststeps/5x5LED) + +[Play with colors and sound](#tutorial:/calliope/firststeps/Output) + +[See how to Controll your mini with the buttons and pins](#tutorial:/calliope/firststeps/Inputs) \ No newline at end of file diff --git a/docs/calliope/firststeps/powerItUp.png b/docs/calliope/firststeps/powerItUp.png new file mode 100644 index 00000000..4efa97d7 Binary files /dev/null and b/docs/calliope/firststeps/powerItUp.png differ diff --git a/docs/calliope/links.md b/docs/calliope/links.md new file mode 100644 index 00000000..5232eeaf --- /dev/null +++ b/docs/calliope/links.md @@ -0,0 +1,47 @@ +# Projects + +Here are some cool tutorials to get you started with your @boardname@! + +## Basic + +```codecard +[ +{ + "name": "Shop", + "url":"https://shop.calliope.cc", + "description": "You can get the mini at the official calliope store.", + "imageUrl": "/docs/calliope/links/thumbnail_shop.gif", + "largeImageUrl": "", + "label": "", + "buttonLabel": "Open Calliope Shop", + "labelClass": "green small ribbon" +}, { + "name": "Projects", + "url":"https://calliope.cc/en/projekte", + "description": "A collection of calliope mini projects", + "imageUrl": "/docs/calliope/links/thumbnail_projects.gif", + "largeImageUrl": "", + "label": "", + "buttonLabel": "View Projects", + "labelClass": "green small ribbon" +}, { + "name": "Teaching materials", + "url":"https://calliope.cc/schulen/schulmaterial", + "description": "", + "imageUrl": "/docs/calliope/links/thumbnail_didactic_material.gif", + "largeImageUrl": "", + "label": "", + "buttonLabel": "View", + "labelClass": "green small ribbon" +}, { + "name": "Forum", + "url":"https://forum.calliope.cc", + "description": "Be a part of our comunity", + "imageUrl": "/docs/calliope/links/thumbnail_community.gif", + "largeImageUrl": "", + "label": "", + "buttonLabel": "Open Forum", + "labelClass": "green small ribbon" +} +] +``` \ No newline at end of file diff --git a/docs/calliope/links/thumbnail_community.gif b/docs/calliope/links/thumbnail_community.gif new file mode 100644 index 00000000..17a03b95 Binary files /dev/null and b/docs/calliope/links/thumbnail_community.gif differ diff --git a/docs/calliope/links/thumbnail_didactic_material.gif b/docs/calliope/links/thumbnail_didactic_material.gif new file mode 100644 index 00000000..89a60bfb Binary files /dev/null and b/docs/calliope/links/thumbnail_didactic_material.gif differ diff --git a/docs/calliope/links/thumbnail_projects.gif b/docs/calliope/links/thumbnail_projects.gif new file mode 100644 index 00000000..2ce6cfc0 Binary files /dev/null and b/docs/calliope/links/thumbnail_projects.gif differ diff --git a/docs/calliope/links/thumbnail_shop.gif b/docs/calliope/links/thumbnail_shop.gif new file mode 100644 index 00000000..3930e9e2 Binary files /dev/null and b/docs/calliope/links/thumbnail_shop.gif differ diff --git a/docs/calliope/tutorials.md b/docs/calliope/tutorials.md new file mode 100644 index 00000000..8e68f97a --- /dev/null +++ b/docs/calliope/tutorials.md @@ -0,0 +1,74 @@ +# Projects + +Here are some cool tutorials to get you started with your @boardname@! + +## Basic + +```codecard +[{ + "name": "Flashing Heart", + "url":"/projects/flashing-heart", + "description": "Make an animated flashing heart.", + "imageUrl": "/docs/calliope/tutorials/01_flashing_heart.gif", + "largeImageUrl": "", + "cardType": "tutorial", + "label": "", + "labelClass": "purple ribbon large" +}, { + "name": "Name Tag", + "description": "Scroll your name on the screen", + "imageUrl": "/docs/calliope/tutorials/02_nametag.gif", + "url": "/projects/name-tag", + "cardType": "tutorial" +}, { + "name": "Smiley Buttons", + "url":"/projects/smiley-buttons", + "description": "Show different smiley images by pressing the buttons.", + "imageUrl": "/docs/calliope/tutorials/03_smiley_button.gif", + "largeImageUrl": "", + "cardType": "tutorial" +}, { + "name": "Dice", + "url":"/projects/dice", + "description": "Shake the dice and see what number comes up!", + "imageUrl": "/docs/calliope/tutorials/04_dice.gif", + "cardType": "tutorial" +}, { + "name": "Love Meter", + "url":"/projects/love-meter", + "description": "The @boardname@ is feeling the love, see how much!", + "imageUrl":"/docs/calliope/tutorials/05_love_meter.gif", + "cardType": "tutorial" +}, { + "name": "Mini Chat", + "url":"/projects/mini-chat", + "description": "Build your own social network made of minis.", + "imageUrl": "/docs/calliope/tutorials/06_mini_chat.gif", + "cardType": "tutorial" +}, { + "name": "Rock Paper Scissors", + "url":"/projects/rock-paper-scissors", + "description": "Make the Rock-Paper-Scissors game on your @boardname@ and challenge your friends.", + "imageUrl":"/docs/calliope/tutorials/07_stone_paper_scissors.gif", + "cardType": "tutorial" +}, { + "name": "Coin Flipper", + "url":"/projects/coin-flipper", + "description": "Guess the coin toss and see if you're lucky.", + "imageUrl": "/docs/calliope/tutorials/08_coin_flipper.gif", + "cardType": "tutorial" +}, { + "name": "Snap the dot", + "url": "/projects/snap-the-dot", + "description": "Use the game blocks to create a skill game", + "imageUrl": "/docs/calliope/tutorials/09_snap_the_dot.gif", + "cardType": "tutorial" +}, { + "name": "Multi Dice", + "url": "/projects/multi-dice", + "description": "Compete with multiple dices", + "imageUrl": "/docs/calliope/tutorials/10_multi_dice.gif", + "cardType": "tutorial" +} +] +``` \ No newline at end of file diff --git a/docs/calliope/tutorials/01_flashing_heart.gif b/docs/calliope/tutorials/01_flashing_heart.gif new file mode 100644 index 00000000..b69cfb81 Binary files /dev/null and b/docs/calliope/tutorials/01_flashing_heart.gif differ diff --git a/docs/calliope/tutorials/01_flashing_heart_animation.gif b/docs/calliope/tutorials/01_flashing_heart_animation.gif new file mode 100644 index 00000000..4660572a Binary files /dev/null and b/docs/calliope/tutorials/01_flashing_heart_animation.gif differ diff --git a/docs/calliope/tutorials/02_nametag.gif b/docs/calliope/tutorials/02_nametag.gif new file mode 100644 index 00000000..76777393 Binary files /dev/null and b/docs/calliope/tutorials/02_nametag.gif differ diff --git a/docs/calliope/tutorials/02_nametag_animation.gif b/docs/calliope/tutorials/02_nametag_animation.gif new file mode 100644 index 00000000..a5eb2f77 Binary files /dev/null and b/docs/calliope/tutorials/02_nametag_animation.gif differ diff --git a/docs/calliope/tutorials/03_smiley_button.gif b/docs/calliope/tutorials/03_smiley_button.gif new file mode 100644 index 00000000..c5e7c955 Binary files /dev/null and b/docs/calliope/tutorials/03_smiley_button.gif differ diff --git a/docs/calliope/tutorials/03_smiley_button_animation.gif b/docs/calliope/tutorials/03_smiley_button_animation.gif new file mode 100644 index 00000000..cfe0a739 Binary files /dev/null and b/docs/calliope/tutorials/03_smiley_button_animation.gif differ diff --git a/docs/calliope/tutorials/04_dice.gif b/docs/calliope/tutorials/04_dice.gif new file mode 100644 index 00000000..2a4b268f Binary files /dev/null and b/docs/calliope/tutorials/04_dice.gif differ diff --git a/docs/calliope/tutorials/04_dice_animation.gif b/docs/calliope/tutorials/04_dice_animation.gif new file mode 100644 index 00000000..755f42a2 Binary files /dev/null and b/docs/calliope/tutorials/04_dice_animation.gif differ diff --git a/docs/calliope/tutorials/05_love_meter.gif b/docs/calliope/tutorials/05_love_meter.gif new file mode 100644 index 00000000..c2c978bc Binary files /dev/null and b/docs/calliope/tutorials/05_love_meter.gif differ diff --git a/docs/calliope/tutorials/05_love_meter_animation.gif b/docs/calliope/tutorials/05_love_meter_animation.gif new file mode 100644 index 00000000..f66fb26c Binary files /dev/null and b/docs/calliope/tutorials/05_love_meter_animation.gif differ diff --git a/docs/calliope/tutorials/06_mini_chat.gif b/docs/calliope/tutorials/06_mini_chat.gif new file mode 100644 index 00000000..582821f2 Binary files /dev/null and b/docs/calliope/tutorials/06_mini_chat.gif differ diff --git a/docs/calliope/tutorials/06_mini_chat_animation.gif b/docs/calliope/tutorials/06_mini_chat_animation.gif new file mode 100644 index 00000000..c7ead9be Binary files /dev/null and b/docs/calliope/tutorials/06_mini_chat_animation.gif differ diff --git a/docs/calliope/tutorials/07_stone_paper_scissors.gif b/docs/calliope/tutorials/07_stone_paper_scissors.gif new file mode 100644 index 00000000..05ba9311 Binary files /dev/null and b/docs/calliope/tutorials/07_stone_paper_scissors.gif differ diff --git a/docs/calliope/tutorials/07_stone_paper_scissors_animation.gif b/docs/calliope/tutorials/07_stone_paper_scissors_animation.gif new file mode 100644 index 00000000..4bac740b Binary files /dev/null and b/docs/calliope/tutorials/07_stone_paper_scissors_animation.gif differ diff --git a/docs/calliope/tutorials/08_coin_flipper.gif b/docs/calliope/tutorials/08_coin_flipper.gif new file mode 100644 index 00000000..863ad248 Binary files /dev/null and b/docs/calliope/tutorials/08_coin_flipper.gif differ diff --git a/docs/calliope/tutorials/08_coin_flipper_animation.gif b/docs/calliope/tutorials/08_coin_flipper_animation.gif new file mode 100644 index 00000000..c3328d2b Binary files /dev/null and b/docs/calliope/tutorials/08_coin_flipper_animation.gif differ diff --git a/docs/calliope/tutorials/09_snap_the_dot.gif b/docs/calliope/tutorials/09_snap_the_dot.gif new file mode 100644 index 00000000..153cea2a Binary files /dev/null and b/docs/calliope/tutorials/09_snap_the_dot.gif differ diff --git a/docs/calliope/tutorials/09_snap_the_dot_animation.gif b/docs/calliope/tutorials/09_snap_the_dot_animation.gif new file mode 100644 index 00000000..d06ba435 Binary files /dev/null and b/docs/calliope/tutorials/09_snap_the_dot_animation.gif differ diff --git a/docs/calliope/tutorials/10_multi_dice.gif b/docs/calliope/tutorials/10_multi_dice.gif new file mode 100644 index 00000000..cc76199a Binary files /dev/null and b/docs/calliope/tutorials/10_multi_dice.gif differ diff --git a/docs/calliope/tutorials/10_multi_dice_animation.gif b/docs/calliope/tutorials/10_multi_dice_animation.gif new file mode 100644 index 00000000..d4fd4366 Binary files /dev/null and b/docs/calliope/tutorials/10_multi_dice_animation.gif differ diff --git a/docs/calliope/tutorials/add_show_led.gif b/docs/calliope/tutorials/add_show_led.gif new file mode 100644 index 00000000..a2f9cbba Binary files /dev/null and b/docs/calliope/tutorials/add_show_led.gif differ diff --git a/docs/calliope/videos.md b/docs/calliope/videos.md new file mode 100644 index 00000000..8a5f6f1f --- /dev/null +++ b/docs/calliope/videos.md @@ -0,0 +1,60 @@ +## Basic + +```codecard +[ { + "name": "LEDs", + "description": "See how these amazing little devices create light in this fun and illuminating video.", + "youTubeId": "qqBmvHD5bCw", + "embedYouTube": "true", + "imageUrl": "/static/mb/behindhardware/leds.jpg" + }, + { + "name": "Buttons", + "description": "Buttons let your fingers talk to the hardware, see how they work in this video.", + "youTubeId": "t_Qujjd_38o", + "imageUrl": "/static/mb/behindhardware/buttons.jpg" + }, + { + "name": "Accelerometer", + "description": "Find out how the accelerometer detects motion in this fun video.", + "youTubeId": "byngcwjO51U", + "imageUrl": "/static/mb/behindhardware/accelerometer.jpg" + }, + { + "name": "Light Sensor", + "description": "Your micro:bit can see the light, how does it do that?", + "youTubeId": "TKhCr-dQMBY", + "imageUrl": "/static/mb/behindhardware/light-sensor.jpg" + }, + { + "name": "Temperature Sensor", + "description": "One of the cool features on your board is the temperature sensor, how does it feel the heat?", + "youTubeId": "_T4N8O9xsMA", + "imageUrl": "/static/mb/behindhardware/temperature-sensor.jpg" + }, + { + "name": "Pin Pressed", + "description": "Touching the pins works like a button, is that magic or what?", + "youTubeId": "GEpZrvbsO7o", + "imageUrl": "/static/mb/behindhardware/pin-pressed.jpg" + }, + { + "name": "Radio", + "description": "Your board can communticate by radio, how does it do that?", + "youTubeId": "Re3H2ISfQE8", + "imageUrl": "/static/mb/behindhardware/radio.jpg" + }, + { + "name": "Servo Motor", + "description": "See how motors work and how you can use the @boardname@ to run servos.", + "youTubeId": "okxooamdAP4", + "imageUrl": "/static/mb/behindhardware/servo.jpg" + }, + { + "name": "Speakers", + "description": "Find out how speakers make sound and how you can connect them to your board.", + "youTubeId": "cxfPNc4Wefo", + "imageUrl": "/static/mb/behindhardware/speakers.jpg" + } +] +``` \ No newline at end of file diff --git a/docs/docs.md b/docs/docs.md deleted file mode 100644 index f8110ca5..00000000 --- a/docs/docs.md +++ /dev/null @@ -1,7 +0,0 @@ -# Documentation - -### @description Links to the documentation, reference and projects. - -* [The @boardname@ APIs](/reference) -* [Blocks language](/blocks) -* [JavaScript language](/javascript) diff --git a/docs/examples/eddystone-beacon.md b/docs/examples/eddystone-beacon.md new file mode 100644 index 00000000..b1cead04 --- /dev/null +++ b/docs/examples/eddystone-beacon.md @@ -0,0 +1,14 @@ +# Eddystone Beacon + +```blocks +led.enable(false) +bluetooth.advertiseUrl( + "https://calliope.cc", + 7, + false +) +``` + +```package +device +``` diff --git a/docs/examples/egg-and-spoon.md b/docs/examples/egg-and-spoon.md new file mode 100644 index 00000000..92d3026b --- /dev/null +++ b/docs/examples/egg-and-spoon.md @@ -0,0 +1,31 @@ +# Egg and Spoon race + +The [Egg and Spoon](https://en.wikipedia.org/wiki/Egg-and-spoon_race) race is a game where a player carries an object (like an egg) across some distance without it falling out of a holder. In the case of the Egg and Spoon, the player must carefully walk with an egg held in a spoon. The egg must remain in the spoon until the player crosses the finish line. The egg can easily roll out of the spoon so the player needs skill and patience to balance the egg until finishing the race. + +You can program your @boardname@ to be an egg and let your hand be the spoon. If you walk too fast or waver in holding the @boardname@, you might "drop the egg!". Try to keep the balance point in the center of the screen. + +```blocks +let accY = 0 +let accX = 0 +let y = 0 +let x = 0 +basic.forever(() => { + led.plot(x, y) + accX = input.acceleration(Dimension.X) + accY = input.acceleration(Dimension.Y) + if (accX < -150 && x > 0) { + x += -1 + } else if (accX > 150 && x < 4) { + x += 1 + } + if (accY < -150 && y > 0) { + y += -1 + } else if (accY > 150 && y < 4) { + y += 1 + } + basic.pause(500) + basic.clearScreen() +}) +x = 2 +y = 2 +``` diff --git a/docs/examples/gameofLife.md b/docs/examples/gameofLife.md new file mode 100644 index 00000000..0da12a30 --- /dev/null +++ b/docs/examples/gameofLife.md @@ -0,0 +1,142 @@ +# Game of Life + +The [Game of Life](https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life) simulates life in a grid world (a two-dimensional block of cells). The cells in the grid have a state of "alive" or "dead". The game starts with a population of cells placed in a certain pattern on the grid. A simulation is run, and based on some simple rules for life and death, cells continue to live, die off, or reproduce. + +## Rules for Life + +The rules for life in the grid are: + +1. A living cell with less than two live cells next to it will die. This is underpopulation, no social support. +2. A living cell with two or three live cells next to it continues to live. This is a healthy population. +3. A living cell with more than three live cells next to it will die. This is over overpopulation, scarce resources. +4. A dead cell with three live cells next to it turns into a living cell. This is reproduction. + +Depending on the pattern of living cells at the start of the game, some population simulations may survive longer than others. + +## Game of Life simulation in LEDs + +Here's a program that simulates cell life in the LED matrix. Use button ``A`` for the next stage of life and button ``B`` to reset. + +```typescript +//https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life +let lifeChart: Image = null + +//Use button A for the next iteration of game of life +input.onButtonPressed(Button.A, () => { + gameOfLife(); + show(); +}) + +//Use button B for reseting to random initial seed state +input.onButtonPressed(Button.B, () => { + reset(); + show(); +}) + +lifeChart = images.createImage(` + . . . . . + . . . . . + . . . . . + . . . . . + . . . . . + `) + +//State holds the information about pixel is live or dead +//false means dead, true means live. +let state = [false, false, false, false, false, + false, false, false, false, false, + false, false, false, false, false, + false, false, false, false, false, + false, false, false, false, false] + +//get & set on any array +function getState(arr: boolean[], x: number, y: number): boolean { + return arr[x * 5 + y]; +} +function setState(arr: boolean[], x: number, y: number, value: boolean): void { + arr[x * 5 + y] = value; +} + +//Generate random initial state. +function reset() { + for (let x = 0; x < 5; x++) { + for (let y = 0; y < 5; y++) { + setState(state, x, y, Math.randomBoolean()); + } + } +} + +//Show the lifeChart based on the state +function show() { + for (let x = 0; x < 5; x++) { + for (let y = 0; y < 5; y++) { + lifeChart.setPixel(x, y, getState(state, x, y)); + } + } + lifeChart.plotImage(0); +} + +//Core function +function gameOfLife() { + let result: boolean[] = []; + let count = 0; + + for (let x = 0; x < 5; x++) { + for (let y = 0; y < 5; y++) { + count = 0; + + //Count the live cells in the next row + if ((x + 1) < 5) { + if (getState(state, x + 1, y)) { + count++; + } + if ((y + 1 < 5) && getState(state, x + 1, y + 1)) { + count++; + } + if ((y - 1 >= 0) && getState(state, x + 1, y - 1)) { + count++; + } + } + + //Count the live cells in the previous row + if ((x - 1) >= 0) { + if (getState(state, x - 1, y)) { + count++; + } + if ((y + 1 < 5) && getState(state, x - 1, y + 1)) { + count++; + } + if ((y - 1 >= 0) && getState(state, x - 1, y - 1)) { + count++; + } + } + + //Count the live cells in the current row exlcuding the current position. + if ((y - 1 >= 0) && getState(state, x, y - 1)) { + count++; + } + if ((y + 1 < 5) && getState(state, x, y + 1)) { + count++; + } + + // Toggle live / dead cells based on the neighbour count. + // Any live cell with fewer than two live neighbours dies, as if caused by underpopulation. + // Any live cell with two or three live neighbours lives on to the next generation. + // Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction. + // Any live cell with more than three live neighbours dies, as if by overpopulation. + switch (count) { + case 0: setState(result, x, y, false); break; + case 1: setState(result, x, y, false); break; + case 2: setState(result, x, y, getState(state, x, y)); break; + case 3: setState(result, x, y, true); break; + default: setState(result, x, y, false); break; + } + } + } + //Update the state + state = result; +} +//Initial reset & show +reset(); +show(); +``` diff --git a/docs/examples/pi-montecarlo.md b/docs/examples/pi-montecarlo.md new file mode 100644 index 00000000..8291620c --- /dev/null +++ b/docs/examples/pi-montecarlo.md @@ -0,0 +1,104 @@ +# Pi Monte Carlo + +Approximate the value of **pi** using your @boardname@! + +## Thinking about it... + +Ok, let's pretend that a circle fits inside a square where the edge of the circle touches the sides of the square. If we say that the radius, called ``r``, of circle is `1` then the length of each side of the square is `2`, or ``2 * r``. The area of the circle is ``pi * (r ** 2)`` and the area of the square then is ``(r * 2) ** 2``. We don't know what ``pi`` is so we can arrange a relationship between the area of the circle and the area of the square to solve for the value of ``pi``. + +### Circle and square + +An interesting relationship between the circle and the square is that the area of the circle divided by the area of the square is: + +``area ratio = (pi * (r ** 2)) / ((r * 2) ** 2) = pi / 4`` + +Well, we can see that if we knew the area of both the circle and the square we could find out what the value of ``pi`` is! It's simply this: + +``` +pi = (area of circle) / (area of square) * 4 +``` + +so then... + +``` +area ratio = (area of circle) / (area of square) +pi = (area ratio) * 4 +``` + +One problem though. We know the area of the square, sure enough it's `4`, but what's the area of the circle? + +That's the dilemma! We need to know the area of the circle to find out what ``pi`` is and we need the value of ``pi`` the find the area of the circle! + +### Dots, lots of dots + +What if we had a lot of really small dots that we could fill into the circle and into the parts of the square that the circle didn't cover. We'll try to cover the area of both shapes with as many dots as possible. + +If we count the number of dots placed in both the circle and the square, we could find the ``area ratio`` between the two shapes. And, in the equation shown above, we can discover ``pi`` if we have this ratio. The ``area ratio`` is: + +``area ratio = (dots in circle) / ((dots in circle) + (dots only in square))`` + +Of course, we can't completely fill the area of both shapes with dots but we could get enough of them in there to give a useful ratio between the circle and the square. + +### Making and counting dots + +To make the "dots" we can randomly make a value and see if it would fit as a coordinate within the shape we're trying to fill. If it fits, increase the count of dots and try to make more for some amount of time. The more dots created, the better the accuracy of our value for ``area ratio``. + +### Monte Carlo method + +This method of filling coordinate points, counting them, and using the difference or ratio of the counts is called the _Monte Carlo_ method or approximation. + +## Monte Carlo approximation of _pi_ + +```blocks +let pir = 0 +let pid = 0 +let y = 0 +let pin = 0 +let x = 0 +let r2 = 0 +let r = 0 +let inside = 0 +let n = 0 + +// A simple Monte-Carlo simulation to approximate Pi. +// +// number of points +n = 1000000 +// +// radius of the circle +r = 4000 +// +// radius square +r2 = r * r +// +basic.forever(() => { + inside = 0 + for (let i = 0; i < n; i++) { + // generate a point within the square + x = Math.randomRange(0, r + 1) + y = Math.randomRange(0, r + 1) + // test if the point is within the circle + // sqrt(x**2 + y**2) < r ==> x**2 + y**2 < r**2 + if (x * x + y * y < r2) { + inside += 1 + } + } + // surface of a square: 4 * r * r surface of a circle: + // r * r * pi => inside / n ~= (r*r*pi) / (4*r*r) ~= + // pi / 4 pi = inside / n * 4 + // + pin = inside * 4 + // only integer arithmetic here... + pid = pin / n + pir = pin % n + // show results + basic.showLeds(` + # # # # # + . # . # . + . # . # . + . # . # . + . # . . # + `) + basic.showString(" " + pid + "." + pir) +}) +``` \ No newline at end of file diff --git a/docs/examples/plot-acceleration.md b/docs/examples/plot-acceleration.md new file mode 100644 index 00000000..5d9d20f0 --- /dev/null +++ b/docs/examples/plot-acceleration.md @@ -0,0 +1,12 @@ +# Plot Acceleration + +Plot acceleration in the ``x`` dimension on the LEDs. + +```blocks +basic.forever(() => { + led.plotBarGraph( + input.acceleration(Dimension.X), + 1023 + ) +}) +``` diff --git a/docs/examples/plot-light-level.md b/docs/examples/plot-light-level.md new file mode 100644 index 00000000..4eaf35b4 --- /dev/null +++ b/docs/examples/plot-light-level.md @@ -0,0 +1,12 @@ +# Plot Light level + +Show the current light level as a bar graph. + +```blocks +basic.forever(() => { + led.plotBarGraph( + input.lightLevel(), + 255 + ) +}) +``` diff --git a/docs/examples/radio-dashboard.md b/docs/examples/radio-dashboard.md new file mode 100644 index 00000000..d4291cbf --- /dev/null +++ b/docs/examples/radio-dashboard.md @@ -0,0 +1,90 @@ +# Radio Dashboard + +```typescript +/** + * Radio monitoring dashboard + * + * Each radio client is represented by a dot on the screen. + * Once a client is registered, it will stay at the same pixel location + * forever. + * + * Radio clients can simply send a number (between 0..255) on group 4. + * They must transmit the serial number using ``radio.setTransmitSerialNumber(true)`` + * + * The received number is used to set the LED brightness for that client. + * + * If the radio packet is not received for 10sec, the LED starts blinking. + */ +const deadPing = 20000; +const lostPing = 10000; + +interface Client { + // client serial id + id: number; + // sprite on screen + sprite: game.LedSprite; + // last ping received + ping: number; +} + +const clients: Client[] = []; + +/* lazy allocate sprite */ +function getClient(id: number): Client { + // needs an id to track radio client's identity + if (!id) + return undefined; + + // look for cached clients + for (const client of clients) + if (client.id == id) + return client; + const n = clients.length; + if (n == 24) // out of pixels + return undefined; + const client: Client = { + id: id, + sprite: game.createSprite(n % 5, n / 5), + ping: input.runningTime() + } + clients.push(client); + return client; +} + +// store data received by clients +radio.onReceivedNumber(function (receivedNumber) { + const serialNumber = radio.receivedPacket(RadioPacketProperty.SerialNumber) + const client = getClient(serialNumber); + if (!client) + return; + + client.ping = input.runningTime() + client.sprite.setBrightness(Math.max(1, receivedNumber & 0xff)); +}) + +// monitor the sprites and start blinking when no packet is received +basic.forever(() => { + const now = input.runningTime() + for (const client of clients) { + // lost signal starts blinking + const lastPing = now - client.ping; + if (lastPing > deadPing) { + client.sprite.setBlink(0) + client.sprite.setBrightness(0) + } + else if (lastPing > lostPing) + client.sprite.setBlink(500); + else + client.sprite.setBlink(0); + } + basic.pause(500) +}) + +// setup the radio and start! +radio.setGroup(4) +game.addScore(1) +``` + +```package +radio +``` diff --git a/docs/examples/rando.md b/docs/examples/rando.md new file mode 100644 index 00000000..009807ee --- /dev/null +++ b/docs/examples/rando.md @@ -0,0 +1,9 @@ +# Rando + +Generate a random coordinate and display it on the LED screen. + +```blocks +basic.forever(() => { + led.toggle(Math.randomRange(0, 5), Math.randomRange(0, 5)) +}) +``` \ No newline at end of file diff --git a/docs/index-ref.json b/docs/index-ref.json index 2e67e9cf..0821d1dd 100644 --- a/docs/index-ref.json +++ b/docs/index-ref.json @@ -1,3 +1,3 @@ { - "appref": "v1.0.25" + "appref": "v2.0.10" } diff --git a/docs/javascript.md b/docs/javascript.md deleted file mode 100644 index 7bd81a92..00000000 --- a/docs/javascript.md +++ /dev/null @@ -1,42 +0,0 @@ -# JavaScript - -Visit the cards below to starting programming JavaScript -with the @boardname@: - -```codecard -[{ - "name": "Calling", - "url": "/js/call" -},{ - "name": "Sequencing", - "url": "/js/sequence" -},{ - "name": "Variables", - "url": "/js/variables" -},{ - "name": "Operators", - "url": "/js/operators" -},{ - "name": "Statements", - "url": "/js/statements" -},{ - "name": "Functions", - "url": "/js/functions" -},{ - "name": "Types", - "url": "/js/types" -},{ - "name": "Classes", - "url": "/js/classes" -},{ - "name": "FAQ", - "url": "/js/faq" -} -] - -``` - -### See Also - -[calling](/js/call), [sequencing](/js/sequence), [variables](/js/variables), [operators](/js/operators), [statements](/js/statements), [functions](/js/functions), -[types](/js/types), [classes](/js/classes), [FAQ](/js/faq) \ No newline at end of file diff --git a/docs/js/call.md b/docs/js/call.md deleted file mode 100644 index d93d23e8..00000000 --- a/docs/js/call.md +++ /dev/null @@ -1,58 +0,0 @@ -# Call a function - -The simplest way to get started in JavaScript with your @boardname@ is to -call one of the @boardname@'s built-in JavaScript functions. Just like Blocks -are organized into categories/drawers, the @boardname@ functions are organized by -namespaces, with names corresponding to the drawer names. The `basic` namespace -contains a number of helpful functions, such as: - -```typescript -basic.showString("Hello!") -``` - -If you want to see all functions available in the `basic` namespace, simply type `basic` -followed by `.` and a list of all the functions will appear. - -![](/static/mb/js/basicFuns.png) - -This feature is known as "Intellisense". Continue typing to select one of the functions, -or click on one of the functions to select. You also narrow down the set of functions by typing, as below: - -![](/static/mb/js/basicIntell.png) - -You can type anything to see what Intellisense will find for you. Here's an example -of what happens when you type the word `for`: -![](/static/mb/js/forIntell.png) - -## Function parameter values - -You might have noticed that the call `showString` above takes one parameter value, -the string to be scrolled on the LED screen. There is a second (optional) -parameter that controls the speed of the scroll. Try this: - -```typescript -basic.showString("Hello!",50) -``` - -Intellisense shows all the available parameters for a function. - -## Left and right parentheses, please! - -Whenever you want to call a function, you give the name of the function -followed by `(` and ending with `)`. Inbetween the left and right -parentheses go the function arguments. If a function has zero arguments, you still -need the parentheses in order to call the function. For example - -```typescript -basic.clearScreen() -``` - -It's a syntax error to have a left parenthesis without the "closing" right parenthesis: - -``` -basic.clearScreen( -``` - -### ~button /js/sequence -NEXT: Sequencing Commands -### ~ diff --git a/docs/js/classes.md b/docs/js/classes.md deleted file mode 100644 index ac5bda15..00000000 --- a/docs/js/classes.md +++ /dev/null @@ -1,268 +0,0 @@ -# Classes - -Traditional JavaScript focuses on functions and prototype-based inheritance as the basic means of building up reusable components, -but this may feel a bit awkward to programmers more comfortable with an object-oriented approach, where classes inherit functionality -and objects are built from these classes. - -Starting with ECMAScript 2015, also known as ECMAScript 6, JavaScript programmers will be able to build their applications using -this object-oriented class-based approach. TypeScript, allows you to use these techniques now, compiling them -down to JavaScript that works across all major browsers and platforms, without having to wait for the next version of JavaScript. - -Let's take a look at a simple class-based example: - -```ts -class Greeter { - greeting: string; - constructor(message: string) { - this.greeting = message; - } - greet() { - return "Hello, " + this.greeting; - } -} - -let greeter = new Greeter("world"); -``` - -We declare a new class `Greeter`. This class has three members: a property called `greeting`, a constructor, and a method `greet`. - -You'll notice that in the class when we refer to one of the members of the class we prepend `this.`. -This denotes that it's a member access. - -In the last line we construct an instance of the `Greeter` class using `new`. -This calls into the constructor we defined earlier, creating a new object with the `Greeter` shape, and running the constructor to initialize it. - -# Inheritance - -### ~hint -### Inheritance is not supported yet for the @boardname@. Coming soon... -### ~ - -In TypeScript, we can use common object-oriented patterns. -Of course, one of the most fundamental patterns in class-based programming is being able to extend existing classes to create new ones using inheritance. - -Let's take a look at an example: - -```ts-ignore -class Animal { - name: string; - constructor(theName: string) { this.name = theName; } - move(distanceInMeters: number = 0) { - console.log(`${this.name} moved ${distanceInMeters}m.`); - } -} - -class Snake extends Animal { - constructor(name: string) { super(name); } - move(distanceInMeters = 5) { - console.log("Slithering..."); - super.move(distanceInMeters); - } -} - -class Horse extends Animal { - constructor(name: string) { super(name); } - move(distanceInMeters = 45) { - console.log("Galloping..."); - super.move(distanceInMeters); - } -} - -let sam = new Snake("Sammy the Python"); -let tom: Animal = new Horse("Tommy the Palomino"); - -sam.move(); -tom.move(34); -``` - -This example covers quite a few of the inheritance features in TypeScript that are common to other languages. -Here we see the `extends` keywords used to create a subclass. -You can see this where `Horse` and `Snake` subclass the base class `Animal` and gain access to its features. - -Derived classes that contain constructor functions must call `super()` which will execute the constructor function on the base class. - -The example also shows how to override methods in the base class with methods that are specialized for the subclass. -Here both `Snake` and `Horse` create a `move` method that overrides the `move` from `Animal`, giving it functionality specific to each class. -Note that even though `tom` is declared as an `Animal`, since its value is a `Horse`, when `tom.move(34)` calls the overriding method in `Horse`: - -```Text -Slithering... -Sammy the Python moved 5m. -Galloping... -Tommy the Palomino moved 34m. -``` - -# Public, private, and protected modifiers - -## Public by default - -In our examples, we've been able to freely access the members that we declared throughout our programs. -If you're familiar with classes in other languages, you may have noticed in the above examples -we haven't had to use the word `public` to accomplish this; for instance, -C# requires that each member be explicitly labeled `public` to be visible. -In TypeScript, each member is `public` by default. - -You may still mark a member `public` explicitly. -We could have written the `Animal` class from the previous section in the following way: - -```ts-ignore -class Animal { - public name: string; - public constructor(theName: string) { this.name = theName; } - public move(distanceInMeters: number) { - console.log(`${this.name} moved ${distanceInMeters}m.`); - } -} -``` - -## Understanding `private` - -When a member is marked `private`, it cannot be accessed from outside of its containing class. For example: - -```ts-ignore -class Animal { - private name: string; - constructor(theName: string) { this.name = theName; } -} - -new Animal("Cat").name; // Error: 'name' is private; -``` - -TypeScript is a structural type system. -When we compare two different types, regardless of where they came from, if the types of all members are compatible, then we say the types themselves are compatible. - -However, when comparing types that have `private` and `protected` members, we treat these types differently. -For two types to be considered compatible, if one of them has a `private` member, -then the other must have a `private` member that originated in the same declaration. -The same applies to `protected` members. - -Let's look at an example to better see how this plays out in practice: - -```ts-ignore -class Animal { - private name: string; - constructor(theName: string) { this.name = theName; } -} - -class Rhino extends Animal { - constructor() { super("Rhino"); } -} - -class Employee { - private name: string; - constructor(theName: string) { this.name = theName; } -} - -let animal = new Animal("Goat"); -let rhino = new Rhino(); -let employee = new Employee("Bob"); - -animal = rhino; -animal = employee; // Error: 'Animal' and 'Employee' are not compatible -``` - -In this example, we have an `Animal` and a `Rhino`, with `Rhino` being a subclass of `Animal`. -We also have a new class `Employee` that looks identical to `Animal` in terms of shape. -We create some instances of these classes and then try to assign them to each other to see what will happen. -Because `Animal` and `Rhino` share the `private` side of their shape from the same declaration of -`private name: string` in `Animal`, they are compatible. However, this is not the case for `Employee`. -When we try to assign from an `Employee` to `Animal` we get an error that these types are not compatible. -Even though `Employee` also has a `private` member called `name`, it's not the one we declared in `Animal`. - -## Understanding `protected` - -The `protected` modifier acts much like the `private` modifier with the exception that members -declared `protected` can also be accessed by instances of deriving classes. For example, - -```ts-ignore -class Person { - protected name: string; - constructor(name: string) { this.name = name; } -} - -class Employee extends Person { - private department: string; - - constructor(name: string, department: string) { - super(name); - this.department = department; - } - - public getElevatorPitch() { - return `Hello, my name is ${this.name} and I work in ${this.department}.`; - } -} - -let howard = new Employee("Howard", "Sales"); -console.log(howard.getElevatorPitch()); -console.log(howard.name); // error -``` - -Notice that while we can't use `name` from outside of `Person`, -we can still use it from within an instance method of `Employee` because `Employee` derives from `Person`. - -A constructor may also be marked `protected`. -This means that the class cannot be instantiated outside of its containing class, but can be extended. For example, - -```ts-ignore -class Person { - protected name: string; - protected constructor(theName: string) { this.name = theName; } -} - -// Employee can extend Person -class Employee extends Person { - private department: string; - - constructor(name: string, department: string) { - super(name); - this.department = department; - } - - public getElevatorPitch() { - return `Hello, my name is ${this.name} and I work in ${this.department}.`; - } -} - -let howard = new Employee("Howard", "Sales"); -let john = new Person("John"); // Error: The 'Person' constructor is protected -``` - -# Readonly modifier - -You can make properties readonly by using the `readonly` keyword. -Readonly properties must be initialized at their declaration or in the constructor. - -```ts-ignore -class Octopus { - readonly name: string; - readonly numberOfLegs: number = 8; - constructor (theName: string) { - this.name = theName; - } -} -let dad = new Octopus("Man with the 8 strong legs"); -dad.name = "Man with the 3-piece suit"; // error! name is readonly. -``` - -## Parameter properties - -In our last example, we had to declare a readonly member `name` and a constructor parameter `theName` in the `Octopus` class, and we then immediately set `name` to `theName`. -This turns out to be a very common practice. -*Parameter properties* let you create and initialize a member in one place. -Here's a further revision of the previous `Octopus` class using a parameter property: - -```ts-ignore -class Octopus { - readonly numberOfLegs: number = 8; - constructor(readonly name: string) { - } -} -``` - -Notice how we dropped `theName` altogether and just use the shortened `readonly name: string` parameter on the constructor to create and initialize the `name` member. -We've consolidated the declarations and assignment into one location. - -Parameter properties are declared by prefixing a constructor parameter with an accessibility modifier or `readonly`, or both. -Using `private` for a parameter property declares and initializes a private member; likewise, the same is done for `public`, `protected`, and `readonly`. - diff --git a/docs/js/faq.md b/docs/js/faq.md deleted file mode 100644 index fded50a4..00000000 --- a/docs/js/faq.md +++ /dev/null @@ -1,58 +0,0 @@ -# Frequently asked questions - -# What is the language supported for the @boardname@? - -For the @boardname@, we support a "static" subset of TypeScript (itself a superset of JavaScript): - -## Supported language features - -* variables with `let`, `const`, and `var` -* functions with lexical scoping and recursion -* top-level code in the file; hello world really is `console.log("Hello world")` -* `if ... else if ... else` statements -* `while` and `do ... while` loops -* `for(;;)` loops (see below about `for ... in/of`) -* `break/continue`; also with labeled loops -* `switch` statement (on numbers only) -* `debugger` statement for breakpoints -* conditional operator `? :`; lazy boolean operators -* namespaces (a form of modules) -* all arithmetic operators (including bitwise operators); note that in microcontroller targets - all arithmetic is performed on integers, also when simulating in the browser -* strings (with a few common methods) -* [string templates](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals) (`` `x is ${x}` ``) -* arrow functions `() => ...` -* classes with fields, methods and constructors; `new` keyword -* array literals `[1, 2, 3]` -* enums - -## Unsupported language features - -We generally stay away from the more dynamic parts of JavaScript. -Things you may miss and we may implement: - -* exceptions (`throw`, `try ... catch`, `try ... finally`) -* `for ... of` statements -* object literals `{ foo: 1, bar: "two" }` -* method-like properties (get/set accessors) -* class inheritance - -For JS-only targets we may implement the following: - -* regular expressions -* classes implementing interfaces - -Things that we are not very likely to implement: - -* file-based modules (`import * from ...`, `module.exports` etc); we do support namespaces -* spread operator -* `yield` expression and ``function*`` -* `await` expression and `async function` -* `typeof` expression -* tagged templates ``tag `text ${expression} more text` ``; regular templates are supported -* binding with arrays or objects: `let [a, b] = ...; let { x, y } = ...` -* `with` statement -* `eval` -* `delete` statement -* `for ... in` statements -* JSX (HTML as part of JavaScript) \ No newline at end of file diff --git a/docs/js/functions.md b/docs/js/functions.md deleted file mode 100644 index efa30457..00000000 --- a/docs/js/functions.md +++ /dev/null @@ -1,161 +0,0 @@ -# Functions - -Functions are the fundamental building block of programs. Here is the simplest -way to make a function that adds two numbers: - -```ts -// Named function -function add(x : number, y : number) { - return x + y; -} - -basic.showNumber(add(1, 2)) -``` - -### ~ hint -For the @boardname@, you must specify a [type](/js/types) for each function parameter. -### ~ - -Functions can refer to variables outside of the function body. -When they do so, they're said to `capture` these variables. - -```ts -let z = 100; - -function addToZ(x: number, y: number) { - return x + y + z; -} - -basic.showNumber(addToZ(1, 2)) -``` - -## Typing the function - -Let's add a return type to our add function: - -```ts -function add(x: number, y: number): number { - return x + y; -} -``` - -TypeScript can figure the return type out by looking at the return statements, so you can optionally leave this off in many cases. - -# Optional and Default Parameters - -In TypeScript, the number of arguments given to a function has to match the number of parameters the function expects. - -```ts-ignore -function buildName(firstName: string, lastName: string) { - return firstName + " " + lastName; -} - -let result1 = buildName("Bob"); // error, too few parameters -let result2 = buildName("Bob", "Adams", "Sr."); // error, too many parameters -let result3 = buildName("Bob", "Adams"); // ah, just right -``` - -In JavaScript, every parameter is optional, and users may leave them off as they see fit. -When they do, their value is `undefined`. -We can get this functionality in TypeScript by adding a `?` to the end of parameters we want to be optional. -For example, let's say we want the last name parameter from above to be optional: - -```ts-ignore -function buildName(firstName: string, lastName?: string) { - if (lastName) - return firstName + " " + lastName; - else - return firstName; -} - -let result1 = buildName("Bob"); // works correctly now -let result2 = buildName("Bob", "Adams", "Sr."); // error, too many parameters -let result3 = buildName("Bob", "Adams"); // ah, just right -``` - -Any optional parameters must follow required parameters. -Had we wanted to make the first name optional rather than the last name, we would need to change the order of parameters in the function, putting the first name last in the list. - -In TypeScript, we can also set a value that a parameter will be assigned if the user does not provide one, or if the user passes `undefined` in its place. -These are called default-initialized parameters. -Let's take the previous example and default the last name to `"Smith"`. - -```ts-ignore -function buildName(firstName: string, lastName = "Smith") { - return firstName + " " + lastName; -} - -let result1 = buildName("Bob"); // works correctly now, returns "Bob Smith" -let result2 = buildName("Bob", undefined); // still works, also returns "Bob Smith" -let result3 = buildName("Bob", "Adams", "Sr."); // error, too many parameters -let result4 = buildName("Bob", "Adams"); // ah, just right -``` - -Default-initialized parameters that come after all required parameters are treated as optional, and just like optional parameters, can be omitted when calling their respective function. -This means optional parameters and trailing default parameters will share commonality in their types, so both - -```ts -function buildName(firstName: string, lastName?: string) { - // ... -} -``` - -and - -```ts -function buildName(firstName: string, lastName = "Smith") { - // ... -} -``` - -share the same type `(firstName: string, lastName?: string) => string`. -The default value of `lastName` disappears in the type, only leaving behind the fact that the parameter is optional. - -Unlike plain optional parameters, default-initialized parameters don't *need* to occur after required parameters. -If a default-initialized parameter comes before a required parameter, users need to explicitly pass `undefined` to get the default initialized value. -For example, we could write our last example with only a default initializer on `firstName`: - -```ts-ignore -function buildName(firstName = "Will", lastName: string) { - return firstName + " " + lastName; -} - -let result1 = buildName("Bob"); // error, too few parameters -let result2 = buildName("Bob", "Adams", "Sr."); // error, too many parameters -let result3 = buildName("Bob", "Adams"); // okay and returns "Bob Adams" -let result4 = buildName(undefined, "Adams"); // okay and returns "Will Adams" -``` - -# Rest Parameters - -Required, optional, and default parameters all have one thing in common: they talk about one parameter at a time. -Sometimes, you want to work with multiple parameters as a group, or you may not know how many parameters a function will ultimately take. -In JavaScript, you can work with the arguments directly using the `arguments` variable that is visible inside every function body. - -In TypeScript, you can gather these arguments together into a variable: - -```ts-ignore -function buildName(firstName: string, ...restOfName: string[]) { - return firstName + " " + restOfName.join(" "); -} - -let employeeName = buildName("Joseph", "Samuel", "Lucas", "MacKinzie"); -``` - -*Rest parameters* are treated as a boundless number of optional parameters. -When passing arguments for a rest parameter, you can use as many as you want; you can even pass none. -The compiler will build an array of the arguments passed in with the name given after the ellipsis (`...`), allowing you to use it in your function. - -The ellipsis is also used in the type of the function with rest parameters: - -```ts-ignore -function buildName(firstName: string, ...restOfName: string[]) { - return firstName + " " + restOfName.join(" "); -} - -let buildNameFun: (fname: string, ...rest: string[]) => string = buildName; -``` - -### ~button /js/types -NEXT: Types -### ~ \ No newline at end of file diff --git a/docs/js/inference.md b/docs/js/inference.md deleted file mode 100644 index e69de29b..00000000 diff --git a/docs/js/operators.md b/docs/js/operators.md deleted file mode 100644 index 52994051..00000000 --- a/docs/js/operators.md +++ /dev/null @@ -1,30 +0,0 @@ -## Operators - -The following JavaScript operators are supported for the @boardname@. - -### ~hint -Note that for the @boardname@ all arithmetic is performed on integers, rather than floating point. -This also is true when simulating in the browser. -### ~ - -# Assignment, arithmetic and bitwise - -* assignment operators - [read more](http://devdocs.io/javascript/operators/assignment_operators) -* arithmetic operators - [read more](http://devdocs.io/javascript/operators/arithmetic_operators) -* bitwise operators - [read more](http://devdocs.io/javascript/operators/bitwise_operators) - -# Comparision and conditional - -* comparison operators - [read more](http://devdocs.io/javascript/operators/comparison_operators) -* conditional operator - [read more](http://devdocs.io/javascript/operators/conditional_operator) - -## More - -* lambda functions `() => { ... }` -* array literals `[1, 2, 3]` -* strings, with a few common methods -* [string templates](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals) (`` `x is ${x}` ``) - -### ~button /js/statements -NEXT: Statements -### ~ \ No newline at end of file diff --git a/docs/js/sequence.md b/docs/js/sequence.md deleted file mode 100644 index f26abb74..00000000 --- a/docs/js/sequence.md +++ /dev/null @@ -1,63 +0,0 @@ -# Sequencing - -By calling one function after another, in sequence, you can create an animation: - -```typescript -basic.showLeds(` - . # . # . - . . . . . - . . # . . - # . . . # - . # # # . - `); -basic.showLeds(` - . # . # . - . . . . . - . . . . . - . # # # . - # . . . # - `); -``` - -### The semicolon - -In JavaScript, the semicolon (;) is used to terminate (or end) a statement. However, in most -cases, the semicolon is optional and can be omitted. So both code sequences below are -legal: - -```typescript -basic.showNumber(1) -basic.showNumber(2) -``` - -```typescript -basic.showNumber(1); -basic.showNumber(2); -``` - -### The empty statement - -In JavaScript, there is the concept of an *empty statement*, which is whitespace followed by -a semicolon in the context where a statement is expected. -So, the following code is an infinite loop -followed by a call to `showNumber` that will never execute: -```typescript-ignore -while(true) ; -basic.showNumber(1); -``` - - -### ~hint -For the @boardname@, we don't allow a program to contain an empty statement, such as shown above. -If you really want an empty statement, you need to use curly braces to delimit an empty statement block: -```typescript -while(true) { } -basic.showNumber(1); -``` -### ~ - -[Read more](http://inimino.org/~inimino/blog/javascript_semicolons) about semicolons in JavaScript. - -### ~button /js/variables -NEXT: Variable Declarations -### ~ \ No newline at end of file diff --git a/docs/js/statements.md b/docs/js/statements.md deleted file mode 100644 index e2e22cb7..00000000 --- a/docs/js/statements.md +++ /dev/null @@ -1,33 +0,0 @@ -# Statements - -The following JavaScript statements are supported for the @boardname@: - -## Variable declarations -* `const` statement - [read more](http://devdocs.io/javascript/statements/const) -* `let` statement - [read more](http://devdocs.io/javascript/statements/let) -* `var` statement - [read more](http://devdocs.io/javascript/statements/var) - -## Block-structured statements - -* `{ }` block statement - [read more](http://devdocs.io/javascript/statements/block) -* `if-else` conditional statement - [read more](http://devdocs.io/javascript/statements/if...else) -* `while` loop - [read more](http://devdocs.io/javascript/statements/do...while) -* `do-while` loop - [read more](http://devdocs.io/javascript/statements/do...while) -* `for(;;)` loop - [read more](http://devdocs.io/javascript/statements/for) -* `switch` statement (on numbers only) - [read more](http://devdocs.io/javascript/statements/switch) - -## Control-flow commands - -* `break` statement - [read more](http://devdocs.io/javascript/statements/break) -* `continue` statement - [read more](http://devdocs.io/javascript/statements/continue) -* `return` statement - [read more](http://devdocs.io/javascript/statements/return) -* `debugger` statement for breakpoints - [read more](http://devdocs.io/javascript/statements/debugger) - -## Labelling statements - -* labelled statement - [read more](http://devdocs.io/javascript/statements/label) -* `default` statement - [read more](http://devdocs.io/javascript/statements/default) - -### ~button /js/functions -NEXT: Functions -### ~ diff --git a/docs/js/types.md b/docs/js/types.md deleted file mode 100644 index 32918d0d..00000000 --- a/docs/js/types.md +++ /dev/null @@ -1,142 +0,0 @@ -# Types - -For programs to be useful, we need to be able to work with some of the simplest units of data: -numbers, strings, structures, boolean values, and the like. - -# Boolean - -The most basic datatype is the simple true/false value, which is called a `boolean` value. - -```ts -let isDone: boolean = false; -``` - -# Number - -### ~ hint -In JavaScript, `numbers` are floating point values. -However, for the @boardname@, `numbers` are integer values. -### ~ - -Integer values can be specified via decimal, hexadecimal and octal notation: - -```ts -let decimal: number = 42; -let hex: number = 0xf00d; -let binary: number = 0b1010; -let octal: number = 0o744; -``` - -# String - -As in other languages, we use the type `string` to refer to textual data. -Use double quotes (`"`) or single quotes (`'`) to surround string data. - -```ts -let color: string = "blue"; -color = 'red'; -``` - -You can also use *template strings*, which can span multiple lines and have embedded expressions. -These strings are surrounded by the backtick/backquote (`` ` ``) character, and embedded expressions are of the form `${ expr }`. - -```ts -let fullName: string = `Bob Bobbington`; -let age: number = 37; -let sentence: string = `Hello, my name is ${ fullName }. - -I'll be ${ age + 1 } years old next month.` -``` - -This is equivalent to declaring `sentence` like so: - -```ts -let fullName: string = `Bob Bobbington`; -let age: number = 37; -let sentence: string = "Hello, my name is " + fullName + ".\n\n" + - "I'll be " + (age + 1) + " years old next month." -``` - -# Array - -Arrays allow you to work with an expandable sequence of values, addressed by an integer-valued index. -Array types can be written in one of two ways. -In the first, you use the type of the elements followed by `[]` to denote an array of that element type: - -```ts -let list: number[] = [1, 2, 3]; -``` - -The second way uses a generic array type, `Array`: - -```ts -let list: Array = [1, 2, 3]; -``` - -### ~hint -For the @boardname@, all elements of an array must have the same type. -### ~ - - -# Enum - -A helpful addition to the standard set of datatypes from JavaScript is the `enum`. -As in languages like C#, an enum is a way of giving more friendly names to sets of numeric values. - -```ts -enum Color {Red, Green, Blue} -let c: Color = Color.Green; -``` - -By default, enums begin numbering their members starting at `0`. -You can change this by manually setting the value of one of its members. -For example, we can start the previous example at `1` instead of `0`: - -```ts -enum Color {Red = 1, Green, Blue} -let c: Color = Color.Green; -``` - -Or, even manually set all the values in the enum: - -```ts -enum Color {Red = 1, Green = 2, Blue = 4} -let c: Color = Color.Green; -``` - -# Any - -The TypeScript type `any` is not supported in the @boardname@. - - -# Void - -`void` is the absence of having any type at all. -You may commonly see this as the return type of functions that do not return a value: - -```ts -function warnUser(): void { - basic.showString("This is my warning message"); -} -``` - -Declaring variables of type `void` is not useful. - -# Type Inference - -In TypeScript, there are several places where type inference is used to provide type information when there is -no explicit type annotation. For example, in this code - -```ts -let x = 3; -let y = x + 3 -``` - -The type of the `x` variable is inferred to be `number`. Similarly, the type of `y` variable also is inferred to be `number`. -This kind of inference takes place when initializing variables and members, -setting parameter default values, and determining function return types. - - -### ~button /js/classes -NEXT: Classes -### ~ \ No newline at end of file diff --git a/docs/js/variables.md b/docs/js/variables.md deleted file mode 100644 index 344454ae..00000000 --- a/docs/js/variables.md +++ /dev/null @@ -1,121 +0,0 @@ -# Variable Declarations - -Declaring a variable in JavaScript has always traditionally been done with the `var` keyword. - -```typescript -var a = 10; -``` - -The `var` construct has some [problems](http://www.typescriptlang.org/docs/handbook/variable-declarations.html), -which is why `let` statements were introduced. Apart from the keyword used, `let` statements are written -the same way `var` statements are. - -```typescript -let a = 10; -``` - -The key difference is not in the syntax, but in the semantics, which we'll now dive into. - -## Block-scoping - -When a variable is declared using `let`, it uses what some call *lexical-scoping* or *block-scoping*. -Unlike variables declared with `var` whose scopes leak out to their containing function, -block-scoped variables are not visible outside of their nearest containing block or `for`-loop. - -```typescript -function f(input: boolean) { - let a = 100; - - if (input) { - // Still okay to reference 'a' - let b = a + 1; - return b; - } - - // Error: 'b' doesn't exist here - return b; -} -``` - -Here, we have two local variables `a` and `b`. -`a`'s scope is limited to the body of `f` while `b`'s scope is limited to the containing `if` statement's block. - -Another property of block-scoped variables is that they can't be read or written to before they're actually declared. -While these variables are "present" throughout their scope, all points up until their declaration are part of their *temporal dead zone*. -This is just a sophisticated way of saying you can't access them before the `let` statement, and luckily TypeScript will let you know that. - -```typescript-ignore -a++; // illegal to use 'a' before it's declared; -let a; -``` - -## Re-declarations - -With `var` declarations, it doesn't matter how many times you declare your variables, you just get one: - -```typescript -var x = 10; -var x = 20; -``` - -In the above example, all declarations of `x` actually refer to the *same* `x`, and this is perfectly valid. -This often ends up being a source of bugs. Thankfully, `let` declarations are not as forgiving. - -```typescript -let x = 10; -let x = 20; // error: can't re-declare 'x' in the same scope -``` - -## Shadowing - -The act of introducing a new name in a more deeply nested scope is called *shadowing*. -It is a bit of a double-edged sword in that it can introduce certain bugs on its own in the -event of accidental shadowing, while also preventing certain bugs. -For instance, imagine a `sumMatrix` function using `let` variables. - -```typescript -function sumMatrix(matrix: number[][]) { - let sum = 0; - for (let i = 0; i < matrix.length; i++) { - var currentRow = matrix[i]; - for (let i = 0; i < currentRow.length; i++) { - sum += currentRow[i]; - } - } - - return sum; -} -``` - -This version of the loop will actually perform the summation correctly because the inner loop's `i` shadows `i` from the outer loop. -Shadowing should *usually* be avoided in the interest of write clearer code, such as - -```typescript -function sumMatrix(matrix: number[][]) { - let sum = 0; - for (let i = 0; i < matrix.length; i++) { - var currentRow = matrix[i]; - for (let j = 0; j < currentRow.length; j++) { - sum += currentRow[j]; - } - } - - return sum; -} -``` -While there are some scenarios where it may be fitting to take advantage of it, you should use your best judgement. - -# `const` declarations - -`const` declarations are another way of declaring variables. - -```typescript -const numLivesForCat = 9; -``` - -They are like `let` declarations but, as their name implies, their value cannot be changed once they are bound. -In other words, they have the same scoping rules as `let`, but you can't re-assign to them. - -### ~button /js/operators -NEXT: Operators -### ~ \ No newline at end of file diff --git a/docs/offline-app.html b/docs/offline-app.html new file mode 100644 index 00000000..08a52bea --- /dev/null +++ b/docs/offline-app.html @@ -0,0 +1,792 @@ + + + + + + Micro:bit offline App + + + + + + + + + + + + + + + +
+ +
+
+ +
+
+

MakeCode Offline App

+
+
+ +
+
+ +
+
+ Please read and accept the following terms to download the app. +
+
+
+

+ MICROSOFT PRE-RELEASE SOFTWARE LICENSE TERMS +

+

+ MICROSOFT MAKECODE SOFTWARE FOR MICRO:BIT +

+

+ +

+

+ These license terms are an agreement between Microsoft Corporation (or based on where you live, one + of its affiliates) and you. They apply to the software named above. The terms also apply to any + Microsoft services or updates for the software, except to the extent those have additional terms. +

+

+ +

+

+ IF YOU COMPLY WITH THESE LICENSE TERMS, YOU HAVE THE RIGHTS BELOW. +

+

+ 1. +          + INSTALLATION AND USE RIGHTS. + You may install and use any number of copies of the software to evaluate it as you develop and test + your software applications for use with micro:bit hardware. +

+

+ 2. +          + PRE-RELEASE SOFTWARE. + The software is a pre-release version. It may not work the way a final version of the software will. + Microsoft may change it for the final, commercial version. We also may not release a commercial + version. Microsoft is not obligated to provide maintenance, technical support or updates to you + for the software. +

+

+ 3. +          + ASSOCIATED ONLINE SERVICES. +         Some features of the software provide access + to, or rely on, online services to provide you information about updates to the software or extensions, + or to enable you to retrieve content, collaborate with others, or otherwise supplement your development + experience. As used throughout these license terms, the term software includes these online + services and features. By using these online services and features you consent to the to the + transmission of information as described in Section 5, DATA. + +

+

+ 4. +          + LICENSES FOR OTHER COMPONENTS. +  The software may include third party components with separate legal notices or governed by + other agreements, as described in the ThirdPartyNotices file accompanying the software. Even + if such components are governed by other agreements, the disclaimers and the limitations on and + exclusions of damages below also apply. +

+

+ 5. +          + DATA. +

+

+ a. +     + Data Collection. + The software may collect information about you and your use of the software, and send that to Microsoft. + Microsoft may use this information to provide services and improve our products and services. + You may opt out of many of these scenarios, but not all, as described in the product documentation. + In using the software, you must comply with applicable law. You can learn more about data collection + and use in the help documentation and the privacy statement at + + http://go.microsoft.com/fwlink/?LinkId=398505 + + . +  Your use of the software operates as your consent to these practices. +

+

+ b. +     + Processing of Personal Data. + To the extent Microsoft is a processor or subprocessor of personal data in connection with the software, + Microsoft makes the commitments in the European Union General Data Protection Regulation Terms + of the Online Services Terms to all customers effective May 25, 2018, at + + http://go.microsoft.com/?linkid=9840733 + + . +

+

+ 6. +          + FEEDBACK. + If you give feedback about the software to Microsoft, you give to Microsoft, without charge, the + right to use, share and commercialize your feedback in any way and for any purpose. You will + not give feedback that is subject to a license that requires Microsoft to license its software + or documentation to third parties because we include your feedback in them. These rights survive + this agreement. +

+

+ 7. +          + SCOPE OF LICENSE. +  The software is licensed, not sold. This agreement only gives you some rights to use the software. + Microsoft reserves all other rights. Unless applicable law gives you more rights despite this + limitation, you may use the software only as expressly permitted in this agreement.  In + doing so, you must comply with any technical limitations in the software that only allow you + to use it in certain ways. You may not: +

+

+ -     work around any technical limitations in the software; +

+

+ -     reverse engineer, decompile or disassemble the software, or attempt to do so, except + and only to the extent required by third party licensing terms governing use of certain open + source components that may be included with the software; +

+

+ -     remove, minimize, block or modify any notices of Microsoft or its suppliers in the + software; + +

+

+ -     use the software in any way that is against the law; or +

+

+ -     share, publish, rent or lease the software, or provide the software as a stand-alone + offering for others to use. +

+

+ 8.   UPDATES. + The software may periodically check for updates and download and install them for you. You may obtain + updates only from Microsoft or authorized sources. Microsoft may need to update your system to + provide you with updates. You agree to receive these automatic updates without any additional + notice. Updates may not include or support all existing software features, services, or peripheral + devices. + +

+

+ 9. +     + EXPORT RESTRICTIONS. +  You must comply with all domestic and international export laws and regulations that apply + to the software, which include restrictions on destinations, end users and end use. For further + information on export restrictions, visit (aka.ms/exporting). +

+

+ 10. +   + SUPPORT SERVICES. + Because the software is “as is,” we may not provide support services for it. +

+

+ 11. +   + ENTIRE AGREEMENT. +  This agreement, and the terms for supplements, updates, Internet-based services and support + services that you use, are the entire agreement for the software and support services. +

+

+ 12. +   + APPLICABLE LAW. + If you acquired the software in the United States, Washington State law applies to interpretation + of and claims for breach of this agreement, and the laws of the state where you live apply to + all other claims. If you acquired the software in any other country, its laws apply. +

+

+ 13. +   + CONSUMER RIGHTS; REGIONAL VARIATIONS. + This agreement describes certain legal rights. You may have other rights, including consumer rights, + under the laws of your state or country. Separate and apart from your relationship with Microsoft, + you may also have rights with respect to the party from which you acquired the software. This + agreement does not change those other rights if the laws of your state or country do not permit + it to do so. For example, if you acquired the software in one of the below regions, or mandatory + country law applies, then the following provisions apply to you: +

+

+ a. +     + Australia. + You have statutory guarantees under the Australian Consumer Law and nothing in this agreement is + intended to affect those rights. +

+

+ b. +     + Canada. + If you acquired the software in Canada, you may stop receiving updates by turning off the automatic + update feature, disconnecting your device from the Internet (if and when you re-connect to the + Internet, however, the software will resume checking for and installing updates), or uninstalling + the software. The product documentation, if any, may also specify how to turn off updates for + your specific device or software. +

+

+ c. +     + Germany and Austria + . +

+

+ (i) +              + Warranty + . The properly licensed software will perform substantially as described in any Microsoft materials + that accompany the software. However, Microsoft gives no contractual guarantee in relation to + the licensed software. +

+

+   +

+

+ (ii) +             + Limitation of Liability + . In case of intentional conduct, gross negligence, claims based on the Product Liability Act, as + well as, in case of death or personal or physical injury, Microsoft is liable according to the + statutory law. +

+

+ Subject to the foregoing clause (ii), Microsoft will only be liable for slight negligence if Microsoft + is in breach of such material contractual obligations, the fulfillment of which facilitate the + due performance of this agreement, the breach of which would endanger the purpose of this agreement + and the compliance with which a party may constantly trust in (so-called "cardinal obligations"). + In other cases of slight negligence, Microsoft will not be liable for slight negligence. +

+

+ 14. +   + LEGAL EFFECT. +  This agreement describes certain legal rights. You may have other rights under the laws of + your country. You may also have rights with respect to the party from whom you acquired the software. + This agreement does not change your rights under the laws of your country if the laws of your + country do not permit it to do so. +

+

+ 15. +   + DISCLAIMER OF WARRANTY. THE SOFTWARE IS LICENSED “AS-IS.”  YOU BEAR THE RISK OF + USING IT. MICROSOFT GIVES NO EXPRESS WARRANTIES, GUARANTEES OR CONDITIONS. TO THE EXTENT PERMITTED + UNDER YOUR LOCAL LAWS, MICROSOFT EXCLUDES THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS + FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +

+

+ 16. +   + LIMITATION ON AND EXCLUSION OF DAMAGES. YOU CAN RECOVER FROM MICROSOFT AND ITS SUPPLIERS ONLY DIRECT + DAMAGES UP TO U.S. $5.00. YOU CANNOT RECOVER ANY OTHER DAMAGES, INCLUDING CONSEQUENTIAL, LOST + PROFITS, SPECIAL, INDIRECT OR INCIDENTAL DAMAGES. +

+

+ This limitation applies to (a) anything related to the software, services, content (including code) + on third party Internet sites, or third party programs; and (b) claims for breach of contract, + breach of warranty, guarantee or condition, strict liability, negligence, or other tort to the + extent permitted by applicable law. +

+

+ It also applies even if Microsoft knew or should have known about the possibility of the damages. + The above limitation or exclusion may not apply to you because your country may not allow the + exclusion or limitation of incidental, consequential or other damages. +

+

+ Please note: As the software is distributed in Quebec, Canada, some of the clauses in this agreement + are provided below in French. +

+

+ Remarque : Ce logiciel étant distribué au Québec, Canada, certaines des clauses + dans ce contrat sont fournies ci-dessous en français. +

+

+ EXONÉRATION DE GARANTIE. +  Le logiciel visé par une licence est offert « tel quel ». Toute utilisation + de ce logiciel est à votre seule risque et péril. Microsoft n’accorde aucune + autre garantie expresse. Vous pouvez bénéficier de droits additionnels en vertu + du droit local sur la protection des consommateurs, que ce contrat ne peut modifier. La ou elles + sont permises par le droit locale, les garanties implicites de qualité marchande, d’adéquation + à un usage particulier et d’absence de contrefaçon sont exclues. + +

+

+ LIMITATION DES DOMMAGES-INTÉRÊTS ET EXCLUSION DE RESPONSABILITÉ POUR LES DOMMAGES. +  Vous pouvez obtenir de Microsoft et de ses fournisseurs une indemnisation en cas de dommages + directs uniquement à hauteur de 5,00 $ US. Vous ne pouvez prétendre à aucune + indemnisation pour les autres dommages, y compris les dommages spéciaux, indirects ou + accessoires et pertes de bénéfices. +

+

+ Cette limitation concerne : +

+

+ -         tout ce qui est relié au logiciel, aux services ou au contenu + (y compris le code) figurant sur des sites Internet tiers ou dans des programmes tiers ; et +

+

+ -         les réclamations au titre de violation de contrat ou de garantie, + ou au titre de responsabilité stricte, de négligence ou d’une autre faute + dans la limite autorisée par la loi en vigueur. +

+

+ Elle s’applique également, même si Microsoft connaissait ou devrait connaître + l’éventualité d’un tel dommage. Si votre pays n’autorise pas + l’exclusion ou la limitation de responsabilité pour les dommages indirects, accessoires + ou de quelque nature que ce soit, il se peut que la limitation ou l’exclusion ci-dessus + ne s’appliquera pas à votre égard. +

+

+ EFFET JURIDIQUE. +  Le présent contrat décrit certains droits juridiques. Vous pourriez avoir d’autres + droits prévus par les lois de votre pays. Le présent contrat ne modifie pas les + droits que vous confèrent les lois de votre pays si celles-ci ne le permettent pas. +

+

+ +

+

+   +

+

+ Micro:bit and micro:bit logo are trademarks and/ or copyrights of the Micro:bit + Educational Foundation. ©Micro:bit Educational Foundation. All rights reserved. + +

+

+   +

+

+ Remainder of this page intentionally left blank. +

+

+ +

+
+
+
+ + +
+ +
+ +
+ + + + + + + diff --git a/docs/packages-ref.json b/docs/packages-ref.json new file mode 100644 index 00000000..262cccf2 --- /dev/null +++ b/docs/packages-ref.json @@ -0,0 +1,3 @@ +{ + "redirect": "/extensions" +} \ No newline at end of file diff --git a/docs/projects.md b/docs/projects.md new file mode 100644 index 00000000..ba0df86d --- /dev/null +++ b/docs/projects.md @@ -0,0 +1,29 @@ +# Projects + +```codecard +[ + { + "name": "First Steps", + "url": "/calliope/firststeps", + "imageUrl": "/docs/calliope/firststeps/connecting.jpg", + "largeImageUrl": "/docs/calliope/firststeps/firstSteps.jpg" + }, + { + "name": "Turorials", + "url": "/calliope/tutorials", + "imageUrl": "/docs/calliope/tutorials/01_flashing_heart.gif" + }, + { + "name": "Calliope Links", + "url": "/calliope/links", + "imageUrl": "/docs/calliope/links/thumbnail_shop.gif" + } +] +``` + +## See Also + +[First Steps](/calliope/firststeps), +[Turorials](/calliope/tutorials), +[Calliope Links](/calliope/links) + diff --git a/docs/projects/SUMMARY.md b/docs/projects/SUMMARY.md new file mode 100644 index 00000000..d25a2576 --- /dev/null +++ b/docs/projects/SUMMARY.md @@ -0,0 +1,29 @@ +# Projects + +* [First Steps](/calliope/firststeps) + * [Get Ready](/calliope/firststeps/firstSteps) + * [The 5x5 LED matrix](/calliope/firststeps/5x5LED) + * [Radio](/calliope/firststeps/Radio) + * [Loops](/calliope/firststeps/Loops) + * [Mathematics](/calliope/firststeps/Mathematics) + * [Inputs](/calliope/firststeps/Inputs) + * [Sensors](/calliope/firststeps/Sensors) + * [Output](/calliope/firststeps/Output) + * [Decisions](/calliope/firststeps/Decisions) + * [Variables](/calliope/firststeps/Variables) +* [Turorials](/calliope/tutorials) + * [Flashing Heart](/projects/flashing-heart) + * [Name Tag](/projects/name-tag) + * [Smiley Buttons](/projects/smiley-buttons) + * [Dice](/projects/dice) + * [Love Meter](/projects/love-meter) + * [Mini Chat](/projects/mini-chat) + * [Rock Paper Scissors](/projects/rock-paper-scissors) + * [Coin Flipper](/projects/coin-flipper) + * [Snap the dot](/projects/snap-the-dot) + * [Multi Dice](/projects/multi-dice) +* [Calliope Links](/calliope/links) + * [Shop](https://shop.calliope.cc) + * [Projects](https://calliope.cc/en/projekte) + * [Teaching materials](https://calliope.cc/schulen/schulmaterial) + * [Forum](https://forum.calliope.cc) diff --git a/docs/projects/coin-flipper.md b/docs/projects/coin-flipper.md new file mode 100644 index 00000000..7c9464e5 --- /dev/null +++ b/docs/projects/coin-flipper.md @@ -0,0 +1,74 @@ +# Coin Flipper + +## Introduction @unplugged + +Let's create a coin flipping program to simulate a real coin toss. We'll use icon images to represent a ``heads`` or ``tails`` result. + +![Simulating coin toss](/docs/calliope/tutorials/08_coin_flipper_animation.gif) + +## Step 1 + +Get an ``||input:on button A pressed||`` block from the ``||input:Input||`` drawer in the toolbox. We'll put our coin flipping code in here. + +```blocks +input.onButtonPressed(Button.A, () => { +}) +``` + +## Step 2 + +Grab an ``||logic:if else||`` block and set it inside ``||input:on button A pressed||``. Put a ``||Math:pick random true or false||`` into the ``||logic:if||`` as its condition. + +The ``||Math:pick random true or false||`` returns a random ``true`` or ``false`` value which we use to determine a ``heads`` or ``tails`` result for a coin toss. + +```blocks +input.onButtonPressed(Button.A, () => { + if (Math.randomBoolean()) { + } else { + } +}) +``` + +## Step 3 + +Now, put a ``||basic:show icon||`` block inside both the ``||logic:if||`` and the ``||logic:else||``. Pick images to mean ``heads`` and ``tails``. + +```blocks +input.onButtonPressed(Button.A, () => { + if (Math.randomBoolean()) { + basic.showIcon(IconNames.Skull) + } else { + basic.showIcon(IconNames.Square) + } +}) +``` + +## Step 4 + +Press button **A** in the simulator to try the coin toss code. + +## Step 5 + +You can animate the coin toss to add the feeling of suspense. Place different ``||basic:show icon||`` blocks before the ``||logic:if||`` to show that the coin is flipping. + +```blocks +input.onButtonPressed(Button.A, () => { + basic.showIcon(IconNames.Diamond) + basic.showIcon(IconNames.SmallDiamond) + basic.showIcon(IconNames.Diamond) + basic.showIcon(IconNames.SmallDiamond) + if (Math.randomBoolean()) { + basic.showIcon(IconNames.Skull) + } else { + basic.showIcon(IconNames.Square) + } +}) +``` + +## Step 6 + +If you have a @boardname@, connect it to USB and click ``|Download|`` to transfer your code. + +## Step 7 + +Press button **A** for a flip. Test your luck and guess ``heads`` or ``tails`` before the toss is over! diff --git a/docs/projects/dice.md b/docs/projects/dice.md new file mode 100644 index 00000000..3de037ea --- /dev/null +++ b/docs/projects/dice.md @@ -0,0 +1,58 @@ +# Dice + +## Introduction @unplugged + +Let's turn the @boardname@ into a dice! +(Want to learn how the accelerometer works? [Watch this video](https://youtu.be/byngcwjO51U)). + +![A mini dice](/docs/calliope/tutorials/04_dice_animation.gif) + +## Step 1 @fullscreen + +We need 3 pieces of code: one to detect a throw (shake), another to pick a random number, and then one to show the number. + +Place the ``||input:on shake||`` block onto the editor workspace. It runs code when you shake the @boardname@. + +```blocks +input.onGesture(Gesture.Shake, () => { + +}) +``` + +## Step 2 @fullscreen + +Get a ``||basic:show number||`` block and place it inside the ``||input:on shake||`` block to display a number. + +```blocks +input.onGesture(Gesture.Shake, () => { + basic.showNumber(0) +}) +``` + +## Step 3 @fullscreen + +Put a ``||Math:pick random||`` block in the ``||basic:show number||`` block to pick a random number. + +```blocks +input.onGesture(Gesture.Shake, () => { + basic.showNumber(Math.randomRange(0, 10)) +}) +``` + +## Step 4 @fullscreen + +A typical dice shows values from `1` to `6`. So, in ``||Math:pick random||``, don't forget to choose the right minimum and maximum values! + +```blocks +input.onGesture(Gesture.Shake, () => { + basic.showNumber(Math.randomRange(1, 6)) +}) +``` + +## Step 5 + +Use the simulator to try out your code. Does it show the number you expected? + +## Step 6 + +If you have a @boardname@ connected, click ``|Download|`` and transfer your code to the @boardname@! diff --git a/docs/projects/flashing-heart.md b/docs/projects/flashing-heart.md new file mode 100644 index 00000000..a8083b80 --- /dev/null +++ b/docs/projects/flashing-heart.md @@ -0,0 +1,46 @@ +# Flashing Heart + +## Introduction @unplugged + +Learn how to use the LEDs and make a flashing heart! +(Want to learn how lights work? [Watch this video](https://youtu.be/qqBmvHD5bCw)). + + +![Heart shape in the LEDs](/docs/calliope/tutorials/01_flashing_heart_animation.gif) + +## Step 1 @fullscreen + +Place the ``||basic:show leds||`` block in the ``||basic:forever||`` block and draw a heart. + +![An animation that shows how to drag a block and paint a heart](/docs/calliope/tutorials/add_show_led.gif) + +## Step 2 @fullscreen + +Place another ``||basic:show leds||`` block. You can leave it blank and draw what you want. + +```blocks +basic.forever(function() { + basic.showLeds(` + . # . # . + # # # # # + # # # # # + . # # # . + . . # . .`); + basic.showLeds(` + . . . . . + . . . . . + . . . . . + . . . . . + . . . . .`); +}) +``` + +## Step 3 @fullscreen + +Look at the virtual @boardname@, you should see the heart and your drawing blink on the screen. + +![Heart shape in the LEDs](/docs/calliope/tutorials/01_flashing_heart_animation.gif) + +## Step 4 @fullscreen + +If you have a @boardname@ connected, click ``|Download|`` to transfer your code and watch the hearts flash! diff --git a/docs/projects/love-meter.md b/docs/projects/love-meter.md new file mode 100644 index 00000000..df09b3a0 --- /dev/null +++ b/docs/projects/love-meter.md @@ -0,0 +1,45 @@ +# Love Meter + +## Introduction @unplugged + +Make a love meter, how sweet! The @boardname@ is feeling the love, then sometimes not so much! +Tell everyone who you are. Show you name on the LEDs. + +![Love meter banner message](/docs/calliope/tutorials/05_love_meter_animation.gif) + +## Step 1 + +Let's build a **LOVE METER** machine. Place an ``||input:on pin pressed||`` block to run code when pin **0** is pressed. Use ``P0`` from the list of pin inputs. + +```blocks +input.onPinPressed(TouchPin.P0, () => { +}); +``` + +## Step 2 + +Using ``||basic:show number||`` and ``||Math:pick random||`` blocks, show a random number from `0` to `100` when pin **0** is pressed. + +```blocks +input.onPinPressed(TouchPin.P0, () => { + basic.showNumber(Math.randomRange(0, 100)); +}); +``` +## Step 3 + +Click on pin **0** in the simulator and see which number is chosen. + +## Step 4 + +Show ``"LOVE METER"`` on the screen when the @boardname@ starts. + +```blocks +basic.showString("LOVE METER"); +input.onPinPressed(TouchPin.P0, () => { + basic.showNumber(Math.randomRange(0, 100)); +}); +``` + +## Step 5 + +Click ``|Download|`` to transfer your code in your @boardname@. Hold the **GND** pin with one hand and press pin **0** with the other hand to trigger this code. diff --git a/docs/projects/mini-chat.md b/docs/projects/mini-chat.md new file mode 100644 index 00000000..c2aaa8a5 --- /dev/null +++ b/docs/projects/mini-chat.md @@ -0,0 +1,67 @@ +# Mini Chat + +## Introduction @unplugged + +![Two @boardname@ connected via radio](/docs/calliope/tutorials/06_mini_chat_animation.gif) + +Use the **radio** to send and receive messages with other @boardname@. + +## Sending a message @fullscreen + +Use ``||input:on button pressed||`` to send a text message over radio with ``||radio:send string||``. +Every @boardname@ nearby will receive this message. + +```blocks +input.onButtonPressed(Button.A, () => { + radio.sendString("Yo"); +}); +``` + +## Receiving a message @fullscreen + +Add a ``||radio:on received string||`` block to run when a message is received. + +```blocks +radio.onReceivedString(function (receivedString) { +}) +``` + +## Displaying text @fullscreen + +Add a ``||basic:show string||`` to display the string on the screen. Pull the ``||variables:receivedString||`` out of ``||radio:on received string||`` and put it into ``||basic:show string||``. + +```blocks +radio.onReceivedString(function (receivedString) { + basic.showString(receivedString); +}) +``` + +## Testing in the simulator @fullscreen + +Press button **A** on the simulator, you will notice that a second @boardname@ appears (if your screen is too small, the simulator might decide not to show it). Try pressing **A** again and notice that the "Yo" message gets displayed on the other @boardname@. + +```blocks +input.onButtonPressed(Button.A, () => { + radio.sendString("Yo"); +}); +radio.onReceivedString(function (receivedString) { + basic.showString(receivedString); +}) +``` + +## Try it for real @fullscreen + +If you two @boardname@s, download the program to each one. Press button **A** on one and see if the other gets a message. + +## Groups @fullscreen + +Use the ``||radio:set group||`` block to assign a **group** number to your program. You will only receive messages from @boardname@s within the same group. Use this to avoid receiving messages from every @boardname@ that is transmitting. + +```blocks +radio.setGroup(123) +``` + + +```package +radio +``` diff --git a/docs/projects/multi-dice.md b/docs/projects/multi-dice.md new file mode 100644 index 00000000..7c3d9b1f --- /dev/null +++ b/docs/projects/multi-dice.md @@ -0,0 +1,95 @@ +# Multi Dice + +## Introduction @unplugged + +![Multiple @boardname@ throwing a dice](/docs/calliope/tutorials/10_multi_dice_animation.gif) + +Build a multi-player dice game using the **radio**. The **radio** blocks let you send wireless messages between a @boardname@ and another @boardname@. + +In this game, you shake to "throw the dice" and send the result to the other @boardname@. If you receive a result of a dice throw equal or greater than yours, you lose. + +## Dice game @fullscreen + +Let's start by rebuilding the **dice** game. If you are unsure about the details, try the **dice** tutorial again. + +```blocks +input.onGesture(Gesture.Shake, function () { + basic.showNumber(Math.randomRange(1, 6)) +}) +``` + +## Dice variable @fullscreen + +We need to store the result of the dice cast in a variable. A **variable** is like a place in the memory of the @boardname@ where you save information, like numbers. + +* Go to the **Variables** toolbox and click ``||Make a Variable||`` to create a new variable. We will call it **dice**. +* Add a ``||set dice to||`` block and drag the ``||pick random||`` into it. +* Drag a ``||dice||`` from the **Variables** toolbox into the ``||basic:show number||`` block. + +```blocks +let dice = 0 +input.onGesture(Gesture.Shake, function () { + dice = Math.randomRange(1, 6) + basic.showNumber(dice) +}) +``` + +## Send the dice @fullscreen + +Put in a ``||radio:send number||`` and a ``||dice||`` to send the value stored in the ``dice`` variable via radio. + +```blocks +let dice = 0 +input.onGesture(Gesture.Shake, function () { + dice = Math.randomRange(1, 6) + basic.showNumber(dice) + radio.sendNumber(dice) +}) +``` + +## Receive the dice @fullscreen + +Go get an ``||radio:on received number||`` event block. This event runs when a radio message from another @boardname@ arrives. The ``receivedNumber`` value is the value of the dice in this game. + +```blocks +radio.onReceivedNumber(function (receivedNumber) { +}) +``` + +## Check your cast @fullscreen + +Add a ``||logic:if||`` block to test if ``receivedNumber`` is greater or equal to ``dice``. +If is, you lost so display a sad face on the screen. + +```blocks +let dice = 0; +radio.onReceivedNumber(function (receivedNumber) { + if (receivedNumber >= dice) { + basic.showIcon(IconNames.Sad) + } +}) +``` + +## Test it! @fullscreen + +Try pressing **SHAKE** in the simulator and see that a second @boardname@ appears. You can play the game on both virtual boards. + +If you have more than one @boardname@, download your code onto each one and try playing the game with your friends! + +```blocks +let dice = 0 +input.onGesture(Gesture.Shake, function () { + dice = Math.randomRange(1, 6) + basic.showNumber(dice) + radio.sendNumber(dice) +}) +radio.onReceivedNumber(function (receivedNumber) { + if (receivedNumber >= dice) { + basic.showIcon(IconNames.Sad) + } +}) +``` + +```package +radio +``` diff --git a/docs/projects/name-tag.md b/docs/projects/name-tag.md new file mode 100644 index 00000000..c2cae4d2 --- /dev/null +++ b/docs/projects/name-tag.md @@ -0,0 +1,38 @@ +# Name Tag + +## Introduction @unplugged + +Tell everyone who you are. Show you name on the LEDs. + +![Name scrolling on the LEDs](/docs/calliope/tutorials/02_nametag_animation.gif) + +## Step 1 @fullscreen + +Place the ``||basic:show string||`` block in the ``||basic:forever||`` block to repeat it. Change the text to your name. + +```blocks +basic.forever(() => { + basic.showString("Emma"); +}); +``` + +## Step 2 @fullscreen + +Look at the simulator and make sure it shows your name on the screen. + +![Name scrolling on the LEDs](/docs/calliope/tutorials/02_nametag_animation.gif) + +## Step 3 @fullscreen + +Place more ``||basic:show string||`` blocks to create your own story. + +```blocks +basic.forever(() => { + basic.showString("Emma"); + basic.showString("<3<3<3"); +}) +``` + +## Step 4 @unplugged + +If you have a @boardname@ connected, click ``|Download|`` to transfer your code and watch your name scroll! diff --git a/docs/projects/rock-paper-scissors.md b/docs/projects/rock-paper-scissors.md new file mode 100644 index 00000000..7a3465f6 --- /dev/null +++ b/docs/projects/rock-paper-scissors.md @@ -0,0 +1,171 @@ +# Rock Paper Scissors + +## Introduction @unplugged + +![Animation of the Rock Paper Scissors game](/docs/calliope/tutorials/07_stone_paper_scissors_animation.gif) + +Use the accelerometer and the screen to build a **Rock Paper Scissors** game that you can play with your friends! + +## Step 1 @fullscreen + +Add a ``||input:on shake||`` block to run code when you shake the @boardname@. + +```blocks +input.onGesture(Gesture.Shake, () => { + +}) +``` + +## Step 2 @fullscreen + +Add a ``hand`` variable and place the ``||variables:set hand to||`` block in the shake event. + + + +## Step 3 @fullscreen + +Add a ``||math:pick random||`` block to pick a random number from `1` to `3` and store it in the variable named ``hand``. + +```blocks +let hand = 0; +input.onGesture(Gesture.Shake, () => { + hand = Math.randomRange(1, 3) +}) +``` + +In a later step, each of the possible numbers (`1`, `2`, or `3`) is matched to its own picture. The picture is shown on the LEDs when its matching number is picked. + +## Step 4 @fullscreen + +Place an ``||logic:if||`` block under the ``||math:pick random||`` and check whether ``hand`` is equal to ``1``. Add a ``||basic:show leds||`` block that shows a picture of a piece of paper. The number `1` will mean paper. + + + +```blocks +let hand = 0; +input.onGesture(Gesture.Shake, () => { + hand = Math.randomRange(1, 3) + if (hand == 1) { + basic.showLeds(` + # # # # # + # . . . # + # . . . # + # . . . # + # # # # # + `) + } +}) +``` + +## Step 5 @fullscreen + +Click on the **SHAKE** button in the simulator. If you try enough times, you should see a picture of paper on the screen. + +![Shaking a @boardname@ simulator](/static/mb/projects/rock-paper-scissors/rpsshake.gif) + +## Step 6 @fullscreen + +Click the **(+)** button to add an ``||logic:else||`` section. + + + +```blocks +let hand = 0; +input.onGesture(Gesture.Shake, () => { + hand = Math.randomRange(1, 3) + if (hand == 1) { + basic.showLeds(` + # # # # # + # . . . # + # . . . # + # . . . # + # # # # # + `) + } else { + + } +}) +``` + +## Step 7 @fullscreen + +Add a ``||basic:show leds||`` block inside the ``||logic:else||``. Make a picture of a scissors in the LEDs. + +```blocks +let hand = 0; +input.onGesture(Gesture.Shake, () => { + hand = Math.randomRange(1, 3) + if (hand == 1) { + basic.showLeds(` + # # # # # + # . . . # + # . . . # + # . . . # + # # # # # + `) + } else { + basic.showLeds(` + # # . . # + # # . # . + . . # . . + # # . # . + # # . . # + `) + } +}) +``` + +## Step 8 @fullscreen + +Click the ``+`` button again to add an ``||logic:else if||`` section. Now, add a conditional block for ``||logic:hand = 2||`` to the condition in ``||logic:else if||``. Since ``hand`` can only be `1`, `2`, or `3`, your code is covering all possible cases! + +![Adding an else if clause](/static/mb/projects/rock-paper-scissors/ifelseif.gif) + +## Step 9 @fullscreen + +Get one more ``||basic:show leds||`` block and put it in the ``||logic:else if||``. Make a picture of a rock in the LEDs. + +```blocks +let hand = 0; +input.onGesture(Gesture.Shake, () => { + hand = Math.randomRange(1, 3) + if (hand == 1) { + basic.showLeds(` + # # # # # + # . . . # + # . . . # + # . . . # + # # # # # + `) + } else if (hand == 2) { + basic.showLeds(` + . . . . . + . # # # . + . # # # . + . # # # . + . . . . . + `) + } else { + basic.showLeds(` + # # . . # + # # . # . + . . # . . + # # . # . + # # . . # + `) + } +}) +``` + +## Step 10 @fullscreen + +Click on the **SHAKE** button in the simulator and check to see that each image is showing up. + +![Shaking a @boardname@ simulator](/static/mb/projects/rock-paper-scissors/rpssim3.gif) + +## Step 11 @fullscreen + +If you have a @boardname@, click on ``|Download|`` and follow the instructions to get the code +onto your @boardname@. Your game is ready! Gather your friends and play Rock Paper Scissors! + + diff --git a/docs/projects/smiley-buttons.md b/docs/projects/smiley-buttons.md new file mode 100644 index 00000000..43257e76 --- /dev/null +++ b/docs/projects/smiley-buttons.md @@ -0,0 +1,81 @@ +# Smiley Buttons + +## Introduction @unplugged + +Code the buttons on the @boardname@ to show that it's happy or sad. +(Want to learn how the buttons works? [Watch this video](https://youtu.be/t_Qujjd_38o)). + +![Pressing the A and B buttons](/docs/calliope/tutorials/03_smiley_button_animation.gif) + +## Step 1 @fullscreen + +Place a ``||input:on button pressed||`` block to run code when button **A** is pressed. + +```blocks +input.onButtonPressed(Button.A, () => { +}); +``` + +## Step 2 @fullscreen + +Place a ``||basic:show leds||`` block inside ``||input:on button pressed||`` to display a smiley on the screen. Press the **A** button in the simulator to see the smiley. + +```blocks +input.onButtonPressed(Button.A, () => { + basic.showLeds(` + # # . # # + # # . # # + . . . . . + # . . . # + . # # # .` + ); +}); +``` + +## Step 3 @fullscreen + +Add ``||input:on button pressed||`` and ``||basic:show leds||`` blocks to display a frowny when button **B** is pressed. + +```blocks +input.onButtonPressed(Button.B, () => { + basic.showLeds(` + # # . # # + # # . # # + . . . . . + . # # # . + # . . . #` + ); +}); +``` + +## Step 4 @fullscreen + +Add a secret mode that happens when **A** and **B** are pressed together. For this case, add multiple ``||basic:show leds||`` blocks to create an animation. + +```blocks +input.onButtonPressed(Button.AB, () => { + basic.showLeds(` + . . . . . + # . # . . + . . . . . + # . . . # + . # # # . + `) + basic.showLeds(` + . . . . . + . . # . # + . . . . . + # . . . # + . # # # . + `) +}) +``` + +## Step 5 + +If you have a @boardname@, connect it to USB and click ``|Download|`` to transfer your code. Press button **A** on your @boardname@. Try button **B** and then **A** and **B** together. + +## Step 6 + +Nice! Now go and show it off to your friends! + diff --git a/docs/projects/snap-the-dot.md b/docs/projects/snap-the-dot.md new file mode 100644 index 00000000..91ba3222 --- /dev/null +++ b/docs/projects/snap-the-dot.md @@ -0,0 +1,94 @@ +# Snap the Dot + +## Introduction @unplugged + +![Animation of the snap the dot game](/docs/calliope/tutorials/09_snap_the_dot_animation.gif) + +Snap the dot is a game of skill where the player has to press **A** exactly when the dot reaches the center of the screen. + +This tutorial shows how to use the game engine. + +## Create a sprite @fullscreen + +Drag a ``||game:create sprite||`` block onto the workspace. A sprite is a single pixel that can move on the screen. It has an ``x`` and ``y`` position along with a direction of motion. + +```blocks +let sprite: game.LedSprite = null +sprite = game.createSprite(2, 2) +``` + +## Move the dot @fullscreen + +The sprite starts in the center facing right. Put a ``||game:move||`` block into the ``||basic:forever||`` to make it move. Notice how it moves to the right but does not bounce back. + +```blocks +let sprite: game.LedSprite = null +sprite = game.createSprite(2, 2) +basic.forever(function () { + sprite.move(1) +}) +``` + +## Bounce @fullscreen + +Grab a ``||game:if on edge, bounce||`` block to make the sprite bounce on the side of the screen. Also, add a ``||basic:pause||`` block to slow down the sprite. + +```blocks +let sprite: game.LedSprite = null +sprite = game.createSprite(2, 2) +basic.forever(function () { + sprite.move(1) + sprite.ifOnEdgeBounce() + basic.pause(100) +}) +``` + +## Test and download + +Use the simulator to find the best speed. If you have a @boardname@, press ``|Download|`` to try it out on the device. + +## Button handling @fullscreen + +When **A** is pressed, we test if the sprite is in the center or not. + +Use a ``||input:on button pressed||`` block to handle the **A** button. Put in a ``||logic:if||`` block and test if ``||game:x||`` is equal to `2`. + +```blocks +let sprite: game.LedSprite = null +input.onButtonPressed(Button.A, function () { + if (sprite.get(LedSpriteProperty.X) == 2) { + } else { + } +}) +sprite = game.createSprite(2, 2) +basic.forever(function () { + sprite.move(1) + basic.pause(100) + sprite.ifOnEdgeBounce() +}) +``` + +## Score and game over + +Finally, pull out an ``||game:add score||`` and a ``||game:game over||`` block to handle both success (sprite in the center) and failure (sprite not in the center). + +```blocks +let sprite: game.LedSprite = null +input.onButtonPressed(Button.A, function () { + if (sprite.get(LedSpriteProperty.X) == 2) { + game.addScore(1) + } else { + game.gameOver() + } +}) +sprite = game.createSprite(2, 2) +basic.forever(function () { + sprite.move(1) + basic.pause(100) + sprite.ifOnEdgeBounce() +}) +``` + +## Test and download + +Your game is ready! If you have a @boardname@, press ``|Download|`` to try it out on the device. diff --git a/docs/reference.md b/docs/reference.md deleted file mode 100644 index c5bdd08e..00000000 --- a/docs/reference.md +++ /dev/null @@ -1,47 +0,0 @@ -# Reference - -### @description List of API categories available in the editors - -```namespaces -basic.showNumber(0); -input.onButtonPressed(Button.A, () => { - -}); -music.playTone(0, 0); -led.plot(0, 0); -radio.sendNumber(0); -``` -## Advanced - -```namespaces -game.addScore(1); -images.createImage(` -. . . . . -. . . . . -. . # . . -. . . . . -. . . . . -`); -pins.digitalReadPin(DigitalPin.P0); -serial.writeNumber(0); -control.inBackground(() => { - -}); -``` - -## Bluetooth - -```namespaces -devices.tellCameraTo(MesCameraEvent.TakePhoto); -bluetooth.onBluetoothConnected(() => {}); -``` - -```package -radio -devices -bluetooth -``` - -### See Also - -[basic](/reference/basic), [input](/reference/input), [music](/reference/music), [led](/reference/led), [Math (blocks)](/blocks/math), [String](/reference/types/string), [game](/reference/game), [images](/reference/images), [pins](/reference/pins), [serial](/reference/serial), [control](/reference/control), [radio](/reference/radio), [devices](/reference/devices), [bluetooth](/reference/bluetooth) diff --git a/docs/reference/basic.md b/docs/reference/basic.md index 91383e9f..aceb095b 100644 --- a/docs/reference/basic.md +++ b/docs/reference/basic.md @@ -1,9 +1,10 @@ # Basic -Provides access to basic @boardname@ functionality. +Use basic @boardname@ functions and actions. ```cards basic.showNumber(0); +basic.showIcon(IconNames.Heart); basic.showLeds(` . . . . . . . . . . @@ -11,30 +12,19 @@ basic.showLeds(` . . . . . . . . . . `); -basic.showString("Hello!"); +basic.showString("hi!"); basic.clearScreen(); basic.forever(() => { }); basic.pause(100); -basic.plotLeds(` -. . . . . -. . . . . -. . # . . -. . . . . -. . . . . -`); -basic.showAnimation(` -. . . . . -. . . . . -. . # . . -. . . . . -. . . . . -`); +basic.showArrow(ArrowNames.North); ``` -### See Also +## See also -[showNumber](/reference/basic/show-number), [showLeds](/reference/basic/show-leds), [showString](/reference/basic/show-string), +[showNumber](/reference/basic/show-number), +[showIcon](/reference/basic/show-icon), +[showLeds](/reference/basic/show-leds), [showString](/reference/basic/show-string), [clearScreen](/reference/basic/clear-screen), [forever](/reference/basic/forever), [pause](/reference/basic/pause), -[showAnimation](/reference/basic/show-animation) +[showArrow](/reference/basic/show-arrow), [showAnimation](/reference/basic/show-animation) diff --git a/docs/reference/basic/clear-screen.md b/docs/reference/basic/clear-screen.md index 7194348a..97a15b3b 100644 --- a/docs/reference/basic/clear-screen.md +++ b/docs/reference/basic/clear-screen.md @@ -6,7 +6,7 @@ Turn off all the LED lights on the [LED screen](/device/screen). basic.clearScreen() ``` -### Example: Vanishing heart +## Example: Vanishing heart The following code shows a heart on the screen and then turns off all the LED lights. @@ -21,7 +21,7 @@ basic.showLeds(` basic.clearScreen() ``` -### See also +## See also [set brightness](/reference/led/set-brightness), [unplot](/reference/led/unplot), [plot](/reference/led/plot), [Image](/reference/images/image) diff --git a/docs/reference/basic/forever.md b/docs/reference/basic/forever.md index d06ec3c8..c7f9bfb6 100644 --- a/docs/reference/basic/forever.md +++ b/docs/reference/basic/forever.md @@ -8,46 +8,47 @@ basic.forever(() => { }) ``` -### Example: compass +## Example: compass The following example constantly checks the [compass heading](/reference/input/compass-heading) and updates the screen with the direction. ```blocks +let degrees = 0 basic.forever(() => { - let heading = input.compassHeading() - if (heading < 45) { - basic.showString("N", 100) - } else if (heading < 135) { - basic.showString("E", 100) - } - else if (heading < 225) { - basic.showString("S", 100) - } - else { - basic.showString("W", 100) + degrees = input.compassHeading() + if (degrees < 45) { + basic.showString("N") + } else if (degrees < 135) { + basic.showString("E") + } else if (degrees < 225) { + basic.showString("S") + } else if (degrees < 315) { + basic.showString("W") + } else { + basic.showString("N") } }) ``` -### Example: counter +## Example: counter -The following example keeps showing the [number](/reference/types/number) stored in a global variable. +The following example keeps showing the [number](/types/number) stored in a global variable. When you press button `A`, the number gets bigger. You can use a program like this to count things with your @boardname@. ```blocks let num = 0 basic.forever(() => { - basic.showNumber(num, 150) + basic.showNumber(num) }) input.onButtonPressed(Button.A, () => { num = num + 1 }) ``` -### Competing for the LED screen +## Competing for the LED screen If different parts of a program are each trying to show something on the LED screen at the same time, @@ -56,14 +57,14 @@ Try this on your @boardname@: ```blocks basic.forever(() => { - basic.showNumber(6789, 150) + basic.showNumber(6789) }) input.onButtonPressed(Button.A, () => { - basic.showNumber(2, 150) + basic.showNumber(2) }) ``` -### See also +## See also [while](/blocks/loops/while), [on button pressed](/reference/input/on-button-pressed), [in background](/reference/control/in-background) diff --git a/docs/reference/basic/pause.md b/docs/reference/basic/pause.md index 887df9cb..4c962a73 100644 --- a/docs/reference/basic/pause.md +++ b/docs/reference/basic/pause.md @@ -7,11 +7,11 @@ You can use this function to slow your program down. basic.pause(400) ``` -### Parameters +## Parameters * ``ms`` is the number of milliseconds that you want to pause (100 milliseconds = 1/10 second, and 1000 milliseconds = 1 second). -### Example: diagonal line +## Example: diagonal line This example draws a diagonal line by turning on LED `0, 0` (top left) through LED `4, 4` (bottom right). The program pauses 500 milliseconds after turning on each LED. @@ -24,7 +24,7 @@ for (let i = 0; i < 5; i++) { } ``` -### See also +## See also [while](/blocks/loops/while), [running time](/reference/input/running-time), [for](/blocks/loops/for) diff --git a/docs/reference/led/plot-leds.md b/docs/reference/basic/plot-leds.md similarity index 76% rename from docs/reference/led/plot-leds.md rename to docs/reference/basic/plot-leds.md index 3c920c9d..db6b2649 100644 --- a/docs/reference/led/plot-leds.md +++ b/docs/reference/basic/plot-leds.md @@ -1,6 +1,6 @@ # Plot LEDs -Display an [Image](/reference/images/image) on the @boardname@'s [LED screen](/device/screen). NOTE: `basic -> plot image` has been replaced by `basic -> show leds`. +Display an [Image](/reference/images/image) on the @boardname@'s [LED screen](/device/screen). ```sig basic.showLeds(` @@ -12,11 +12,11 @@ basic.showLeds(` `) ``` -### Parameters +## Parameters * leds - a series of LED on/off states that form an image (see steps below) -### Example: smiley +## Example: smiley ```blocks basic.showLeds(` @@ -28,7 +28,7 @@ basic.showLeds(` `) ``` -### See also +## See also [show animation](/reference/basic/show-animation), [image](/reference/images/image), [show image](/reference/images/show-image), [scroll image](/reference/images/scroll-image) diff --git a/docs/reference/basic/show-animation.md b/docs/reference/basic/show-animation.md index 3259b049..b91554e7 100644 --- a/docs/reference/basic/show-animation.md +++ b/docs/reference/basic/show-animation.md @@ -1,4 +1,4 @@ -# Show Animation +# show Animation Show a group of image frames (pictures) one after another on the [LED screen](/device/screen). It pauses the amount of time you tell it after each frame. @@ -12,12 +12,12 @@ basic.showAnimation(` `) ``` -### Parameters +## Parameters -* `leds` is a [String](/reference/types/string) that shows which LEDs are on and off, in groups one after another. -* `interval` is an optional [Number](/reference/types/number). It means the number of milliseconds to pause after each image frame. +* `leds` is a [string](/types/string) that shows which LEDs are on and off, in groups one after another. +* `interval` is an optional [number](/types/number). It means the number of milliseconds to pause after each image frame. -### Example: Animating a group of image frames +## Example: Animating a group of image frames In this animation, each row is 15 spaces wide because there are three frames in the animation, and each frame is @@ -33,13 +33,13 @@ basic.showAnimation(` `) ``` -### ~hint +## ~hint If the animation is too fast, make `interval` bigger. -### ~ +## ~ -### Example: animating frames with a pause +## Example: animating frames with a pause This example shows six frames on the screen, pausing 500 milliseconds after each frame. @@ -57,8 +57,8 @@ basic.showAnimation(` `, 500) ``` -### ~hint +## ~hint Use [forever](/reference/basic/forever) to show an animation over and over. -### ~ +## ~ diff --git a/docs/reference/basic/show-arrow.md b/docs/reference/basic/show-arrow.md new file mode 100644 index 00000000..82f60f4d --- /dev/null +++ b/docs/reference/basic/show-arrow.md @@ -0,0 +1,29 @@ +# Show Arrow + +Shows the selected arrow on the LED screen + +```sig +basic.showArrow(ArrowNames.North) +``` + + +## Parameters + +* ``direction``, the identifier of the arrow to display +* ``interval`` (optional), the time to display in milliseconds. default is 400. + +## Example + +This program shows all eight arrows. + +```blocks +for (let index = 0; index <= 7; index++) { + basic.showArrow(index) + basic.pause(300) +} +``` + +## See also + +[showIcon](/reference/basic/show-icon), +[showLeds](/reference/basic/show-leds) \ No newline at end of file diff --git a/docs/reference/basic/show-icon.md b/docs/reference/basic/show-icon.md new file mode 100644 index 00000000..d76264b2 --- /dev/null +++ b/docs/reference/basic/show-icon.md @@ -0,0 +1,26 @@ +# Show Icon + +Shows the selected icon on the LED screen + +```sig +basic.showIcon(IconNames.Heart) +``` + +## Parameters + +* ``icon``, the identifier of the icon to display +* ``interval`` (optional), the time to display in milliseconds. default is 400. + +## Example + +This program shows a happy face and then a sad face with the ``show icon`` function, with a one second pause in between. + +```blocks +basic.showIcon(IconNames.Happy) +basic.pause(1000) +basic.showIcon(IconNames.Sad) +``` + +## See also + +[showLeds](/reference/basic/show-leds) \ No newline at end of file diff --git a/docs/reference/basic/show-leds.md b/docs/reference/basic/show-leds.md index 0e7a42b9..7125078b 100644 --- a/docs/reference/basic/show-leds.md +++ b/docs/reference/basic/show-leds.md @@ -13,13 +13,19 @@ basic.showLeds(` ) ``` -### Parameters +## Parameters -* `leds` is a [string](/reference/types/string) that controls which LEDs are on and off. -* `interval` is an optional [number](/reference/types/number) that means how many milliseconds to wait after showing a picture. +* `leds` is a [string](/types/string) that controls which LEDs are on and off. +* `interval` is an optional [number](/types/number) that means how many milliseconds to wait after showing a picture. If you are programming with blocks, `interval` is set at 400 milliseconds. -### Example +## ~ hint + +See how the @boardname@ shows numbers, text, and displays images by watching this video about [LEDs](https://www.youtube.com/watch?v=qqBmvHD5bCw). + +## ~ + +## Example This program shows a picture with the ``show leds`` function. @@ -34,14 +40,14 @@ basic.showLeds(` ) ``` -### ~hint +## ~hint If you are programming in JavaScript, `#` means an LED that is turned on and `.` means an LED that is turned off. -### ~ +## ~ -### See also +## See also -[plot leds](/reference/led/plot-leds), [show animation](/reference/basic/show-animation) +[plot leds](/reference/basic/plot-leds), [show animation](/reference/basic/show-animation) diff --git a/docs/reference/basic/show-number.md b/docs/reference/basic/show-number.md index ef741701..804b96ad 100644 --- a/docs/reference/basic/show-number.md +++ b/docs/reference/basic/show-number.md @@ -2,47 +2,47 @@ Show a number on the [LED screen](/device/screen). It will slide left if it has more than one digit. -~~~~sig -basic.showNumber(2, 150) -~~~~ +```sig +basic.showNumber(2) +``` -### Parameters +## Parameters -* `value` is a [Number](/reference/types/number). -* `interval` is an optional [Number](/reference/types/number). It means the number of milliseconds before sliding the `value` left by one LED each time. Bigger intervals make the sliding slower. +* `value` is a [Number](/types/number). +* `interval` is an optional [Number](/types/number). It means the number of milliseconds before sliding the `value` left by one LED each time. Bigger intervals make the sliding slower. -### Examples: +## Examples: To show the number 10: -~~~~blocks +```blocks basic.showNumber(10) -~~~~ +``` To show the number stored in a variable: -~~~~blocks +```blocks let x = 1 basic.showNumber(x) -~~~~ +``` -### Example: count to 5 +## Example: count to 5 This example uses a [for](/blocks/loops/for) loop to show numbers ``0`` through ``5`` on the screen: -~~~~blocks +```blocks for (let i = 0; i < 6; i++) { basic.showNumber(i) basic.pause(200) } -~~~~ +``` -### Other show functions +## Other show functions -* Use [show string](/reference/basic/show-string) to show a [String](/reference/types/string) with letters on the screen. +* Use [show string](/reference/basic/show-string) to show a [String](/types/string) with letters on the screen. * Use [show animation](/reference/basic/show-animation) to show a group of pictures on the screen, one after another. -### See also +## See also -[show string](/reference/basic/show-string), [show animation](/reference/basic/show-animation), [Number](/reference/types/number), [math](/blocks/math) +[show string](/reference/basic/show-string), [show animation](/reference/basic/show-animation), [Number](/types/number), [math](/blocks/math) diff --git a/docs/reference/basic/show-string.md b/docs/reference/basic/show-string.md index 930c9810..78136312 100644 --- a/docs/reference/basic/show-string.md +++ b/docs/reference/basic/show-string.md @@ -1,17 +1,17 @@ # Show String -Show a number on the [LED screen](/device/screen). It will slide left if it is bigger than the screen. +Show a string on the [LED screen](/device/screen). It will scroll to left if it's bigger than the screen. ```sig -basic.showString("Hello!") +basic.showString("hi!") ``` -### Parameters +## Parameters -* `text` is a [String](/reference/types/string). It can contain letters, numbers, and punctuation. -* `interval` is an optional [Number](/reference/types/number). It means the number of milliseconds before sliding the [String](/reference/types/string) left by one LED each time. Bigger intervals make the sliding slower. +* `text` is a [String](/types/string). It can contain letters, numbers, and punctuation. +* `interval` is an optional [Number](/types/number). It means the number of milliseconds before sliding the [String](/types/string) left by one LED each time. Bigger intervals make the sliding slower. -### Examples: +## Examples: To show the word **Hello**: @@ -19,19 +19,19 @@ To show the word **Hello**: basic.showString("Hello") ``` -To show what is stored in a [String](/reference/types/string) variable: +To show what is stored in a [String](/types/string) variable: ```blocks let s = "Hi" basic.showString(s) ``` -### Other show functions +## Other show functions * Use [show number](/reference/basic/show-number) to show a number on the [LED screen](/device/screen). * Use [show animation](/reference/basic/show-animation) to show a group of pictures on the screen, one after another. -### See also +## See also -[String](/reference/types/string), [show number](/reference/basic/show-number), [show animation](/reference/basic/show-animation) +[String](/types/string), [show number](/reference/basic/show-number), [show animation](/reference/basic/show-animation) diff --git a/docs/reference/bluetooth.md b/docs/reference/bluetooth.md index d2fa66b2..1a20ac00 100644 --- a/docs/reference/bluetooth.md +++ b/docs/reference/bluetooth.md @@ -2,12 +2,12 @@ Support for additional Bluetooth services. -### ~hint +## ~hint ![](/static/bluetooth/Bluetooth_SIG.png) For another device like a smartphone to use any of the Bluetooth "services" which the @boardname@ has, it must first be [paired with the @boardname@](/reference/bluetooth/bluetooth-pairing). Once paired, the other device may connect to the @boardname@ and exchange data relating to many of the @boardname@'s features. -### ~ +## ~ ```cards @@ -19,6 +19,7 @@ bluetooth.startMagnetometerService(); bluetooth.startTemperatureService(); bluetooth.onBluetoothConnected(() => {}); bluetooth.onBluetoothDisconnected(() => {}); +bluetooth.setTransmitPower(7); ``` ## UART @@ -26,25 +27,39 @@ bluetooth.onBluetoothDisconnected(() => {}); ```cards bluetooth.startUartService(); bluetooth.uartReadUntil(""); +bluetooth.uartWriteLine(""); bluetooth.uartWriteString(""); bluetooth.uartWriteNumber(0); bluetooth.uartWriteValue("", 0); +bluetooth.onUartDataReceived(",", () => {}) ``` -```package -bluetooth +## Eddystone + +```cards +bluetooth.advertiseUid(42, 1, 7, true); +bluetooth.advertiseUrl("https://makecode.microbit.org/", 7, true); +bluetooth.stopAdvertising(); ``` -### Advanced +## Advanced For more advanced information on the @boardname@ Bluetooth UART service including information on using a smartphone, see the [Lancaster University @boardname@ runtime technical documentation](http://lancaster-university.github.io/microbit-docs/ble/uart-service/) -### See Also +## See Also [startAccelerometerService](/reference/bluetooth/start-accelerometer-service), [startButtonService](/reference/bluetooth/start-button-service), [startIOPinService](/reference/bluetooth/start-io-pin-service), [startLEDService](/reference/bluetooth/start-led-service), [startMagnetometerService](/reference/bluetooth/start-magnetometer-service), [startTemperatureService](/reference/bluetooth/start-temperature-service), [startUartService](/reference/bluetooth/start-uart-service), [uartReadUntil](/reference/bluetooth/uart-read-until), +[uartWriteLine](/reference/bluetooth/uart-write-line), [uartWriteString](/reference/bluetooth/uart-write-string), [uartWriteNumber](/reference/bluetooth/uart-write-number), [uartWriteValue](/reference/bluetooth/uart-write-value), -[onBluetoothConnected](/reference/bluetooth/on-bluetooth-connected), [onBluetoothDisconnected](/reference/bluetooth/on-bluetooth-disconnected) +[onBluetoothConnected](/reference/bluetooth/on-bluetooth-connected), +[onBluetoothDisconnected](/reference/bluetooth/on-bluetooth-disconnected), +[advertiseUrl](/reference/bluetooth/advertise-url), +[stopAdvertising](/reference/bluetooth/stop-advertising) + +```package +bluetooth +``` diff --git a/docs/reference/bluetooth/about-bluetooth.md b/docs/reference/bluetooth/about-bluetooth.md index c93e6cf7..5716be71 100755 --- a/docs/reference/bluetooth/about-bluetooth.md +++ b/docs/reference/bluetooth/about-bluetooth.md @@ -18,21 +18,21 @@ A Bluetooth device contains a table of data called an Attribute Table which can The Attribute Table contains something like a series of records of various types. The main types are called Services, Characteristics and Descriptors. Let's look at each of these terms in turn. -### Attributes +## Attributes Services, Characteristics and Descriptors are all types of Attribute. Hence Generic Attribute Profile, Attribute Table and something called the Attribute Protocol. All attributes have a type which is identified by a UUID (Universally Unique Identifer). Some Attributes are defined by the Bluetooth SIG, the technical standards body for Bluetooth and these have UUIDs which are 16 bits in length. Some Attributes are custom designed for a particular device by the product team and these have 128 bit UUIDs. The @boardname@ uses a mixture of 16 bit and 128 bit UUIDs. -### Structure +## Structure Services, Characteristics and Descriptors are organised in a hierarchy with Services at the top and Descriptors at the bottom. Services contain one or more Characteristics. A Characteristic owns zero or more Descriptors. Zero because Descriptors are completely optional whereas a Service must contain at least one Characteristic. ![](/static/bluetooth/gatt_hierarchy.png) -### Services +## Services A Service is a container for logically related Bluetooth data items. Those data items are in fact called Characteristics. A Service can be thought of as the owner of the Characteristics inside it. Often a Service represents a particular feature (e.g. a hardware feature) of a device like the buttons or a particular sensor. An example of a Bluetooth SIG defined Service is the Device Information Service which, as the name suggests, is a container for various items of information about the device such as its manufacturer and serial number. The @boardname@ has this service. -### Characteristics +## Characteristics Characteristics are items of data which relate to a particular internal state of the device or perhaps some state of the environment which the device can measure using a sensor. The current battery level is an example of internal state data whereas the ambient temperature could perhaps be measured by a sensor. Sometimes Characteristics represent configuration data such as the frequency at which you want something to be measured. In any of these cases, the way a device can expose such data to other devices to use via Bluetooth is by making them available as a Characteristic. An example of a Bluetooth SIG defined Characteristic is the Serial Number String which you'll find inside the Device Information service. @@ -46,11 +46,11 @@ Sometimes the device will have been programmed to respond in a special way when Permissions are to do with security and further describe the security conditions that must be met before read or write access to the characteristic is to be granted. -### Descriptors +## Descriptors Descriptors contain meta data which either augments the details relating to the Characteristic which the Descriptor belongs to or allows the configuration of a behaviour involving that Characteristic. Notification messages are switched on or off using a special descriptor called the Client Characteristic Configuration Descriptor for example. -### Profile +## Profile A Bluetooth profile is a specification which pulls together all the required information about how a device behaves, how it can be accessed in terms of its services, characteristics and descriptors, security rules, concurrency limitations and so on. @@ -73,10 +73,10 @@ Full documentation for the @boardname@ Bluetooth profile as used by this applica The @boardname@'s accelerometer (motion detector), magnetometer (digital compass), two buttons on the front, LED Display, IO pins on the edge connector, internal message bus and internal temperature sensor are all exposed as Services so that applications can exploit these features of the device. In addition: * the Bluetooth SIG defined Device Information Service is included to allow applications to obtain information such as firmware version details over Bluetooth -* there's a Device Firmware Update (DFU) service which allows new @boardname@ code to be flahsed to the device over Bluetooth instead of over USB +* there's a Device Firmware Update (DFU) service which allows new @boardname@ code to be flashed to the device over Bluetooth instead of over USB * there's a UART service which allows arbitrary data to be exchanged with the @boardname@ in a way resembling traditional serial communications. -Everything you can do with the @boardname@ over Bluetooth is achieved through read, write and notify operations. Not all characteristics support all three so check the profile documentation. Often there are Characteristics whose purpose is to allow you to write configuration values which control other behviours. Technically these are called Control Points. For example you can specify the frequency with which accelerometer data is sampled before it is transmitted as a Notification message to your application. +Everything you can do with the @boardname@ over Bluetooth is achieved through read, write and notify operations. Not all characteristics support all three so check the profile documentation. Often there are Characteristics whose purpose is to allow you to write configuration values which control other behaviours. Technically these are called Control Points. For example you can specify the frequency with which accelerometer data is sampled before it is transmitted as a Notification message to your application. ## Want to Know More? @@ -86,14 +86,14 @@ That's it! Enjoy using Bluetooth on the @boardname@! Martin Woolley, Bluetooth SIG. Twitter: @bluetooth_mdw -#### Video +### Video https://www.youtube.com/watch?v=aep_GVowKfs -### See also +## See also [About Bluetooth](/reference/bluetooth/about-bluetooth), [@boardname@ Bluetooth profile overview ](http://lancaster-university.github.io/microbit-docs/ble/profile/), [@boardname@ Bluetooth profile reference](http://lancaster-university.github.io/microbit-docs/resources/bluetooth/microbit-profile-V1.9-Level-2.pdf), [Bluetooth on @boardname@ resources](http://bluetooth-mdw.blogspot.co.uk/p/bbc-microbit.html), [Bluetooth SIG](https://www.bluetooth.com) ```package bluetooth -``` \ No newline at end of file +``` diff --git a/docs/reference/bluetooth/advertise-uid-buffer.md b/docs/reference/bluetooth/advertise-uid-buffer.md new file mode 100644 index 00000000..f4219e85 --- /dev/null +++ b/docs/reference/bluetooth/advertise-uid-buffer.md @@ -0,0 +1,37 @@ +# Advertise UID Buffer + +Advertises a UID via the Eddystone protocol over Bluetooth. + +## ~hint + +## Eddystone + +Bluetooth beacons are used to indicate proximity to a place or object of interest. +Beacons use Bluetooth advertising to broadcast a small amount of data, +which can be received and acted upon by anyone in range with a suitable device and software, typically a smartphone and application. + +There are various beacon message formats, which define the way Bluetooth advertising packets are used as containers for beacon data. +iBeacon is Apple's beacon message format. Eddystone comes from Google. + +Read more at https://lancaster-university.github.io/microbit-docs/ble/eddystone/ . + +## ~ + +```sig +bluetooth.advertiseUidBuffer(pins.createBuffer(16), 7, true); +``` + +## Parameters + +* ``buffer`` - a 16 bytes buffer containing the namespace (first 10 bytes) and instance (last 6 bytes). +* ``power`` - a [number](/types/number) representing the power level between 0 (short) and 7 (maximum range). +* ``connectable`` - a [boolean](/blocks/logic/boolean) indicating whether or not the @boardname@ should accept connections. + + +## See Also + +[stop-advertising](/reference/bluetooth/stop-advertising), [advertise-uid](/reference/bluetooth/advertise-uid) + +```package +bluetooth +``` diff --git a/docs/reference/bluetooth/advertise-uid.md b/docs/reference/bluetooth/advertise-uid.md new file mode 100644 index 00000000..710b677d --- /dev/null +++ b/docs/reference/bluetooth/advertise-uid.md @@ -0,0 +1,46 @@ +# Advertise UID + +Advertises a UID via the Eddystone protocol over Bluetooth. + +## ~hint + +## Eddystone + +Bluetooth beacons are used to indicate proximity to a place or object of interest. +Beacons use Bluetooth advertising to broadcast a small amount of data, +which can be received and acted upon by anyone in range with a suitable device and software, typically a smartphone and application. + +There are various beacon message formats, which define the way Bluetooth advertising packets are used as containers for beacon data. +iBeacon is Apple's beacon message format. Eddystone comes from Google. + +Read more at https://lancaster-university.github.io/microbit-docs/ble/eddystone/ . + +## ~ + +```sig +bluetooth.advertiseUid(42, 1, 7, true); +``` + +## Parameters + +* ``namespace`` last 4 bytes of the namespace uid (6 to 9) +* ``instance`` last 4 bytes of the instance (2 to 5) +* ``power`` - a [number](/types/number) representing the power level between 0 (short) and 7 (maximum range). +* ``connectable`` - a [boolean](/blocks/logic/boolean) indicating whether or not the @boardname@ should accept connections. + +## Encoding + +The bytes of ``namespace`` and ``instance`` are encoded to generate the 10 bytes UID namespace and 6 bytes UID instance. + +``` +UID namespace: [0, ..., namespace] +UID instance: [0, ..., instance] +``` + +## See Also + +[stop-advertising](/reference/bluetooth/stop-advertising), [advertise-uid-buffer](/reference/bluetooth/advertise-uid-buffer) + +```package +bluetooth +``` diff --git a/docs/reference/bluetooth/advertise-url.md b/docs/reference/bluetooth/advertise-url.md new file mode 100644 index 00000000..45a687f1 --- /dev/null +++ b/docs/reference/bluetooth/advertise-url.md @@ -0,0 +1,42 @@ +# Advertise Url + +Advertises a URL via the Eddystone protocol over Bluetooth. + +## ~hint + +## Eddystone + +Bluetooth beacons are used to indicate proximity to a place or object of interest. +Beacons use Bluetooth advertising to broadcast a small amount of data, +which can be received and acted upon by anyone in range with a suitable device and software, typically a smartphone and application. + +There are various beacon message formats, which define the way Bluetooth advertising packets are used as containers for beacon data. +iBeacon is Apple's beacon message format. Eddystone comes from Google. + +Read more at https://lancaster-university.github.io/microbit-docs/ble/eddystone/ . + +## ~ + +```sig +bluetooth.advertiseUrl("https://makecode.microbit.org/", 7, true); +``` + +## Parameters + +* ``url`` - a [string](/types/string) containing the URL to broadcast, at most 17 characters long, excluding the protocol (eg: ``https://``) which gets encoded as 1 byte. +* ``power`` - a [number](/types/number) representing the power level between 0 (short) and 7 (maximum range). +* ``connectable`` - a [boolean](/blocks/logic/boolean) indicating whether or not the @boardname@ should accept connections. + +## Example: Broadcast a secret code + +```blocks +bluetooth.advertiseUrl("https://pxt.io?secret=42", 7, true); +``` + +## See Also + +[stop-advertising](/reference/bluetooth/stop-advertising), [advertise-uid](/reference/bluetooth/advertise-uid) + +```package +bluetooth +``` diff --git a/docs/reference/bluetooth/bluetooth-pairing.md b/docs/reference/bluetooth/bluetooth-pairing.md index 6c104605..effe2d46 100755 --- a/docs/reference/bluetooth/bluetooth-pairing.md +++ b/docs/reference/bluetooth/bluetooth-pairing.md @@ -1,100 +1,21 @@ # Bluetooth Pairing -### ~hint ![](/static/bluetooth/Bluetooth_SIG.png) -For another device like a smartphone to use any of the Bluetooth "services" which the @boardname@ has, it must first be [paired with the @boardname@](/reference/bluetooth/bluetooth-pairing). Once paired, the other device may connect to the @boardname@ and exchange data relating to many of the @boardname@'s features. +For another device like a smartphone to use any of the Bluetooth "services" which the @boardname@ has, it must first be paired with the @boardname@. Once paired, the other device may connect to the @boardname@ and exchange data relating to many of the @boardname@'s features. -### ~ +Follow the [Bluetooth Pairing Guide](https://microbit.org/guide/mobile/) to pair your @boardname@ to your computer or phone. -### What is 'pairing'? +If you need additional help in pairing your @boardname@ to another device, see these guides also: -'Pairing' is what you have to do to have your @boardname@ trust another device like a smartphone and similarly, have your smartphone trust your @boardname@. Why 'trust'? Well, pairing is all about security. You wouldn't usually want just anyone's smartphone connecting to your @boardname@ and making it do things so by pairing *your* smartphone with *your* @boardname@ you ensure that only your devices can talk to each other. - -Once you've paired your @boardname@ with another device it also means that they are able to exchange information privately, without someone else being able to "see" the data they're exchanging over the air using Bluetooth. This is accomplished by data being [encrypted](https://en.wikipedia.org/wiki/Encryption) and pairing makes it possible for devices who trust each other to encrypt and decrypt data from each other. - -# How do you pair your @boardname@ with another device? - -Making your @boardname@ pair requires you to follow some simple steps which will be described shortly. What you do with the device you're pairing it to will vary slightly depending on what that device is. We'll look at how it's done with common smartphones and tablets here too. - -To get your @boardname@ ready for pairing do the following: - -1. Hold down buttons A and B on the front of your @boardname@ together. The front is the side with two buttons and the LED display. Keep the two buttons held down. Don't let go of them yet! -2. While still holding down buttons A and B, press and then release the reset button on the back of the @boardname@. Keep holding down buttons A and B. -3. You should see "PAIRING MODE!" start to scroll across the @boardname@ display. When you see this message start to appear you can release buttons A and B. -4. Eventually you'll see a strange pattern on your @boardname@ display. This is like your @boardname@'s signature. Other people's @boardname@s will probably display a different pattern. - -Your @boardname@ is now ready to be paired with the other device. Read the section below which relates to your 'other' device and watch the video too. - -### How do you pair your @boardname@ with a Windows smartphone or tablet? - -1. Go into Settings -2. Select Bluetooth -3. Switch your @boardname@ into 'pairing mode' using the steps above -4. Wait until 'PAIRING MODE!' has finished scrolling across the @boardname@ display. You should see your @boardname@ listed on your Windows smartphone with a name something like '@boardname@ [zatig]'. Note that the 5 characters in brackets at the end will vary. -5. On the Windows smartphone, tap the @boardname@ named in the device list. This will initiate the pairing process. -6. The @boardname@ will display a left pointing arrow and the Windows smartphone will pop up a box into which you will be invited to enter a "pin" (Personal Identity Number). -7. Press button A on the @boardname@ and watch carefully as the @boardname@ displays a sequence of 6 random numbers. You may find it easier to write them down than to remember them. -8. Enter the 6 digits which the @boardname@ displayed into your Windows smartphone in the pop-up box provided and then select "done". -9. If you entered the right number the @boardname@ will display a tick / check mark. If you made a mistake it will display a cross or X and you should repeat the process to try again. - -#### Video -https://www.youtube.com/watch?v=AoW3mit7jIg +* [Pairing and Flashing](https://support.microbit.org/a/solutions/articles/19000051025) +* [Pairing Modes](https://support.microbit.org/a/solutions/articles/19000080745) +* [Troubleshooting Guide](https://support.microbit.org/a/solutions/articles/19000069393) -### How do you pair your @boardname@ with an Android smartphone or tablet? - -1. Go into Settings -2. Select Bluetooth -3. Switch your @boardname@ into 'pairing mode' using the steps above -4. Wait until 'PAIRING MODE!' has finished scrolling across the @boardname@ display. You should see your @boardname@ listed on your Android smartphone under the heading "Available devices" with a name something like '@boardname@ [zatig]'. Note that the 5 characters in brackets at the end will vary. -5. On the Android smartphone, tap the @boardname@ named in the Available devices list. This will initiate the pairing process. -6. The @boardname@ will display a left pointing arrow and the Android smartphone will pop up a box into which you will be invited to enter a "pin" (Personal Identity Number). -7. Press button A on the @boardname@ and watch carefully as the @boardname@ displays a sequence of 6 random numbers. You may find it easier to write them down than to remember them. -8. Enter the 6 digits which the @boardname@ displayed into your Android smartphone in the pop-up box provided and then select "done". -9. If you entered the right number the @boardname@ will display a tick / check mark. If you made a mistake it will display a cross or X and you should repeat the process to try again. - -#### Video -https://www.youtube.com/watch?v=7hLBfdAGkZI - -### How do you pair your @boardname@ with an Apple iOS smartphone or tablet? - -The steps to pair with an Apple iOS device are different to those followed for an Android or Windows device. To trigger pairing you need an application which will try to interact with your @boardname@ and it's that interaction that triggers the iOS pairing process. There are many you could use but for the purposes of this documentation we'll suggest you install the "nRF Master Control Panel" (nRF MCP) application from Nordic Semiconductor. You'll find it in the Apple app store. It's a really useful Bluetooth application which will help you learn about Bluetooth as well as it having the ability to trigger the pairing process. After installing nRF MCP you should follow these steps to pair with your @boardname@: - -1. Switch your @boardname@ into 'pairing mode' using the steps above -2. Wait until 'PAIRING MODE!' has finished scrolling across the @boardname@ display. -3. Launch the nRF MCP application. Your @boardname@ should be listed and have a "Connect" button next to it. -4. Select "Connect" to connect your Apple device to the @boardname@. This will trigger the pairing process. -5. The @boardname@ will display a left pointing arrow and the Apple device will pop up a box into which you will be invited to enter a "pin" (Personal Identity Number). -6. Press button A on the @boardname@ and watch carefully as the @boardname@ displays a sequence of 6 random numbers. You may find it easier to write them down than to remember them. -7. Enter the 6 digits which the @boardname@ displayed into your Apple device in the pop-up box provided and then select "Pair". -8. If you entered the right number the @boardname@ will display a tick / check mark. If you made a mistake it will display a cross or X and you should repeat the process to try again. - -#### Video -https://www.youtube.com/watch?v=wslwyAMwMhs +## Apps -### How often do I need to pair my @boardname@ with my phone? +## See also -You do *not* need to pair your @boardname@ and smartphone or tablet every time you use them together. Pairing establishes 'trust' which will be retained until it is somehow lost. When another device wants to talk to your @boardname@ it must connect to it but connecting and pairing are not the same thing. - -There are circumstances which will result in pairing data being lost however and when this happens you will need to pair again. - -Currently, flashing new code via a USB cable causes the @boardname@'s Bluetooth pairing data to be lost. Consequently, if you do flash new code to your @boardname@ using a USB cable you will need to pair again. - -In contrast if you upload new code to your @boardname@ over Bluetooth, using for example the Samsung @boardname@ application for Android devices, you will not need to pair again. - -If you do find yourself needing to pair again you will first need to remove the pairing from your other device (i.e. smartphone or tablet): - -* On Android go into Settings/Bluetooth, select the 'cog' next to your @boardname@ and then select FORGET -* On iOS go into Settings/Bluetooth, select your @boardname@ and then select Forget This Device -* On a Windows device go into Settings/Bluetooth. Press and hold the @boardname@ entry on the Windows device. A pop-up will appear with the option "delete". Select "delete" to unpair your @boardname@. - -### See also - -[About Bluetooth](/reference/bluetooth/about-bluetooth), [@boardname@ Bluetooth profile overview ](http://lancaster-university.github.io/microbit-docs/ble/profile/), [@boardname@ Bluetooth profile reference](http://lancaster-university.github.io/microbit-docs/resources/bluetooth/microbit-profile-V1.9-Level-2.pdf), [Bluetooth on @boardname@ resources](http://bluetooth-mdw.blogspot.co.uk/p/bbc-microbit.html), [Bluetooth SIG](https://www.bluetooth.com) - - -```package -bluetooth -``` \ No newline at end of file +[About Bluetooth](/reference/bluetooth/about-bluetooth) diff --git a/docs/reference/bluetooth/on-bluetooth-connected.md b/docs/reference/bluetooth/on-bluetooth-connected.md index 42f3e4d9..e2dd3b65 100755 --- a/docs/reference/bluetooth/on-bluetooth-connected.md +++ b/docs/reference/bluetooth/on-bluetooth-connected.md @@ -1,11 +1,11 @@ # On Bluetooth Connected -### ~hint +## ~hint ![](/static/bluetooth/Bluetooth_SIG.png) For another device like a smartphone to use any of the Bluetooth "services" which the @boardname@ has, it must first be [paired with the @boardname@](/reference/bluetooth/bluetooth-pairing). Once paired, the other device may connect to the @boardname@ and exchange data relating to many of the @boardname@'s features. -### ~ +## ~ This block starts an [event handler](/reference/event-handler) which in this case will run when something connects to your @boardname@ using Bluetooth. @@ -14,7 +14,7 @@ when something connects to your @boardname@ using Bluetooth. bluetooth.onBluetoothConnected(() => {}); ``` -### Example +## Example You could use this event handler to display a letter "C" on the @boardname@ LED grid so you know you have a Bluetooth connection. Or you might want to send some data you've been accumulating to your smartphone as soon as it connects to your @boardname@. Maybe you've been using the accelerometer in your @boardname@ to count your steps for example. Using this event handler you could send the accumulated step count to your phone when it establishes a Bluetooth connection. @@ -24,11 +24,11 @@ bluetooth.onBluetoothConnected(() => { }); ``` -### Video - on Bluetooth connected +## Video - on Bluetooth connected http://www.youtube.com/watch?v=HyBcsD9Eh6I -### See also +## See also [About Bluetooth](/reference/bluetooth/about-bluetooth), [@boardname@ Bluetooth profile overview ](http://lancaster-university.github.io/microbit-docs/ble/profile/), [@boardname@ Bluetooth profile reference](http://lancaster-university.github.io/microbit-docs/resources/bluetooth/microbit-profile-V1.9-Level-2.pdf), [Bluetooth on @boardname@ resources](http://bluetooth-mdw.blogspot.co.uk/p/bbc-microbit.html), [Bluetooth SIG](https://www.bluetooth.com) diff --git a/docs/reference/bluetooth/on-bluetooth-disconnected.md b/docs/reference/bluetooth/on-bluetooth-disconnected.md index 619f359d..0187b182 100755 --- a/docs/reference/bluetooth/on-bluetooth-disconnected.md +++ b/docs/reference/bluetooth/on-bluetooth-disconnected.md @@ -1,11 +1,11 @@ # On Bluetooth Disconnected -### ~hint +## ~hint ![](/static/bluetooth/Bluetooth_SIG.png) For another device like a smartphone to use any of the Bluetooth "services" which the @boardname@ has, it must first be [paired with the @boardname@](/reference/bluetooth/bluetooth-pairing). Once paired, the other device may connect to the @boardname@ and exchange data relating to many of the @boardname@'s features. -### ~ +## ~ This block starts an [event handler](/reference/event-handler) which in this case will run when a device which is connected to your @boardname@ over Bluetooth disconnects. @@ -16,7 +16,7 @@ bluetooth.onBluetoothDisconnected(() => { }); ``` -### Example: Displaying "D" when a Bluetooth connection to the @boardname@ is closed +## Example: Displaying "D" when a Bluetooth connection to the @boardname@ is closed ```blocks bluetooth.onBluetoothDisconnected(() => { @@ -24,11 +24,11 @@ bluetooth.onBluetoothDisconnected(() => { }); ``` -### Video - on Bluetooth disconnected +## Video - on Bluetooth disconnected http://www.youtube.com/watch?v=HyBcsD9Eh6I -### See also +## See also [About Bluetooth](/reference/bluetooth/about-bluetooth), [@boardname@ Bluetooth profile overview ](http://lancaster-university.github.io/microbit-docs/ble/profile/), [@boardname@ Bluetooth profile reference](http://lancaster-university.github.io/microbit-docs/resources/bluetooth/microbit-profile-V1.9-Level-2.pdf), [Bluetooth on @boardname@ resources](http://bluetooth-mdw.blogspot.co.uk/p/bbc-microbit.html), [Bluetooth SIG](https://www.bluetooth.com) diff --git a/docs/reference/bluetooth/on-uart-data-received.md b/docs/reference/bluetooth/on-uart-data-received.md new file mode 100644 index 00000000..48d7202f --- /dev/null +++ b/docs/reference/bluetooth/on-uart-data-received.md @@ -0,0 +1,21 @@ +# Bluetooth On UART Data Received + +Registers an event to be fired when one of the delimiter is matched. + +```sig +bluetooth.onUartDataReceived(",", () => {}) +``` + +## Parameters + +* `delimiters` is a [string](/types/string) containing any of the character to match + +## Example + +Read values separated by `,`: + +```blocks +bluetooth.onUartDataReceived(serial.delimiters(Delimiters.Comma), () => { + basic.showString(serial.readUntil(serial.delimiters(Delimiters.Comma))) +}) +``` diff --git a/docs/reference/bluetooth/set-transmit-power.md b/docs/reference/bluetooth/set-transmit-power.md new file mode 100644 index 00000000..4d4da7ca --- /dev/null +++ b/docs/reference/bluetooth/set-transmit-power.md @@ -0,0 +1,26 @@ +# Bluetooth Set Transmit Power + +## ~hint +![](/static/bluetooth/Bluetooth_SIG.png) + +For another device like a smartphone to use any of the Bluetooth "services" which the @boardname@ has, it must first be [paired with the @boardname@](/reference/bluetooth/bluetooth-pairing). Once paired, the other device may connect to the @boardname@ and exchange data relating to many of the @boardname@'s features. + +## ~ + +Change the output power level of the transmitter to the given value. + +```sig +bluetooth.setTransmitPower(7); +``` + +## Parameters + +* `power`: a [number](/types/number) in the range ``0..7``, where ``0`` is the lowest power and ``7`` is the highest. + +## See also + +[About Bluetooth](/reference/bluetooth/about-bluetooth), [@boardname@ Bluetooth profile overview ](http://lancaster-university.github.io/microbit-docs/ble/profile/), [@boardname@ Bluetooth profile reference](http://lancaster-university.github.io/microbit-docs/resources/bluetooth/microbit-profile-V1.9-Level-2.pdf), [Bluetooth on @boardname@ resources](http://bluetooth-mdw.blogspot.co.uk/p/bbc-microbit.html), [Bluetooth SIG](https://www.bluetooth.com) + +```package +bluetooth +``` diff --git a/docs/reference/bluetooth/start-accelerometer-service.md b/docs/reference/bluetooth/start-accelerometer-service.md index 3254fc66..b5e37465 100755 --- a/docs/reference/bluetooth/start-accelerometer-service.md +++ b/docs/reference/bluetooth/start-accelerometer-service.md @@ -1,11 +1,11 @@ # Bluetooth Accelerometer Service -### ~hint +## ~hint ![](/static/bluetooth/Bluetooth_SIG.png) For another device like a smartphone to use any of the Bluetooth "services" which the @boardname@ has, it must first be [paired with the @boardname@](/reference/bluetooth/bluetooth-pairing). Once paired, the other device may connect to the @boardname@ and exchange data relating to many of the @boardname@'s features. -### ~ +## ~ The Bluetooth accelerometer service allows another device such as a smartphone to wirelessly receive data from the @boardname@'s accelerometer. An accelerometer detects motion. More precisely, it measures acceleration in one or more of three directions which we call X, Y and Z. @@ -17,7 +17,7 @@ No additional code is needed on the @boardname@ to use the Bluetooth acceleromet bluetooth.startAccelerometerService(); ``` -### Example: Starting the Bluetooth accelerometer service +## Example: Starting the Bluetooth accelerometer service The following code shows the Bluetooth accelerometer service being started: @@ -25,15 +25,15 @@ The following code shows the Bluetooth accelerometer service being started: bluetooth.startAccelerometerService(); ``` -### Video - Accelerometer service demo - Starts at 0:18 +## Video - Accelerometer service demo - Starts at 0:18 http://www.youtube.com/watch?v=aep_GVowKfs#t=18s -### Advanced +## Advanced For more advanced information on the @boardname@ Bluetooth accelerometer service including information on using a smartphone, see the [Lancaster University @boardname@ runtime technical documentation](http://lancaster-university.github.io/microbit-docs/ble/accelerometer-service/) -### See also +## See also [About Bluetooth](/reference/bluetooth/about-bluetooth), [@boardname@ Bluetooth profile overview ](http://lancaster-university.github.io/microbit-docs/ble/profile/), [@boardname@ Bluetooth profile reference](http://lancaster-university.github.io/microbit-docs/resources/bluetooth/microbit-profile-V1.9-Level-2.pdf), [Bluetooth on @boardname@ resources](http://bluetooth-mdw.blogspot.co.uk/p/bbc-microbit.html), [Bluetooth SIG](https://www.bluetooth.com) diff --git a/docs/reference/bluetooth/start-button-service.md b/docs/reference/bluetooth/start-button-service.md index f4cdaf09..bbfc4865 100755 --- a/docs/reference/bluetooth/start-button-service.md +++ b/docs/reference/bluetooth/start-button-service.md @@ -1,11 +1,11 @@ # Bluetooth Button Service -### ~hint +## ~hint ![](/static/bluetooth/Bluetooth_SIG.png) For another device like a smartphone to use any of the Bluetooth "services" which the @boardname@ has, it must first be [paired with the @boardname@](/reference/bluetooth/bluetooth-pairing). Once paired, the other device may connect to the @boardname@ and exchange data relating to many of the @boardname@'s features. -### ~ +## ~ The Bluetooth button service makes it possible for another device such as a smartphone to be notified wirelessly whenever a button on the front of a @boardname@ is pressed. Each of the two @boardname@ buttons can be in one of three possible states: @@ -21,7 +21,7 @@ No additional code is needed on the @boardname@ to use the Bluetooth button serv bluetooth.startButtonService(); ``` -### Example: Starting the Bluetooth button service +## Example: Starting the Bluetooth button service The following code shows the Bluetooth button service being started: @@ -29,15 +29,15 @@ The following code shows the Bluetooth button service being started: bluetooth.startButtonService(); ``` -### Video - Button service demo - Starts at 0:59 +## Video - Button service demo - Starts at 0:59 http://www.youtube.com/watch?v=aep_GVowKfs -### Advanced +## Advanced For more advanced information on the @boardname@ Bluetooth button service including information on using a smartphone, see the [Lancaster University @boardname@ runtime technical documentation](http://lancaster-university.github.io/microbit-docs/ble/button-service/) -### See also +## See also [About Bluetooth](/reference/bluetooth/about-bluetooth), [@boardname@ Bluetooth profile overview ](http://lancaster-university.github.io/microbit-docs/ble/profile/), [@boardname@ Bluetooth profile reference](http://lancaster-university.github.io/microbit-docs/resources/bluetooth/microbit-profile-V1.9-Level-2.pdf), [Bluetooth on @boardname@ resources](http://bluetooth-mdw.blogspot.co.uk/p/bbc-microbit.html), [Bluetooth SIG](https://www.bluetooth.com) diff --git a/docs/reference/bluetooth/start-io-pin-service.md b/docs/reference/bluetooth/start-io-pin-service.md index a85e98e2..b3bb27ba 100755 --- a/docs/reference/bluetooth/start-io-pin-service.md +++ b/docs/reference/bluetooth/start-io-pin-service.md @@ -1,13 +1,13 @@ # Bluetooth IO Pin Service -### ~hint +## ~hint ![](/static/bluetooth/Bluetooth_SIG.png) For another device like a smartphone to use any of the Bluetooth "services" which the @boardname@ has, it must first be [paired with the @boardname@](/reference/bluetooth/bluetooth-pairing). Once paired, the other device may connect to the @boardname@ and exchange data relating to many of the @boardname@'s features. -### ~ +## ~ -The Bluetooth IO pin service makes it possible for another device such as a smartphone to communicate with other electronic 'things' connected to a @boardname@'s edge connector. You could for example, use your smartphone to switch on or off a light which is connected to the @boardname@ or your smartphone could receive data collected from a sensor connected to the @boardname@. In fact you could do both of these things at the same time since the Bluetooth IO pin service lets you interact with multiple 'pins' on the edge conector in different ways all at the same time. +The Bluetooth IO pin service makes it possible for another device such as a smartphone to communicate with other electronic 'things' connected to a @boardname@'s edge connector. You could for example, use your smartphone to switch on or off a light which is connected to the @boardname@ or your smartphone could receive data collected from a sensor connected to the @boardname@. In fact you could do both of these things at the same time since the Bluetooth IO pin service lets you interact with multiple 'pins' on the edge connector in different ways all at the same time. No additional code is needed on the @boardname@ to use the Bluetooth IO pin service from another device. @@ -15,7 +15,7 @@ No additional code is needed on the @boardname@ to use the Bluetooth IO pin serv bluetooth.startIOPinService(); ``` -### Example: Starting the Bluetooth IO pin service +## Example: Starting the Bluetooth IO pin service The following code shows the Bluetooth IO pin service being started: @@ -23,17 +23,17 @@ The following code shows the Bluetooth IO pin service being started: bluetooth.startIOPinService(); ``` -### Video - IO pin service demo starts at 3:49 +## Video - IO pin service demo starts at 3:49 http://www.youtube.com/watch?v=aep_GVowKfs -### Advanced +## Advanced For more advanced information on the @boardname@ Bluetooth IO pin service including information on using a smartphone, see the [Lancaster University @boardname@ runtime technical documentation](http://lancaster-university.github.io/microbit-docs/ble/iopin-service/) -### See also +## See also -[About Bluetooth](/reference/bluetooth/about-bluetooth), [@boardname@ Bluetooth profile overview ](http://lancaster-university.github.io/microbit-docs/ble/profile/), [@boardname@ Bluetooth profile reference](http://lancaster-university.github.io/microbit-docs/resources/bluetooth/microbit-profile-V1.9-Level-2.pdf), [Bluetooth on @boardname@ resources](http://bluetooth-mdw.blogspot.co.uk/p/bbc-microbit.html), [Bluetooth SIG](https://www.bluetooth.com) +[About Bluetooth](/reference/bluetooth/about-bluetooth), [@boardname@ Bluetooth profile overview ](http://lancaster-university.github.io/microbit-docs/ble/profile/), [@boardname@ Bluetooth profile reference](http://lancaster-university.github.io/microbit-docs/resources/bluetooth/microbit-profile-V1.9-Level-2.pdf), [Bluetooth on @boardname@ resources](http://bluetooth-mdw.blogspot.co.uk/p/bbc-microbit.html), [Bluetooth SIG](https://www.bluetooth.com) ```package bluetooth diff --git a/docs/reference/bluetooth/start-led-service.md b/docs/reference/bluetooth/start-led-service.md index 1fe344c4..439303cd 100755 --- a/docs/reference/bluetooth/start-led-service.md +++ b/docs/reference/bluetooth/start-led-service.md @@ -1,11 +1,11 @@ # Bluetooth LED Service -### ~hint +## ~hint ![](/static/bluetooth/Bluetooth_SIG.png) For another device like a smartphone to use any of the Bluetooth "services" which the @boardname@ has, it must first be [paired with the @boardname@](/reference/bluetooth/bluetooth-pairing). Once paired, the other device may connect to the @boardname@ and exchange data relating to many of the @boardname@'s features. -### ~ +## ~ The Bluetooth LED service allows another device such as a smartphone to send short text strings or patterns over a Bluetooth connection to a @boardname@ for display on its LED matrix. Text will scroll across the @boardname@ and the speed at which it scrolls can also be controlled using the Bluetooth LED service. Devices using the LED service may also read the current state of the @boardname@'s LED matrix. @@ -17,7 +17,7 @@ No additional code is needed on the @boardname@ to use the Bluetooth LED service bluetooth.startLEDService(); ``` -### Example: Starting the Bluetooth LED service +## Example: Starting the Bluetooth LED service The following code shows the Bluetooth LED service being started: @@ -25,15 +25,15 @@ The following code shows the Bluetooth LED service being started: bluetooth.startLEDService(); ``` -### Video - LED service demo starts at 2:00 +## Video - LED service demo starts at 2:00 http://www.youtube.com/watch?v=aep_GVowKfs -### Advanced +## Advanced For more advanced information on the @boardname@ Bluetooth LED service including information on using a smartphone, see the [Lancaster University @boardname@ runtime technical documentation](http://lancaster-university.github.io/microbit-docs/ble/led-service/) -### See also +## See also [About Bluetooth](/reference/bluetooth/about-bluetooth), [@boardname@ Bluetooth profile overview ](http://lancaster-university.github.io/microbit-docs/ble/profile/), [@boardname@ Bluetooth profile reference](http://lancaster-university.github.io/microbit-docs/resources/bluetooth/microbit-profile-V1.9-Level-2.pdf), [Bluetooth on @boardname@ resources](http://bluetooth-mdw.blogspot.co.uk/p/bbc-microbit.html), [Bluetooth SIG](https://www.bluetooth.com) diff --git a/docs/reference/bluetooth/start-magnetometer-service.md b/docs/reference/bluetooth/start-magnetometer-service.md index 64bf2192..3fd422cf 100755 --- a/docs/reference/bluetooth/start-magnetometer-service.md +++ b/docs/reference/bluetooth/start-magnetometer-service.md @@ -1,11 +1,11 @@ # Bluetooth Magnetometer Service -### ~hint +## ~hint ![](/static/bluetooth/Bluetooth_SIG.png) For another device like a smartphone to use any of the Bluetooth "services" which the @boardname@ has, it must first be [paired with the @boardname@](/reference/bluetooth/bluetooth-pairing). Once paired, the other device may connect to the @boardname@ and exchange data relating to many of the @boardname@'s features. -### ~ +## ~ The Bluetooth magnetometer service allows another device such as a smartphone to wirelessly receive data from the @boardname@'s magnetometer. The magnetometer measures the strength and direction of magnetic fields including the earth's and so it can be used as a digital compass and indicate the way the @boardname@ is pointing relative to magnetic north. @@ -17,7 +17,7 @@ No additional code is needed on the @boardname@ to use the Bluetooth magnetomete bluetooth.startMagnetometerService(); ``` -### Example: Starting the Bluetooth magnetometer service +## Example: Starting the Bluetooth magnetometer service The following code shows the Bluetooth magnetometer service being started: @@ -25,15 +25,15 @@ The following code shows the Bluetooth magnetometer service being started: bluetooth.startMagnetometerService(); ``` -### Video - Magnetometer service demo +## Video - Magnetometer service demo http://www.youtube.com/watch?v=C_0VL4Gp4_U -### Advanced +## Advanced For more advanced information on the @boardname@ Bluetooth magnetometer service including information on using a smartphone, see the [Lancaster University @boardname@ runtime technical documentation](http://lancaster-university.github.io/microbit-docs/ble/magnetometer-service/) -### See also +## See also [About Bluetooth](/reference/bluetooth/about-bluetooth), [@boardname@ Bluetooth profile overview ](http://lancaster-university.github.io/microbit-docs/ble/profile/), [@boardname@ Bluetooth profile reference](http://lancaster-university.github.io/microbit-docs/resources/bluetooth/microbit-profile-V1.9-Level-2.pdf), [Bluetooth on @boardname@ resources](http://bluetooth-mdw.blogspot.co.uk/p/bbc-microbit.html), [Bluetooth SIG](https://www.bluetooth.com) diff --git a/docs/reference/bluetooth/start-temperature-service.md b/docs/reference/bluetooth/start-temperature-service.md index 37a8bf59..f9c18b30 100755 --- a/docs/reference/bluetooth/start-temperature-service.md +++ b/docs/reference/bluetooth/start-temperature-service.md @@ -1,11 +1,11 @@ # Bluetooth Temperature Service -### ~hint +## ~hint ![](/static/bluetooth/Bluetooth_SIG.png) For another device like a smartphone to use any of the Bluetooth "services" which the @boardname@ has, it must first be [paired with the @boardname@](/reference/bluetooth/bluetooth-pairing). Once paired, the other device may connect to the @boardname@ and exchange data relating to many of the @boardname@'s features. -### ~ +## ~ A @boardname@ is able to provide a rough measure of the current environmental temperature. It's an approximation only as in fact the temperature value is inferred from the temperature of its main processor. The Bluetooth temperature service allows another device such as a smartphone to wirelessly find out the @boardname@'s current temperature reading or to receive a constant stream of temperature data values. Temperature values are expressed in degrees celsius. @@ -17,7 +17,7 @@ No additional code is needed on the @boardname@ to use the Bluetooth temperature bluetooth.startTemperatureService(); ``` -### Example: Starting the Bluetooth temperature service +## Example: Starting the Bluetooth temperature service The following code shows the Bluetooth temperature service being started: @@ -25,15 +25,15 @@ The following code shows the Bluetooth temperature service being started: bluetooth.startTemperatureService(); ``` -### Video - Temperature service demo - Starts at 3:05 +## Video - Temperature service demo - Starts at 3:05 http://www.youtube.com/watch?v=aep_GVowKfs -### Advanced +## Advanced For more advanced information on the @boardname@ Bluetooth temperature service including information on using a smartphone, see the [Lancaster University @boardname@ runtime technical documentation](http://lancaster-university.github.io/microbit-docs/ble/temperature-service/) -### See also +## See also [About Bluetooth](/reference/bluetooth/about-bluetooth), [@boardname@ Bluetooth profile overview ](http://lancaster-university.github.io/microbit-docs/ble/profile/), [@boardname@ Bluetooth profile reference](http://lancaster-university.github.io/microbit-docs/resources/bluetooth/microbit-profile-V1.9-Level-2.pdf), [Bluetooth on @boardname@ resources](http://bluetooth-mdw.blogspot.co.uk/p/bbc-microbit.html), [Bluetooth SIG](https://www.bluetooth.com) diff --git a/docs/reference/bluetooth/start-uart-service.md b/docs/reference/bluetooth/start-uart-service.md index 6c98be93..d0bb16a5 100755 --- a/docs/reference/bluetooth/start-uart-service.md +++ b/docs/reference/bluetooth/start-uart-service.md @@ -1,13 +1,13 @@ # Bluetooth UART Service -### ~hint +## ~hint ![](/static/bluetooth/Bluetooth_SIG.png) For another device like a smartphone to use any of the Bluetooth "services" which the @boardname@ has, it must first be [paired with the @boardname@](/reference/bluetooth/bluetooth-pairing). Once paired, the other device may connect to the @boardname@ and exchange data relating to many of the @boardname@'s features. -### ~ +## ~ -The Bluetooth UART service allows another device such as a smartphone to exchange any data it wants to with the @boardname@, in small chunks which are intended to be joined together. [UART[(https://en.wikipedia.org/wiki/Universal_asynchronous_receiver/transmitter) stands for Universal Asynchronous Receiver Transmitter and is one way in which serial data communications can be performed, usually between two devices connected by a physical, wired connection. The Bluetooth UART service emulates the behaviour of a physical UART system and allows the exchange of a maximum of 20 bytes of data at a time in either direction. +The Bluetooth UART service allows another device such as a smartphone to exchange any data it wants to with the @boardname@, in small chunks which are intended to be joined together. [UART](https://en.wikipedia.org/wiki/Universal_asynchronous_receiver/transmitter) stands for Universal Asynchronous Receiver Transmitter and is one way in which serial data communications can be performed, usually between two devices connected by a physical, wired connection. The Bluetooth UART service emulates the behaviour of a physical UART system and allows the exchange of a maximum of 20 bytes of data at a time in either direction. When this service is used, the @boardname@ sets up a 60 byte buffer and data it receives will be accumulated in the buffer until it is full. When using the UART service from your @boardname@ code, you can indicate a special character which will be used to mean that the entire message in at most three chunks has now been sent by the other, connected device, at which point the @boardname@ will release the entire contents of its buffer to any code trying to read it. In other words this special character, known as a 'delimiter' is used by the device connected to the @boardname@ to mean "I've sent my whole message, you can now use it". @@ -19,7 +19,7 @@ To use the Bluetooth UART service from another device you'll need additional @bo bluetooth.startUartService(); ``` -### Example: Starting the Bluetooth UART service +## Example: Starting the Bluetooth UART service The following code shows the Bluetooth UART service being started: @@ -27,15 +27,15 @@ The following code shows the Bluetooth UART service being started: bluetooth.startUartService(); ``` -### Video - UART service guessing game +## Video - UART service guessing game https://www.youtube.com/watch?v=PgGeWddMAZ0 -### Advanced +## Advanced For more advanced information on the @boardname@ Bluetooth UART service including information on using a smartphone, see the [Lancaster University @boardname@ runtime technical documentation](http://lancaster-university.github.io/microbit-docs/ble/uart-service/) -### See also +## See also [About Bluetooth](/reference/bluetooth/about-bluetooth), [@boardname@ Bluetooth profile overview ](http://lancaster-university.github.io/microbit-docs/ble/profile/), [@boardname@ Bluetooth profile reference](http://lancaster-university.github.io/microbit-docs/resources/bluetooth/microbit-profile-V1.9-Level-2.pdf), [Bluetooth on @boardname@ resources](http://bluetooth-mdw.blogspot.co.uk/p/bbc-microbit.html), [Bluetooth SIG](https://www.bluetooth.com) diff --git a/docs/reference/bluetooth/stop-advertising.md b/docs/reference/bluetooth/stop-advertising.md new file mode 100644 index 00000000..2753a273 --- /dev/null +++ b/docs/reference/bluetooth/stop-advertising.md @@ -0,0 +1,38 @@ +# Stop Advertising + +Stops advertising URL via the Eddystone protocol over Bluetooth. + +## ~hint + +## Eddystone + +Bluetooth beacons are used to indicate proximity to a place or object of interest. +Beacons use Bluetooth advertising to broadcast a small amount of data, +which can be received and acted upon by anyone in range with a suitable device and software, typically a smartphone and application. + +There are various beacon message formats, which define the way Bluetooth advertising packets are used as containers for beacon data. +iBeacon is Apple's beacon message format. Eddystone comes from Google. + +Read more at https://lancaster-university.github.io/microbit-docs/ble/eddystone/ . + +## ~ + +```sig +bluetooth.stopAdvertising(); +``` + +## Example: stop advertising on button pressed + +```blocks +input.onButtonPressed(Button.A, () => { + bluetooth.stopAdvertising(); +}) +``` + +## See Also + +[advertise-url](/reference/bluetooth/advertise-url) + +```package +bluetooth +``` \ No newline at end of file diff --git a/docs/reference/bluetooth/uart-read-until.md b/docs/reference/bluetooth/uart-read-until.md index 57d27523..8f063a77 100644 --- a/docs/reference/bluetooth/uart-read-until.md +++ b/docs/reference/bluetooth/uart-read-until.md @@ -1,11 +1,11 @@ # UART Read -### ~hint +## ~hint ![](/static/bluetooth/Bluetooth_SIG.png) For another device like a smartphone to use any of the Bluetooth "services" which the @boardname@ has, it must first be [paired with the @boardname@](/reference/bluetooth/bluetooth-pairing). Once paired, the other device may connect to the @boardname@ and exchange data relating to many of the @boardname@'s features. -### ~ +## ~ The [Bluetooth UART service](/reference/bluetooth/start-uart-service) allows another device such as a smartphone to exchange any data it wants to with the @boardname@, in small chunks. @@ -15,7 +15,7 @@ With the Bluetooth UART service running, this block allows a @boardname@ to read bluetooth.uartReadUntil(""); ``` -### Example: Starting the Bluetooth UART service and then reading data received from another device which is terminated by ":" character and then displaying it +## Example: Starting the Bluetooth UART service and then reading data received from another device which is terminated by ":" character and then displaying it ```blocks let uartData = ""; @@ -35,15 +35,15 @@ bluetooth.onBluetoothDisconnected(() => { ``` -### Video - UART service guessing game +## Video - UART service guessing game https://www.youtube.com/watch?v=PgGeWddMAZ0 -### Advanced +## Advanced For more advanced information on the @boardname@ Bluetooth UART service including information on using a smartphone, see the [Lancaster University @boardname@ runtime technical documentation](http://lancaster-university.github.io/microbit-docs/ble/uart-service/) -### See also +## See also [About Bluetooth](/reference/bluetooth/about-bluetooth), [@boardname@ Bluetooth profile overview ](http://lancaster-university.github.io/microbit-docs/ble/profile/), [@boardname@ Bluetooth profile reference](http://lancaster-university.github.io/microbit-docs/resources/bluetooth/microbit-profile-V1.9-Level-2.pdf), [Bluetooth on @boardname@ resources](http://bluetooth-mdw.blogspot.co.uk/p/bbc-microbit.html), [Bluetooth SIG](https://www.bluetooth.com) diff --git a/docs/reference/bluetooth/uart-write-line.md b/docs/reference/bluetooth/uart-write-line.md new file mode 100644 index 00000000..5a24714d --- /dev/null +++ b/docs/reference/bluetooth/uart-write-line.md @@ -0,0 +1,51 @@ +# UART Write Line + +## ~hint +![](/static/bluetooth/Bluetooth_SIG.png) + +For another device like a smartphone to use any of the Bluetooth "services" which the @boardname@ has, it must first be [paired with the @boardname@](/reference/bluetooth/bluetooth-pairing). Once paired, the other device may connect to the @boardname@ and exchange data relating to many of the @boardname@'s features. + +## ~ + +The [Bluetooth UART service](/reference/bluetooth/start-uart-service) allows another device such as a smartphone to exchange any data it wants to with the @boardname@, in small chunks. + +With the Bluetooth UART service running, this block allows a @boardname@ to send a line of text to a Bluetooth connected device. + +```sig +bluetooth.uartWriteLine(""); +``` + +## Example: Starting the Bluetooth UART service and then sending "HELLO" whenever button A is pressed and another device has connected over Bluetooth + +```blocks +let connected = 0; +bluetooth.onBluetoothConnected(() => { + basic.showString("C"); + connected = 1; +}); +bluetooth.onBluetoothDisconnected(() => { + basic.showString("D"); + connected = 0; +}); +input.onButtonPressed(Button.A, () => { + if (connected == 1) { + bluetooth.uartWriteLine("HELLO"); + } +}); +``` + +## Video - UART service guessing game + +https://www.youtube.com/watch?v=PgGeWddMAZ0 + +## Advanced + +For more advanced information on the @boardname@ Bluetooth UART service including information on using a smartphone, see the [Lancaster University @boardname@ runtime technical documentation](http://lancaster-university.github.io/microbit-docs/ble/uart-service/) + +## See also + +[About Bluetooth](/reference/bluetooth/about-bluetooth), [@boardname@ Bluetooth profile overview ](http://lancaster-university.github.io/microbit-docs/ble/profile/), [@boardname@ Bluetooth profile reference](http://lancaster-university.github.io/microbit-docs/resources/bluetooth/microbit-profile-V1.9-Level-2.pdf), [Bluetooth on @boardname@ resources](http://bluetooth-mdw.blogspot.co.uk/p/bbc-microbit.html), [Bluetooth SIG](https://www.bluetooth.com) + +```package +bluetooth +``` diff --git a/docs/reference/bluetooth/uart-write-number.md b/docs/reference/bluetooth/uart-write-number.md index 34b13099..b92a2420 100644 --- a/docs/reference/bluetooth/uart-write-number.md +++ b/docs/reference/bluetooth/uart-write-number.md @@ -1,11 +1,11 @@ # UART Write Number -### ~hint +## ~hint ![](/static/bluetooth/Bluetooth_SIG.png) For another device like a smartphone to use any of the Bluetooth "services" which the @boardname@ has, it must first be [paired with the @boardname@](/reference/bluetooth/bluetooth-pairing). Once paired, the other device may connect to the @boardname@ and exchange data relating to many of the @boardname@'s features. -### ~ +## ~ The [Bluetooth UART service](/reference/bluetooth/start-uart-service) allows another device such as a smartphone to exchange any data it wants to with the @boardname@, in small chunks. @@ -15,11 +15,11 @@ With the Bluetooth UART service running, this block allows a @boardname@ to send bluetooth.uartWriteNumber(42); ``` -### Advanced +## Advanced For more advanced information on the @boardname@ Bluetooth UART service including information on using a smartphone, see the [Lancaster University @boardname@ runtime technical documentation](http://lancaster-university.github.io/microbit-docs/ble/uart-service/) -### See also +## See also [About Bluetooth](/reference/bluetooth/about-bluetooth), [@boardname@ Bluetooth profile overview ](http://lancaster-university.github.io/microbit-docs/ble/profile/), [@boardname@ Bluetooth profile reference](http://lancaster-university.github.io/microbit-docs/resources/bluetooth/microbit-profile-V1.9-Level-2.pdf), [Bluetooth on @boardname@ resources](http://bluetooth-mdw.blogspot.co.uk/p/bbc-microbit.html), [Bluetooth SIG](https://www.bluetooth.com) diff --git a/docs/reference/bluetooth/uart-write-string.md b/docs/reference/bluetooth/uart-write-string.md index 3581c405..695ac943 100644 --- a/docs/reference/bluetooth/uart-write-string.md +++ b/docs/reference/bluetooth/uart-write-string.md @@ -1,11 +1,11 @@ # UART Write String -### ~hint +## ~hint ![](/static/bluetooth/Bluetooth_SIG.png) For another device like a smartphone to use any of the Bluetooth "services" which the @boardname@ has, it must first be [paired with the @boardname@](/reference/bluetooth/bluetooth-pairing). Once paired, the other device may connect to the @boardname@ and exchange data relating to many of the @boardname@'s features. -### ~ +## ~ The [Bluetooth UART service](/reference/bluetooth/start-uart-service) allows another device such as a smartphone to exchange any data it wants to with the @boardname@, in small chunks. @@ -15,7 +15,7 @@ With the Bluetooth UART service running, this block allows a @boardname@ to send bluetooth.uartWriteString(""); ``` -### Example: Starting the Bluetooth UART service and then sending "HELLO" whenever button A is pressed and another device has connected over Bluetooth +## Example: Starting the Bluetooth UART service and then sending "HELLO" whenever button A is pressed and another device has connected over Bluetooth ```blocks let connected = 0; @@ -34,15 +34,15 @@ input.onButtonPressed(Button.A, () => { }); ``` -### Video - UART service guessing game +## Video - UART service guessing game https://www.youtube.com/watch?v=PgGeWddMAZ0 -### Advanced +## Advanced For more advanced information on the @boardname@ Bluetooth UART service including information on using a smartphone, see the [Lancaster University @boardname@ runtime technical documentation](http://lancaster-university.github.io/microbit-docs/ble/uart-service/) -### See also +## See also [About Bluetooth](/reference/bluetooth/about-bluetooth), [@boardname@ Bluetooth profile overview ](http://lancaster-university.github.io/microbit-docs/ble/profile/), [@boardname@ Bluetooth profile reference](http://lancaster-university.github.io/microbit-docs/resources/bluetooth/microbit-profile-V1.9-Level-2.pdf), [Bluetooth on @boardname@ resources](http://bluetooth-mdw.blogspot.co.uk/p/bbc-microbit.html), [Bluetooth SIG](https://www.bluetooth.com) diff --git a/docs/reference/bluetooth/uart-write-value.md b/docs/reference/bluetooth/uart-write-value.md index 1f684246..b2351793 100644 --- a/docs/reference/bluetooth/uart-write-value.md +++ b/docs/reference/bluetooth/uart-write-value.md @@ -1,11 +1,11 @@ # UART Write Value -### ~hint +## ~hint ![](/static/bluetooth/Bluetooth_SIG.png) For another device like a smartphone to use any of the Bluetooth "services" which the @boardname@ has, it must first be [paired with the @boardname@](/reference/bluetooth/bluetooth-pairing). Once paired, the other device may connect to the @boardname@ and exchange data relating to many of the @boardname@'s features. -### ~ +## ~ The [Bluetooth UART service](/reference/bluetooth/start-uart-service) allows another device such as a smartphone to exchange any data it wants to with the @boardname@, in small chunks. @@ -15,11 +15,11 @@ With the Bluetooth UART service running, this block allows a @boardname@ to send bluetooth.uartWriteValue("x", 42); ``` -### Advanced +## Advanced For more advanced information on the @boardname@ Bluetooth UART service including information on using a smartphone, see the [Lancaster University @boardname@ runtime technical documentation](http://lancaster-university.github.io/microbit-docs/ble/uart-service/) -### See also +## See also [About Bluetooth](/reference/bluetooth/about-bluetooth), [@boardname@ Bluetooth profile overview ](http://lancaster-university.github.io/microbit-docs/ble/profile/), [@boardname@ Bluetooth profile reference](http://lancaster-university.github.io/microbit-docs/resources/bluetooth/microbit-profile-V1.9-Level-2.pdf), [Bluetooth on @boardname@ resources](http://bluetooth-mdw.blogspot.co.uk/p/bbc-microbit.html), [Bluetooth SIG](https://www.bluetooth.com) diff --git a/docs/reference/control.md b/docs/reference/control.md index f546edc8..eb644622 100644 --- a/docs/reference/control.md +++ b/docs/reference/control.md @@ -8,8 +8,12 @@ control.inBackground(() => { }); control.reset(); control.waitMicros(4); +control.onEvent(0, 0, () => { }); +control.raiseEvent(0, 0); +control.eventTimestamp(); +control.eventValue(); ``` -### See Also +## See Also -[inBackground](/reference/control/in-background), [reset](/reference/control/reset), [wait-micros](/reference/control/wait-micros) +[inBackground](/reference/control/in-background), [reset](/reference/control/reset), [waitMicros](/reference/control/wait-micros), [onEvent](/reference/control/on-event), [raiseEvent](/reference/control/raise-event), [eventTimestamp](/reference/control/event-timestamp), [eventValue](/reference/control/event-value) diff --git a/docs/reference/control/assert.md b/docs/reference/control/assert.md new file mode 100644 index 00000000..7c232276 --- /dev/null +++ b/docs/reference/control/assert.md @@ -0,0 +1,29 @@ +# assert + +Stop the program if the assertion condition is false. + +```sig +control.assert(false) +``` + +You can insist that your program will stop at an assert block if a certain condition you check is false. The error number in the assert is written to the serial port with a failure message. + +## Parameters + +* **cond**: a [boolean](/types/boolean) where true means everything is ok or false which means, stop the program! +* **msg**: an optional [string](/types/string) with a message describing the failed assertion. + +## Example + +Stop the program if a sensor connected to pin `P0` sends a low (`0`) signal. + +```blocks +basic.forever(() => { + control.assert(pins.digitalReadPin(DigitalPin.P0) == 1) + basic.pause(1000) +}) +``` + +## See also + +[panic](/reference/control/panic) diff --git a/docs/reference/control/device-name.md b/docs/reference/control/device-name.md index f7ef5f4f..a314d20e 100644 --- a/docs/reference/control/device-name.md +++ b/docs/reference/control/device-name.md @@ -1,6 +1,6 @@ # Device Name -Gets a friendly name for the device derived from the its serial number. +Make a friendly name for the device based on its serial number. ```sig control.deviceName(); diff --git a/docs/reference/control/in-background.md b/docs/reference/control/in-background.md index 93849411..7ac747c5 100644 --- a/docs/reference/control/in-background.md +++ b/docs/reference/control/in-background.md @@ -7,15 +7,15 @@ control.inBackground(() => { }) ``` -### ~hint +## ~hint For more information, read [The @boardname@ - a reactive system](/device/reactive). It is pretty advanced! -### ~ +## ~ -### Example +## Example This program shows how running in the background can say what is stored in a variable like `num`, while another part (``on button pressed``) @@ -25,7 +25,7 @@ changes what is stored there. let num = 0 control.inBackground(() => { while (true) { - basic.showNumber(num, 150) + basic.showNumber(num) basic.pause(100) } }) @@ -40,14 +40,14 @@ with a ``forever`` loop. ```blocks let num = 0 basic.forever(() => { - basic.showNumber(num, 150) + basic.showNumber(num) }) input.onButtonPressed(Button.A, () => { num++; }) ``` -### See also +## See also [while](/blocks/loops/while), [forever](/reference/basic/forever), [on button pressed](/reference/input/on-button-pressed) diff --git a/docs/reference/control/panic.md b/docs/reference/control/panic.md new file mode 100644 index 00000000..79394491 --- /dev/null +++ b/docs/reference/control/panic.md @@ -0,0 +1,40 @@ +# panic + +Display an error number and stop the program. + +```sig +control.panic(0) +``` + +If your board has some way to display error information, ``||control:panic||`` will work +with it to show error numbers. + +Your program stops when you use ``||control:panic||``. Use this when you think something bad enough has +happened and your program can't run properly anymore. + +## Parameters + +* **code**: an error [number](/types/number) you match to an error situation in your program. + +### ~hint +**System error codes** + +The @boardname@ has error codes reserved for use by the system software. The ```panic()``` function is for advanced usage only. You must carefully chose an error code that doesn't match one currently used by the @boardname@ system. +### ~ + +## Example + +Send a 'code red' error that you created to the error display if the input from pin `P0` is lower than `10`. + +```blocks +let codeRed = 1110; +let codeBlue = 1111; + +if (pins.analogReadPin(AnalogPin.P0) < 10) { + control.panic(codeRed) +} +``` + +## See also + +[assert](/reference/control/assert), [error codes](/device/error-codes) \ No newline at end of file diff --git a/docs/reference/control/raise-event.md b/docs/reference/control/raise-event.md index 8a5c8741..42bc4547 100644 --- a/docs/reference/control/raise-event.md +++ b/docs/reference/control/raise-event.md @@ -8,3 +8,7 @@ control.raiseEvent(control.eventSourceId(EventBusSource.MICROBIT_ID_BUTTON_A), c **This is an advanced API.** For more information, see the [@boardname@ runtime messageBus documentation](https://lancaster-university.github.io/microbit-docs/ubit/messageBus/) + +## See Also + +[radio raise event](/reference/radio/raise-event) \ No newline at end of file diff --git a/docs/reference/control/reset.md b/docs/reference/control/reset.md index adf1b116..8131c07a 100644 --- a/docs/reference/control/reset.md +++ b/docs/reference/control/reset.md @@ -7,8 +7,15 @@ This function is like pressing the reset button on the back of the @boardname@. ```sig control.reset() ``` +## ~hint -### Example +**Simulator** + +The **reset** function works only on a real @boardname@ and not in the simulator. + +## ~ + +## Example This program will count as high as you like when you press button `A`. When you get tired of counting, press button `B` to reset the @@ -26,12 +33,6 @@ input.onButtonPressed(Button.B, () => { }); ``` -#### ~hint - -This program works better on a real @boardname@ than in the simulator. - -#### ~ - -### See Also +## See also [clear screen](/reference/basic/clear-screen), [game over](/reference/game/game-over) diff --git a/docs/reference/control/wait-micros.md b/docs/reference/control/wait-micros.md index 9e4404e2..016af05b 100644 --- a/docs/reference/control/wait-micros.md +++ b/docs/reference/control/wait-micros.md @@ -6,7 +6,7 @@ Blocks the current fiber for the given amount of micro-seconds. control.waitMicros(4) ``` -### Example +## Example This program sends a 10 micro-second HIGH pulse through pin ``P0``. @@ -21,12 +21,12 @@ control.waitMicros(10) pins.digitalWritePin(DigitalPin.P0, 0) ``` -#### ~hint +### ~hint This function is not supported in the simulator. -#### ~ +### ~ -### See Also +## See Also [pause](/reference/basic/pause) diff --git a/docs/reference/devices.md b/docs/reference/devices.md index e94704b3..487d4cb1 100644 --- a/docs/reference/devices.md +++ b/docs/reference/devices.md @@ -2,6 +2,12 @@ Control a phone with the @boardname@ via Bluetooth. +## ~ hint + +**App required** You must use one of the [micro:bit apps](https://microbit.org/guide/mobile/) to use this functionality. + +## ~ + ```cards devices.tellCameraTo(MesCameraEvent.TakePhoto); devices.tellRemoteControlTo(MesRemoteControlEvent.play); @@ -22,6 +28,6 @@ devices.onSignalStrengthChanged(() => { devices ``` -### See Also +## See Also [tellCameraTo](/reference/devices/tell-camera-to), [tellRemoteControlTo](/reference/devices/tell-remote-control-to), [raiseAlertTo](/reference/devices/raise-alert-to), [onNotified](/reference/devices/on-notified), [onGamepadButton](/reference/devices/on-gamepad-button), [signalStrength](/reference/devices/signal-strength), [onSignalStrengthChanged](/reference/devices/on-signal-strength-changed) diff --git a/docs/reference/devices/on-gamepad-button.md b/docs/reference/devices/on-gamepad-button.md index 6eede4cc..14e74931 100644 --- a/docs/reference/devices/on-gamepad-button.md +++ b/docs/reference/devices/on-gamepad-button.md @@ -2,23 +2,21 @@ Register code to run when the @boardname@ receives a command from the paired gamepad. -### ~hint +## ~hint -The functions in the ``devices`` namespace allow the @boardname@ to communicate with a separate (remote) device, -such as a smartphone, over Bluetooth (Smart). -The set of supported events will depend on the remote device and the @boardname@ apps available for the remote device. +**App required** You must use one of the [micro:bit apps](https://microbit.org/guide/mobile/) to use this functionality. -### ~ +## ~ ```sig devices.onGamepadButton(MesDpadButtonInfo.ADown, () => {}) ``` -### Parameters +## Parameters * ``body``: Action code to run when the the @boardname@ receives a command from the paired gamepad. -### See Also +## See Also [tell remote control to](/reference/devices/tell-remote-control-to), [raise alert to](/reference/devices/raise-alert-to), [signal strength](/reference/devices/signal-strength), [on signal strength changed](/reference/devices/on-signal-strength-changed) diff --git a/docs/reference/devices/on-notified.md b/docs/reference/devices/on-notified.md index 456d88af..8f86bb19 100644 --- a/docs/reference/devices/on-notified.md +++ b/docs/reference/devices/on-notified.md @@ -1,25 +1,22 @@ -# On Signal Strength Changed +# On Notified Register code to run when the signal strength of the paired device changes. -### ~hint +## ~hint -The functions in the ``devices`` namespace allow the @boardname@ to communicate with a separate (remote) device, -such as a smartphone, over Bluetooth (Smart). -The set of supported events will depend on the remote device and the @boardname@ apps available for the remote device. - -### ~ +**App required** You must use one of the [micro:bit apps](https://microbit.org/guide/mobile/) to use this functionality. +## ~ ```sig devices.onNotified(MesDeviceInfo.IncomingCall, () => {}) ``` -### Parameters +## Parameters * ``body``: code to run when the signal strength changes. -### Examples +## Examples Display the signal strength on screen: @@ -29,7 +26,7 @@ devices.onNotified(MesDeviceInfo.IncomingCall, () => { }) ``` -### See Also +## See Also [tell remote control to](/reference/devices/tell-remote-control-to), [raise alert to](/reference/devices/raise-alert-to), [signal strength](/reference/devices/signal-strength) diff --git a/docs/reference/devices/on-signal-strength-changed.md b/docs/reference/devices/on-signal-strength-changed.md index b51b3345..14db9594 100644 --- a/docs/reference/devices/on-signal-strength-changed.md +++ b/docs/reference/devices/on-signal-strength-changed.md @@ -2,34 +2,33 @@ Register code to run when the signal strength of the paired device changes. -### ~hint +## ~hint -The functions in the ``devices`` namespace allow the @boardname@ to communicate with a separate (remote) device, -such as a smartphone, over Bluetooth (Smart). -The set of supported events will depend on the remote device and the @boardname@ apps available for the remote device. +**App required** You must use one of the [micro:bit apps](https://microbit.org/guide/mobile/) to use this functionality. + +## ~ -### ~ ```sig devices.onSignalStrengthChanged(() => {}) ``` -### Parameters +## Parameters * ``body``: code to run when the signal strength changes. -### Examples +## Examples Display the signal strength on screen: ```blocks devices.onSignalStrengthChanged(() => { - basic.showNumber(devices.signalStrength(), 150) + basic.showNumber(devices.signalStrength()) }) ``` -### See Also +## See Also [tell remote control to](/reference/devices/tell-remote-control-to), [raise alert to](/reference/devices/raise-alert-to), [signal strength](/reference/devices/signal-strength) diff --git a/docs/reference/devices/raise-alert-to.md b/docs/reference/devices/raise-alert-to.md index a0fabbab..9371ffe7 100644 --- a/docs/reference/devices/raise-alert-to.md +++ b/docs/reference/devices/raise-alert-to.md @@ -2,62 +2,61 @@ Raise an alert on a remote device. -### ~hint +## ~hint -The functions in the ``devices`` namespace allow the @boardname@ to communicate with a separate (remote) device, -such as a smartphone, over Bluetooth (Smart). -The set of supported events will depend on the remote device and the @boardname@ apps available for the remote device. +**App required** You must use one of the [micro:bit apps](https://microbit.org/guide/mobile/) to use this functionality. + +## ~ -### ~ ```sig -export function raiseAlertTo(event: string) +devices.raiseAlertTo(MesAlertEvent.Vibrate) ``` -### Parameters +## Parameters * event - an event identifier -### Examples +## Examples To tell the connected device to display toast ```blocks -devices.raiseAlertTo("display toast") +devices.raiseAlertTo(MesAlertEvent.DisplayToast) ``` To tell the connected device to vibrate ```blocks -devices.raiseAlertTo("vibrate") +devices.raiseAlertTo(MesAlertEvent.Vibrate) ``` To tell the connected device to play a sound ```blocks -devices.raiseAlertTo("play sound") +devices.raiseAlertTo(MesAlertEvent.PlaySound) ``` To tell the connected device to play a ringtone ```blocks -devices.raiseAlertTo("play ringtone") +devices.raiseAlertTo(MesAlertEvent.PlayRingtone) ``` To tell the connected device to find my phone ```blocks -devices.raiseAlertTo("find my phone") +devices.raiseAlertTo(MesAlertEvent.FindMyPhone) ``` To tell the connected device to ring alarm ```blocks -devices.raiseAlertTo("ring alarm") +devices.raiseAlertTo(MesAlertEvent.RingAlarm) ``` -### See also +## See also [tell remote control to](/reference/devices/tell-remote-control-to), [tell camera to](/reference/devices/tell-camera-to) diff --git a/docs/reference/devices/signal-strength.md b/docs/reference/devices/signal-strength.md index 7df8b9f4..5eb2b6a6 100644 --- a/docs/reference/devices/signal-strength.md +++ b/docs/reference/devices/signal-strength.md @@ -2,33 +2,32 @@ Returns the signal strength reported by the paired device from ``0`` (no signal) to ``4`` (full strength). -### ~hint +## ~hint -The functions in the ``devices`` namespace allow the @boardname@ to communicate with a separate (remote) device, -such as a smartphone, over Bluetooth (Smart). -The set of supported events will depend on the remote device and the @boardname@ apps available for the remote device. +**App required** You must use one of the [micro:bit apps](https://microbit.org/guide/mobile/) to use this functionality. + +## ~ -### ~ ```sig devices.signalStrength(); ``` -### Returns +## Returns * the signal strength from ``0`` (no signal) to ``4`` (full strength). -### Examples +## Examples Display the signal strength on screen: ```blocks devices.onSignalStrengthChanged(() => { - basic.showNumber(devices.signalStrength(), 150) + basic.showNumber(devices.signalStrength()) }) ``` -### See Also +## See Also [tell remote control to](/reference/devices/tell-remote-control-to), [raise alert to](/reference/devices/raise-alert-to), [on signal strength changed](/reference/devices/on-signal-strength-changed) diff --git a/docs/reference/devices/tell-camera-to.md b/docs/reference/devices/tell-camera-to.md index 70b9ac7c..3870d785 100644 --- a/docs/reference/devices/tell-camera-to.md +++ b/docs/reference/devices/tell-camera-to.md @@ -2,73 +2,72 @@ Access the photo/video-taking functionality of a remote device using the ``tell camera to`` function. -### ~hint +## ~hint -The functions in the ``devices`` namespace allow the @boardname@ to communicate with a separate (remote) device, -such as a smartphone, over Bluetooth (Smart). -The set of supported events will depend on the remote device and the @boardname@ apps available for the remote device. +**App required** You must use one of the [micro:bit apps](https://microbit.org/guide/mobile/) to use this functionality. + +## ~ -### ~ ```sig -devices.tellCameraTo() +devices.tellCameraTo(MesCameraEvent.TakePhoto) ``` -### Parameters +## Parameters * event - an event identifier -### Examples +## Examples To tell the connected device to take a picture: ```blocks -devices.tellCameraTo("take photo") +devices.tellCameraTo(MesCameraEvent.TakePhoto) ``` -To tell the connected device to start recording a video +To tell the connected device to start recording a video: ```blocks -devices.tellCameraTo("start video capture") +devices.tellCameraTo(MesCameraEvent.StartVideoCapture) ``` -To tell the connected device to stop recording a video +To tell the connected device to stop recording a video: ```blocks -devices.tellCameraTo("stop video capture") +devices.tellCameraTo(MesCameraEvent.StopVideoCapture) ``` -To tell the connected device to toggle front-rear +To tell the connected device to toggle front-rear: ```blocks -devices.tellCameraTo("toggle front-rear") +devices.tellCameraTo(MesCameraEvent.ToggleFrontRear) ``` -To tell the connected device to launch photo mode +To tell the connected device to launch photo mode: ```blocks -devices.tellCameraTo("launch photo mode") +devices.tellCameraTo(MesCameraEvent.LaunchPhotoMode) ``` -To tell the connected device to launch video mode +To tell the connected device to launch video mode: ```blocks -devices.tellCameraTo("launch video mode") +devices.tellCameraTo(MesCameraEvent.LaunchVideoMode) ``` -To tell the connected device to stop photo mode +To tell the connected device to stop photo mode: ```blocks -devices.tellCameraTo("stop photo mode") +devices.tellCameraTo(MesCameraEvent.StopPhotoMode) ``` -To tell the connected device to stop video mode +To tell the connected device to stop video mode: ```blocks -devices.tellCameraTo("stop video mode") +devices.tellCameraTo(MesCameraEvent.StopVideoMode) ``` -### See Also +## See Also [tell remote control to](/reference/devices/tell-remote-control-to), [raise alert to](/reference/devices/raise-alert-to) diff --git a/docs/reference/devices/tell-remote-control-to.md b/docs/reference/devices/tell-remote-control-to.md index 266a983e..51639734 100644 --- a/docs/reference/devices/tell-remote-control-to.md +++ b/docs/reference/devices/tell-remote-control-to.md @@ -2,23 +2,22 @@ Control the presentation of media content available on a remote device using the `tell remote control` to function. -### ~hint +## ~hint -The functions in the ``devices`` namespace allow the @boardname@ to communicate with a separate (remote) device, -such as a smartphone, over Bluetooth (Smart). -The set of supported events will depend on the remote device and the @boardname@ apps available for the remote device. +**App required** You must use one of the [micro:bit apps](https://microbit.org/guide/mobile/) to use this functionality. + +## ~ -### ~ ```sig -devices.tellRemoteControlTo(event: string) +devices.tellRemoteControlTo(MesRemoteControlEvent.play) ``` -### Parameters +## Parameters * event - an event identifier -### Event values +## Event values * play * stop @@ -30,57 +29,57 @@ devices.tellRemoteControlTo(event: string) * previous track * next track -### Examples +## Examples To tell the connected device to start playing: ```blocks -devices.tellRemoteControlTo("play") +devices.tellRemoteControlTo(MesRemoteControlEvent.play) ``` To tell the connected device to stop playing ```blocks -devices.tellRemoteControlTo("stop") +devices.tellRemoteControlTo(MesRemoteControlEvent.stop) ``` To tell the connected device to go to next track ```blocks -devices.tellRemoteControlTo("next track") +devices.tellRemoteControlTo(MesRemoteControlEvent.nextTrack) ``` To tell the connected device to go to previous track ```blocks -devices.tellRemoteControlTo("previous track") +devices.tellRemoteControlTo(MesRemoteControlEvent.previousTrack) ``` To tell the connected device to go forward ```blocks -devices.tellRemoteControlTo("forward") +devices.tellRemoteControlTo(MesRemoteControlEvent.forward) ``` To tell the connected device to rewind ```blocks -devices.tellRemoteControlTo("rewind") +devices.tellRemoteControlTo(MesRemoteControlEvent.rewind) ``` To tell the connected device volume up ```blocks -devices.tellRemoteControlTo("volume up") +devices.tellRemoteControlTo(MesRemoteControlEvent.volumeUp) ``` To tell the connected device volume down ```blocks -devices.tellRemoteControlTo("volume down") +devices.tellRemoteControlTo(MesRemoteControlEvent.volumeDown) ``` -### See also +## See also [tell camera to](/reference/devices/tell-camera-to), [raise alert to](/reference/devices/raise-alert-to) diff --git a/docs/reference/event-handler.md b/docs/reference/event-handler.md index 03605161..0027a7a1 100644 --- a/docs/reference/event-handler.md +++ b/docs/reference/event-handler.md @@ -4,7 +4,7 @@ Event handlers - how they work. An event handler is code that is associated with a particular event, such as "button A pressed". You create (or register) the association between an event and an event handler by calling a function named "on ". After registering an event handler with an event, then whenever that event occurs, the event handler code executes. -### Registering an event handler +## Registering an event handler Functions named "on " create an association between an event and the event handler code. For example, the following code registers the event handler (the code between the `do` and `end` keywords) with the event of a press of button A: @@ -16,7 +16,7 @@ input.onButtonPressed(Button.A, () => { After this code executes, then whenever button A is pressed in the future, the string "hello" will be printed. -### Event handlers are active for the entire program execution +## Event handlers are active for the entire program execution Once you have registered an event handler for an event, like above, that event handler is active for the rest of the program execution. If you want to stop the string "hello" from printing each time button A is pressed then you need to arrange for the following code to execute: @@ -27,7 +27,7 @@ input.onButtonPressed(Button.A, () => { The above code associated an event handler that does nothing with the event of a press of button A. -### There is only one event handler per event +## There is only one event handler per event The above example also illustrates that there is only one event handler for each event. What is the result of the following code? @@ -49,11 +49,11 @@ input.onButtonPressed(Button.A, () => { }) ``` -### To learn more +## To learn more To learn more about how the @boardname@ queues up and schedules event handlers, see [the @boardname@ - a reactive system](/device/reactive) -### see also +## see also [on button pressed](/reference/input/on-button-pressed), [on pin up](/reference/input/on-pin-pressed), [on shake](/reference/input/on-gesture) diff --git a/docs/reference/game.md b/docs/reference/game.md index 89f1f7ae..40cb964d 100644 --- a/docs/reference/game.md +++ b/docs/reference/game.md @@ -1,15 +1,64 @@ # Game -A single-LED sprite game engine +Make games with sprites. Keep score and controls gameplay. + +## ~ hint + +Once the game engine is started, it will render the sprites to the screen and potentially override any kind of animation you are trying to show. +Using [game pause](/reference/game/pause) and [game resume](/reference/game/resume) to disable and enable the game rendering loop. + +## ~ + +## Sprites + +```cards +game.createSprite(0,0); +game.createSprite(0,0).delete(); +game.createSprite(0,0).move(0); +game.createSprite(0,0).turn(Direction.Left,0); +game.createSprite(0,0).ifOnEdgeBounce(); +game.createSprite(0,0).get(LedSpriteProperty.X); +game.createSprite(0,0).set(LedSpriteProperty.X, 0); +game.createSprite(0,0).change(LedSpriteProperty.X, 0); +game.createSprite(0,0).isTouching(null); +game.createSprite(0,0).isTouchingEdge(); +``` + +## Scoring ```cards game.addScore(1); game.score(); -game.startCountdown(10000); -game.gameOver(); game.setScore(0); ``` -### See Also +## Life -[addScore](/reference/game/change-score-by), [score](/reference/game/score), [startCountdown](/reference/game/start-countdown), [gameOver](/reference/game/game-over), [setScore](/reference/game/set-score) +```cards +game.setLife(0) +game.addLife(0) +game.removeLife(0) +``` + +## Game control + +```cards +game.startCountdown(10000); +game.gameOver(); +game.pause(); +game.resume(); +game.isGameOver() +game.isRunning(); +game.isPaused(); +``` + +## See also + +[create sprite](/reference/game/create-sprite), [move](/reference/game/move), [turn](/reference/game/turn), +[ifOnEdgeBounce](/reference/game/if-on-edge-bounce), [get](/reference/game/get), [set](/reference/game/set), +[change](/reference/game/change), [is touching](/reference/game/is-touching) [is touching edge](/reference/game/is-touching-edge), +[add score](/reference/game/add-score), [score](/reference/game/score), [set score](/reference/game/set-score), +[set life](/reference/game/set-life), [add life](/reference/game/add-life), [remove life](/reference/game/remove-life), +[start countdown](/reference/game/start-countdown), [game over](/reference/game/game-over), +[pause](/reference/game/pause), [resume](/reference/game/resume), +[is game over](/reference/game/is-game-over,) [is running](/reference/game/is-running), [is paused](/reference/game/is-paused) diff --git a/docs/reference/game/add-life.md b/docs/reference/game/add-life.md new file mode 100644 index 00000000..897ae9b7 --- /dev/null +++ b/docs/reference/game/add-life.md @@ -0,0 +1,33 @@ +# add Life + +Increase the number of lives remaining by some amount. + +```sig +game.addLife(0) +``` + +The life count in the game is increased by the number of lives you say. + +## Parameters + +* **life**: a [number](/types/number) to add to the life count. + +## Example #example + +Add `20` more lives to the life count if the player's score reaches `10000` points. + +```blocks +let giveLives = true + +if (game.score() > 9999) { + if (giveLives) { + game.addLife(20) + giveLives = false + } +} +``` + +## See also #seealso + +[set life](/reference/game/set-life), +[remove life](/reference/game/remove-life) \ No newline at end of file diff --git a/docs/reference/game/add-score.md b/docs/reference/game/add-score.md new file mode 100644 index 00000000..70b5e2f4 --- /dev/null +++ b/docs/reference/game/add-score.md @@ -0,0 +1,30 @@ +# add Score + +Add more to the current score for the game. + +```sig +game.addScore(1) +``` +### Parameters + +* a [number](/types/number) that means how much to add to the score. A negative number means to subtract from the score. + +### Examples + +This program is a simple game. +Press button ``A`` as much as possible to increase the score. +Press ``B`` to display the score and reset the score. + +```blocks +input.onButtonPressed(Button.B, () => { + basic.showNumber(game.score()) + game.setScore(0) +}) +input.onButtonPressed(Button.A, () => { + game.addScore(1) +}) +``` + +### See Also + +[score](/reference/game/score), [set score](/reference/game/set-score), [start countdown](/reference/game/start-countdown) diff --git a/docs/reference/game/change-score-by.md b/docs/reference/game/change-score-by.md index 6002d4d5..a3cb236e 100644 --- a/docs/reference/game/change-score-by.md +++ b/docs/reference/game/change-score-by.md @@ -5,11 +5,11 @@ Add the amount you say to the score for the game. ```sig game.addScore(1) ``` -### Parameters +## Parameters -* a [number](/reference/types/number) that means how much to add to the score. A negative number means to subtract from the score. +* a [number](/types/number) that means how much to add to the score. A negative number means to subtract from the score. -### Examples +## Examples This program is a simple game. Press button ``A`` as much as possible. @@ -22,6 +22,6 @@ input.onButtonPressed(Button.A, () => { game.startCountdown(10000) ``` -### See Also +## See Also [score](/reference/game/score), [start countdown](/reference/game/start-countdown) diff --git a/docs/reference/game/change-sprite-property.md b/docs/reference/game/change-sprite-property.md deleted file mode 100644 index 4eb6d5fc..00000000 --- a/docs/reference/game/change-sprite-property.md +++ /dev/null @@ -1,37 +0,0 @@ -# Get Sprite Property - -Change the kind of [number](/reference/types/number) you say for a [sprite](/reference/game/create-sprite). - -```sig -let item: game.LedSprite = null; -item.set(LedSpriteProperty.X, 0); -``` - -### Parameters - -* the **sprite** you want to change -* the kind of [number](/reference/types/number) you want to change for the sprite, like - * ``x``, how far up or down the sprite is on the screen (`0`-`4`) - * ``y``, how far left or right the sprite is on the screen (`0`-`4`) - * ``direction``, which way the sprite is pointing (this works the same way as the [turn](/reference/game/turn) function) - * ``brightness``, how bright the LED sprite is (this works the same way as the [brightness](/reference/led/brightness) function) - * ``blink``, how fast the sprite is blinking (the bigger the number is, the faster the sprite is blinking) - -### Example - -This program makes a sprite on the left side of the screen, -waits two seconds (2000 milliseconds), -and then moves it to the middle of the screen. - -```blocks -let ball = game.createSprite(0, 2); -basic.pause(2000); -ball.change(LedSpriteProperty.X, 2); -``` - -### See also - -[turn](/reference/game/turn), -[brightness](/reference/led/brightness), -[get sprite property](/reference/game/get-sprite-property), -[set sprite property](/reference/game/set-sprite-property) diff --git a/docs/reference/game/change.md b/docs/reference/game/change.md new file mode 100644 index 00000000..00d9a231 --- /dev/null +++ b/docs/reference/game/change.md @@ -0,0 +1,35 @@ +# change (Sprite Property) + +Change the kind of [number](/types/number) you say for a [sprite](/reference/game/create-sprite). + +```sig +game.createSprite(0,0).change(LedSpriteProperty.X, 0); +``` + +## Parameters + +* **property**: the property of the **Sprite** you want to change, like: +>* ``x`` - how far up or down the sprite is on the screen (`0`-`4`) +>* ``y`` - how far left or right the sprite is on the screen (`0`-`4`) +>* ``direction`` - which way the sprite is pointing (this works the same way as the [turn](/reference/game/turn) function) +>* ``brightness`` - how bright the LED sprite is (this works the same way as the [brightness](/reference/led/brightness) function) +>* ``blink`` - how fast the sprite is blinking (the bigger the number is, the faster the sprite is blinking) + +## Example + +This program makes a sprite on the left side of the screen, +waits two seconds (2000 milliseconds), +and then moves it to the middle of the screen. + +```blocks +let ball = game.createSprite(0, 2); +basic.pause(2000); +ball.change(LedSpriteProperty.X, 2); +``` + +## See also + +[turn](/reference/game/turn), +[brightness](/reference/led/brightness), +[get sprite property](/reference/game/get), +[set sprite property](/reference/game/set) diff --git a/docs/reference/game/clear.md b/docs/reference/game/clear.md index 4ced5a51..93b89c15 100644 --- a/docs/reference/game/clear.md +++ b/docs/reference/game/clear.md @@ -4,17 +4,17 @@ The clear function for images. Turn off all the pixels in an [Image](/reference/images/image). -### JavaScript +## JavaScript ```sig export function clear(img: micro_bit.Image) ``` -### Parameters +## Parameters * none -### Example +## Example The following example turns off the pixels of `img` when the A input button is pressed: @@ -33,7 +33,7 @@ input.onButtonPressed(Button.A, () => { }) ``` -### See also +## See also [Image](/reference/images/image), [show animation](/reference/basic/show-animation), [show image](/reference/images/show-image), [scroll image](/reference/images/scroll-image), [create image](/reference/images/create-image) diff --git a/docs/reference/game/create-sprite.md b/docs/reference/game/create-sprite.md index ab166a9c..01583333 100644 --- a/docs/reference/game/create-sprite.md +++ b/docs/reference/game/create-sprite.md @@ -10,14 +10,25 @@ into another sprite. game.createSprite(2, 2); ``` -### Parameters +## Parameters * ``x``: The left-to-right place on the LED screen where the sprite will start out. * ``y``: The top-to-bottom place on the LED screen where the sprite will start out. `0` and `4` mean the edges of the screen, and `2` means in the middle. -### Example +## Returns + +* a new **LedSprite** at the location you say. + +## ~ hint + +Once the game engine is started, it will render the sprites to the screen and potentially override any kind of animation you are trying to show. +Using [game pause](/reference/game/pause) and [game resume](/reference/game/resume) to disable and enable the game rendering loop. + +## ~ + +## Example This program starts a sprite in the middle of the screen. Next, the sprite turns toward the lower-right corner. @@ -29,9 +40,9 @@ item.turn(Direction.Right, 45); item.move(2); ``` -### See also +## See also [move](/reference/game/move), [turn](/reference/game/turn), -[touching](/reference/game/touching) +[is-touching](/reference/game/is-touching) diff --git a/docs/reference/game/delete.md b/docs/reference/game/delete.md new file mode 100644 index 00000000..0ab5130c --- /dev/null +++ b/docs/reference/game/delete.md @@ -0,0 +1,21 @@ +# delete + +Delete a sprite from the game. + +```sig +game.createSprite(0,0).delete() +``` + +## Example + +This program makes a sprite and shows the number of its brightness on the screen. Then, it deletes the sprite. + +```blocks +let ball = game.createSprite(0, 2); +basic.showNumber(ball.get(LedSpriteProperty.Brightness)); +ball.delete(); +``` + +## See also + +[create sprite](/reference/game/create-sprite) diff --git a/docs/reference/game/game-over.md b/docs/reference/game/game-over.md index e39aba7f..2e50fea5 100644 --- a/docs/reference/game/game-over.md +++ b/docs/reference/game/game-over.md @@ -6,7 +6,7 @@ End the game and show the score. game.gameOver(); ``` -### Example +## Example This program asks you to pick a button. If you press button `A`, the program says `YOU WIN!`. @@ -22,7 +22,7 @@ input.onButtonPressed(Button.B, () => { }); ``` -### See Also +## See Also [score](/reference/game/score), -[change score by](/reference/game/change-score-by), [start countdown](/reference/game/start-countdown) +[add score](/reference/game/add-score), [start countdown](/reference/game/start-countdown) diff --git a/docs/reference/game/get-sprite-property.md b/docs/reference/game/get-sprite-property.md deleted file mode 100644 index 35fcdcc6..00000000 --- a/docs/reference/game/get-sprite-property.md +++ /dev/null @@ -1,39 +0,0 @@ -# Get Sprite Property - -Find something out about a [sprite](/reference/game/create-sprite). - -```sig -let item: game.LedSprite = null; -item.get(LedSpriteProperty.X); -``` - -### Parameters - -* the **sprite** you want to know something about -* the kind of [number](/reference/types/number) you want to know about the sprite, like - * ``x``, how far up or down the sprite is on the screen (`0`-`4`) - * ``y``, how far left or right the sprite is on the screen (`0`-`4`) - * ``direction``, which way the sprite is pointing (this works the same way as the [turn](/reference/game/turn) function) - * ``brightness``, how bright the LED sprite is (this works the same way as the [brightness](/reference/led/brightness) function) - * ``blink``, how fast the sprite is blinking (the bigger the number is, the faster the sprite is blinking) - -### Returns - -The [number](/reference/types/number) you asked for. - -### Example - -This program makes a sprite and shows the number of its brightness on the screen. - -```blocks -let ball = game.createSprite(0, 2); -basic.showNumber(ball.get(LedSpriteProperty.Brightness)); -``` - -### See also - -[turn](/reference/game/turn), -[brightness](/reference/led/brightness), -[change sprite property](/reference/game/change-sprite-property), -[set sprite property](/reference/game/set-sprite-property) - diff --git a/docs/reference/game/get.md b/docs/reference/game/get.md new file mode 100644 index 00000000..d2608e3e --- /dev/null +++ b/docs/reference/game/get.md @@ -0,0 +1,37 @@ +# get (Sprite Property) + +Find something out about a [sprite](/reference/game/create-sprite). + +```sig +game.createSprite(0,0).get(LedSpriteProperty.X); +``` + +## Parameters + +* **property**: the property of the **Sprite** you want to know about, like: +>* ``x`` - how far up or down the sprite is on the screen (`0`-`4`) +>* ``y`` - how far left or right the sprite is on the screen (`0`-`4`) +>* ``direction`` - which way the sprite is pointing (this works the same way as the [turn](/reference/game/turn) function) +>* ``brightness`` - how bright the LED sprite is (this works the same way as the [brightness](/reference/led/brightness) function) +>* ``blink`` - how fast the sprite is blinking (the bigger the number is, the faster the sprite is blinking) + +## Returns + +* a [number](/types/number) value of the property you asked for. + +## Example + +This program makes a sprite and shows the number of its brightness on the screen. + +```blocks +let ball = game.createSprite(0, 2); +basic.showNumber(ball.get(LedSpriteProperty.Brightness)); +``` + +## See also + +[turn](/reference/game/turn), +[brightness](/reference/led/brightness), +[change sprite property](/reference/game/change), +[set sprite property](/reference/game/set) + diff --git a/docs/reference/game/if-on-edge-bounce.md b/docs/reference/game/if-on-edge-bounce.md index 7091679f..841eaf5a 100644 --- a/docs/reference/game/if-on-edge-bounce.md +++ b/docs/reference/game/if-on-edge-bounce.md @@ -4,15 +4,14 @@ Make a [sprite](/reference/game/create-sprite) on the edge of the [LED screen](/device/screen) bounce away. ```sig -let item = game.createSprite(0, 2); -item.ifOnEdgeBounce(); +game.createSprite(0, 2).ifOnEdgeBounce(); ``` -### Parameters +## Parameters * a **sprite** that might be on the edge of the LED screen. -### Example +## Example This program makes a sprite on the right edge of the screen with a direction of 90 degrees, and bounces it so it has a direction of -90 @@ -27,8 +26,8 @@ input.onButtonPressed(Button.B, () => { }); ``` -### See also +## See also [create sprite](/reference/game/create-sprite), -[touching](/reference/game/touching), -[touching edge](/reference/game/touching-edge) +[is touching](/reference/game/is-touching), +[is touching edge](/reference/game/is-touching-edge) diff --git a/docs/reference/game/is-deleted.md b/docs/reference/game/is-deleted.md new file mode 100644 index 00000000..ac1f4272 --- /dev/null +++ b/docs/reference/game/is-deleted.md @@ -0,0 +1,33 @@ +# Is Deleted + +Find out if the sprite is deleted from the game engine or not. + +```sig +game.createSprite(0,0).isDeleted() +``` + +## Returns + +* a [boolean](/types/boolean) value that is `true` if the sprite is deleted from the game engine or `false` if not. + +## Example + +This game has 5 sprites initially. After 1 second, the third sprite is deleted and all remaining sprites are moved by 1. + +```blocks +let sprites: game.LedSprite[] = [] +for (let i = 0; i <= 4; i++) { + sprites.push(game.createSprite(0, i)) +} +basic.pause(1000) +sprites[2].delete() +for (let sprite of sprites) { + if (!(sprite.isDeleted())) { + sprite.move(1) + } +} +``` + +## See also + +[delete sprite](/reference/game/delete) \ No newline at end of file diff --git a/docs/reference/game/is-game-over.md b/docs/reference/game/is-game-over.md new file mode 100644 index 00000000..8be9eebd --- /dev/null +++ b/docs/reference/game/is-game-over.md @@ -0,0 +1,25 @@ +# is Game Over + +Find out if the game is over or not. + +```sig +game.isGameOver() +``` + +## Returns + +* a [boolean](/types/boolean) value that is `true` if the game is over or `false` if not. +# Example + +Be kind and give the player some points for trying. + +```blocks +if (game.isGameOver() && game.score() < 10) { + game.addScore(10 - game.score()) +} +``` + +## See also + +[is running](/reference/game/is-running), +[is paused](/reference/game/is-paused) \ No newline at end of file diff --git a/docs/reference/game/is-paused.md b/docs/reference/game/is-paused.md new file mode 100644 index 00000000..7f497d5d --- /dev/null +++ b/docs/reference/game/is-paused.md @@ -0,0 +1,28 @@ +# is Paused + +Find out if the game is paused or not. + +```sig +game.isPaused() +``` + +## Returns + +* a [boolean](/types/boolean) value that is `true` if the game is paused or `false` if not. + +## Example + +Resume the game if it's paused and button **B** is pressed. + +```blocks +input.onButtonPressed(Button.B, function () { + if (game.isPaused()) { + game.resume() + } +}) +``` + +## See also + +[is running](/reference/game/is-running), +[is game over](/reference/game/is-game-over) \ No newline at end of file diff --git a/docs/reference/game/is-running.md b/docs/reference/game/is-running.md new file mode 100644 index 00000000..40ee9565 --- /dev/null +++ b/docs/reference/game/is-running.md @@ -0,0 +1,28 @@ +# is Running + +Find out if the game is currently running or not. + +```sig +game.isRunning() +``` + +## Returns + +* a [boolean](/types/boolean) value that is `true` if the game is running or `false` if not. + +## Example + +If the game is currently running, end the game if button **B** is pressed. + +```blocks +input.onButtonPressed(Button.B, function () { + if (game.isRunning()) { + game.gameOver() + } +}) +``` + +## See also + +[is paused](/reference/game/is-paused), +[is game over](/reference/game/is-game-over) \ No newline at end of file diff --git a/docs/reference/game/touching-edge.md b/docs/reference/game/is-touching-edge.md similarity index 70% rename from docs/reference/game/touching-edge.md rename to docs/reference/game/is-touching-edge.md index ac08e98a..6016209e 100644 --- a/docs/reference/game/touching-edge.md +++ b/docs/reference/game/is-touching-edge.md @@ -6,19 +6,18 @@ Sprites are touching the edge if they overlap with an LED on the edge of the screen. ```sig -let item: game.LedSprite = null; -item.isTouchingEdge(); +game.createSprite(0, 2).isTouchingEdge(); ``` -### Parameters +## Parameters -* a **sprite** that might be touching the edge of the screen +* a **sprite** that might be touching the edge of the screen. -### Returns +## Returns -`true` if the sprite is touching the edge of the screen +* `true` if the sprite is touching the edge of the screen. -### Example +## Example This program makes a sprite in the middle of the left edge of the LED screen. Then it says `EDGY!` if it's on the edge (which it is!), and `SAFE!` if it's @@ -33,8 +32,8 @@ if (item.isTouchingEdge()) { } ``` -### See also +## See also [create sprite](/reference/game/create-sprite), -[touching](/reference/game/touching), +[is touching](/reference/game/is-touching), [if on edge, bounce](/reference/game/if-on-edge-bounce) diff --git a/docs/reference/game/touching.md b/docs/reference/game/is-touching.md similarity index 74% rename from docs/reference/game/touching.md rename to docs/reference/game/is-touching.md index 3ed0a9d8..dfd1f386 100644 --- a/docs/reference/game/touching.md +++ b/docs/reference/game/is-touching.md @@ -5,20 +5,18 @@ Find whether the sprite is touching another sprite you say. Sprites are touching if they share the same LED. ```sig -let item: game.LedSprite = null; -item.isTouching(null); +game.createSprite(0, 2).isTouching(null); ``` -### Parameters +## Parameters -* a **sprite** you are checking -* another **sprite** that might be touching the one you are checking +* another **sprite** that might be touching the one you are checking. -### Returns +## Returns -`true` if the two sprites are touching. +* `true` if the two sprites are touching. -### Example +## Example This program creates two sprites called ``matter`` and ``antimatter``, and then checks whether they are touching. If they are, there is an @@ -34,8 +32,8 @@ if (matter.isTouching(antimatter)) { } ``` -### See also +## See also [create sprite](/reference/game/create-sprite), -[touching edge](/reference/game/touching-edge), +[is touching edge](/reference/game/is-touching-edge), [if on edge, bounce](/reference/game/if-on-edge-bounce) diff --git a/docs/reference/game/move.md b/docs/reference/game/move.md index 299070c0..b4989d95 100644 --- a/docs/reference/game/move.md +++ b/docs/reference/game/move.md @@ -3,15 +3,14 @@ Move the sprite the number of LEDs you say. ```sig -let item: game.LedSprite = null; -item.move(1); +game.createSprite(0, 2).move(1); ``` -### Parameters +## Parameters -* a [number](/reference/types/number) that means how many LEDs the sprite should move +* **leds**: a [number](/types/number) that means how many LEDs the sprite should move. -### Example +## Example This program starts a sprite in the middle of the screen. Next, the sprite turns toward the lower-right corner. @@ -23,7 +22,7 @@ item.turn(Direction.Right, 45); item.move(2); ``` -### See also +## See also [turn](/reference/game/turn), [create sprite](/reference/game/create-sprite) diff --git a/docs/reference/game/pause.md b/docs/reference/game/pause.md new file mode 100644 index 00000000..083bbb1f --- /dev/null +++ b/docs/reference/game/pause.md @@ -0,0 +1,11 @@ +# Pause + +Pauses the game rendering engine to allow other animations on the screen. + +```sig +game.pause() +``` + +### See Also + +[resume](/reference/game/resume) diff --git a/docs/reference/game/remove-life.md b/docs/reference/game/remove-life.md new file mode 100644 index 00000000..a2308314 --- /dev/null +++ b/docs/reference/game/remove-life.md @@ -0,0 +1,33 @@ +# remove Life + +Decrease the number of lives remaining by some amount. + +```sig +game.removeLife(0) +``` + +The life count in the game is decreased by the number of lives you say. If the life count reaches `0` when these lives are removed, then the game is over. + +## Parameters + +* **life**: a [number](/types/number) to remove from the count. + +## Example #example + +Take away `20` lives count if the player's score reaches `10000` points. + +```blocks +let giveLives = true + +if (game.score() > 9999) { + if (giveLives) { + game.removeLife(20) + giveLives = false + } +} +``` + +## See also #seealso + +[set life](/reference/game/set-life), +[add life](/reference/game/add-life) \ No newline at end of file diff --git a/docs/reference/game/resume.md b/docs/reference/game/resume.md new file mode 100644 index 00000000..cc1a01df --- /dev/null +++ b/docs/reference/game/resume.md @@ -0,0 +1,11 @@ +# Resume + +Resumes the game rendering engine after a pause. + +```sig +game.resume() +``` + +### See Also + +[pause](/reference/game/pause) diff --git a/docs/reference/game/score.md b/docs/reference/game/score.md index 3ddeef93..b2fe712a 100644 --- a/docs/reference/game/score.md +++ b/docs/reference/game/score.md @@ -6,7 +6,7 @@ Find the number of points scored in your game. game.score() ``` -### Example +## Example This program adds one point to your score every time you press button `A`, and shows an animation. Then it waits 500 milliseconds (half a @@ -20,6 +20,6 @@ input.onButtonPressed(Button.A, () => { }); ``` -### See Also +## See Also [change score by](/reference/game/score), [start countdown](/reference/game/start-countdown) diff --git a/docs/reference/game/set-life.md b/docs/reference/game/set-life.md new file mode 100644 index 00000000..b3187ad2 --- /dev/null +++ b/docs/reference/game/set-life.md @@ -0,0 +1,26 @@ +# set Life + +Set the game life count to this amount. + +```sig +game.setLife(0) +``` + +Your program has a life counter which you can set to record the number of lives remaining for a player in your game. If you set the life count to `0` or less, the game ends. + +## Parameters + +* **value**: a [number](/types/number) to set the life count to. + +## Example #example + +Set the player life count to `9` lives before starting the game. + +```blocks +game.setLife(9) +``` + +## See also #seealso + +[add life](/reference/game/add-life), +[remove life](/reference/game/remove-life) \ No newline at end of file diff --git a/docs/reference/game/set-score.md b/docs/reference/game/set-score.md index fda88506..e6cda6e6 100644 --- a/docs/reference/game/set-score.md +++ b/docs/reference/game/set-score.md @@ -5,11 +5,11 @@ Sets the current score. ```sig game.setScore(1) ``` -### Parameters +## Parameters -* a [number](/reference/types/number) that represents the new score. +* a [number](/types/number) that represents the new score. -### Examples +## Examples This program is a simple game. Press button ``A`` as much as possible to increase the score. @@ -25,6 +25,6 @@ input.onButtonPressed(Button.A, () => { }) ``` -### See Also +## See Also -[score](/reference/game/score), [start countdown](/reference/game/start-countdown) +[score](/reference/game/score), [add score](/reference/game/add-score), [start countdown](/reference/game/start-countdown) diff --git a/docs/reference/game/set-sprite-property.md b/docs/reference/game/set-sprite-property.md deleted file mode 100644 index 60fbfbaf..00000000 --- a/docs/reference/game/set-sprite-property.md +++ /dev/null @@ -1,37 +0,0 @@ -# Set Sprite Property - -Make a [sprite](/reference/game/create-sprite) store the kind of [number](/reference/types/number) you say. - -```sig -let item: game.LedSprite = null; -item.set(LedSpriteProperty.X, 0); -``` - -### Parameters - -* the **sprite** you want to make store the number you say -* the kind of [number](/reference/types/number) you want to store in the sprite, like - * ``x``, how far up or down the sprite is on the screen (`0`-`4`) - * ``y``, how far left or right the sprite is on the screen (`0`-`4`) - * ``direction``, which way the sprite is pointing (this works the same way as the [turn](/reference/game/turn) function) - * ``brightness``, how bright the LED sprite is (this works the same way as the [brightness](/reference/led/brightness) function) - * ``blink``, how fast the sprite is blinking (the bigger the number is, the faster the sprite is blinking) - -### Example - -This program makes a sprite on the left side of the screen, -waits two seconds (2000 milliseconds), -and then moves it to the right side of the screen. - -```blocks -let ball = game.createSprite(0, 2); -basic.pause(2000); -ball.set(LedSpriteProperty.X, 4); -``` - -### See also - -[turn](/reference/game/turn), -[brightness](/reference/led/brightness), -[change sprite property](/reference/game/change-sprite-property), -[get sprite property](/reference/game/get-sprite-property) diff --git a/docs/reference/game/set.md b/docs/reference/game/set.md new file mode 100644 index 00000000..7a6ccb1b --- /dev/null +++ b/docs/reference/game/set.md @@ -0,0 +1,35 @@ +# set (Sprite Property) + +Make a [sprite](/reference/game/create-sprite) store the kind of [number](/types/number) you say. + +```sig +game.createSprite(0,0).set(LedSpriteProperty.X, 0); +``` + +## Parameters + +* **property**: the property of the **Sprite** you want to store a value for, like: +>* ``x`` - how far up or down the sprite is on the screen (`0`-`4`) +>* ``y`` - how far left or right the sprite is on the screen (`0`-`4`) +>* ``direction`` - which way the sprite is pointing (this works the same way as the [turn](/reference/game/turn) function) +>* ``brightness`` - how bright the LED sprite is (this works the same way as the [brightness](/reference/led/brightness) function) +>* ``blink`` - how fast the sprite is blinking (the bigger the number is, the faster the sprite is blinking) + +## Example + +This program makes a sprite on the left side of the screen, +waits two seconds (2000 milliseconds), +and then moves it to the right side of the screen. + +```blocks +let ball = game.createSprite(0, 2); +basic.pause(2000); +ball.set(LedSpriteProperty.X, 4); +``` + +## See also + +[turn](/reference/game/turn), +[brightness](/reference/led/brightness), +[change sprite property](/reference/game/change), +[get sprite property](/reference/game/get) diff --git a/docs/reference/game/start-countdown.md b/docs/reference/game/start-countdown.md index 7d768194..89ca2a77 100644 --- a/docs/reference/game/start-countdown.md +++ b/docs/reference/game/start-countdown.md @@ -6,11 +6,11 @@ Start counting down time from the number of milliseconds you say. game.startCountdown(1000) ``` -### Parameters +## Parameters -* ``ms`` is a [number](/reference/types/number) that says how many milliseconds to count down (one second is 1000 milliseconds) +* ``ms`` is a [number](/types/number) that says how many milliseconds to count down (one second is 1000 milliseconds) -### Examples +## Examples This program is a simple game. Press button ``A`` as much as possible. @@ -23,7 +23,7 @@ input.onButtonPressed(Button.A, () => { game.startCountdown(10000) ``` -### See Also +## See Also -[score](/reference/game/score), [change score by](/reference/game/change-score-by) +[score](/reference/game/score), [add score](/reference/game/add-score) diff --git a/docs/reference/game/turn.md b/docs/reference/game/turn.md index 4d602431..72e44d11 100644 --- a/docs/reference/game/turn.md +++ b/docs/reference/game/turn.md @@ -3,17 +3,16 @@ Turn the sprite as much as you say in the direction you say. ```sig -let item: game.LedSprite = null; -item.turn(Direction.Right, 45); +game.createSprite(0, 2).turn(Direction.Right, 45); ``` -### Parameters +## Parameters -* a choice whether the sprite should turn **left** or **right** -* a [number](/reference/types/number) that means how much the sprite should turn. - This number is in **degrees**, so a straight left or right turn is 90 degrees. +* **direction**: a choice whether the sprite should turn **left** or **right** +* **degrees**: a [number](/types/number) degrees of angle that the sprite should turn. +A straight left or right turn is 90 degrees. -### Example +## Example This program starts a sprite in the middle of the screen. @@ -26,7 +25,7 @@ item.turn(Direction.Right, 45); item.move(2); ``` -### See also +## See also [move](/reference/game/move), diff --git a/docs/reference/images.md b/docs/reference/images.md index a302bb06..9ea3794a 100644 --- a/docs/reference/images.md +++ b/docs/reference/images.md @@ -1,6 +1,6 @@ # Images -Creation, manipulation and display of LED images. +Create, show, and scroll images on the LED display. ```cards images.createImage(` @@ -17,8 +17,16 @@ images.createBigImage(` . . . . . . . . . . `); +images.createImage(``).showImage(0); +images.createImage(``).scrollImage(0,0); +images.arrowImage(ArrowNames.North) +images.iconImage(IconNames.Heart) +images.arrowNumber(ArrowNames.North) ``` -### See Also +## See Also -[createImage](/reference/images/create-image), [createBigImage](/reference/images/create-big-image) +[createImage](/reference/images/create-image), [createBigImage](/reference/images/create-big-image), +[showImage](/reference/images/show-image), [scrollImage](/reference/images/scroll-image), +[arrowImage](/reference/images/arrow-image), [iconImage](/reference/images/icon-image), [arrowNumber](/reference/images/arrow-number), +[pixel](/reference/images/pixel), [set-pixel](/reference/images/set-pixel) diff --git a/docs/reference/images/arrow-image.md b/docs/reference/images/arrow-image.md new file mode 100644 index 00000000..98b8c36c --- /dev/null +++ b/docs/reference/images/arrow-image.md @@ -0,0 +1,41 @@ +# arrow Image + +Create an arrow shaped [image](/reference/images/image) for the [LED screen](/device/screen). + +```sig +images.arrowImage(ArrowNames.North) +``` + +The arrow points in the direction of the arrow name you choose, like `North`. + +## Parameters + +* **i**: the arrow name to make an arrow [image](/reference/images/image) for. You can make an arrow image that points in one of these directions: + +>* `North` +>* `NorthEast` +>* `East` +>* `SouthEast` +>* `South` +>* `SouthWest` +>* `West` +>* `NorthWest` + +## Example + +Display a left arrow when button A is pressed or a right arrow when button B is pressed. + +```blocks +let arrowLeft = images.arrowImage(ArrowNames.West) +let arrowRight = images.arrowImage(ArrowNames.East) + +input.onButtonPressed(Button.A, () => { + arrowLeft.showImage(0); +}); +input.onButtonPressed(Button.B, () => { + arrowRight.showImage(0); +}); +``` +## See also + +[arrow number](/reference/images/arrow-number) diff --git a/docs/reference/images/arrow-number.md b/docs/reference/images/arrow-number.md new file mode 100644 index 00000000..710325c5 --- /dev/null +++ b/docs/reference/images/arrow-number.md @@ -0,0 +1,33 @@ +# arrow Number + +Get the number that matches an arrow image name. + +```sig +images.arrowNumber(ArrowNames.North) +``` + +Each arrow image name has a number for it. You can find the number for any arrow name with ``||Images:arrow number||``. + +## Parameters + +* **arrow**: the arrow name to get an arrow number for. These are the arrow names: + +>* `North` +* `NorthEast` +* `East` +* `SouthEast` +* `South` +* `SouthWest` +* `West` +* `NorthWest` + +## Example + +Get the arrow number for `ArrowNames.South`. + +```blocks +let arrowSouthNumber = images.arrowNumber(ArrowNames.South) +``` +## See also + +[arrow image](/reference/images/arrow-image) \ No newline at end of file diff --git a/docs/reference/images/create-big-image.md b/docs/reference/images/create-big-image.md index 1a5395c3..c5c75db1 100644 --- a/docs/reference/images/create-big-image.md +++ b/docs/reference/images/create-big-image.md @@ -14,13 +14,13 @@ images.createBigImage(` `); ``` -### Parameters +## Parameters -* ``leds`` is a [string](/reference/types/string) that says which LEDs +* ``leds`` is a [string](/types/string) that says which LEDs on the screen should be on and which should be off. -### Example: Flip-flopping arrow +## Example: Flip-flopping arrow This program makes a big image with a picture of an arrow pointing up, and an arrow pointing down. If you press button `A`, the program will @@ -44,9 +44,9 @@ input.onButtonPressed(Button.B, () => { }); ``` -### See also +## See also -[Getting Started](/getting-started), [image](/reference/images/image), +[image](/reference/images/image), [create image](/reference/images/create-image), [show image](/reference/images/show-image), [scroll image](/reference/images/scroll-image), [show animation](/reference/basic/show-animation) diff --git a/docs/reference/images/create-image.md b/docs/reference/images/create-image.md index 935c6b66..d4ab2563 100644 --- a/docs/reference/images/create-image.md +++ b/docs/reference/images/create-image.md @@ -13,12 +13,12 @@ images.createImage(` `) ``` -### Parameters +## Parameters -* ``leds`` is a [string](/reference/types/string) that says which LEDs +* ``leds`` is a [string](/types/string) that says which LEDs on the screen should be on and which should be off. -### Example: Flip-flopping arrow +## Example: Flip-flopping arrow If you press button `A`, this program will make a picture of an arrow and show it on the LED screen. If you press button `B`, the @@ -45,9 +45,9 @@ input.onButtonPressed(Button.B, () => { }); ``` -### See also +## See also -[Getting Started](/getting-started), [image](/reference/images/image), +[image](/reference/images/image), [create big image](/reference/images/create-big-image), [show image](/reference/images/show-image), [scroll image](/reference/images/scroll-image), [show animation](/reference/basic/show-animation) diff --git a/docs/reference/images/icon-image.md b/docs/reference/images/icon-image.md new file mode 100644 index 00000000..d8ae4333 --- /dev/null +++ b/docs/reference/images/icon-image.md @@ -0,0 +1,33 @@ +# icon Image + +Create an icon [image](/reference/images/image) for the [LED screen](/device/screen). + +```sig +images.iconImage(IconNames.Heart); +``` + +There are lots of pre-made icon images you can use to display on the [LED screen](/device/screen) of the @boardname@. You choose an icon by its name. + +## Parameters + +* **i**: the icon name of the image you want to show on the [LED screen](/device/screen). You pick an icon image such as: `IconNames.Heart`. + +## Example + +Show a happy face when button A is pressed or a sad face when button B is pressed. + +```blocks +let iamHappy = images.iconImage(IconNames.Happy) +let iamSad = images.iconImage(IconNames.Sad) + +input.onButtonPressed(Button.A, () => { + iamHappy.showImage(0); +}); +input.onButtonPressed(Button.B, () => { + iamSad.showImage(0); +}); +``` + +## See also + +[arrow image](/reference/images/arrow-image) \ No newline at end of file diff --git a/docs/reference/images/image.md b/docs/reference/images/image.md index 15770c97..d6281869 100644 --- a/docs/reference/images/image.md +++ b/docs/reference/images/image.md @@ -2,11 +2,11 @@ An image for the @boardname@ screen. -### @parent blocks/language +## @parent blocks/language An *Image* is a matrix of pixels to show on the [LED screen](/device/screen) -### Block Editor: Show LEDs +## Block Editor: Show LEDs To display an image: @@ -22,7 +22,7 @@ basic.showLeds(` `) ``` -### Creating an image +## Creating an image To create an image that you can later modify, see the [create image](/reference/images/create-image) function. @@ -38,7 +38,7 @@ You should see code similar to this: ![](/static/mb/blocks/image-0.png) -### Image functions +## Image functions * [create image](/reference/images/create-image): create an image from a series of on/off LED states * [clear](/reference/basic/clear-screen): turn off all the pixels in an image @@ -47,7 +47,7 @@ You should see code similar to this: * [show image](/reference/images/show-image): show an image on the screen * [scroll image](/reference/images/scroll-image): scroll an image on the screen -### See also +## See also [Show LEDs](/reference/basic/show-leds), [create image](/reference/images/create-image), [show image](/reference/images/show-image), [LED screen](/device/screen) diff --git a/docs/reference/images/pixel.md b/docs/reference/images/pixel.md index f11b8147..0d7a3c2f 100644 --- a/docs/reference/images/pixel.md +++ b/docs/reference/images/pixel.md @@ -1,51 +1,41 @@ # Pixel -The pixel function. - Get the state of a pixel in an [Image](/reference/images/image). -### JavaScript + +## JavaScript ```sig -export function pixel(_this: micro_bit.Image, x: number, y: number) : boolean +let item: Image = null; +item.pixel(0, 0) ``` +## Parameters -### Parameters +* x - [Number](/types/number); the *x coordinate* or horizontal position of a pixel in an [image](/reference/images/image) +* y - [Number](/types/number); the *y coordinate* or vertical position of a pixel in an [image](/reference/images/image) -* x - [Number](/reference/types/number); the *x coordinate* or horizontal position of a pixel in an [image](/reference/images/image) -* y - [Number](/reference/types/number); the *y coordinate* or vertical position of a pixel in an [image](/reference/images/image) - -### x, y coordinates? +## x, y coordinates? To figure out the ``x``, ``y`` coordinates, see [LED screen](/device/screen). -### Returns +## Returns * [Boolean](/blocks/logic/boolean) - `true` for on and `false` for off -### Example +## Example This example gets the state of pixel `0, 0` in the `img` variable: -### ~hide - ```blocks let img = images.createImage(` . . # . . . . . . . . # . # . . . # . . . . # . . . . . . . -. # . # . . . # . . -. . # . . . . . . . +. # . # . . . # . .. . # . . . . . . . `) -``` - -### ~ - -```typescript-ignore let state = img.pixel(0, 0) ``` -### See also - -[set pixel](/reference/images/set-pixel), [show image](/reference/images/show-image), [image](/reference/images/image), [create image](/reference/images/create-image), [scroll image](/reference/images/scroll-image) +## See also +[set pixel](/reference/images/set-pixel), [show image](/reference/images/show-image), [image](/reference/images/image), [create image](/reference/images/create-image), [scroll image](/reference/images/scroll-image) \ No newline at end of file diff --git a/docs/reference/images/plot-frame.md b/docs/reference/images/plot-frame.md index b49ed1de..0db48dcb 100644 --- a/docs/reference/images/plot-frame.md +++ b/docs/reference/images/plot-frame.md @@ -4,21 +4,21 @@ The plot frame function. Display an [Image](/reference/images/image) on the @boardname@'s [LED screen](/device/screen) -### JavaScript +## JavaScript ```sig export function plotFrame(_this: micro_bit.Image, index: number) ``` -### Parameters +## Parameters -* index - [Number](/reference/types/number); which frame of the image to display +* index - [Number](/types/number); which frame of the image to display -### Difference from `plot image` +## Difference from `plot image` The `plot frame` function takes the index of the frame (if there are two frames, then the possible indices are 0 and 1), whereas `plot image` accepts an offset (if there are two frames, the offset would range between 0 and 9). -### Example +## Example ```blocks let img = images.createImage(` @@ -31,7 +31,7 @@ let img = images.createImage(` img.plotFrame(1) ``` -### See also +## See also [create image](/reference/images/create-image), [show animation](/reference/basic/show-animation), [image](/reference/images/image), [show image](/reference/images/show-image), [scroll image](/reference/images/scroll-image) diff --git a/docs/reference/images/plot-image.md b/docs/reference/images/plot-image.md index b51daa76..df87bc65 100644 --- a/docs/reference/images/plot-image.md +++ b/docs/reference/images/plot-image.md @@ -4,21 +4,21 @@ The plot image function. Display an [Image](/reference/images/image) on the @boardname@'s [LED screen](/device/screen) -### JavaScript +## JavaScript ```sig export function plotImage(_this: micro_bit.Image, xOffset: number) ``` -### Parameters +## Parameters -* x offset - [Number](/reference/types/number); the horizontal starting point of an image; use 0 for the first frame of the image, 5 for the second frame of the image, 10 for the third frame and so on. +* x offset - [Number](/types/number); the horizontal starting point of an image; use 0 for the first frame of the image, 5 for the second frame of the image, 10 for the third frame and so on. -### Difference from `show image` +## Difference from `show image` The `show image` function has a built in delay of 400ms after display of the image, whereas `plot image` has no built-in delay. -### Example +## Example ```blocks let img = images.createImage(` @@ -31,7 +31,7 @@ let img = images.createImage(` img.plotImage(0) ``` -### See also +## See also [create image](/reference/images/create-image), [show animation](/reference/basic/show-animation), [image](/reference/images/image), [show image](/reference/images/show-image), [scroll image](/reference/images/scroll-image) diff --git a/docs/reference/images/scroll-image.md b/docs/reference/images/scroll-image.md index 7b041286..7821ec2e 100644 --- a/docs/reference/images/scroll-image.md +++ b/docs/reference/images/scroll-image.md @@ -8,24 +8,21 @@ let item: Image = null; item.scrollImage(5, 200); ``` -### Parameters +## Parameters -* a [number](/reference/types/number) that means - how many LEDs to scroll at a time, from right to left or - left to right. If you use a positive number like `2`, the image - will scroll from the right side of the screen to the left. - If you use a negative number like `-2`, the image will scroll - in the other direction. If you use `5` or `-5`, the image - will scroll one **frame** at a time. (A frame is a part of the - image. It is a square with five LEDs on a side). This is - useful for **animation**. +* a [number](/types/number) that means + how many LEDs to scroll at a time from right to left. + You must use a positive number like `2`. + If you use `5`, the image will scroll one **frame** at a time. + (A frame is a part of the image. It is a square with five LEDs + on a side). This is useful for **animation**. -* a [number](/reference/types/number) that means +* a [number](/types/number) that means how many milliseconds to wait before scrolling the amount that ``offset`` says. (1000 milliseconds is one second.) The bigger you make this number, the slower the image will scroll. -### Example +## Example This program scrolls an image of two arrows five LEDs at a time, with a pause of 200 milliseconds between each time it scrolls. @@ -47,7 +44,7 @@ basic.forever(() => { }); ``` -### See also +## See also [show image](/reference/images/show-image), [image](/reference/images/image), [create image](/reference/images/create-image), [show animation](/reference/basic/show-animation) diff --git a/docs/reference/images/set-pixel.md b/docs/reference/images/set-pixel.md index 1be28eb5..5a06d3de 100644 --- a/docs/reference/images/set-pixel.md +++ b/docs/reference/images/set-pixel.md @@ -1,28 +1,27 @@ # Set Pixel -The set pixel function. #set pixel. - Set the on/off state of pixel in an [Image](/reference/images/image). -### JavaScript +## JavaScript ```sig -export function setPixel(_this: micro_bit.Image, x: number, y: number, value: boolean) +let item: Image = null; +item.setPixel(0, 0, true) ``` -### Parameters +## Parameters -* x - [Number](/reference/types/number); the *x coordinate* or horizontal position of a pixel in an [image](/reference/images/image) -* x - [Number](/reference/types/number); the *y coordinate* or vertical position of a pixel in an [image](/reference/images/image) +* x - [Number](/types/number); the *x coordinate* or horizontal position of a pixel in an [image](/reference/images/image) +* y - [Number](/types/number); the *y coordinate* or vertical position of a pixel in an [image](/reference/images/image) * value -[Boolean](/blocks/logic/boolean); the on/off state of a pixel; `true` for on, `false` for off -### x, y coordinates? +## x, y coordinates? To figure out the ``x``, ``y`` coordinates, see [LED screen](/device/screen). -### Example +## Example -The following example creates an image and stores it in the `img` variable. The `set pixel` function sets the centre pixel off, before `img` is shown using `show image`. +The following example creates an image and stores it in the `img` variable. The `set pixel` function sets the center pixel off, before `img` is shown using `show image`. ```blocks let img = images.createImage(` @@ -35,8 +34,6 @@ let img = images.createImage(` img.setPixel(2, 2, false) img.showImage(0) ``` + ## See also -### See also - -[pixel](/reference/images/pixel), [show image](/reference/images/show-image), [image](/reference/images/image), [create image](/reference/images/create-image), [scroll image](/reference/images/scroll-image) - + [pixel](/reference/images/pixel), [show image](/reference/images/show-image), [image](/reference/images/image), [create image](/reference/images/create-image), [scroll image](/reference/images/scroll-image) \ No newline at end of file diff --git a/docs/reference/images/show-frame.md b/docs/reference/images/show-frame.md index 18134bb4..d0e72154 100644 --- a/docs/reference/images/show-frame.md +++ b/docs/reference/images/show-frame.md @@ -4,21 +4,21 @@ The show frame function. Display an [Image](/reference/images/image) on the @boardname@'s [LED screen](/device/screen) -### JavaScript +## JavaScript ```sig export function showFrame(img: micro_bit.Image, frame: number) ``` -### Parameters +## Parameters -* index - [Number](/reference/types/number); which frame of the image to display +* index - [Number](/types/number); which frame of the image to display -### Difference from `plot frame` +## Difference from `plot frame` The `show frame` function is the same as [plot frame](/reference/images/plot-frame), but contains a built-in delay after the LED screen has been updated (whereas `plot frame` has no built-in delay) -### Example +## Example ```blocks let img = images.createImage(` @@ -31,7 +31,7 @@ let img = images.createImage(` img.showFrame(1) ``` -### See also +## See also [create image](/reference/images/create-image), [show animation](/reference/basic/show-animation), [image](/reference/images/image), [show image](/reference/images/show-image), [scroll image](/reference/images/scroll-image) diff --git a/docs/reference/images/show-image.md b/docs/reference/images/show-image.md index fe038d38..3867e500 100644 --- a/docs/reference/images/show-image.md +++ b/docs/reference/images/show-image.md @@ -9,12 +9,12 @@ let item: Image = null; item.showImage(0); ``` -### Parameters +## Parameters * an [image](/reference/images/image) (picture). It is usually a square with five LEDs on a side, but it might be wider. -* a [number](/reference/types/number) that says how many LEDs from the left of the picture the @boardname@ should start. `0` means start at the first **frame** of the picture, `5` means start at the second frame, `10` means start at the third, and so on. +* a [number](/types/number) that says how many LEDs from the left of the picture the @boardname@ should start. `0` means start at the first **frame** of the picture, `5` means start at the second frame, `10` means start at the third, and so on. -### Example: Flip-flopping arrow +## Example: Flip-flopping arrow This program makes a big image with a frame of an arrow pointing up, and a frame of an arrow pointing down. If you press button `A`, the @@ -39,9 +39,9 @@ input.onButtonPressed(Button.B, () => { }); ``` -### See also +## See also -[Getting Started](/getting-started), [image](/reference/images/image), +[image](/reference/images/image), [create image](/reference/images/create-image), [create big image](/reference/images/create-big-image), [scroll image](/reference/images/scroll-image), [show animation](/reference/basic/show-animation) diff --git a/docs/reference/images/width.md b/docs/reference/images/width.md index 31df2f77..e81f2e1e 100644 --- a/docs/reference/images/width.md +++ b/docs/reference/images/width.md @@ -8,17 +8,13 @@ Get the width of an [Image](/reference/images/image) in columns. images.createImage().width(); ``` -### Parameters +## Returns -* none - -### Returns - -* [Number](/reference/types/number) - the number of columns in a image. This function returns 5 if the image has 1 frame, 10 for 2 frames, 15 for 3 frames and so on. Divide the number of columns by 5 to find out how many frames an image has (see example below). +* [Number](/types/number) - the number of columns in a image. This function returns 5 if the image has 1 frame, 10 for 2 frames, 15 for 3 frames and so on. Divide the number of columns by 5 to find out how many frames an image has (see example below). The following example gets the width of `img` and stores it in the `w` variable: -### ~hide +## ~hide ```blocks let img = images.createImage(` @@ -30,13 +26,13 @@ let img = images.createImage(` `) ``` -### ~ +## ~ ```typescript-ignore let w = img.width() ``` -### Example: show each frame +## Example: show each frame The following example uses the `width` function with a [for](/blocks/loops/for) loop to show each image frame on the screen: @@ -54,7 +50,7 @@ for (let i = 0; i < img2.width() / 5; i++) { } ``` -### See also +## See also [show image](/reference/images/show-image), [image](/reference/images/image), [create image](/reference/images/create-image), [scroll image](/reference/images/scroll-image), [show animation](/reference/basic/show-animation) diff --git a/docs/reference/input.md b/docs/reference/input.md index bc186bd4..80920799 100644 --- a/docs/reference/input.md +++ b/docs/reference/input.md @@ -13,6 +13,7 @@ input.onPinPressed(TouchPin.P0, () => { }); input.buttonIsPressed(Button.A); +input.isGesture(Gesture.Shake); input.compassHeading(); input.pinIsPressed(TouchPin.P0); input.temperature(); @@ -21,25 +22,12 @@ input.lightLevel(); input.rotation(Rotation.Pitch); input.magneticForce(Dimension.X); input.runningTime(); +input.runningTimeMicros(); input.setAccelerometerRange(AcceleratorRange.OneG); -input.calibrate(); -input.onLogoDown(() => { - -}); -input.onLogoUp(() => { - -}); -input.onScreenDown(() => { - -}); -input.onScreenUp(() => { - -}); -input.onShake(() => { - -}); ``` -### See Also +## See also -[onButtonPressed](/reference/input/on-button-pressed), [onGesture](/reference/input/on-gesture), [onPinPressed](/reference/input/on-pin-pressed), [buttonIsPressed](/reference/input/button-is-pressed), [compassHeading](/reference/input/compass-heading), [pinIsPressed](/reference/input/pin-is-pressed), [temperature](/reference/input/temperature), [acceleration](/reference/input/acceleration), [lightLevel](/reference/input/light-level), [rotation](/reference/input/rotation), [magneticForce](/reference/input/magnetic-force), [runningTime](/reference/input/running-time), [setAccelerometerRange](/reference/input/set-accelerometer-range) +[onButtonPressed](/reference/input/on-button-pressed), [onGesture](/reference/input/on-gesture), [onPinPressed](/reference/input/on-pin-pressed), [buttonIsPressed](/reference/input/button-is-pressed), +[is gesture](/reference/input/is-gesture), +[compassHeading](/reference/input/compass-heading), [pinIsPressed](/reference/input/pin-is-pressed), [temperature](/reference/input/temperature), [acceleration](/reference/input/acceleration), [lightLevel](/reference/input/light-level), [rotation](/reference/input/rotation), [magneticForce](/reference/input/magnetic-force), [runningTime](/reference/input/running-time), [setAccelerometerRange](/reference/input/set-accelerometer-range), [calibrate-compass](/reference/input/calibrate-compass) diff --git a/docs/reference/input/acceleration.md b/docs/reference/input/acceleration.md index 67e55c83..83b35731 100644 --- a/docs/reference/input/acceleration.md +++ b/docs/reference/input/acceleration.md @@ -1,6 +1,6 @@ # Acceleration -Get the acceleration value (milli g-force), in one of three specified dimensions. +Get the acceleration value (milli g-force) in one of three dimensions, or the combined force in all directions (x, y, and z). Find the acceleration of the @boardname@ (how fast it is speeding up or slowing down). @@ -15,17 +15,41 @@ A **g** is as much acceleration as you get from Earth's gravity. ## ~ +Watch this video to learn how the accelerometer on the @boardname@ works: +https://www.youtube.com/watch?v=byngcwjO51U -### Parameters +## Parameters -* ``dimension`` means which direction you are checking for acceleration, either `Dimension.X` (left and right), `Dimension.Y` (forward and backward), or `Dimension.Z` (up and down) +* **dimension**: the direction you are checking for acceleration, or the total strength of force. +>`x`: acceleration in the left and right direction.
+`y`: acceleration in the forward and backward direction.
+`z`: acceleration in the up and down direction.
+`strength`: the resulting strength of acceleration from all three dimensions (directions). -### Returns +### ~hint -* a [number](/reference/types/number) that means the amount of acceleration. When the @boardname@ is lying flat on a surface with the screen pointing up, `x` is `0`, `y` is `0`, and `z` is `-1023`. +**Forces in space** -### Example: bar chart +Since we don't live on a flat world, forces happen in three dimensional space. If the movement of an object isn't exactly in the direction of one axis, we need a way to calculate its acceleration from the values measured for all the axes together. + +If you put your @boardname@ on a level table and push it diagonally, you have an acceleration in two dimensions. You can find the acceleration in that direction just like how you calculate the long side of a triangle using the two shorter sides (**X** and **Y**): + +```strength2D = Math.sqrt((accelX * accelX) + (accelY * accelY))``` + +If you decide to lift your @boardname@ off the table, then you've just added another dimension, so insert the acceleration value for the **Z** axis into the equation: + +```strength3D = Math.sqrt((accelX * accelX) + (accelY * accelY) + (accelZ * accelZ))``` + +This calculation is called the [Euclidean norm](https://en.wikipedia.org/wiki/Euclidean_norm) of acceleration. + +### ~ + +## Returns + +* a [number](/types/number) that means the amount of acceleration. When the @boardname@ is lying flat on a surface with the screen pointing up, `x` is `0`, `y` is `0`, `z` is `-1023`, and `strength` is `1023`. + +## Example: bar chart This example shows the acceleration of the @boardname@ with a bar graph. @@ -34,9 +58,18 @@ basic.forever(() => { led.plotBarGraph(input.acceleration(Dimension.X), 1023) }) ``` +### Example: quake meter +Every 5 seconds, with the @boardname@ facing upward on a flat surface, show how much the earth is shaking (if at all). -### See also +```blocks +basic.forever(() => { + basic.showNumber(input.acceleration(Dimension.Strength)) + basic.pause(5000) +}) +``` + +## See also [set accelerometer range](/reference/input/set-accelerometer-range), [compass heading](/reference/input/compass-heading), diff --git a/docs/reference/input/button-is-pressed.md b/docs/reference/input/button-is-pressed.md index 7cc7235e..c75136bb 100644 --- a/docs/reference/input/button-is-pressed.md +++ b/docs/reference/input/button-is-pressed.md @@ -6,17 +6,17 @@ Check whether a button is pressed right now. The @boardname@ has two buttons: bu input.buttonIsPressed(Button.A); ``` -### Parameters +## Parameters -* ``button`` is a [String](/reference/types/string). You should store `A` in it to check the left button, `B` to check the right button, or `A+B` to check both at the same time. +* ``button`` is a [String](/types/string). You should store `A` in it to check the left button, `B` to check the right button, or `A+B` to check both at the same time. -### Returns +## Returns -* [Boolean](/blocks/logic/boolean) that is `true` if the button you are checking is pressed, `false` if it is not pressed. +* a [boolean](/blocks/logic/boolean) value that is `true` if the button you are checking is pressed, `false` if it is not pressed. -### Example +## Example -This program uses an [if](/blocks/logic/if) to run +This program uses an [``||logic:if||``](/blocks/logic/if) to run one part of the program if the `A` button is pressed, and another part if it is not pressed. @@ -25,15 +25,19 @@ basic.forever(() => { let pressed = input.buttonIsPressed(Button.A) if (pressed) { // this part runs if the A button is pressed - basic.showNumber(1, 150) + basic.showNumber(1) } else { // this part runs if the A button is *not* pressed - basic.showNumber(0, 150) + basic.showNumber(0) } }) ``` -### See also +Find out how buttons provide input to the @boardname@ in this video: + +https://www.youtube.com/watch?v=t_Qujjd_38o + +## See also [on button pressed](/reference/input/on-button-pressed), [if](/blocks/logic/if), [forever](/reference/basic/forever) diff --git a/docs/reference/input/calibrate-compass.md b/docs/reference/input/calibrate-compass.md new file mode 100644 index 00000000..673fd554 --- /dev/null +++ b/docs/reference/input/calibrate-compass.md @@ -0,0 +1,33 @@ +# Calibrate Compass + +Runs the compass calibration sequence. + +```sig +input.calibrateCompass(); +``` + +## Calibration + +The calibration will ask you to draw a circle or fill the LED screen by tilting the +@boardname@. + +The compass calibration is stored in memory by the @boardname@, so next time you press the reset button or remove and replace the power the calibration will be remembered. + +When you flash a new program to your @boardname@ via USB, this memory is cleared so you will have to re-calibrate it. + +If you are calibrating or using the compass near metal, it might +confuse the @boardname@. + +## Example + +This example runs the calibration when the user presses **A+B** buttons. + +```blocks +input.onButtonPressed(Button.AB, () => { + input.calibrateCompass(); +}) +``` + +## See also + +[compassHeading](/reference/input/compass-heading) diff --git a/docs/reference/input/compass-heading.md b/docs/reference/input/compass-heading.md index 58fd4556..849bbafe 100644 --- a/docs/reference/input/compass-heading.md +++ b/docs/reference/input/compass-heading.md @@ -2,7 +2,7 @@ Find which direction on a compass the @boardname@ is facing. -The @boardname@ measures the **compass heading** from `0` to `360` +The @boardname@ measures the **compass heading** from `0` to `359` degrees with its **magnetometer** chip. Different numbers mean north, east, south, and west. @@ -10,11 +10,11 @@ east, south, and west. input.compassHeading(); ``` -### Returns +## Returns -* a [number](/reference/types/number) from `0` to `360` degrees, which means the compass heading. If the compass isn't ready, it returns `-1003`. +* a [number](/types/number) from `0` to `359` degrees, which means the compass heading. If the compass isn't ready, it returns `-1003`. -### Example +## Example This program finds the compass heading and stores it in the `degrees` variable. @@ -23,42 +23,59 @@ This program finds the compass heading and stores it in the let degrees = input.compassHeading() ``` -### ~hint +## ~hint When you run a program that uses this function in a browser, click and drag the compass needle on the screen to change the compass heading. -### ~ +## ~ -### Example: compass +## Example: compass This program finds the compass heading and then shows a letter that means whether the @boardname@ is facing north (N), south (S), east (E), or west (W). ```blocks +let degrees = 0 basic.forever(() => { - let degrees = input.compassHeading() - if (degrees < 45) - basic.showString("N") - else if (degrees < 135) - basic.showString("E") - else if (degrees < 225) - basic.showString("S") - else basic.showString("W") + degrees = input.compassHeading() + if (degrees < 45) { + basic.showArrow(ArrowNames.North) + } else if (degrees < 135) { + basic.showArrow(ArrowNames.East) + } else if (degrees < 225) { + basic.showArrow(ArrowNames.South) + } else if (degrees < 315) { + basic.showArrow(ArrowNames.West) + } else { + basic.showArrow(ArrowNames.North) + } }) ``` -### Calibration +## Calibration Every time you start to use the compass (for example, if you have just -turned the @boardname@ on), the @boardname@ will start to **calibrate** +turned the @boardname@ on), the @boardname@ will start to [calibrateCompass](/reference/input/calibrate-compass) (adjust itself). It will ask you to draw a circle by tilting the @boardname@. If you are calibrating or using the compass near metal, it might confuse the @boardname@. -### See also +## ~ hint -[acceleration](/reference/input/acceleration) +Keep the calibration handy by running it when the user pressed **A+B**. + +```block +input.onButtonPressed(Button.AB, () => { + input.calibrateCompass(); +}) +``` + +## ~ + +## See also + +[acceleration](/reference/input/acceleration), [calibrateCompass](/reference/input/calibrate-compass) diff --git a/docs/reference/input/is-gesture.md b/docs/reference/input/is-gesture.md new file mode 100644 index 00000000..3becc968 --- /dev/null +++ b/docs/reference/input/is-gesture.md @@ -0,0 +1,28 @@ +# Is Gesture + +Tests if a gesture is currently detected. + +```sig +input.isGesture(Gesture.Shake) +``` + +## Parameters + +* ``gesture`` means the way you hold or move the @boardname@. This can be `shake`, `logo up`, `logo down`, `screen up`, `screen down`, `tilt left`, `tilt right`, `free fall`, `3g`, or `6g`. + +## Example: random number + +This program shows a number from `2` to `9` when you shake the @boardname@. + +```blocks +forever(function() { + if (input.isGesture(Gesture.Shake)) { + let x = Math.randomRange(2, 9) + basic.showNumber(x) + } +}) +``` + +## See Also + +[on gesture](/reference/input/on-gesture) diff --git a/docs/reference/input/light-level.md b/docs/reference/input/light-level.md index 66d3f2a8..558aab08 100644 --- a/docs/reference/input/light-level.md +++ b/docs/reference/input/light-level.md @@ -14,11 +14,15 @@ has to be turned on first. input.lightLevel(); ``` -### Returns +Learn more about how light level is detected in this light sensor video: -* a [Number](/reference/types/number) that means a light level from ``0`` (dark) to ``255`` (bright). +https://www.youtube.com/watch?v=TKhCr-dQMBY. -### Example: show light level +## Returns + +* a [Number](/types/number) that means a light level from ``0`` (dark) to ``255`` (bright). + +## Example: show light level When you press button `B` on the microbit, this program shows the light level @@ -31,7 +35,7 @@ input.onButtonPressed(Button.B, () => { }) ``` -### Example: chart light level +## Example: chart light level This program shows the light level with a [bar chart](/reference/led/plot-bar-graph) on the @boardname@ screen. If you carry the @boardname@ around to different places with different light levels, @@ -43,7 +47,7 @@ basic.forever(() => { }) ``` -### See also +## See also [acceleration](/reference/input/acceleration), [compass-heading](/reference/input/compass-heading) diff --git a/docs/reference/input/magnetic-force.md b/docs/reference/input/magnetic-force.md index 9b83c835..14373484 100644 --- a/docs/reference/input/magnetic-force.md +++ b/docs/reference/input/magnetic-force.md @@ -13,18 +13,18 @@ The @boardname@ measures magnetic force with **microteslas**. ## ~ -### Parameters +## Parameters * ``dimension`` means which direction the @boardname@ should measure magnetic force in: either `Dimension.X` (the left-right direction), `Dimension.Y` (the forward/backward direction), or `Dimension.Z` (the up/down direction) -### Returns +## Returns -* a [number](/reference/types/number) of microteslas that means the strength of the magnet +* a [number](/types/number) of microteslas that means the strength of the magnet -### Example: metal detector +## Example: metal detector This program makes the center LED of the @boardname@ get brighter when the magnetic force is stronger, and dimmer when it is weaker. @@ -37,6 +37,6 @@ basic.forever(() => { }) ``` -### See also +## See also [compass heading](/reference/input/compass-heading) diff --git a/docs/reference/input/on-button-pressed.md b/docs/reference/input/on-button-pressed.md index ede3f410..c17d7049 100644 --- a/docs/reference/input/on-button-pressed.md +++ b/docs/reference/input/on-button-pressed.md @@ -5,11 +5,18 @@ This handler works when button `A` or `B` is pressed, or `A` and `B` together. When you are using this function in a web browser, click the buttons on the screen instead of the ones on the @boardname@. +* For button `A` or `B`: This handler works when the button is pushed down and released within 1 second. +* For `A` and `B` together: This handler works when `A` and `B` are both pushed down, then one of them is released within 1.5 seconds of pushing down the second button. + ```sig input.onButtonPressed(Button.A, () => {}) ``` -### Example: count button clicks +Find out how buttons provide input to the @boardname@ in this video: + +https://www.youtube.com/watch?v=t_Qujjd_38o + +## Example: count button clicks This example counts how many times you press the `A` button. Each time you press the button, the [LED screen](/device/screen) shows the `count` variable getting bigger. @@ -23,25 +30,25 @@ input.onButtonPressed(Button.A, () => { }) ``` -### Example: roll dice +## Example: roll dice This example shows a number from 1 to 6 when you press the `B` button. ```blocks input.onButtonPressed(Button.B, () => { - let dice = Math.random(6) + 1 + let dice = Math.randomRange(0, 5) + 1 basic.showNumber(dice) }) ``` -### ~hint +## ~hint -This program adds a `1` to `random(6)` so the numbers on the dice will come out right. +This program adds a `1` to `random(5)` so the numbers on the dice will come out right. Otherwise, sometimes they would show a `0`. -### ~ +## ~ -### See also +## See also [button is pressed](/reference/input/button-is-pressed), [forever](/reference/basic/forever), [random](/blocks/math) diff --git a/docs/reference/input/on-gesture.md b/docs/reference/input/on-gesture.md index eaa2d4b2..29e98e5a 100644 --- a/docs/reference/input/on-gesture.md +++ b/docs/reference/input/on-gesture.md @@ -9,18 +9,21 @@ input.onGesture(Gesture.Shake,() => { }) ``` -### Parameters +## Parameters * ``gesture`` means the way you hold or move the @boardname@. This can be `shake`, `logo up`, `logo down`, `screen up`, `screen down`, `tilt left`, `tilt right`, `free fall`, `3g`, or `6g`. -### Example: random number +## Example: random number -This program shows a number from `0` to `9` when you shake the @boardname@. +This program shows a number from `2` to `9` when you shake the @boardname@. ```blocks input.onGesture(Gesture.Shake,() => { - let x = Math.random(10) - basic.showNumber(x, 100) + let x = Math.randomRange(2, 9) + basic.showNumber(x) }) ``` +## See Also + +[is gesture](/reference/input/is-gesture) \ No newline at end of file diff --git a/docs/reference/input/on-pin-pressed.md b/docs/reference/input/on-pin-pressed.md index b5ac4f98..7d384c6e 100644 --- a/docs/reference/input/on-pin-pressed.md +++ b/docs/reference/input/on-pin-pressed.md @@ -2,8 +2,9 @@ Start an [event handler](/reference/event-handler) (part of the program that will run when something happens, like when a button is -pressed). This handler works when you press pin `0`, `1`, or `2` -together with `GND`. When you are using this function in a web +pressed). This handler works when you touch pin `0`, `1`, or `2` +together with `GND`, and release it within 1 second. +When you are using this function in a web browser, click the pins on the screen instead of the ones on the @boardname@. @@ -28,21 +29,27 @@ instead of the USB cable. * ``name`` means the pin that is being pressed, either `P0`, `P1`, or `P2` -### Example: pin pressed counter +## Pin presses in action + +See how the @boardname@ detects a press at a pin or on something connected to a pin in this video: + +https://www.youtube.com/watch?v=GEpZrvbsO7o + +## Example: pin pressed counter This program counts how many times you press the `P0` pin. Every time you press the pin, the program shows the number of times on the screen. ```blocks let count = 0 -basic.showNumber(count, 100) +basic.showNumber(count) input.onPinPressed(TouchPin.P0, () => { count = count + 1 - basic.showNumber(count, 100) + basic.showNumber(count) }) ``` -### See also +## See also [@boardname@ pins](/device/pins), [pin is pressed](/reference/input/pin-is-pressed), [analog read pin](/reference/pins/analog-read-pin), [analog write pin](/reference/pins/analog-write-pin), [digital read pin](/reference/pins/digital-read-pin), [digital write pin](/reference/pins/digital-write-pin) diff --git a/docs/reference/input/on-pin-released.md b/docs/reference/input/on-pin-released.md index 82bbd53b..724a3282 100644 --- a/docs/reference/input/on-pin-released.md +++ b/docs/reference/input/on-pin-released.md @@ -28,7 +28,7 @@ instead of the USB cable. * ``name`` means the pin that is being released, either `P0`, `P1`, or `P2` -### Example: pin pressed counter +## Example: pin pressed counter This program counts how many times you release the `P0` pin. Every time you release the pin, the program shows the number of times on the screen. @@ -42,7 +42,7 @@ input.onPinReleased(TouchPin.P0, () => { }) ``` -### See also +## See also [@boardname@ pins](/device/pins), [pin is pressed](/reference/input/pin-is-pressed), [analog read pin](/reference/pins/analog-read-pin), [analog write pin](/reference/pins/analog-write-pin), [digital read pin](/reference/pins/digital-read-pin), [digital write pin](/reference/pins/digital-write-pin) diff --git a/docs/reference/input/pin-is-pressed.md b/docs/reference/input/pin-is-pressed.md index f10e4537..4ba150a5 100644 --- a/docs/reference/input/pin-is-pressed.md +++ b/docs/reference/input/pin-is-pressed.md @@ -17,29 +17,35 @@ instead of the USB cable. ## ~ -### Parameters +## Parameters -* a [string](/reference/types/string) that holds the pin name (**P0**, **P1**, or **P2**) +* a [string](/types/string) that holds the pin name (**P0**, **P1**, or **P2**) -### returns +## returns * a [boolean](/blocks/logic/boolean) that means whether the pin you say is pressed (`true` or `false`) -### Example +## Pin presses in action + +See how the @boardname@ detects a press at a pin or on something connected to a pin in this video: + +https://www.youtube.com/watch?v=GEpZrvbsO7o + +## Example This program shows `1` if `P0` is pressed, and `0` if `P0` is not pressed: ```blocks basic.forever(() => { if (input.pinIsPressed(TouchPin.P0)) { - basic.showNumber(1, 150) + basic.showNumber(1) } else { - basic.showNumber(0, 150) + basic.showNumber(0) } }) ``` -### See also +## See also [@boardname@ pins](/device/pins), [on pin pressed](/reference/input/on-pin-pressed), [analog read pin](/reference/pins/analog-read-pin), [analog write pin](/reference/pins/analog-write-pin), [digital read pin](/reference/pins/digital-read-pin), [digital write pin](/reference/pins/digital-write-pin) diff --git a/docs/reference/input/rotation.md b/docs/reference/input/rotation.md index 86d49c65..a4e9cb6c 100644 --- a/docs/reference/input/rotation.md +++ b/docs/reference/input/rotation.md @@ -9,26 +9,25 @@ input.rotation(Rotation.Roll); ## ~hint The @boardname@ has a part called the **accelerometer** that can -check how the @boardname@ is moving. +check how the @boardname@ is moving. Watch this video to learn how the accelerometer works: + +https://www.youtube.com/watch?v=byngcwjO51U ## ~ -### Parameters +## Parameters * ``kind`` means which direction you are checking: `Rotation.Pitch` (up and down) or `Rotation.Roll` (left and right) -### Returns +## Returns -* a [number](/reference/types/number) that means how much the microbit is tilted in the direction you say, from `0` to `360` degrees +* a [number](/types/number) that means how much the @boardname@ is tilted in the direction you ask for. This is a value in degrees between `-180` to `180` in either the `Rotation.Pitch` or the `Rotation.Roll` direction of rotation. -### Example: @boardname@ leveler +## Example: @boardname@ leveler -This program helps you move the @boardname@ until it is level. When -it is level, the @boardname@ shows a smiley. - -If you are running this program in a browser, you can tilt the -@boardname@ with your mouse. +This program helps you move the @boardname@ until it is level. When it is level, the @boardname@ shows a smiley. +If you are running this program in a browser, you can tilt the @boardname@ with your mouse. ```blocks let pitch = 0; @@ -55,7 +54,7 @@ basic.forever(() => { }); ``` -### See also +## See also [acceleration](/reference/input/acceleration), [compass-heading](/reference/input/compass-heading) diff --git a/docs/reference/input/running-time-micros.md b/docs/reference/input/running-time-micros.md new file mode 100644 index 00000000..413cf4ef --- /dev/null +++ b/docs/reference/input/running-time-micros.md @@ -0,0 +1,17 @@ +# Running Time Micros + +Find how long it has been since the program started in micro-seconds. + +```sig +input.runningTimeMicros(); +``` + +## Returns + +* the [Number](/types/number) of microseconds since the program started. +(One second is 1000000 microseconds.) + +## See also + +[show number](/reference/basic/show-number), [pause](/reference/basic/pause) + diff --git a/docs/reference/input/running-time.md b/docs/reference/input/running-time.md index 974ee043..099fb640 100644 --- a/docs/reference/input/running-time.md +++ b/docs/reference/input/running-time.md @@ -1,17 +1,17 @@ # Running Time -Find how long it has been since the program started. +Find how long it has been since the program started in milli-seconds. ```sig input.runningTime(); ``` -### Returns +## Returns -* the [Number](/reference/types/number) of milliseconds since the program started. +* the [Number](/types/number) of milliseconds since the program started. (One second is 1000 milliseconds.) -### Example: elapsed time +## Example: elapsed time When you press button `B` on the microbit, this program finds the number of milliseconds since the program started @@ -25,7 +25,7 @@ input.onButtonPressed(Button.B, () => { ``` -### See also +## See also [show number](/reference/basic/show-number), [pause](/reference/basic/pause) diff --git a/docs/reference/input/set-accelerometer-range.md b/docs/reference/input/set-accelerometer-range.md index f6310982..9051cf6c 100644 --- a/docs/reference/input/set-accelerometer-range.md +++ b/docs/reference/input/set-accelerometer-range.md @@ -9,17 +9,17 @@ or low acceleration. input.setAccelerometerRange(AcceleratorRange.OneG); ``` -### Parameters +## Parameters * ``range`` means the biggest number of gravities of acceleration you will be measuring (either `1g`, `2g`, `4g`, or `8g`). Any bigger numbers will be ignored by your @boardname@, both when you are picking a number of gravities, and when you are measuring acceleration. -### Example +## Example -This program says the highest acceleration that your @boardname@ -will measure is 4G. Then it measures acceleration from side to side +This program sets the highest acceleration that your @boardname@ +will measure is 4G. Then it shows acceleration from side to side until you stop the program. ```blocks @@ -29,13 +29,13 @@ basic.forever(() => { }); ``` -#### ~hint +### ~hint This program does not work in the simulator, only in a @boardname@. -#### ~ +### ~ -### See Also +## See Also [compass heading](/reference/input/compass-heading), [light level](/reference/input/light-level) diff --git a/docs/reference/input/temperature.md b/docs/reference/input/temperature.md index 75d7b2ec..654bd135 100644 --- a/docs/reference/input/temperature.md +++ b/docs/reference/input/temperature.md @@ -7,18 +7,23 @@ The @boardname@ can find the temperature nearby by checking how hot its computer input.temperature(); ``` -### Returns +## Returns -* a [Number](/reference/types/number) that means the Celsius temperature. +* a [number](/types/number) that is the temperature in degrees Celsius. -### How does it work? +## How does it work? The @boardname@ checks how hot its CPU (main computer chip) is. Because the @boardname@ does not usually get very hot, the temperature of the CPU is usually close to the temperature of wherever you are. The @boardname@ might warm up a little if you make it work hard, though! -### Example: @boardname@ thermometer +Learn more about how the @boardname@ can detect hot or cold in this video: + +https://www.youtube.com/watch?v=_T4N8O9xsMA + + +## Example: @boardname@ thermometer The following example uses `temperature` and `show number` to show the temperature of the room. @@ -28,31 +33,31 @@ basic.forever(() => { basic.showNumber(temp) }) ``` -### Example: Fahrenheit thermometer +## Example: Fahrenheit thermometer This program measures the temperature using Fahrenheit degrees. Fahrenheit is a way of measuring temperature that is commonly used in the United States. To make a Celsius temperature into a Fahrenheit one, multiply the Celsius temperature by -``18``, divide by ``10`` and add ``32``. +``1.8`` and add ``32``. ```blocks basic.forever(() => { let c = input.temperature() - let f = (c * 18) / 10 + 32 + let f = (1.8 * c) + 32 basic.showNumber(f) }) ``` -### ~hint +## ~hint Try comparing the temperature your @boardname@ shows to a real thermometer in the same place. You might be able to figure out how much to subtract from the number the @boardname@ shows to get the real temperature. Then you can change your program so the @boardname@ is a better thermometer. -### ~ +## ~ -### See also +## See also [compass-heading](/reference/input/compass-heading), [acceleration](/reference/input/acceleration) diff --git a/docs/reference/led.md b/docs/reference/led.md index 117aff0d..105b865b 100644 --- a/docs/reference/led.md +++ b/docs/reference/led.md @@ -8,18 +8,15 @@ led.unplot(0, 0); led.point(0, 0); led.toggle(0, 0); led.brightness(); +led.plotBrightness(0, 0, 255) led.setBrightness(255); led.stopAnimation(); led.plotBarGraph(0, 0); -led.fadeIn(); -led.fadeOut(); -led.plotAll(); -led.screenshot(); -led.toggleAll(); -led.setDisplayMode(DisplayMode.BackAndWhite); +led.setDisplayMode(DisplayMode.BlackAndWhite); led.enable(false) ``` -### See Also +## See Also -[plot](/reference/led/plot), [unplot](/reference/led/unplot), [point](/reference/led/point), [brightness](/reference/led/brightness), [setBrightness](/reference/led/set-brightness), [stopAnimation](/reference/led/stop-animation), [plotBarGraph](/reference/led/plot-bar-graph), [fadeIn](/reference/led/fade-in), [fadeOut](/reference/led/fade-out), [plotAll](/reference/led/plot-all), [screenshot](/reference/led/screenshot), [toggle](/reference/led/toggle), [toggleAll](/reference/led/toggle-all), [setDisplayMode](/reference/led/set-display-mode), [enabled](/reference/led/enable) +[plot](/reference/led/plot), [unplot](/reference/led/unplot), [point](/reference/led/point), [brightness](/reference/led/brightness), [setBrightness](/reference/led/set-brightness), [stopAnimation](/reference/led/stop-animation), [plotBarGraph](/reference/led/plot-bar-graph), [toggle](/reference/led/toggle), [setDisplayMode](/reference/led/set-display-mode), [enabled](/reference/led/enable), +[plotBrightness](/reference/led/plot-brightness), diff --git a/docs/reference/led/brightness.md b/docs/reference/led/brightness.md index 1772fead..40b7ea7c 100644 --- a/docs/reference/led/brightness.md +++ b/docs/reference/led/brightness.md @@ -6,11 +6,11 @@ Find how bright the [LED screen](/device/screen) is _when it is turned on_. led.brightness(); ``` -### Returns +## Returns -* a [number](/reference/types/number) that means how bright the screen is when it is turned on, from `0` (darkest) to `255` (brightest). For example, the number `127` means the screen is halfway bright when it is turned on. +* a [number](/types/number) that means how bright the screen is when it is turned on, from `0` (darkest) to `255` (brightest). For example, the number `127` means the screen is halfway bright when it is turned on. -### Example: highest brightness +## Example: highest brightness This program makes the screen completely bright when it is turned on (if it is not that way already): @@ -21,7 +21,7 @@ if (led.brightness() < 255) { ``` -### Example: change brightness +## Example: change brightness This program makes the screen brightness 100% (255). Then it turns on the center LED (`2, 2`), waits for one second and then sets the screen @@ -34,7 +34,7 @@ basic.pause(1000) led.setBrightness(led.brightness() / 2) ``` -### See also +## See also [set brightness](/reference/led/set-brightness), [fade in](/reference/led/fade-in), [fade out](/reference/led/fade-out) diff --git a/docs/reference/led/enable.md b/docs/reference/led/enable.md index 861be1b3..9123e2fb 100644 --- a/docs/reference/led/enable.md +++ b/docs/reference/led/enable.md @@ -6,21 +6,21 @@ Turns the LED screen on and off led.enable(false); ``` -### Parameters +## Parameters -* ``on`` is a [boolean](/reference/types/boolean) that defines the on/off state of the screen +* ``on`` is a [boolean](/types/boolean) that defines the on/off state of the screen -### Example: Turning off the screen +## Example: Turning off the screen This program turns off the screen when pressing button ``B`` -```typescript +```blocks input.onButtonPressed(Button.B, () => { led.enable(false) }); ``` -### Pins: P3, P4, P6, P7, P9, P10 +## Pins: P3, P4, P6, P7, P9, P10 These pins are coupled to the LED matrix display, and also it’s associated ambient light sensing mode. To disable the display driver feature (which will automatically disable the light sensing feature) call the DAL function ``led.enable(false)``. @@ -28,6 +28,6 @@ To turn the display driver back on again later, call ``led.enable(true)``. More information at http://tech.microbit.org/hardware/edgeconnector_ds/ . -### See also +## See also [unplot](/reference/led/unplot), [point](/reference/led/point), [LED screen](/device/screen) diff --git a/docs/reference/led/fade-in.md b/docs/reference/led/fade-in.md index b39a3f13..7e085d71 100644 --- a/docs/reference/led/fade-in.md +++ b/docs/reference/led/fade-in.md @@ -6,11 +6,11 @@ Gradually increase the [LED screen](/device/screen) brightness until the LED lig led.fadeIn(700); ``` -### Parameters +## Parameters -* ms - [Number](/reference/types/number); the speed by which the screen brightness is increased, expressed in milliseconds (1,000 milliseconds = 1 second). The smaller the number the faster the screen brightness increased. +* ms - [Number](/types/number); the speed by which the screen brightness is increased, expressed in milliseconds (1,000 milliseconds = 1 second). The smaller the number the faster the screen brightness increased. -### Example: fading dot +## Example: fading dot The following code turns on centre LED and then gradually increases and decreases the screen brightness (the centre LED pulses 5 times): @@ -24,7 +24,7 @@ for (let i = 0; i < 5; i++) { } ``` -### See also +## See also [brightness](/reference/led/brightness), [fade out](/reference/led/fade-out), [set brightness](/reference/led/set-brightness) diff --git a/docs/reference/led/fade-out.md b/docs/reference/led/fade-out.md index 43176868..519b327d 100644 --- a/docs/reference/led/fade-out.md +++ b/docs/reference/led/fade-out.md @@ -6,11 +6,11 @@ Gradually decrease the [LED screen](/device/screen) brightness until the LED lig led.fadeOut(700); ``` -### Parameters +## Parameters -* ms - [Number](/reference/types/number); the speed that the screen brightness is decreased, expressed in milliseconds (1,000 milliseconds = 1 second). The smaller the number the faster the screen brightness decreased. +* ms - [Number](/types/number); the speed that the screen brightness is decreased, expressed in milliseconds (1,000 milliseconds = 1 second). The smaller the number the faster the screen brightness decreased. -### Example: fade away letter A +## Example: fade away letter A The following example sets the screen brightness to the maximum brightness, displays the letter A, and then gradually fades the letter away: @@ -20,7 +20,7 @@ basic.showString("A", 1000) led.fadeOut(1000) ``` -### See also +## See also [brightness](/reference/led/brightness), [fade in](/reference/led/fade-in), [set brightness](/reference/led/set-brightness) diff --git a/docs/reference/led/plot-all.md b/docs/reference/led/plot-all.md index e9ea97b3..ef0dafa9 100644 --- a/docs/reference/led/plot-all.md +++ b/docs/reference/led/plot-all.md @@ -6,7 +6,7 @@ Turn on all the 25 LEDs on the [LED screen](/device/screen). led.plotAll() ``` -### See also +## See also [LED screen](/device/screen), [clear screen](/reference/basic/clear-screen) diff --git a/docs/reference/led/plot-bar-graph.md b/docs/reference/led/plot-bar-graph.md index 934394ef..e64fbee5 100644 --- a/docs/reference/led/plot-bar-graph.md +++ b/docs/reference/led/plot-bar-graph.md @@ -1,30 +1,29 @@ -# Plot Bar Graph +# plot Bar Graph -Displays a bar graph of the numbers you say. -A bar graph is a kind of chart that shows numbers as lines with different lengths. +Display a bar graph for a number value. ```sig led.plotBarGraph(2, 20); ``` -### Parameters +A bar graph is a kind of chart that shows numbers as lines with different lengths. -* ``value`` is a [number](/reference/types/number) that means what you +## Parameters + +* **value**: a [number](/types/number) that is the value of what you are measuring or trying to show. For example, if you are measuring the temperature of ice with the @boardname@, ``value`` might be `0` - because the temperature might be 0 degrees centigrade. -* ``high`` is a [number](/reference/types/number) that means the highest - possible number that the ``value`` parameter can be. This number is - also the tallest that the lines in the bar chart can be. + if the temperature is 0 degrees Celsius. +* **high**: a [number](/types/number) that is the highest + possible number (maximum) that the **value** parameter can be. The lines in the bar graph will reach their highest point when **value** reaches this number. If **high** is `0`, then the largest value recently plotted is used as the maximum. -### Example: chart acceleration +## Example: chart acceleration -This program shows a bar graph of the [acceleration](/reference/input/acceleration) +Show a bar graph of the [acceleration](/reference/input/acceleration) in the `x` direction of the @boardname@. The @boardname@'s `x` direction is from left to right (or right to left). -The more you speed up moving the @boardname@ in this direction, -the taller the lines in the bar graph will be, -until they are as tall as the parameter `high` says they can be. +The faster you move the @boardname@ in this direction, +the taller the lines in the bar graph will be. The **high** paramter is `1023` which sets the highest possible value of acceleration to show. ```blocks basic.forever(() => { @@ -33,7 +32,7 @@ basic.forever(() => { }) ``` -### See also +## See also [brightness](/reference/led/brightness), [fade in](/reference/led/fade-in), [fade out](/reference/led/fade-out), [LED screen](/device/screen), [stop animation](/reference/led/stop-animation) diff --git a/docs/reference/led/plot-brightness.md b/docs/reference/led/plot-brightness.md new file mode 100644 index 00000000..3f3e7f38 --- /dev/null +++ b/docs/reference/led/plot-brightness.md @@ -0,0 +1,63 @@ +# Plot Brightness + +Turn on a LED light with a specific brightness on the [LED screen](/device/screen). + +```sig +led.plotBrightness(0,0, 128); +``` + +### Parameters + +* ``x`` is a [number](/types/number) that means the + horizontal spot on the LED screen (from left to right: 0, 1, 2, 3, + or 4) +* ``y`` is a [number](/types/number) that means the vertical + spot on the LED screen (from top to bottom: 0, 1, 2, 3, or 4) +* ``brightness` is a [number](/types/number) that represents the brightness of the LED, from 0 (off) to 255 (full brightness) + +If a parameter is [out of bounds](/reference/out-of-bounds) (a value +other than 0 to 4), then this function will do nothing. + +### ~hint + +The LED screen is a solid square of LEDs with five LEDs on each side. +To learn more about how you number the LEDs with ``x`` and ``y`` +coordinates, see [LED screen](/device/screen). + +### ~ + +### Example: One LED + +This program turns on the bottom right LED at 50% brightness + +```blocks +led.plotBrightness(2, 2, 128) +``` + + +### Example: Square + +This program uses a [for loop](/blocks/loops/for) +and the `plotBrightness` function +to make a square around the edges of the LED screen. + +```blocks +for (let i = 0; i < 5; i++) { + led.plotBrightness(0, i, 64) + led.plotBrightness(4, i, 128) + led.plotBrightness(i, 0, 172) + led.plotBrightness(i, 4, 255) + basic.pause(500) +} +``` + +### ~hint + +Use the [point](/reference/led/point) function to find out if an LED is +on or off. + +### ~ + +### See also + +[plot](/reference/led/plot), [unplot](/reference/led/unplot), [point](/reference/led/point), [LED screen](/device/screen) diff --git a/docs/reference/led/plot.md b/docs/reference/led/plot.md index 0a200889..90d77b1c 100644 --- a/docs/reference/led/plot.md +++ b/docs/reference/led/plot.md @@ -12,26 +12,26 @@ Use [unplot](/reference/led/unplot) to turn **off** an LED. ## ~ -### Parameters +## Parameters -* ``x`` is a [number](/reference/types/number) that means the +* ``x`` is a [number](/types/number) that means the horizontal spot on the LED screen (from left to right: 0, 1, 2, 3, or 4) -* ``y`` is a [number](/reference/types/number) that means the vertical +* ``y`` is a [number](/types/number) that means the vertical spot on the LED screen (from top to bottom: 0, 1, 2, 3, or 4) If a parameter is [out of bounds](/reference/out-of-bounds) (a value other than 0 to 4), then this function will do nothing. -### ~hint +## ~hint The LED screen is a solid square of LEDs with five LEDs on each side. To learn more about how you number the LEDs with ``x`` and ``y`` coordinates, see [LED screen](/device/screen). -### ~ +## ~ -### Example: One LED +## Example: One LED This program turns on the bottom right LED. @@ -40,7 +40,7 @@ led.plot(4, 4) ``` -### Example: Square +## Example: Square This program uses a [for loop](/blocks/loops/for) and the `plot` function @@ -56,13 +56,13 @@ for (let i = 0; i < 5; i++) { } ``` -### ~hint +## ~hint Use the [point](/reference/led/point) function to find out if an LED is on or off. -### ~ +## ~ -### See also +## See also [unplot](/reference/led/unplot), [point](/reference/led/point), [LED screen](/device/screen) diff --git a/docs/reference/led/point.md b/docs/reference/led/point.md index 13f740ae..259d50c4 100644 --- a/docs/reference/led/point.md +++ b/docs/reference/led/point.md @@ -7,30 +7,30 @@ Find whether the LED you say on the led.point(0,0); ``` -### Parameters +## Parameters -* ``x`` is a [number](/reference/types/number) that means the +* ``x`` is a [number](/types/number) that means the horizontal spot on the LED screen (from left to right: 0, 1, 2, 3, or 4) -* ``y`` is a [number](/reference/types/number) that means the vertical +* ``y`` is a [number](/types/number) that means the vertical spot on the LED screen (from top to bottom: 0, 1, 2, 3, or 4) If a parameter is [out of bounds](/reference/out-of-bounds) (a value other than 0 to 4), this function will return `false`. -### Returns +## Returns * a [boolean](/blocks/logic/boolean). If it is `true`, that means the LED is on. If it is `false`, that means the LED is off. -### ~hint +## ~hint The LED screen is a solid square of LEDs with five LEDs on each side. To learn more about how you number the LEDs with ``x`` and ``y`` coordinates, see [LED screen](/device/screen). -### ~ +## ~ -### Example: Toggle off +## Example: Toggle off This program turns the center LED (2, 2) off if it is already on. (If it is already off, this program leaves it off.) @@ -41,7 +41,7 @@ if (led.point(2, 2)) { } ``` -### See also +## See also [unplot](/reference/led/unplot), [plot](/reference/led/plot), [LED screen](/device/screen) diff --git a/docs/reference/led/screenshot.md b/docs/reference/led/screenshot.md index 8d138c93..fc33c1ef 100644 --- a/docs/reference/led/screenshot.md +++ b/docs/reference/led/screenshot.md @@ -6,15 +6,15 @@ Make an [Image](/reference/images/image) out of the current state of the [LED sc led.screenshot(); ``` -### Parameters +## Parameters * none -### Returns +## Returns * an [Image](/reference/images/image) of what is currently visible on the [LED screen](/device/screen) -### See also +## See also [create image](/reference/images/create-image), [LED screen](/device/screen), diff --git a/docs/reference/led/set-brightness.md b/docs/reference/led/set-brightness.md index fd6df280..3be2a3c9 100644 --- a/docs/reference/led/set-brightness.md +++ b/docs/reference/led/set-brightness.md @@ -7,14 +7,20 @@ turned on. led.setBrightness(121) ``` -### Parameters +## Parameters -* ``value`` is a [number](/reference/types/number) that means how +* ``value`` is a [number](/types/number) that means how bright the screen is when it is turned on, from `0` (darkest) to `255` (brightest). For example, the number `127` means the screen is halfway bright when it is turned on. -### Example: change brightness +## ~ hint + +The brightness is not supported in the simulator. You will need to try it on the @boardname@ itself! + +## ~ + +## Example: change brightness This program makes the screen brightness 100% (`255`). Then it turns on the center LED (`2, 2`), waits for one second, and then sets the screen @@ -27,6 +33,6 @@ basic.pause(1000) led.setBrightness(led.brightness() / 2) ``` -### See also +## See also [brightness](/reference/led/brightness), [fade in](/reference/led/fade-in), [fade out](/reference/led/fade-out), [LED screen](/device/screen) diff --git a/docs/reference/led/set-display-mode.md b/docs/reference/led/set-display-mode.md index 36ec168f..06c83b4a 100644 --- a/docs/reference/led/set-display-mode.md +++ b/docs/reference/led/set-display-mode.md @@ -1,8 +1,26 @@ -# Set Display Mode +# set Display Mode -Sets the display mode between black and white and greyscale for rendering [LEDs](/device/screen). +Set the display mode to either black and white or greyscale for rendering [LEDs](/device/screen). ```sig led.setDisplayMode(DisplayMode.Greyscale) ``` +The LED screen can create a sense of color depth with the display mode setting. Color depth is the difference in darkness between the pixels in the display. The `greyscale` mode makes the pixels appear +to have some amount of brightness to represent the grey value of real color. The `black and white` mode just shows an image on the pixels with the LEDs either on or off. + +## Parameters + +* ``mode`` the display mode type. This is either `BlackAndWhite` or `GreyScale`. + +## Example + +Set the display mode to `black and white`. + +```blocks +led.setDisplayMode(DisplayMode.BlackAndWhite) +``` + +## See also + +[set brightness](/reference/led/set-brightness) \ No newline at end of file diff --git a/docs/reference/led/stop-animation.md b/docs/reference/led/stop-animation.md index 238019a0..050d0a2f 100644 --- a/docs/reference/led/stop-animation.md +++ b/docs/reference/led/stop-animation.md @@ -7,7 +7,7 @@ play. led.stopAnimation() ``` -### Example +## Example This program sets up the ``stop animation`` part of the program, and then shows a string that you can stop with button ``B``. @@ -19,14 +19,14 @@ input.onButtonPressed(Button.B, () => { basic.showString("STOP ME! STOP ME! PLEASE, WON'T SOMEBODY STOP ME?"); ``` -### ~hint +## ~hint It's important to set up ``stop animation`` before showing the animation, so the ``stop animation`` part of the program will be ready to go. -### ~ +## ~ -### See Also +## See Also [show animation](/reference/basic/show-animation) diff --git a/docs/reference/led/toggle-all.md b/docs/reference/led/toggle-all.md index 00170e99..c0788157 100644 --- a/docs/reference/led/toggle-all.md +++ b/docs/reference/led/toggle-all.md @@ -6,11 +6,11 @@ Toggle all the 25 LEDs on the [LED screen](/device/screen) - if an LED is on bef led.toggleAll() ``` -### Parameters +## Parameters * none -### Example +## Example The following code will result in every LED being on except for the LED at coordinate (2,2) @@ -26,7 +26,7 @@ led.plot(2, 2) led.toggleAll() ``` -### See also +## See also [toggle](/reference/led/toggle), [LED screen](/device/screen), [clear screen](/reference/basic/clear-screen) diff --git a/docs/reference/led/toggle.md b/docs/reference/led/toggle.md index 5cfa5b28..e7267d94 100644 --- a/docs/reference/led/toggle.md +++ b/docs/reference/led/toggle.md @@ -6,18 +6,18 @@ Toggle a LED light on the [LED screen](/device/screen), meaning to turn it on ( led.toggle(0,0) ``` -### Parameters +## Parameters -* x - [Number](/reference/types/number); the *x coordinate* or horizontal position (0, 1, 2, 3, 4) -* y - [Number](/reference/types/number); the *y coordinate* or vertical position (0, 1, 2, 3, 4) +* x - [Number](/types/number); the *x coordinate* or horizontal position (0, 1, 2, 3, 4) +* y - [Number](/types/number); the *y coordinate* or vertical position (0, 1, 2, 3, 4) If a parameter is [out of bounds](/reference/out-of-bounds) (a value other than 0-4), then this function will do nothing. -### x, y coordinates? +## x, y coordinates? The LED screen is made up of 25 LEDs arranged in a 5x5 grid. To figure out the ``x``, ``y`` coordinates, see [LED screen](/device/screen). -### Example +## Example This code toggles the centre LED: @@ -25,7 +25,7 @@ This code toggles the centre LED: led.toggle(2, 2) ``` -### See also +## See also [toggle all](/reference/led/toggle-all), [plot](/reference/led/plot), [unplot](/reference/led/unplot), [point](/reference/led/point), [LED screen](/device/screen), diff --git a/docs/reference/led/unplot.md b/docs/reference/led/unplot.md index 0cbb9ad1..3db65be6 100644 --- a/docs/reference/led/unplot.md +++ b/docs/reference/led/unplot.md @@ -12,26 +12,26 @@ Use [plot](/reference/led/plot) to turn **on** an LED. ## ~ -### Parameters +## Parameters -* ``x`` is a [number](/reference/types/number) that means the +* ``x`` is a [number](/types/number) that means the horizontal spot on the LED screen (from left to right: 0, 1, 2, 3, or 4) -* ``y`` is a [number](/reference/types/number) that means the vertical +* ``y`` is a [number](/types/number) that means the vertical spot on the LED screen (from top to bottom: 0, 1, 2, 3, or 4) If a parameter is [out of bounds](/reference/out-of-bounds) (a value other than 0 to 4), then this function will do nothing. -### ~hint +## ~hint The LED screen is a solid square of LEDs with five LEDs on each side. To learn more about how you number the LEDs with ``x`` and ``y`` coordinates, see [LED screen](/device/screen). -### ~ +## ~ -### Example: Center off +## Example: Center off This program shows a picture on the LED screen, and then turns off the center LED with `unplot`. @@ -47,14 +47,14 @@ basic.pause(500) led.unplot(2, 2) ``` -### ~hint +## ~hint Use the [point](/reference/led/point) function to find out if an LED is on or off. -### ~ +## ~ -### See also +## See also [plot](/reference/led/plot), [point](/reference/led/point), [LED screen](/device/screen) diff --git a/docs/reference/music.md b/docs/reference/music.md index c75c0320..92d0c5e9 100644 --- a/docs/reference/music.md +++ b/docs/reference/music.md @@ -6,12 +6,19 @@ Generation of music tones through pin ``P0``. music.playTone(0, 0); music.ringTone(0); music.rest(0); +music.beginMelody(music.builtInMelody(Melodies.Entertainer), MelodyOptions.Once); +music.stopMelody(MelodyStopOptions.All); +music.onEvent(MusicEvent.MelodyNotePlayed, () => {}); music.beat(BeatFraction.Whole); music.tempo(); music.changeTempoBy(20); music.setTempo(120); ``` -### See Also +## See Also -[playTone](/reference/music/play-tone), [ringTone](/reference/music/ring-tone), [rest](/reference/music/rest), [beat](/reference/music/beat), [tempo](/reference/music/tempo), [changeTempoBy](/reference/music/change-tempo-by), [setTempo](/reference/music/set-tempo) +[playTone](/reference/music/play-tone), [ringTone](/reference/music/ring-tone), [rest](/reference/music/rest), +[beginMelody](/reference/music/begin-melody), +[stopMelody](/reference/music/stop-melody), +[onEvent](/reference/music/on-event), +[beat](/reference/music/beat), [tempo](/reference/music/tempo), [changeTempoBy](/reference/music/change-tempo-by), [setTempo](/reference/music/set-tempo), diff --git a/docs/reference/music/beat.md b/docs/reference/music/beat.md index 5c62f689..dc33bbef 100644 --- a/docs/reference/music/beat.md +++ b/docs/reference/music/beat.md @@ -2,21 +2,23 @@ Returns the duration of a beat in milli-seconds -## Simulator - -This function only works on the @boardname@ and in some browsers. - ```sig music.beat(BeatFraction.Whole) ``` -### Parameters +## ~ hint + +**Simulator**: This function only works on the @boardname@ and in some browsers. + +## ~ + +## Parameters * ``BeatFraction`` means fraction of a beat (BeatFraction.Whole, BeatFraction.Sixteenth etc) -### Returns +## Returns -* a [number](/reference/types/number) that means the amount of milli-seconds a beat fraction represents. +* a [number](/types/number) that means the amount of milli-seconds a beat fraction represents. ## Example @@ -25,6 +27,6 @@ music.beat(BeatFraction.Whole) music.playTone(Note.C, music.beat(BeatFraction.Quarter)) ``` -### See also +## See also [play tone](/reference/music/play-tone), [ring tone](/reference/music/ring-tone), [rest](/reference/music/rest), [set tempo](/reference/music/set-tempo), [change tempo by](/reference/music/change-tempo-by) \ No newline at end of file diff --git a/docs/reference/music/begin-melody.md b/docs/reference/music/begin-melody.md new file mode 100644 index 00000000..6a9af12d --- /dev/null +++ b/docs/reference/music/begin-melody.md @@ -0,0 +1,64 @@ +# begin Melody + +Begin playing a musical melody through pin ``P0`` of the @boardname@. + +```sig +music.beginMelody(music.builtInMelody(Melodies.Entertainer), MelodyOptions.Once) +``` + +## ~ hint + +**Simulator**: This function only works on the @boardname@ and in some browsers. + +## ~ + +There are built-in melodies that you can choose from the ``||start melody||`` block. These are already composed for you and are easy to use by just selecting the one you want. If you want to play your own melody, you can [compose](/reference/music/making-melodies) one and use it instead of one of the built-in ones. + +Melodies are a sequence of notes, each played for some small amount time, one after the other. The notes in a melody are held in an [array](/types/array) of [strings](/types/string). Each string in the array is a note of the melody. You make a melody by assembling the notes along with the _duration_ that the note plays for. The melody is [formed](/reference/music/making-melodies) like this: + +``NOTE[octave][:duration] eg: ['g5:1']`` + +```block +music.beginMelody(['g4:1', 'c5', 'e', 'g:2', 'e:1', 'g:3'], MelodyOptions.Once) +``` + +Melodies are played either in the _foreground_ or _background_. This allows more than one melody to be active at once. If a melody is set to play in the background, it can be interrupeted, or paused, temporarily while a melody set for the foreground is played. If the foreground melody is not set to play ``forever``, then the background melody resumes when the foreground melody is finished. + +You can set options for how you want the melody to play. You can ask that the melody plays just one time, ``once``, or have it keep repeating, ``forever``. With these options the melody will play in the foreground either once or continue to repeat. Of course, if you set ``forever``, any melody that was started in background will never play unless you [stop](/reference/music/stop-melody) the foreground melody. To make a background melody, set the option to ``once in background`` or ``forever in background``. + +## Parameters + +* **melody**: A built-in melody or an [array](/types/array) representation of a [melody](reference/music/making-melodies) you wish to play. +* **options**: the play option for the melody: +>* ``once``: play the melody in the foreground one time +>* ``forever``: play the melody in the foreground and keep repeating it +>* ``once in background``: play the melody in the background one time +>* ``forever in background``: play the melody in the background and keep repeating it + +## Examples + +### Play the "Entertainer" + +This example plays the ``Entertainer`` built-in melody. + +```blocks +music.beginMelody(music.builtInMelody(Melodies.Entertainer), MelodyOptions.Once) +``` + +### Play a composed melody forever + +Play a made-up melody in the background forever. + +```blocks +music.beginMelody(['g4:1', 'c5', 'e', 'g:2', 'e:1', 'g:3'], MelodyOptions.ForeverInBackground) +``` + +## See also + +[stop melody](/reference/music/stop-melody), [play tone](/reference/music/play-tone), +[rest](/reference/music/rest), [ring tone](/reference/music/ring-tone), +[tempo](/reference/music/tempo), [set tempo](/reference/music/set-tempo), +[change tempo by](/reference/music/change-tempo-by) + +[Making Melodies](/reference/music/making-melodies) + diff --git a/docs/reference/music/change-tempo-by.md b/docs/reference/music/change-tempo-by.md index 8f66b4c7..1e646a26 100644 --- a/docs/reference/music/change-tempo-by.md +++ b/docs/reference/music/change-tempo-by.md @@ -3,21 +3,23 @@ Makes the [tempo](/reference/music/tempo) (speed of a piece of music) faster or slower by the amount you say. -## Simulator - -This function only works on the @boardname@ and in some browsers. - ```sig music.changeTempoBy(20) ``` -### Parameters +## ~ hint -* ``bpm`` is a [number](/reference/types/number) that says how much to +**Simulator**: This function only works on the @boardname@ and in some browsers. + +## ~ + +## Parameters + +* ``bpm`` is a [number](/types/number) that says how much to change the bpm (beats per minute, or number of beats in a minute of the music that the @boardname@ is playing). -### Examples +## Examples This program makes the music faster by 12 bpm. @@ -31,7 +33,7 @@ This program makes the music _slower_ by 12 bpm. music.changeTempoBy(-12) ``` -### See also +## See also [play tone](/reference/music/play-tone), [ring tone](/reference/music/ring-tone) diff --git a/docs/reference/music/making-melodies.md b/docs/reference/music/making-melodies.md new file mode 100644 index 00000000..85f35670 --- /dev/null +++ b/docs/reference/music/making-melodies.md @@ -0,0 +1,74 @@ +# Making melodies + +Composing some sound, or maybe some music, is done by putting tones to together, one after another. A _melody_ is a sequence of these tones each played, for some short amount of time, one after the other until all notes have played. + +## Musical notes + +A _note_ is a tone that is recognized as part of music. A note has a name like '**C**'. A note is played for an amount of time called its _duration_. + +On your @boardname@, a note is played on the speaker by sending a signal to a it with a certain _frequency_ called [Hertz](http://wikipedia.org/Hertz). Frequency is how fast something vibrates during one second. If you ring a bell that was made to play an '**A**' note, the bell will vibrate at 440 Hertz (440 times per second). So, notes are just certain frequencies that have special names. + +## ~ hint + +Watch this video to see how speakers and headphones make sound when connected to your @boardname@. + +https://www.youtube.com/watch?v=cxfPNc4Wefo + +### ~ + +In history, music came from tones that seemed nice to hear. The tones were played on wood, strings, metal, and skins. These tones were given names and they became what we know today as musical notes. Notes were named so we could write them down and remember how to play them again later. + +## How are notes named? + +Basic notes have names that use one of the first nine letters of the alphabet. They are: + +``|A|``, ``|B|``, ``|C|``, ``|D|``, ``|E|``, ``|F|``, ``|G|`` + +Ther are other notes named like the basic notes but have extra parts to the name called _sharp_ and _flat_. These other notes are just a bit different from the basic notes and have frequencies a little higher or lower than the basic note. This makes music a little more complicated but much more interesting! + +Some of these other notes look like: + +``|C#|``, ``|Eb|`` + +When a small amount music or even a song is written down it is called [sheet music](https://wikipedia.org/wiki/Sheet_music). + +## Sounds and music in code + +Of course, we can't use written music in our code. We can make music another way. The way to do it is to put names of notes in [strings](/types/string). We make our notes using letters, symbols, and numbers. The notes of a melody are put together in an array like: + +```block +let melody = ['E3:3', 'R:1', 'D#:3', 'R:1', 'D:4', 'R:1', 'C#:8'] +``` + +In JavaScript code, it looks like this: + +```typescript +let melody = ['E3:3', 'R:1', 'D#:3', 'R:1', 'D:4', 'R:1', 'C#:8'] +``` + +What you see here is not some alien language but a bunch of notes with their duration. The form of a single note is **note : duration** or ``'C:2'``. This means play the '**C**' note for **2** beats of time. The notes are placed one after the other, in an array, with a comma between them, like ``'B:2', 'C#:6'``. If you want a note to play for **4** beats, you don't need to use any duration number (a note with 4 beats is called a _whole_ note). Just say something like ``'E'`` with no colon (leave out the ``':'``) and no duration number. + +You might notice that the sound string has an ``'R:1'`` in it. The '**R**` means _rest_ and to rest for one beat. A rest is a pause, or a time of silence, in the sound. + + +#### ~ hint + +**Duration** + +The amount of time a note is played (duration) is measured as _beats_. The standard number _beats per minute_ (bpm) in music is 120 bpm which is one-half of a second of time. A _whole_ note lasts for 4 beats and a _quarter_ note takes just one beat. + +#### ~ + +## Example + +Compose the first few notes of Beethoven's 5th symphony. + +```blocks +let beet5 = ['G:1', 'G:1', 'G:1', 'Eb', 'F:1', 'F:1', 'F:1', 'D'] +``` + +## See also + +[begin melody](/reference/music/begin-melody) + +[Tempo](https://wikipedia.org/wiki/Tempo) diff --git a/docs/reference/music/on-event.md b/docs/reference/music/on-event.md new file mode 100644 index 00000000..4c019542 --- /dev/null +++ b/docs/reference/music/on-event.md @@ -0,0 +1,65 @@ +# On Event + +Raises events for melodies or music events. + +```sig +music.onEvent(MusicEvent.MelodyNotePlayed, () => {}) +``` + +## Parameters + +* ``value`` the kind of event +* ``handler`` the code to run when the event is raised. + +## Example + +This example prints all the events to the serial output. + +```blocks +music.onEvent(MusicEvent.MelodyRepeated, () => { + serial.writeLine("melody repeated") +}) +music.onEvent(MusicEvent.MelodyEnded, () => { + serial.writeLine("melody ended") +}) +music.onEvent(MusicEvent.MelodyStarted, () => { + serial.writeLine("melody started") +}) +music.onEvent(MusicEvent.MelodyRepeated, () => { + serial.writeLine("background melody repeated") +}) +music.onEvent(MusicEvent.BackgroundMelodyStarted, () => { + serial.writeLine("background started") +}) +music.onEvent(MusicEvent.BackgroundMelodyEnded, () => { + serial.writeLine("background ended") +}) +music.onEvent(MusicEvent.BackgroundMelodyPaused, () => { + serial.writeLine("background paused") +}) +music.onEvent(MusicEvent.BackgroundMelodyResumed, () => { + serial.writeLine("background resumed") +}) +music.onEvent(MusicEvent.BackgroundMelodyRepeated, () => { + serial.writeLine("background repeated") +}) +input.onButtonPressed(Button.A, () => { + music.beginMelody(music.builtInMelody(Melodies.BaDing), MelodyOptions.Once) +}) +music.setTempo(100) +music.beginMelody(music.builtInMelody(Melodies.Ringtone), MelodyOptions.ForeverInBackground) +``` + +## Background melody + +The events related to background melody get triggered by a melody that is played inside a run in background block. + +``` +control.inBackground(function () { + basic.pause(Math.randomRange(0, 5000)) + music.beginMelody(music.builtInMelody(Melodies.Entertainer), MelodyOptions.Once) +}) +music.onEvent(MusicEvent.BackgroundMelodyStarted, function () { + basic.showIcon(IconNames.EigthNote) +}) +``` diff --git a/docs/reference/music/play-tone.md b/docs/reference/music/play-tone.md index 39276e0b..b9cd9224 100644 --- a/docs/reference/music/play-tone.md +++ b/docs/reference/music/play-tone.md @@ -2,18 +2,20 @@ Play a musical tone through pin ``P0`` of the @boardname@ for as long as you say. -## Simulator +## ~ hint This function only works on the @boardname@ and in some browsers. +## ~ + ```sig music.playTone(440, 120) ``` -### Parameters +## Parameters -* ``frequency`` is the [number](/reference/types/number) of Hertz (how high or low the tone is). -* ``ms`` is the [number](/reference/types/number) of milliseconds that the tone lasts +* ``frequency`` is the [number](/types/number) of Hertz (how high or low the tone is). +* ``ms`` is the [number](/types/number) of milliseconds that the tone lasts ## Example @@ -25,7 +27,16 @@ let freq = music.noteFrequency(Note.C) music.playTone(freq, 1000) ``` -### See also + +## Using other pins + +Use [analogSetPitchPin](/reference/pins/analog-set-pitch-pin) to change that pin used to generate music. + +```blocks +pins.analogSetPitchPin(AnalogPin.P1); +``` + +## See also [rest](/reference/music/rest), [ring tone](/reference/music/ring-tone) , [tempo](/reference/music/tempo), [set tempo](/reference/music/set-tempo), [change tempo by](/reference/music/change-tempo-by) diff --git a/docs/reference/music/rest.md b/docs/reference/music/rest.md index 10909ad4..019e5ccc 100644 --- a/docs/reference/music/rest.md +++ b/docs/reference/music/rest.md @@ -2,17 +2,19 @@ Rest (play no sound) through pin `PO` for the amount of time you say. -## Simulator - -This function only works on the @boardname@ and in some browsers. - ```sig music.rest(400) ``` -### Parameters +### ~ hint -* ``ms`` is a [number](/reference/types/number) saying how many +**Simulator**: This function only works on the @boardname@ and in some browsers. + +## ~ + +## Parameters + +* ``ms`` is a [number](/types/number) saying how many milliseconds the @boardname@ should rest. One second is 1000 milliseconds. @@ -24,7 +26,7 @@ music.playTone(frequency, 1000) music.rest(1000) ``` -### See also +## See also [play tone](/reference/music/play-tone), [ring tone](/reference/music/ring-tone) , [tempo](/reference/music/tempo), [set tempo](/reference/music/set-tempo), [change tempo by](/reference/music/change-tempo-by) diff --git a/docs/reference/music/ring-tone.md b/docs/reference/music/ring-tone.md index 2da40aeb..fd5d06d4 100644 --- a/docs/reference/music/ring-tone.md +++ b/docs/reference/music/ring-tone.md @@ -3,22 +3,24 @@ Play a musical tone through pin `P0` with the pitch as high or low as you say. The tone will keep playing until you tell it not to. -## Simulator - -This function only works on the @boardname@ and in some browsers. - ```sig music.ringTone(440) ``` -### Parameters +## ~ hint -* ``frequency`` is a [number](/reference/types/number) that says +**Simulator**: This function only works on the @boardname@ and in some browsers. + +## ~ + +## Parameters + +* ``frequency`` is a [number](/types/number) that says how high-pitched or low-pitched the tone is. This number is in **Hz** (**Hertz**), which is a measurement of frequency or pitch. -### Example +## Example This program checks the **accelerometer** for the @boardname@'s **acceleration** (how much the @boardname@ is speeding up or slowing @@ -32,7 +34,15 @@ basic.forever(() => { }) ``` -### See also +## Using other pins + +Use [analogSetPitchPin](/reference/pins/analog-set-pitch-pin) to change that pin used to generate music. + +```blocks +pins.analogSetPitchPin(AnalogPin.P1); +``` + +## See also [rest](/reference/music/rest), [play tone](/reference/music/play-tone), [tempo](/reference/music/tempo), [set tempo](/reference/music/set-tempo), diff --git a/docs/reference/music/set-play-tone.md b/docs/reference/music/set-play-tone.md new file mode 100644 index 00000000..81c168cd --- /dev/null +++ b/docs/reference/music/set-play-tone.md @@ -0,0 +1,38 @@ +# Set Play Tone + +Replaces the implementation of the [music play tone](/reference/music/play-tone). + + +```sig +music.setPlayTone((frequency: number, duration: number) => {}) +``` + +## Parameters + +* ``f`` the replacement function + +## Example + +This example send the frequency and duration over radio +and plays it on the remote @boardname@. + +```typescript +input.onButtonPressed(Button.A, () => { + music.playTone(440, 120) + led.toggle(0, 0) +}) +radio.onReceivedNumber(function (receivedNumber) { + const freq = receivedNumber >> 16; + const duration = receivedNumber & 0xffff; + music.playTone(freq, duration); +}) +input.onButtonPressed(Button.B, () => { + music.setPlayTone((frequency: number, duration: number) => { + radio.sendNumber((frequency << 16) | (duration & 0xffff)); + }) +}) +``` +## See also + +[rest](/reference/music/rest), [ring tone](/reference/music/ring-tone) , [tempo](/reference/music/tempo), [set tempo](/reference/music/set-tempo), +[change tempo by](/reference/music/change-tempo-by) diff --git a/docs/reference/music/set-tempo.md b/docs/reference/music/set-tempo.md index 83f5c477..a2b31f1a 100644 --- a/docs/reference/music/set-tempo.md +++ b/docs/reference/music/set-tempo.md @@ -5,15 +5,17 @@ Makes the tempo (speed of a piece of music) as fast or slow as you say. ```sig music.setTempo(60) ``` -## Simulator +## ~ hint -This function only works on the @boardname@ and in some browsers. +**Simulator**: This function only works on the @boardname@ and in some browsers. -### Parameters +## ~ -* ``bpm`` is a [number](/reference/types/number) that means the beats per minute you want (the number of beats in a minute of the music that the @boardname@ is playing). +## Parameters -### See also +* ``bpm`` is a [number](/types/number) that means the beats per minute you want (the number of beats in a minute of the music that the @boardname@ is playing). + +## See also [play tone](/reference/music/play-tone), [ring tone](/reference/music/ring-tone) , [rest](/reference/music/rest), [tempo](/reference/music/tempo), [change tempo by](/reference/music/change-tempo-by) diff --git a/docs/reference/music/stop-melody.md b/docs/reference/music/stop-melody.md new file mode 100644 index 00000000..eef9d5a0 --- /dev/null +++ b/docs/reference/music/stop-melody.md @@ -0,0 +1,40 @@ +# stop Melody + +Stop playing a musical melody. + +```sig +music.stopMelody(MelodyStopOptions.All) +``` + +Melodies are played either in the _foreground_ or _background_. This allows more than one melody to be active at once. If a melody is set to play in the background, it can be interrupeted, or paused, temporarily while a melody set for the foreground is played. If the foreground melody is not set to play ``forever``, then the background melody resumes when the foreground melody is finished. + +When a melody begins, it has an option set for how the melody is to play. The melody plays just one time, ``once``, or it will keep repeating, ``forever``. With these options the melody will play in the foreground either once or continue to repeat. Of course, if you set ``forever``, any melody that was started in background will never play unless you stop the foreground melody. + +You can stop either a ``foreground`` melody, a ``background`` melody, or ``all`` melodies. + +## ~ hint + +**Simulator**: This function only works on the @boardname@ and in some browsers. + +## ~ + +## Parameters + +* **options**: specify which melodies (foreground, background or both) to stop: +>* ``all``: stop all melodies +>* ``foreground``: stop the foreground melody +>* ``background``: stop the background melody + +## Example + +Play the ``Entertainer`` built-in melody and then stop it after 5 seconds. + +```blocks +music.beginMelody(music.builtInMelody(Melodies.Entertainer), MelodyOptions.Forever) +basic.pause(5000) +music.stopMelody(MelodyStopOptions.All) +``` + +## See also + +[start melody](/reference/music/begin-melody) diff --git a/docs/reference/music/tempo.md b/docs/reference/music/tempo.md index 9fe81623..827cc8fa 100644 --- a/docs/reference/music/tempo.md +++ b/docs/reference/music/tempo.md @@ -6,12 +6,12 @@ Finds the tempo (speed of a piece of music). music.tempo() ``` -### Returns +## Returns -* a [number](/reference/types/number) that means the beats per minute (number of +* a [number](/types/number) that means the beats per minute (number of beats in a minute of the music that the @boardname@ is playing). -### See also +## See also [play tone](/reference/music/play-tone), [ring tone](/reference/music/ring-tone), [rest](/reference/music/rest), [set tempo](/reference/music/set-tempo), [change tempo by](/reference/music/change-tempo-by) diff --git a/docs/reference/out-of-bounds.md b/docs/reference/out-of-bounds.md index 7bbc627d..ab408f8a 100644 --- a/docs/reference/out-of-bounds.md +++ b/docs/reference/out-of-bounds.md @@ -6,18 +6,18 @@ Many of the @boardname@ functions have parameters. If a parameter is an unexpect For example, the [plot](/reference/led/plot) function has two parameters: -### syntax +## syntax ```sig led.plot(0,0) ``` -### parameters +## parameters * x - the *x coordinate* or horizontal position (0, 1, 2, 3, 4) * y - the *y coordinate* or vertical position (0, 1, 2, 3, 4) -### out of bounds +## out of bounds here's an example of code with an out of bounds parameter (the *x* and *y* parameters are outside the expected range of 0-4): @@ -25,11 +25,11 @@ here's an example of code with an out of bounds parameter (the *x* and *y* param led.plot(9, -21) ``` -### what happens? +## what happens? Typically, when a parameter supplied to a function is out of bounds that function does nothing (as if the function never executed). So, in the above case, the LED screen will not change. -### return value +## return value If you call the `point` function with an out of bounds parameter, the function returns `false`: diff --git a/docs/reference/pins.md b/docs/reference/pins.md index 1887499e..ae0305d5 100644 --- a/docs/reference/pins.md +++ b/docs/reference/pins.md @@ -5,25 +5,44 @@ Control currents in Pins for analog/digital signals, servos, i2c, ... ```cards pins.digitalReadPin(DigitalPin.P0); pins.digitalWritePin(DigitalPin.P0, 0); -pins.analogReadPin(AnalogPin.P1); -pins.analogWritePin(AnalogPin.P1, 1023); -pins.analogSetPeriod(AnalogPin.P1, 20000); +pins.analogReadPin(AnalogPin.P0); +pins.analogWritePin(AnalogPin.P0, 1023); +pins.analogSetPeriod(AnalogPin.P0, 20000); pins.map(0, 0, 1023, 0, 4); pins.onPulsed(DigitalPin.P0, PulseValue.High, () => { }); pins.pulseDuration(); pins.pulseIn(DigitalPin.P0, PulseValue.High); -pins.servoWritePin(AnalogPin.P1, 180); -pins.servoSetPulse(AnalogPin.P1, 1500); -pins.i2cReadNumber(0, NumberFormat.Int8LE); -pins.i2cWriteNumber(0, 0, NumberFormat.Int8LE); -pins.spiWrite(0); pins.setPull(DigitalPin.P0, PinPullMode.PullDown); pins.analogPitch(0, 0); -pins.analogSetPitchPin(AnalogPin.P1); +pins.analogSetPitchPin(AnalogPin.P0); ``` -### See Also +## Servos -[digitalReadPin](/reference/pins/digital-read-pin), [digitalWritePin](/reference/pins/digital-write-pin), [analogReadPin](/reference/pins/analog-read-pin), [analogWritePin](/reference/pins/analog-write-pin), [analogSetPeriod](/reference/pins/analog-set-period), [map](/reference/pins/map), [onPulsed](/reference/pins/on-pulsed), [pulseDuration](/reference/pins/pulse-duration), [pulseIn](/reference/pins/pulse-in), [servoWritePin](/reference/pins/servo-write-pin), [servoSetPulse](/reference/pins/servo-set-pulse), [i2cReadNumber](/reference/pins/i2c-read-number), [i2cWriteNumber](/reference/pins/i2c-write-number), [setPull](/reference/pins/set-pull), [analogPitch](/reference/pins/analog-pitch), [analogSetPitchPin](/reference/pins/analog-set-pitch-pin), [spiWrite](/reference/pins/spi-write) +```cards +pins.servoWritePin(AnalogPin.P0, 180); +pins.servoSetPulse(AnalogPin.P0, 1500); +``` + +## I2C + +```cards +pins.i2cReadNumber(0, NumberFormat.Int8LE); +pins.i2cWriteNumber(0, 0, NumberFormat.Int8LE); +``` + +## SPI + +```cards +pins.spiWrite(0); +pins.spiFrequency(1000000); +pins.spiFormat(8,3); +pins.spiPins(DigitalPin.P0, DigitalPin.P1, DigitalPin.P2); +``` + +## See Also + +[digitalReadPin](/reference/pins/digital-read-pin), [digitalWritePin](/reference/pins/digital-write-pin), [analogReadPin](/reference/pins/analog-read-pin), [analogWritePin](/reference/pins/analog-write-pin), [analogSetPeriod](/reference/pins/analog-set-period), [map](/reference/pins/map), [onPulsed](/reference/pins/on-pulsed), [pulseDuration](/reference/pins/pulse-duration), [pulseIn](/reference/pins/pulse-in), [servoWritePin](/reference/pins/servo-write-pin), [servoSetPulse](/reference/pins/servo-set-pulse), [i2cReadNumber](/reference/pins/i2c-read-number), [i2cWriteNumber](/reference/pins/i2c-write-number), [setPull](/reference/pins/set-pull), [analogPitch](/reference/pins/analog-pitch), [analogSetPitchPin](/reference/pins/analog-set-pitch-pin), [spiWrite](/reference/pins/spi-write), +[spiPins](/reference/pins/spi-pins),[spiFormat](/reference/pins/spi-format),[spiFrequency](/reference/pins/spi-frequency) diff --git a/docs/reference/pins/analog-pitch.md b/docs/reference/pins/analog-pitch.md index 603d5c29..7c201714 100644 --- a/docs/reference/pins/analog-pitch.md +++ b/docs/reference/pins/analog-pitch.md @@ -1,31 +1,33 @@ # Analog Pitch -Emits a Pulse With Modulation (PWM) signal to the current pitch [pin](/device/pins). Use [analog set pitch pin](/reference/pins/analog-set-pitch-pin) to set the current pitch pin. +Emits a Pulse With Modulation (PWM) signal to the pin ``P0``. +Use [analog set pitch pin](/reference/pins/analog-set-pitch-pin) to set the current pitch pin. ```sig pins.analogPitch(440, 300) ``` -### Parameters +## Parameters -* `frequency` : [Number](/reference/types/number) -* `ms`: [Number](/reference/types/number) +* `frequency` : [Number](/types/number) +* `ms`: [Number](/types/number) -### Example +## Example ```blocks -pins.analogSetPitchPin("P0") +pins.analogSetPitchPin(AnalogPin.P0); let frequency1 = 440 let duration = 1000 +pins.analogSetPitchPin(AnalogPin.P1); pins.analogPitch(frequency1, duration) ``` -### Some common notes +## Some common notes * 440 = A4 on piano * see [piano key frequencies ](https://en.wikipedia.org/wiki/Piano_key_frequencies) for more information -### See also +## See also [@boardname@ pins](/device/pins), [analog set period](/reference/pins/analog-set-period), [analog set pitch pin](/reference/pins/analog-set-pitch-pin) diff --git a/docs/reference/pins/analog-read-pin.md b/docs/reference/pins/analog-read-pin.md index cce390d6..21278fee 100644 --- a/docs/reference/pins/analog-read-pin.md +++ b/docs/reference/pins/analog-read-pin.md @@ -4,17 +4,17 @@ Read an **analog** signal (`0` through `1023`) from the [pin](/device/pins) you say. ```sig -pins.analogReadPin(AnalogPin.P1) +pins.analogReadPin(AnalogPin.P0) ``` -### Parameters +## Parameters -* ``name`` is a [string](/reference/types/string) with the name of the pin +* ``name`` is a [string](/types/string) with the name of the pin you say (`P0` through `P4`, or `P10`) -### Returns +## Returns -* a [number](/reference/types/number) from `0` through `1023` +* a [number](/types/number) from `0` through `1023` This program reads pin `P1` and shows the number on the LED screen. @@ -26,13 +26,13 @@ basic.forever(() => { }); ``` -#### ~hint +### ~hint If you are using **analog read pin** with another @boardname@ running **analog write pin**, then things can get tricky. Remember that the @boardname@ that runs **analog set pin** writes 0's and 1's at a very high frequency to achieve an average of the desired value. Sadly, if you try to read that average from another @boardname@, then the @boardname@ will either read 0 or 1023. You could try to read a higher number of values (e.g. a million) in a loop, then computer then average. Alternatively, you can plug in a capacitor in-between the two @boardname@s. -#### ~ +### ~ -### See also +## See also [@boardname@ pins](/device/pins), [on pin pressed](/reference/input/on-pin-pressed), diff --git a/docs/reference/pins/analog-set-period.md b/docs/reference/pins/analog-set-period.md index ac38e6fb..e7bb4e84 100644 --- a/docs/reference/pins/analog-set-period.md +++ b/docs/reference/pins/analog-set-period.md @@ -5,23 +5,23 @@ analog [pin](/device/pins). Before you call this function, you should set the specified pin as analog. ```sig -pins.analogSetPeriod(AnalogPin.P1, 20000) +pins.analogSetPeriod(AnalogPin.P0, 20000) ``` -### Parameters +## Parameters -* ``name``: a [string](/reference/types/string) that specifies the pin to configure (`P0` through `P4`, or `P10`) -* ``micros``: a [number](/reference/types/number) that specifies the analog period in microseconds. +* ``name``: a [string](/types/string) that specifies the pin to configure (`P0` through `P4`, or `P10`) +* ``micros``: a [number](/types/number) that specifies the analog period in microseconds. The following code first sets `P0` to analog with **analog write pin**, and then sets the PWM period of `P0` to 20,000 microseconds. ```blocks -pins.analogWritePin(AnalogPin.P1, 512) -pins.analogSetPeriod(AnalogPin.P1, 20000) +pins.analogWritePin(AnalogPin.P0, 512) +pins.analogSetPeriod(AnalogPin.P0, 20000) ``` -### See also +## See also [@boardname@ pins](/device/pins), [on pin pressed](/reference/input/on-pin-pressed), diff --git a/docs/reference/pins/analog-set-pitch-pin.md b/docs/reference/pins/analog-set-pitch-pin.md index ca861947..8bc6cd4f 100644 --- a/docs/reference/pins/analog-set-pitch-pin.md +++ b/docs/reference/pins/analog-set-pitch-pin.md @@ -3,28 +3,28 @@ Specify which [pin](/device/pins) (P0, P1, P2) is used to generate tones. ```sig -pins.analogSetPitchPin(AnalogPin.P1) +pins.analogSetPitchPin(AnalogPin.P0) ``` -### Parameters +## Parameters -* `name` - [String](/reference/types/string); the pin name ("P0", "P1", or "P2") +* `name` - [String](/types/string); the pin name ("P0", "P1", or "P2") -### Example +## Example ```blocks -pins.analogSetPitchPin(AnalogPin.P1) +pins.analogSetPitchPin(AnalogPin.P0) let frequency = 440 let duration = 1000 pins.analogPitch(frequency, duration) ``` -### Some common notes +## Some common notes * 440 = A4 on piano * see [piano key frequencies ](https://en.wikipedia.org/wiki/Piano_key_frequencies) for more information -### See also +## See also [@boardname@ pins](/device/pins), [analog set period](/reference/pins/analog-set-period), [analog pitch](/reference/pins/analog-pitch) diff --git a/docs/reference/pins/analog-write-pin.md b/docs/reference/pins/analog-write-pin.md index 483c3dc1..4c87ab97 100644 --- a/docs/reference/pins/analog-write-pin.md +++ b/docs/reference/pins/analog-write-pin.md @@ -4,31 +4,31 @@ Write an **analog** signal (`0` through `1023`) to the [pin](/device/pins) you say. ```sig -pins.analogWritePin(AnalogPin.P1, 400) +pins.analogWritePin(AnalogPin.P0, 400) ``` -### Parameters +## Parameters -* ``name`` is a [string](/reference/types/string) that is the pin name you say (`P0` through `P4`, or `P10`) -* ``value`` is a [number](/reference/types/number) from `0` through `1023` +* ``name`` is a [string](/types/string) that is the pin name you say (`P0` through `P4`, or `P10`) +* ``value`` is a [number](/types/number) from `0` through `1023` -### Example +## Example This program writes `1023` to pin `P0`. ```blocks -pins.analogWritePin(AnalogPin.P1, 1023) +pins.analogWritePin(AnalogPin.P0, 1023) ``` -#### ~hint +### ~hint When you tell it to write `256` (for example), this function does not _really_ write `256`. Instead, it writes a lot of different numbers, and their average is `256`. -#### ~ +### ~ -### See also +## See also [@boardname@ pins](/device/pins), [on pin pressed](/reference/input/on-pin-pressed), [analog read pin](/reference/pins/analog-read-pin), [digital read pin](/reference/pins/digital-read-pin), [digital write pin](/reference/pins/digital-write-pin) diff --git a/docs/reference/pins/digital-read-pin.md b/docs/reference/pins/digital-read-pin.md index 78acaad3..f3338b87 100644 --- a/docs/reference/pins/digital-read-pin.md +++ b/docs/reference/pins/digital-read-pin.md @@ -7,22 +7,22 @@ the @boardname@ board. pins.digitalReadPin(DigitalPin.P3) ``` -### ~avatar +## ~avatar Some pins are also used by the [LED screen](/device/screen). Please read the [page about pins](/device/pins) carefully. -### ~ +## ~ -### Parameters +## Parameters -* ``name`` is a [string](/reference/types/string) that stores the name of the pin (``P0``, ``P1``, or ``P2``, up through ``P20``) +* ``name`` is a [string](/types/string) that stores the name of the pin (``P0``, ``P1``, or ``P2``, up through ``P20``) -### Returns +## Returns -* a [number](/reference/types/number) that can be `0` or `1` +* a [number](/types/number) that can be `0` or `1` -### Example: football score keeper +## Example: football score keeper This program reads pin `P0` to find when a goal is scored. When `P0` is `1`, the program makes the score bigger and plays a buzzer sound @@ -54,13 +54,13 @@ input.onButtonPressed(Button.B, () => { pins.digitalWritePin(DigitalPin.P1, 0); }); ``` -#### ~hint +### ~hint Remember to connect `GND` on both @boardname@s together! -#### ~ +### ~ -### See also +## See also [@boardname@ pins](/device/pins), [digital write pin](/reference/pins/digital-write-pin), diff --git a/docs/reference/pins/digital-write-pin.md b/docs/reference/pins/digital-write-pin.md index 5abe4a0b..9b03fec0 100644 --- a/docs/reference/pins/digital-write-pin.md +++ b/docs/reference/pins/digital-write-pin.md @@ -7,19 +7,19 @@ the @boardname@ board. pins.digitalWritePin(DigitalPin.P1, 1) ``` -### ~avatar +## ~avatar Some pins are also used by the [LED screen](/device/screen). Please read the [page about pins](/device/pins) carefully. -### ~ +## ~ -### Parameters +## Parameters -* ``name`` is a [string](/reference/types/string) that stores the name of the pin (``P0``, ``P1``, or ``P2``, up through ``P20``) -* ``value`` is a [number](/reference/types/number) that can be either `0` or `1` +* ``name`` is a [string](/types/string) that stores the name of the pin (``P0``, ``P1``, or ``P2``, up through ``P20``) +* ``value`` is a [number](/types/number) that can be either `0` or `1` -### Example: football score keeper +## Example: football score keeper This program reads pin `P0` to find when a goal is scored. When `P0` is `1`, the program makes the score bigger and plays a buzzer sound @@ -53,7 +53,7 @@ input.onButtonPressed(Button.B, () => { }); ``` -### See also +## See also [@boardname@ pins](/device/pins), [digital read pin](/reference/pins/digital-read-pin), diff --git a/docs/reference/pins/i2c-read-buffer.md b/docs/reference/pins/i2c-read-buffer.md new file mode 100644 index 00000000..ccbddfcb --- /dev/null +++ b/docs/reference/pins/i2c-read-buffer.md @@ -0,0 +1,57 @@ +# i2c Read Buffer + +Read data into a buffer from a device at an I2C address. + +```sig +pins.i2cReadBuffer(0, 0, false); +``` + +A device connected to the I2C pins on the @boardname@ at the address is selected to read data from. If it has data available to transfer, the data is received and copied into a buffer for your program to use. Your program says how big (how many bytes to receive) the buffer should be. You won't get back that many bytes of data if the connected device has less to send than what you asked for. + +### ~ hint + +**Simulator**: This function needs real hardware to work with. It's not supported in the simulator. + +### ~ + +## Parameters + +* **address**: the 7-bit I2C address to read the data from. +* **size**: the [number](/types/number) of bytes to read into the buffer from the device. +* **repeated**: if `true`, don't send a stop condition after the read. Otherwise, a stop condition is sent when `false` (the default). + +### ~ hint + +#### Repeated start + +A [repeated start condition](http://www.i2c-bus.org/repeated-start-condition/) is set to help make sure that when you want to read data miltiple times from the device at once, it can happen without interruption. A start conditon is sent (if **repeated** is `true`) each time a buffer is read without a matching stop condition. When the last buffer is read, the stop conditon can be sent by setting **repeated** to `false`. For single reads, don't use **repeated** or set it to `false`. + +#### Reserved addresses + +Some sensors on your @boardname@ use the same I2C bus that is connected to the pins that you program. This means that you should be careful to **NOT** use an address for your device that is the same as the any of the ones used by the sensors on the board. Check the [I2C sensor addresses](https://tech.microbit.org/hardware/i2c/) list before you assign one to your device. This will help you keep the addresses separate. + +#### Bus address format + +The @boardname@ uses 7-bit values to address the devices connected on the I2C bus. Before an address is transmitted, it is adjusted temporarily to an 8-bit value so that the valid address bits are sent properly. This means that the value of an 8-bit address present on the bus will appear as twice that of what you specified. This is fine though, since the device you are addressing will decode it to match the address you gave. If your device address is specified as an 8-bit address, you will need to use an address that is half that value when you read to or write from it. + +### ~ + +## Returns + +* a [buffer](/types/buffer) that contains the data read from the device at the I2C address. The number of bytes returned to you is less than or equal to amount you asked for in the **size** parameter. + +## Example + +Tell a device connected to the I2C pins with the address of `141` to respond to a _read status_ command. The device sends the status data on the I2C wires if receives a command byte equal to `0`. `32` bytes of status data are read into a buffer. + +```blocks +const i2cDevice = 141; +pins.i2cWriteNumber(i2cDevice, NumberFormat.UInt8LE, 0) +let i2cBuffer = pins.i2cReadBuffer(i2cDevice, 32, false); +``` + +## See also + +[i2c write buffer](/reference/pins/i2c-write-buffer), [buffer](/types/buffer) + +[What's I2C?](http://www.i2c-bus.org/) diff --git a/docs/reference/pins/i2c-read-number.md b/docs/reference/pins/i2c-read-number.md index bbd7df7b..d27e5d2b 100644 --- a/docs/reference/pins/i2c-read-number.md +++ b/docs/reference/pins/i2c-read-number.md @@ -1,38 +1,70 @@ -# I2C Read Number +# i2c Read Number -Read one number from the specified 7-bit I2C address, in the specified -number format. +Read one number from an I2C address using a specified number format. ```sig -pins.i2cReadNumber(0, NumberFormat.Int8LE); +pins.i2cReadNumber(0, NumberFormat.Int8LE, false); ``` -### Parameters +### ~ hint -* ``address``: the 7-bit I2C address from which to read the number. -* ``format``: the number format. Formats include - **Int8LE**, **UInt8LE**, **Int16LE**, **UInt16LE**, **Int32LE**, - **Int8BE**, **UInt8BE**, **Int16BE**, **UInt16BE**, and - **Int32BE**. - * **Int** stands for "integer", and **UInt** stands for "unsigned integer". - * **LE** stands for "little-endian" and **BE** stands for "big-endian". - * The number in each format name stands for the number of bits in the format. +**Simulator**: This function needs real hardware to work with. It's not supported in the simulator. -### Example +### ~ + +## Parameters + +* **address**: the 7-bit I2C address of the device you want to read a number from. +* **format**: the [NumberFormat](/types/buffer/number-format) of the number value to read. +* **repeated**: if `true`, don't send a stop condition after the read. Otherwise, a stop condition is sent when `false` (the default). + +### ~ hint + +#### Repeated start + +A [repeated start condition](http://www.i2c-bus.org/repeated-start-condition/) is set to help make sure that when you want to read multiple numbers from the device at one time, it can happen without interruption. A start conditon is sent (if **repeated** is `true`) each time a number is read without a matching stop condition. When the last number is read, the stop conditon can be sent by setting **repeated** to `false`. For single reads, don't use **repeated** or set it to `false`. + +#### Reserved addresses + +Some sensors on your @boardname@ use the same I2C bus that is connected to the pins that you program. This means that you should be careful to **NOT** use an address for your device that is the same as the any of the ones used by the sensors on the board. Check the [I2C sensor addresses](https://tech.microbit.org/hardware/i2c/) list before you assign one to your device. This will help you keep the addresses separate. + +#### Bus address format + +The @boardname@ uses 7-bit values to address the devices connected on the I2C bus. Before an address is transmitted, it is adjusted temporarily to an 8-bit value so that the valid address bits are sent properly. This means that the value of an 8-bit address present on the bus will appear as twice that of what you specified. This is fine though, since the device you are addressing will decode it to match the address you gave. If your device address is specified as an 8-bit address, you will need to use an address that is half that value when you read to or write from it. + +### ~ + +## Returns + +* a number from the device with the [NumberFormat](/types/buffer/number-format) you asked for. + +## Examples + +### Read a big endian number from a device The following example reads a number in big-endian, 16-bit, unsigned integer format from the 7-bit I2C address `32`. +Read a number from the device at a 7-bit I2C address as a 16-bit number. The `16`, big-endian, and integer chosen for the format. + ```blocks -pins.i2cReadNumber(32, NumberFormat.UInt16BE); +let inValue = pins.i2cReadNumber(32, NumberFormat.UInt16BE, false); ``` -#### ~hint +### Repeated reads -This function is not supported in the simulator. +Read three bytes from a device at address `33` at one time. -#### ~ +```blocks +let nums: number[] = [] -### See also +nums[0] = pins.i2cReadNumber(33, NumberFormat.UInt8LE, true) +nums[1] = pins.i2cReadNumber(33, NumberFormat.UInt8LE, true) +nums[2] = pins.i2cReadNumber(33, NumberFormat.UInt8LE, false) +``` -[I2C](https://en.wikipedia.org/wiki/I%C2%B2C) +## See also + +[i2c write number](/reference/pins/i2c-write-number) + +[What's I2C?](http://www.i2c-bus.org/), [number format](/types/buffer/number-format) diff --git a/docs/reference/pins/i2c-write-buffer.md b/docs/reference/pins/i2c-write-buffer.md new file mode 100644 index 00000000..58e66d7e --- /dev/null +++ b/docs/reference/pins/i2c-write-buffer.md @@ -0,0 +1,57 @@ +# i2c Write Buffer + +Write data from buffer to a device at an I2C address. + +```sig +pins.i2cWriteBuffer(0, null, false); +``` + +A device connected to the I2C pins on the @boardname@ at the address is selected to write data to. If the device is ready to take in your data, some or all of the data in your buffer is written to it. + +### ~ hint + +**Simulator**: This function needs real hardware to work with. It's not supported in the simulator. + +### ~ + +## Parameters + +* **address**: the 7-bit I2C address to read the data from. +* **buffer**: a [buffer](/types/buffer) that contains the data to write to the device at the I2C address. +* **repeated**: if `true`, don't send a stop condition after the write. Otherwise, a stop condition is sent when `false` (the default). + +### ~ hint + +#### Repeated start + +A [repeated start condition](http://www.i2c-bus.org/repeated-start-condition/) is set to help make sure that when you want to write data miltiple times from the device at once, it can happen without interruption. A start conditon is sent (if **repeated** is `true`) each time a buffer is written without a matching stop condition. When the last buffer is written, the stop conditon can be sent by setting **repeated** to `false`. For single writes, don't use **repeated** or set it to `false`. + +#### Reserved addresses + +Some sensors on your @boardname@ use the same I2C bus that is connected to the pins that you program. This means that you should be careful to **NOT** use an address for your device that is the same as the any of the ones used by the sensors on the board. Check the [I2C sensor addresses](https://tech.microbit.org/hardware/i2c/) list before you assign one to your device. This will help you keep the addresses separate. + +#### Bus address format + +The @boardname@ uses 7-bit values to address the devices connected on the I2C bus. Before an address is transmitted, it is adjusted temporarily to an 8-bit value so that the valid address bits are sent properly. This means that the value of an 8-bit address present on the bus will appear as twice that of what you specified. This is fine though, since the device you are addressing will decode it to match the address you gave. If your device address is specified as an 8-bit address, you will need to use an address that is half that value when you read to or write from it. + +### ~ + +## Example + +Tell a device connected to the I2C pins with the address of `141` to respond to a _read status_ command. The device sends the status data on the I2C wires if receives a command byte equal to `0`. `32` bytes of status data is read into a buffer. + +The third byte is changed and the buffer is sent back to have the device update its status. + +```blocks +const i2cDevice = 141; +pins.i2cWriteNumber(i2cDevice, NumberFormat.UInt8LE, 0) +let i2cBuffer = pins.i2cReadBuffer(i2cDevice, 32, false); +i2cBuffer.setNumber(NumberFormat.UInt8LE, 2, 0) +pins.i2cWriteBuffer(i2cDevice, i2cBuffer, false) +``` + +## See also + +[i2c read buffer](/reference/pins/i2c-read-buffer), [buffer](/types/buffer) + +[What's I2C?](http://www.i2c-bus.org/) diff --git a/docs/reference/pins/i2c-write-number.md b/docs/reference/pins/i2c-write-number.md index b386b257..b630d9ee 100644 --- a/docs/reference/pins/i2c-write-number.md +++ b/docs/reference/pins/i2c-write-number.md @@ -1,39 +1,61 @@ -# I2C Write Number +# i2c Write Number -Write the specified number to the specified 7-bit I2C address in the -specified number format. +Write a number to a device at an I2C address using a specified number format. ```sig -pins.i2cWriteNumber(0, 0, NumberFormat.Int8LE); +pins.i2cWriteNumber(0, 0, NumberFormat.Int8LE, true); ``` -### Parameters +### ~ hint -* ``address``: the 7-bit I2C address to which to send ``value`` -* ``value``: the number to send to ``address`` -* ``format``: the number format for ``value``. Formats include - **Int8LE**, **UInt8LE**, **Int16LE**, **UInt16LE**, **Int32LE**, - **Int8BE**, **UInt8BE**, **Int16BE**, **UInt16BE**, and - **Int32BE**. - * **Int** stands for "integer", and **UInt** stands for "unsigned integer". - * **LE** stands for "little-endian" and **BE** stands for "big-endian". - * The number in each format name stands for the number of bits in the format. +**Simulator**: This function needs real hardware to work with. It's not supported in the simulator. -### Example +### ~ -The following example sends the value `2055` to the 7-bit I2C -address `32` in big-endian 32-bit integer format. +## Parameters + +* **address**: the 7-bit I2C address of the device to send to send **value** to. +* **value**: the number to send to **address**. +* **format**: the [NumberFormat](/types/buffer/number-format) for **value**. +* **repeated**: if `true`, don't send a stop condition after the write. Otherwise, a stop condition is sent when `false` (the default). + +### ~ hint + +#### Repeated start + +A [repeated start condition](http://www.i2c-bus.org/repeated-start-condition/) is set to help make sure that when you want to write multiple numbers from the device at one time, it can happen without interruption. A start conditon is sent (if **repeated** is `true`) each time a number is written without a matching stop condition. When the last number is written, the stop conditon can be sent by setting **repeated** to `false`. For single writes, don't use **repeated** or set it to `false`. + +#### Reserved addresses + +Some sensors on your @boardname@ use the same I2C bus that is connected to the pins that you program. This means that you should be careful to **NOT** use an address for your device that is the same as the any of the ones used by the sensors on the board. Check the [I2C sensor addresses](https://tech.microbit.org/hardware/i2c/) list before you assign one to your device. This will help you keep the addresses separate. + +#### Bus address format + +The @boardname@ uses 7-bit values to address the devices connected on the I2C bus. Before an address is transmitted, it is adjusted temporarily to an 8-bit value so that the valid address bits are sent properly. This means that the value of an 8-bit address present on the bus will appear as twice that of what you specified. This is fine though, since the device you are addressing will decode it to match the address you gave. If your device address is specified as an 8-bit address, you will need to use an address that is half that value when you read to or write from it. +### ~ + +## Examples + +### Write a big endian number to a device + +Send the value `2055` to the 7-bit I2C address as a 32-bit number. The `32`, big-endian, and integer chosen for the format. ```blocks -pins.i2cWriteNumber(32, 2055, NumberFormat.Int32BE); +pins.i2cWriteNumber(32, 2055, NumberFormat.Int32BE, false); ``` -#### ~hint +### Repeated writes -This function is not supported in the simulator. +Send three byte values to a device at address `33`. -#### ~ +```blocks +pins.i2cWriteNumber(33, 19, NumberFormat.Int32BE, true); +pins.i2cWriteNumber(33, 61, NumberFormat.Int32BE, true); +pins.i2cWriteNumber(33, 87, NumberFormat.Int32BE, false); +``` -### See also +## See also -[I2C](https://en.wikipedia.org/wiki/I%C2%B2C) +[i2c read number](/reference/pins/i2c-read-number) + +[What's I2C?](http://www.i2c-bus.org/), [number format](/types/buffer/number-format) diff --git a/docs/reference/pins/map.md b/docs/reference/pins/map.md index ada4f0be..7f40a6da 100644 --- a/docs/reference/pins/map.md +++ b/docs/reference/pins/map.md @@ -14,13 +14,13 @@ calling this function. pins.map(0, 0, 4, 0, 1023); ``` -### Parameters +## Parameters -* ``value``: a [number](/reference/types/number) that specifies the value to map -* ``fromLow``: a [number](/reference/types/number) that specifies the lower bound of the origin interval -* ``fromHigh``: a [number](/reference/types/number) that specifies the upper bound of the origin interval -* ``toLow``: a [number](/reference/types/number) that specifies the lower bound of the target interval -* ``toHigh``: a [number](/reference/types/number) that specifies the upper bound of the target interval +* ``value``: a [number](/types/number) that specifies the value to map +* ``fromLow``: a [number](/types/number) that specifies the lower bound of the origin interval +* ``fromHigh``: a [number](/types/number) that specifies the upper bound of the origin interval +* ``toLow``: a [number](/types/number) that specifies the lower bound of the target interval +* ``toHigh``: a [number](/types/number) that specifies the upper bound of the target interval ## Example @@ -28,12 +28,12 @@ This example maps the value read from the analog pin `P0` to an LED coordinate between `0` and `4`. ```blocks -let value1 = pins.analogReadPin(AnalogPin.P1) +let value1 = pins.analogReadPin(AnalogPin.P0) let index = pins.map(value1, 0, 1023, 0, 4) led.plot(0, index) ``` -### See also +## See also [analog read pin](/reference/pins/analog-read-pin) diff --git a/docs/reference/pins/on-pulsed.md b/docs/reference/pins/on-pulsed.md index 42bdc52a..4ec62f90 100644 --- a/docs/reference/pins/on-pulsed.md +++ b/docs/reference/pins/on-pulsed.md @@ -1,22 +1,26 @@ -# On Pulsed +# on Pulsed -Configure the specified pin for digital input, and then -execute the associated code block whenever the pin -pulses **High** or **Low** (as specified). +Set a pin to use as a digital input and then run some code when the pin pulses either ``high`` or ``low``. ```sig pins.onPulsed(DigitalPin.P0, PulseValue.High, () => { }); ``` -### Parameters +### ~ hint -* ``name``: The @boardname@ hardware pin to configure (``P0`` through ``P20``) -* ``pulse``: Which state will cause the associated block to execute (**High** or **Low**) +**Simulator**: This function needs real hardware to work with. It's not supported in the simulator. -### Example +### ~ -The following example configures pin ``P2`` for digital input, -and then displays the string `LOW` whenever ``P2`` pulses low. +## Parameters + +* **name**: the @boardname@ hardware pin to set for digital input (``P0`` through ``P20``). +* **pulse**: the state that will cause the code inside the block to run, either ``high`` or ``low``. +* **body**: the code to run when the pin in **name** is pulsed to the state set in **pulse**. + +## Example + +Configure pin ``P2`` for digital input. Display the string `"LOW"` whenever ``P2`` pulses ``low``. ```blocks pins.onPulsed(DigitalPin.P2, PulseValue.Low, () => { @@ -24,7 +28,7 @@ pins.onPulsed(DigitalPin.P2, PulseValue.Low, () => { }); ``` -### See also +## See also [servo set pulse](/reference/pins/servo-set-pulse), [pulse duration](/reference/pins/pulse-duration), diff --git a/docs/reference/pins/pulse-duration.md b/docs/reference/pins/pulse-duration.md index b5277359..a03e64cd 100644 --- a/docs/reference/pins/pulse-duration.md +++ b/docs/reference/pins/pulse-duration.md @@ -1,21 +1,26 @@ -# Pulse Duration +# pulse Duration -Gets the duration of the last pulse in microseconds. - -This function should be called from an **on pulsed** handler. +Get the duration of the last pulse in microseconds. ```sig pins.pulseDuration(); ``` -### Returns +A pin pulse is detected in the [onPulsed](/reference/pins/on-pulsed) event. You use **pulseDuration** inside that event to get the duration of the pulse that triggered the event. -The duration of the last pulse, measured in microseconds. +### ~ hint -### Example +**Simulator**: This function needs real hardware to work with. It's not supported in the simulator. -The following example waits for pin ``P0`` to be pulsed high, and then -displays the duration of the pulse in microseconds on the LED screen. +### ~ + +## Returns + +* a [number](/types/number) that is the duration of the last pulse, measured in microseconds. + +## Example + +Wait for pin ``P0`` to be pulsed high. Display the duration of the pulse in microseconds on the LED screen. ```blocks pins.onPulsed(DigitalPin.P0, PulseValue.High, () => { @@ -23,7 +28,7 @@ pins.onPulsed(DigitalPin.P0, PulseValue.High, () => { }); ``` -### See also +## See also [servo set pulse](/reference/pins/servo-set-pulse), [on pulsed](/reference/pins/on-pulsed), diff --git a/docs/reference/pins/pulse-in.md b/docs/reference/pins/pulse-in.md index 3aa09fd2..4b580870 100644 --- a/docs/reference/pins/pulse-in.md +++ b/docs/reference/pins/pulse-in.md @@ -1,32 +1,37 @@ -# Pulse In +# pulse In -Returns the duration of a pulse (high or low) from a [pin](/device/pins) on -the @boardname@ board in microseconds. +Get the duration, in microseconds, of a pulse (high or low) from one of the pins. ```sig pins.pulseIn(DigitalPin.P0, PulseValue.High) ``` -### ~avatar +## ~avatar Some pins are also used by the [LED screen](/device/screen). Please read the [page about pins](/device/pins) carefully. +## ~ + +### ~ hint + +**Simulator**: This function needs real hardware to work with. It's not supported in the simulator. + ### ~ -### Parameters +## Parameters -* ``name`` is a [string](/reference/types/string) that stores the name of the pin (``P0``, ``P1``, or ``P2``, up through ``P20``) -* ``value`` is the value of the pulse, ``high`` or ``low`` -* ``maxDuration``, maximum duration in micro-seconds. If no pulse is received +* ``name`` the name of the pin (``P0``, ``P1``, or ``P2``, up through ``P20``). +* ``value`` the value of the pulse, either ``high`` or ``low``. +* ``maxDuration``, maximum duration to wait for the pulse in microseconds. If no pulse is received, the duration returned is `0`. -### Returns +## Returns -* a [number](/reference/types/number) that represents the pulse duration in micro-seconds +* a [number](/types/number) that is the pulse duration in microseconds. -### Example: Measuring distance with a sonar +## Example: Measuring distance with a sonar -The following script sends a pulse on ``P0`` and reads the pulse returned by a HC-SR04 sonar to determine the distance of the object in front of the sensor. +Send a pulse on ``P0`` and read a pulse returned by a HC-SR04 sonar ultrasonic sensor. The sensor determines the distance of the object in front of it. ```blocks basic.forever(() => { @@ -43,12 +48,6 @@ basic.forever(() => { }) ``` -#### ~hint +## See also -This function is not supported in the simulator. - -#### ~ - -### See also - -[digital write pin](/reference/pins/digital-write-pin), +[digital write pin](/reference/pins/digital-write-pin) diff --git a/docs/reference/pins/servo-set-pulse.md b/docs/reference/pins/servo-set-pulse.md index 7fe17aba..ab5e1443 100644 --- a/docs/reference/pins/servo-set-pulse.md +++ b/docs/reference/pins/servo-set-pulse.md @@ -7,23 +7,26 @@ ms, and set the pulse width to the specified value. pins.servoSetPulse(AnalogPin.P1, 1500) ``` -### Parameters +## Parameters -* ``name``: a [string](/reference/types/string) that specifies the pin to configure (`P0` through `P4`, or `P10`) -* ``micros``: a [number](/reference/types/number) that specifies the analog period in microseconds. +* ``name``: a [string](/types/string) that specifies the pin to configure (`P0` through `P4`, or `P10`) +* ``micros``: a [number](/types/number) that specifies the analog period in microseconds. -### Example +## Example The following code sets the servo pulse to `1000` microseconds. ```blocks -pins.servoSetPulse(AnalogPin.P1, 1000) +pins.servoSetPulse(AnalogPin.P0, 1000) ``` -### See also +## See also [@boardname@ pins](/device/pins), [on pin pressed](/reference/input/on-pin-pressed), [analog read pin](/reference/pins/analog-read-pin), [digital read pin](/reference/pins/digital-read-pin), [digital write pin](/reference/pins/digital-write-pin) + +[Brief Guide to Servos](https://www.kitronik.co.uk/pdf/a-brief-guide-to-servos.pdf) + diff --git a/docs/reference/pins/servo-write-pin.md b/docs/reference/pins/servo-write-pin.md index 7a0683fa..09b670fd 100644 --- a/docs/reference/pins/servo-write-pin.md +++ b/docs/reference/pins/servo-write-pin.md @@ -9,40 +9,41 @@ full speed in one direction, `180` specifies full speed in the other, and approximately `90` specifies no movement.) ```sig -pins.servoWritePin(AnalogPin.P1, 180) +pins.servoWritePin(AnalogPin.P0, 180) ``` -### Parameters +## Parameters -* ``name``: a [string](/reference/types/string) that specifies the pin name (`P0` through `P4`, or `P10`) -* ``value``: a [number](/reference/types/number) from `0` through `180` +* ``name``: a [string](/types/string) that specifies the pin name (`P0` through `P4`, or `P10`) +* ``value``: a [number](/types/number) from `0` through `180` -### Examples +## Examples -#### Setting the shaft angle to midpoint on a servo +### Setting the shaft angle to midpoint on a servo ```blocks -pins.servoWritePin(AnalogPin.P1, 90) +pins.servoWritePin(AnalogPin.P0, 90) ``` -#### Controlling the shaft by using the tilt information of the accelerometer +### Controlling the shaft by using the tilt information of the accelerometer ```blocks basic.forever(() => { let millig = input.acceleration(Dimension.X) // map accelerometer readings to angle let angle = pins.map(millig, -1023, 1023, 0, 180) - pins.servoWritePin(AnalogPin.P1, angle) + pins.servoWritePin(AnalogPin.P0, angle) }) ``` -#### Setting the full speed on a continuous servo +### Setting the full speed on a continuous servo ```blocks -pins.servoWritePin(AnalogPin.P1, 0) +pins.servoWritePin(AnalogPin.P0, 0) ``` -### See also +## See also [@boardname@ pins](/device/pins), [servo set pulse](/reference/pins/servo-set-pulse) +[Brief Guide to Servos](https://www.kitronik.co.uk/pdf/a-brief-guide-to-servos.pdf) diff --git a/docs/reference/pins/set-events.md b/docs/reference/pins/set-events.md index 105a5cb9..3eac8aba 100644 --- a/docs/reference/pins/set-events.md +++ b/docs/reference/pins/set-events.md @@ -1,4 +1,4 @@ -# Set Events +# set Events Configure the type of events emitted by a given pin. @@ -6,15 +6,20 @@ Configure the type of events emitted by a given pin. pins.setEvents(DigitalPin.P0, PinEventType.Edge); ``` -### Parameters +### ~ hint + +**Simulator**: This function needs real hardware to work with. It's not supported in the simulator. + +### ~ + +## Parameters * ``name``: The @boardname@ hardware pin to configure (``P0`` through ``P20``) * ``type``: The type of events this pin should emit -### Example +## Example -The following example configures pin ``P0`` and then -subscribes to the rise and fall events. +The following example configures pin ``P0`` and then subscribes to the rise and fall events. ```blocks control.onEvent(control.eventSourceId(EventBusSource.MICROBIT_ID_IO_P0), control.eventValueId(EventBusValue.MICROBIT_PIN_EVT_RISE), () => { diff --git a/docs/reference/pins/set-pull.md b/docs/reference/pins/set-pull.md index e8e22fc5..8de7d274 100644 --- a/docs/reference/pins/set-pull.md +++ b/docs/reference/pins/set-pull.md @@ -14,12 +14,14 @@ button press. pins.setPull(DigitalPin.P9, PinPullMode.PullDown); ``` -### Parameters +The pull-up and -down resistors are about 13kOhm. + +## Parameters * ``name``: The @boardname@ hardware pin to configure (``P0``-``P20``) * ``pull``: The pull to which to set the pin (**down**, **up**, or **none**) -### Example +## Example The following example sets the pull of pin ``P0`` to **up** (high). @@ -27,6 +29,6 @@ The following example sets the pull of pin ``P0`` to **up** (high). pins.setPull(DigitalPin.P0, PinPullMode.PullUp); ``` -### See also +## See also [@boardname@ | mbed](https://developer.mbed.org/platforms/Microbit/) diff --git a/docs/reference/pins/spi-format.md b/docs/reference/pins/spi-format.md new file mode 100644 index 00000000..7272b5c3 --- /dev/null +++ b/docs/reference/pins/spi-format.md @@ -0,0 +1,43 @@ +# spi Format + +Set the Serial Peripheral Interface (SPI) format. + +```sig +pins.spiFormat(8, 3); +``` + +The data sent over a SPI connection has a number of _bits_ to represent each value. Also, position of the clock signal (SCK), ``high`` or ``low``, and the exact time when a data value is read is determined by the SPI _mode_. Both the bits and mode values together are called the _SPI format_. + +### ~ hint + +**Simulator**: This function needs real hardware to work with. It's not supported in the simulator. + +### ~ + +The default number of bits is `8` and the default mode value is `3`. + +## Parameters + +* **bits**: the [number](types/number) of bits for each data value sent and received on the SPI connection. This value must be ``8`` since only 8 bits is currently supported for SPI data values. +* **mode**: a [number](/types/number) that is the mode value for the SPI clock (**SCK**) signalling. The different modes are: +>* `0`: the data line is active when **SCK** goes to ``high`` and the data values are read when **SCK** goes to ``high`` +>* `1`: the data line is active when **SCK** goes to ``high`` and the data values are read when **SCK** goes to ``low`` +>* `2`: the data line is active when **SCK** goes to ``low`` and the data values are read when **SCK** goes to ``high`` +>* `3`: the data line is active when **SCK** goes to ``low`` and the data values are read when **SCK** goes to ``low`` + +## Example + +Set the pins and format for the SPI connection. + +```blocks +pins.spiPins(DigitalPin.P15, DigitalPin.P14, DigitalPin.P13); +pins.spiFormat(8, 3); +``` + +## See also + +[spi write](/reference/pins/spi-write), +[spi pins](/reference/pins/spi-pins), +[spi frequency](/reference/pins/spi-frequency) + +[SPI Programming](https://developer.mbed.org/handbook/SPI) diff --git a/docs/reference/pins/spi-frequency.md b/docs/reference/pins/spi-frequency.md new file mode 100644 index 00000000..7dd81241 --- /dev/null +++ b/docs/reference/pins/spi-frequency.md @@ -0,0 +1,46 @@ +# spi Frequency + +Set the Serial Peripheral Interface (SPI) clock frequency. + +```sig +pins.spiFrequency(1000000); +``` + +The @boardname@ sets the rate of data transfer and control timing for a SPI connection. This data rate and timing signal is controlled by the **SCK** pin. The signal on this pin is _clocked_ using the frequency set for it. + +### ~ hint + +**Simulator**: This function needs real hardware to work with. It's not supported in the simulator. + +### ~ + +The default clock frequency is 1 Mhz (10000000 Hz). You can set the frequency for the SPI connection to some other value if you need a different data rate. + +## Parameters + +* **frequency**: a [number](/types/number) to set as the frequency for SPI bus clock. This value is the number of clock changes per second (Hz). + +## Example + +Read the value of the _WHOAMI_ register from the device connected to the SPI bus. The chip select line is connected to pin **0** and the SPI signals use pins **P13**, **P14**, and **P15**. + +```blocks +pins.digitalWritePin(DigitalPin.P0, 1); +pins.spiPins(DigitalPin.P15, DigitalPin.P14, DigitalPin.P13); +pins.spiFormat(8, 3); +pins.spiFrequency(1000000); +pins.digitalWritePin(DigitalPin.P0, 0); +let command = pins.spiWrite(143); +let whoami = pins.spiWrite(0); +pins.digitalWritePin(DigitalPin.P0, 1); +basic.showNumber(whoami); +serial.writeLine("WHOAMI register value: " + whoami) +``` + +## See also + +[spi write](/reference/pins/spi-write), +[spi pins](/reference/pins/spi-pins), +[spi format](/reference/pins/spi-format) + +[SPI Programming](https://developer.mbed.org/handbook/SPI) diff --git a/docs/reference/pins/spi-pins.md b/docs/reference/pins/spi-pins.md new file mode 100644 index 00000000..3d75d180 --- /dev/null +++ b/docs/reference/pins/spi-pins.md @@ -0,0 +1,43 @@ +# spi Pins + +Set the Serial Peripheral Interface (SPI) signalling pins + +```sig +pins.spiPins(DigitalPin.P0, DigitalPin.P1, DigitalPin.P2); +``` + +To configure the @boardname@ to write to an external device using a SPI connection, each SPI signal line is assigned to unique a pin. A SPI connection uses 3 signalling lines called **MOSI**, **MISO**, and **SCK**. + +### ~ hint + +**Simulator**: This function needs real hardware to work with. It's not supported in the simulator. + +### ~ + +If you don't set the pins for the SPI connection, the default pin assignments are used: + +* **P15** = **MOSI**, @boardname@ SPI data output pin +* **P14** = **MISO**, @boardname@ SPI data input pin +* **P13** = **SCK**, @boardname@ SPI serial clock output pin + +## Parameters + +* **mosi**: the pin for SPI data output, the **MOSI** signal pin. +* **miso**: the pin for SPI data input, the **MISO** signal pin. +* **sck**: the pin for SPI serial clock output, the **SCK** signal pin. + +## Example + +Set the pin assignments for a SPI connection to the default pins. + +```blocks +pins.spiPins(DigitalPin.P15, DigitalPin.P14, DigitalPin.P13); +``` + +## See also + +[spi write](/reference/pins/spi-write), +[spi frequency](/reference/pins/spi-frequency), +[spi format](/reference/pins/spi-format) + +[SPI Programming](https://developer.mbed.org/handbook/SPI) diff --git a/docs/reference/pins/spi-write.md b/docs/reference/pins/spi-write.md index ffee6be7..b7345f51 100644 --- a/docs/reference/pins/spi-write.md +++ b/docs/reference/pins/spi-write.md @@ -1,19 +1,48 @@ -# SPI Write +# spi Write -Write to the SPI Slave and return the response. +Write a data value to the SPI slave device and return its response. ```sig pins.spiWrite(0); ``` -### Parameters +Data values are written to a SPI slave device connected to the @boardname@ by the [SPI pins](/reference/pins/spi-pins). The data value might be either a command for the connected device or some value for its use. If the write operation causes the connected device to send a value back to the @boardname@, this will be the return value for the **spiWrite** function. -* ``value``: value Data to be sent to the SPI slave +### ~ hint -### Returns +**Simulator**: This function needs real hardware to work with. It's not supported in the simulator. -* a [number](/reference/types/number) Response from the SPI slave +### ~ -### See also +## Parameters -[SPI](https://developer.mbed.org/handbook/SPI) +* ``value``: a [number](/types/number) which is the data value to send to the SPI slave device. + +## Returns + +* a [number](/types/number) value which is the response from the SPI slave device. + +## Example + +Send the command to read the value of the _WHOAMI_ register from the device connected to the SPI bus. The chip select line is connected to pin **0** and the SPI signals use pins **P13**, **P14**, and **P15**. + +```blocks +pins.digitalWritePin(DigitalPin.P0, 1); +pins.spiPins(DigitalPin.P15, DigitalPin.P14, DigitalPin.P13); +pins.spiFormat(8, 3); +pins.spiFrequency(1000000); +pins.digitalWritePin(DigitalPin.P0, 0); +let command = pins.spiWrite(143); +let whoami = pins.spiWrite(0); +pins.digitalWritePin(DigitalPin.P0, 1); +basic.showNumber(whoami); +serial.writeLine("WHOAMI register value: " + whoami) +``` + +## See also + +[spi pins](/reference/pins/spi-pins), +[spi frequency](/reference/pins/spi-frequency), +[spi format](/reference/pins/spi-format) + +[SPI Programming](https://developer.mbed.org/handbook/SPI) diff --git a/docs/reference/radio.md b/docs/reference/radio.md index 5f258bf7..f0965a67 100644 --- a/docs/reference/radio.md +++ b/docs/reference/radio.md @@ -1,31 +1,42 @@ # Radio -Communicate data using radio packets +Send and receive data using radio packets. ```cards radio.sendNumber(0); radio.sendValue("name", 0); radio.sendString(""); -radio.onDataPacketReceived(() => { - -}); +radio.onReceivedNumber(function (receivedNumber) { }); +radio.onReceivedValue(function (name, value) { }); +radio.onReceivedString(function (receivedString) { }); +radio.receivedPacket(RadioPacketProperty.SignalStrength) radio.setGroup(0); +``` + +## Advanced + +```cards +radio.writeReceivedPacketToSerial(); radio.setTransmitPower(7); radio.setTransmitSerialNumber(false); -radio.writeReceivedPacketToSerial(); +radio.raiseEvent(0, 0); ``` ```package radio ``` -### See Also +## See Also -[sendNumber](/reference/radio/send-number), -[sendValue](/reference/radio/send-value), -[sendString](/reference/radio/send-string), -[onDataPacketReceived](/reference/radio/on-data-packet-received), -[setGroup](/reference/radio/set-group), -[setTransmitPower](/reference/radio/set-transmit-power), -[setTransmitSerialNumber](/reference/radio/set-transmit-serial-number), -[writeReceivedPacketToSerial](/reference/radio/write-received-packet-to-serial) +[send number](/reference/radio/send-number), +[send value](/reference/radio/send-value), +[send string](/reference/radio/send-string), +[on received number](/reference/radio/on-received-number), +[on received value](/reference/radio/on-received-value), +[on received string](/reference/radio/on-received-string), +[received packet](/reference/radio/received-packet), +[set group](/reference/radio/set-group), +[set transmit power](/reference/radio/set-transmit-power), +[set transmit serial number](/reference/radio/set-transmit-serial-number), +[write received packet to serial](/reference/radio/write-received-packet-to-serial), +[raise event](/reference/radio/raise-event) diff --git a/docs/reference/radio/on-data-packet-received.md b/docs/reference/radio/on-data-packet-received.md index 176e5591..8a308d1a 100644 --- a/docs/reference/radio/on-data-packet-received.md +++ b/docs/reference/radio/on-data-packet-received.md @@ -1,45 +1,42 @@ # On Data Packet Received Run part of a program when the @boardname@ receives a -[number](/reference/types/number) or [string](/reference/types/string) over ``radio``. +[number](/types/number) or [string](/types/string) over radio. +## ~ hint -```sig -radio.onDataPacketReceived(({receivedNumber, receivedString, time, serial, signal}) => { }); -``` +**Deprecated** -### ~hint +This API has been deprecated! + +* To receive a [string](/types/string) use [on received string](/reference/radio/on-received-string) instead. +* To receive a [number](/types/number) use [on received number](/reference/radio/on-received-number) instead. +* To receive a name-value pair use [on received value](/reference/radio/on-received-value) instead. + +## ~ + +## ~hint To add or remove the parts of the packet from the block, try clicking the blue gear in the corner! -### ~ +## ~ -### Callback Parameters +## Callback Parameters * ``packet`` - the [packet](/reference/radio/packet) that was received by the radio. The packet has the following properties: - * `receivedNumber` - The [number](/reference/types/number) that was sent in this packet or `0` if this packet did not contain a number. See [send number](/reference/radio/send-number) and [send value](/reference/radio/send-value) - * `receivedString` - The [string](/reference/types/string) that was sent in this packet or the empty string if this packet did not contain a string. See [send string](/reference/radio/send-string) and [send value](/reference/radio/send-value) + * `receivedNumber` - The [number](/types/number) that was sent in this packet or `0` if this packet did not contain a number. See [send number](/reference/radio/send-number) and [send value](/reference/radio/send-value) + * `receivedString` - The [string](/types/string) that was sent in this packet or the empty string if this packet did not contain a string. See [send string](/reference/radio/send-string) and [send value](/reference/radio/send-value) * `time` - The system time of the @boardname@ that sent this packet at the time the packet was sent. * `serial` - The serial number of the @boardname@ that sent this packet or `0` if the @boardname@ did not include its serial number. - * `signal` - How strong the radio signal is from `255` (weak) to `0` (strong). + * `signal` - How strong the radio signal is from `-128` (weak) to `-42` (strong). -### Example +## Troubleshooting -This program keeps sending numbers that says how fast the @boardname@ is -slowing down or speeding up. It also receives numbers for the same -thing from nearby @boardname@s. It shows these numbers as a -[bar graph](/reference/led/plot-bar-graph). +The on radio data event can only be created once, due to the hardware restrictions. -```blocks -basic.forever(() => { - radio.sendNumber(input.acceleration(Dimension.X)); -}) -radio.onDataPacketReceived(({ receivedNumber }) => { - led.plotBarGraph(receivedNumber, 1023); -}) -``` +The radio set group might need to be set, synchronized , before the radio events will function. -### See also +## See also [send number](/reference/radio/send-number), [send string](/reference/radio/send-string), @@ -48,4 +45,4 @@ radio.onDataPacketReceived(({ receivedNumber }) => { ```package radio -``` \ No newline at end of file +``` diff --git a/docs/reference/radio/on-data-received.md b/docs/reference/radio/on-data-received.md index 19a2fa4f..ad18a561 100644 --- a/docs/reference/radio/on-data-received.md +++ b/docs/reference/radio/on-data-received.md @@ -1,16 +1,25 @@ -# On Data Received - -> Note: This API has been deprecated! Use [on data packet received](/reference/radio/on-data-packet-received) instead. +# on Data Received Run part of a program when the @boardname@ receives a -[number](/reference/types/number) or [string](/reference/types/string) over ``radio``. - +[number](/types/number) or [string](/types/string) over radio. ```sig radio.onDataReceived(() => { }); ``` -### Example +## ~ hint + +**Deprecated** + +This API has been deprecated! Use [on received number](/reference/radio/on-received-number) instead. + +## ~ + +```sig +radio.onDataReceived(() => { }); +``` + +## Example This program keeps sending numbers that says how fast the @boardname@ is slowing down or speeding up. It also receives numbers for the same @@ -26,9 +35,9 @@ radio.onDataReceived(() => { }) ``` -### See also +## See also -[on data packet received](/reference/radio/on-data-packet-received), +[on received number](/reference/radio/on-received-number), [send number](/reference/radio/send-number), [set group](/reference/radio/set-group) ```package diff --git a/docs/reference/radio/on-received-buffer.md b/docs/reference/radio/on-received-buffer.md new file mode 100644 index 00000000..bd07af47 --- /dev/null +++ b/docs/reference/radio/on-received-buffer.md @@ -0,0 +1,61 @@ +# on Received Buffer + +Run part of a program when the @boardname@ receives a buffer over ``radio``. + +```sig +radio.onReceivedBuffer(function (receivedBuffer) {}) +``` + +The data contained in **receivedBuffer** is put there as a data [type](/types). The data might be a [number](/types/number) or a [string](/types/string). When using buffers though, the way the data is placed in the buffer must have a specific format. In particular, numbers must have a certain order when their individual _bytes_ are placed into the buffer. The numbers must also be retrieved from the buffer using the order that they were placed in when set there. You can read more about [number formats](/types/buffer/number-format). + +## Parameters + +* **receivedBuffer**: The buffer that was sent in this packet or the empty string if this packet did not contain a string. See [send buffer](/reference/radio/send-buffer) + +## Example: Remote level + +Two @boardname@s work like remote levels. They lie flat and detect any change in the horizontal position of the plane that they sit in. Each board sends its level measurements to the other. Each level measurement is shown on the screen. + +```typescript +let ax = 0; +let ay = 0; +basic.forever(() => { + ax = input.acceleration(Dimension.X); + ay = input.acceleration(Dimension.Y); + + // encode data in buffer + let buf = pins.createBuffer(4) + buf.setNumber(NumberFormat.Int16LE, 0, ax) + buf.setNumber(NumberFormat.Int16LE, 2, ay) + radio.sendBuffer(buf) +}) + +radio.onReceivedBuffer(function (receivedBuffer) { + // decode data from buffer + ax = receivedBuffer.getNumber(NumberFormat.Int16LE, 0); + ay = receivedBuffer.getNumber(NumberFormat.Int16LE, 2); + + // display + basic.clearScreen() + led.plot( + pins.map(ax, -1023, 1023, 0, 4), + pins.map(ay, -1023, 1023, 0, 4) + ) +}); +``` + + +## ~hint + +A radio that can both transmit and receive is called a _transceiver_. + +## ~ + +## See also + +[send buffer](/reference/radio/send-buffer), +[number formats](/types/buffer/number-format) + +```package +radio +``` diff --git a/docs/reference/radio/on-received-number.md b/docs/reference/radio/on-received-number.md new file mode 100644 index 00000000..ffa2e4e4 --- /dev/null +++ b/docs/reference/radio/on-received-number.md @@ -0,0 +1,74 @@ +# on Received Number + +Run part of a program when the @boardname@ receives a +[number](/types/number) over ``radio``. + +```sig +radio.onReceivedNumber(function (receivedNumber) {}) +``` + +## Parameters + +* **receivedNumber**: The [number](/types/number) that was sent in this packet or `0` if this packet did not contain a number. See [send number](/reference/radio/send-number) and [send value](/reference/radio/send-value) + +## ~ hint + +Watch this video to see how the radio hardware works on the @boardname@: + +https://www.youtube.com/watch?v=Re3H2ISfQE8 + +## ~ + +## Examples + +### Tell me how fast + +This program keeps sending numbers that say how fast the @boardname@ is +slowing down or speeding up. It also receives numbers for the same +thing from nearby @boardname@s. It shows these numbers as a +[bar graph](/reference/led/plot-bar-graph). + +```blocks +basic.forever(() => { + radio.sendNumber(input.acceleration(Dimension.X)); +}) +radio.onReceivedNumber(function (receivedNumber) { + led.plotBarGraph(receivedNumber, 1023); +}) +``` + +### What's the distance? + +This program uses the signal strength from received packets to graph the +approximate distance between two @boardname@s. + +```blocks +basic.forever(() => { + radio.sendNumber(0) +}) +radio.onReceivedNumber(function (receivedNumber) { + led.plotBarGraph( + Math.abs(radio.receivedPacket(RadioPacketProperty.SignalStrength) + 42), + 128 - 42 + ) +}) +``` + +## Troubleshooting + +The ``||radio:onReceivedNumber||`` event can only be created once, due to the hardware restrictions. + +The radio set group might need to be set, synchronized, before the radio events will function. + +## See also + +[on received string](/reference/radio/on-received-string), +[received packet](/reference/radio/received-packet), +[send number](/reference/radio/send-number), +[send string](/reference/radio/send-string), +[send value](/reference/radio/send-value), +[set group](/reference/radio/set-group) + +```package +radio +``` diff --git a/docs/reference/radio/on-received-string.md b/docs/reference/radio/on-received-string.md new file mode 100644 index 00000000..cb22faf6 --- /dev/null +++ b/docs/reference/radio/on-received-string.md @@ -0,0 +1,51 @@ +# on Received String + +Run part of a program when the @boardname@ receives a [string](/types/string) over ``radio``. + +```sig +radio.onReceivedString(function (receivedString) {}) +``` + +## Parameters + +* **receivedString**: The [string](/types/string) that was sent in this packet or the empty string if this packet did not contain a string. See [send string](/reference/radio/send-string) and [send value](/reference/radio/send-value) + +## ~ hint + +Watch this video to see how the radio hardware works on the @boardname@: + +https://www.youtube.com/watch?v=Re3H2ISfQE8 + +## ~ + +## Example + +This program continuously sends a cheerful message. It also receives a messages from nearby @boardname@s. It shows these messages on the screen. + +```blocks +basic.forever(() => { + radio.sendString("I'm happy"); +}) +radio.onReceivedString(function (receivedString) { + basic.showString(receivedString) +}) +``` + +## Troubleshooting + +The ``||radio:on received string||`` event can only be created once, due to the hardware restrictions. + +The radio set group might need to be set, synchronized, before the radio events will function. + +## See also + +[on received number](/reference/radio/on-received-number), +[received packet](/reference/radio/received-packet), +[send number](/reference/radio/send-number), +[send string](/reference/radio/send-string), +[send value](/reference/radio/send-value), +[set group](/reference/radio/set-group) + +```package +radio +``` diff --git a/docs/reference/radio/on-received-value.md b/docs/reference/radio/on-received-value.md new file mode 100644 index 00000000..8b61fb40 --- /dev/null +++ b/docs/reference/radio/on-received-value.md @@ -0,0 +1,57 @@ +# on Received Value + +Run part of a program when the @boardname@ receives a name-value-pair over ``radio``. + +```sig +radio.onReceivedValue(function (name, value) {}) +``` + +## Parameters + +* **name**: a [string](/types/string) that is a name for the value received. +* **value**: a [number](/types/number) that is the value received. + +## ~ hint + +Watch this video to see how the radio hardware works on the @boardname@: + +https://www.youtube.com/watch?v=Re3H2ISfQE8 + +## ~ + +## Example + +This program keeps sending numbers that say how fast the @boardname@ is +slowing down or speeding up. When it receives numbers for the same +thing from nearby @boardname@s, show the numbers as a +[bar graph](/reference/led/plot-bar-graph). + +```blocks +basic.forever(() => { + radio.sendValue("accel-x", input.acceleration(Dimension.X)) +}) +radio.onReceivedValue(function (name, value) { + if (name == "accel-x") { + led.plotBarGraph(value, 1023); + } +}) +``` + +## Troubleshooting + +The ``||radio:on received value||`` event can only be created once, due to the hardware restrictions. + +The radio set group might need to be set, synchronized , before the radio events will function. + +## See also + +[on received number](/reference/radio/on-received-number), +[received packet](/reference/radio/received-packet), +[send number](/reference/radio/send-number), +[send string](/reference/radio/send-string), +[send value](/reference/radio/send-value), +[set group](/reference/radio/set-group) + +```package +radio +``` diff --git a/docs/reference/radio/packet.md b/docs/reference/radio/packet.md index d8dfc990..2c129161 100644 --- a/docs/reference/radio/packet.md +++ b/docs/reference/radio/packet.md @@ -4,13 +4,52 @@ A packet that was received by the radio. ## Properties -* `receivedNumber` - The [number](/reference/types/number) that was sent in this packet or `0` if this packet did not contain a number. See [send number](/reference/radio/send-number) and [send value](/reference/radio/send-value) -* `receivedString` - The [string](/reference/types/string) that was sent in this packet or the empty string if this packet did not contain a string. See [send string](/reference/radio/send-string) and [send value](/reference/radio/send-value) +* `receivedNumber` - The [number](/types/number) that was sent in this packet or `0` if this packet did not contain a number. See [send number](/reference/radio/send-number) and [send value](/reference/radio/send-value) +* `receivedString` - The [string](/types/string) that was sent in this packet or the empty string if this packet did not contain a string. See [send string](/reference/radio/send-string) and [send value](/reference/radio/send-value) * `time` - The system time of the @boardname@ that sent this packet at the time the packet was sent. * `serial` - The serial number of the @boardname@ that sent this packet or `0` if the @boardname@ did not include its serial number. -* `signal` - How strong the radio signal is from `255` (weak) to `0` (strong). +* `signal` - How strong the radio signal is. The exact range of values varies, but it goes approximately from `-128` dB (weak) to `-42` dB (strong). -### See also +## Packet layout + +This section documents the data layout of the packet if you need to interpret the data outside of MakeCode. + + Packet byte layout + | 0 | 1 ... 4 | 5 ... 8 | 9 ... 28 + ---------------------------------------------------------------- + | packet type | system time | serial number | payload + +* Serial number defaults to 0 unless enabled by user +* system time is milli-seconds since started, it will wrap around after a month or so + +### Packet types + +* PACKET_TYPE_NUMBER 0 + + payload: number (9 ... 12) + + +* PACKET_TYPE_VALUE 1 + + payload: number (9 ... 12), name length (13), name (14 ... 26) + +* PACKET_TYPE_STRING 2 + + payload: string length (9), string (10 ... 28) + +* PACKET_TYPE_BUFFER 3 + + payload: buffer length (9), buffer (10 ... 28) + +* PACKET_TYPE_DOUBLE 4 + + payload: number (9 ... 16) + +* PACKET_TYPE_DOUBLE_VALUE 5 + + payload: number (9 ... 16), name length (17), name (18 ... 26) + +## See also [on data packet received](/reference/radio/on-data-packet-received), diff --git a/docs/reference/radio/raise-event.md b/docs/reference/radio/raise-event.md new file mode 100644 index 00000000..947f8d77 --- /dev/null +++ b/docs/reference/radio/raise-event.md @@ -0,0 +1,14 @@ +# raise Event + +Sends an event over radio to be raised in the event bus of other @boardname@. + +```sig +radio.raiseEvent(control.eventSourceId(EventBusSource.MICROBIT_ID_BUTTON_A), control.eventValueId(EventBusValue.MICROBIT_EVT_ANY)); +``` + +**This is an advanced API.** For more information, see the +[@boardname@ runtime messageBus documentation](https://lancaster-university.github.io/microbit-docs/ubit/messageBus/) + +## See Also + +[control raise event](/reference/control/raise-event) \ No newline at end of file diff --git a/docs/reference/radio/receive-number.md b/docs/reference/radio/receive-number.md index d8ce45d3..83e00a40 100644 --- a/docs/reference/radio/receive-number.md +++ b/docs/reference/radio/receive-number.md @@ -1,18 +1,24 @@ -# Receive Number +# receive Number -> Note: This API has been deprecated! Use [on data packet received](/reference/radio/on-data-packet-received) instead. - -Receives the next number sent by a @boardname@ in the same ``radio`` group. +Receive the next number sent by a @boardname@ in the same ``radio`` group. ```sig radio.receiveNumber(); ``` -### Returns +## ~ hint -* the first [number](/reference/types/number) that the @boardname@ received. If it did not receive any numbers, this function will return `0`. +**Deprecated** -### Example: Simple number receiver +This API has been deprecated! Use [on received number](/reference/radio/on-received-number) instead. + +## ~ + +## Returns + +* the first [number](/types/number) that the @boardname@ received. If it did not receive any numbers, this function will return `0`. + +## Example: Simple number receiver This example receives the number broadcasted another @boardname@ and shows it as a bar graph. @@ -23,7 +29,7 @@ radio.onDataReceived(() => { }) ``` -### Example: Light level receiver +## Example: Light level receiver This example shows the light level from the [light level sender example](/reference/radio/send-number) as a number. @@ -36,7 +42,7 @@ basic.forever(() => { }) ``` -### Example: Mailbot +## Example: Mailbot This example receives the light level from the [light level sender example](/reference/radio/send-number) and shows a text string like **ALERT** if the light level becomes much brighter. @@ -58,7 +64,7 @@ basic.forever(() => { }) ``` -### See also +## See also [send number](/reference/radio/send-number), [on data received](/reference/radio/on-data-received) diff --git a/docs/reference/radio/receive-string.md b/docs/reference/radio/receive-string.md index e5bcf8f5..3c6ae814 100644 --- a/docs/reference/radio/receive-string.md +++ b/docs/reference/radio/receive-string.md @@ -1,19 +1,24 @@ -# Receive String +# receive String -> Note: This API has been deprecated! Use [on data packet received](/reference/radio/on-data-packet-received) instead. - -Find the next string sent by `radio` from another @boardname@. +Find the next string sent by radio from another @boardname@. ```sig radio.receiveString() ``` +## ~ hint -### Returns +**Deprecated** -* the first [string](/reference/types/string) that was sent. If no +This API has been deprecated! Use [on received string](/reference/radio/on-received-string) instead. + +## ~ + +## Returns + +* the first [string](/types/string) that was sent. If no string was sent, then this function returns an empty (blank) string. -### Example: Simple receiver +## Example: Simple receiver Show the string sent by another @boardname@. @@ -23,7 +28,7 @@ radio.onDataReceived(() => { }); ``` -### Example: Two-way radio +## Example: Two-way radio If you load this program onto two or more @boardname@s, you can send a code word from one of them to the others by pressing button `A`. The other @boardname@s will receive the code word and then show it. @@ -39,13 +44,13 @@ radio.onDataReceived(() => { }); ``` -### ~hint +## ~hint A radio that can both transmit and receive is called a _transceiver_. -### ~ +## ~ -### Example: Mood radio +## Example: Mood radio This is a simple program to send whether you are happy or sad over ```radio```. Use the `A` or `B` button to select an emotion. @@ -84,7 +89,7 @@ radio.onDataReceived(() => { }); ``` -### See also +## See also [send string](/reference/radio/send-string), [on data received](/reference/radio/on-data-received) diff --git a/docs/reference/radio/received-packet.md b/docs/reference/radio/received-packet.md new file mode 100644 index 00000000..3dd95504 --- /dev/null +++ b/docs/reference/radio/received-packet.md @@ -0,0 +1,48 @@ +# received Packet + +Get one of the properties from the last received radio packet. + +```sig +radio.receivedPacket(RadioPacketProperty.SignalStrength) +``` + +In addition to a [number](types/number), [string](/types/string), or name-value pair, the packet received also contains other information about the transmission of the packet. You can get this additional information by selecting a property from the packet. + +## Parameters + +* **type**: the property type to get from the packet. These are: +>* ``signal strength``: the strength of the radio signal when the packet was received. +>* ``serial number``: the serial number of the board sending the packet. +>* ``time``: the time when the packet was sent. + +## Returns + +* a [number](/types/number) that is the property selected in the **type** parameter: +>* ``signal strength``: the value ranges from `-128` to `-42` (`-128` means a weak signal and `-42` means a strong one.) +>* ``serial number``: the value is the serial number of the board sending the packet. +>* ``time``: the value is the system time, in microseconds, of the sender at the time when the packet was sent. + +## Example + +This program uses the signal strength from received packets to graph the +approximate distance between two @boardname@s. + +```blocks +basic.forever(() => { + radio.sendNumber(0) +}) +radio.onReceivedNumber(function (receivedNumber) { + led.plotBarGraph( + Math.abs(radio.receivedPacket(RadioPacketProperty.SignalStrength) + 42), + 128 - 42 + ) +}) +``` + +## See also + +[set transmit serial number](/reference/radio/set-transmit-serial-number) + +```package +radio +``` \ No newline at end of file diff --git a/docs/reference/radio/received-signal-strength.md b/docs/reference/radio/received-signal-strength.md index 8475282c..95516040 100644 --- a/docs/reference/radio/received-signal-strength.md +++ b/docs/reference/radio/received-signal-strength.md @@ -1,29 +1,39 @@ -# Received Signal Strength +# received Signal Strength -> Note: This API has been deprecated! Use [on data packet received](/reference/radio/on-data-packet-received) instead. - -Find how strong the ``radio`` signal is, from `255` to `0`. -(`255` means a weak signal and `0` means a strong one.) - -The @boardname@ finds the signal strength by checking how strong it was -the last time it ran the -[on data packet received](/reference/radio/on-data-packet-received) function. That means -it needs to run **receive number** first. +Find how strong the radio signal is. ```sig radio.receivedSignalStrength(); ``` -### Returns +## ~ hint -* a [number](/reference/types/number) between `255` and `0` that means +**Deprecated** + +This API has been deprecated! Use [received packet](/reference/radio/received-packet) instead. + +## ~ + +Find how strong the ``radio`` signal is, from `-128` to `-42`. +(`-128` means a weak signal and `-42` means a strong one.) + +The @boardname@ finds the signal strength by checking how strong it was +the last time it ran the +[on received number](/reference/radio/on-received-number) function. That means +it needs to run **receive number** first. + + + +## Returns + +* a [number](/types/number) between `-128` and `-42` that means how strong the signal is. -### Simulator +## Simulator This function only works on the @boardname@, not in browsers. -### Example +## Example This example shows how strong the radio signal of the [light level sender example](/reference/radio/send-number) is. @@ -37,9 +47,9 @@ basic.forever(() => { }); ``` -### See also +## See also -[on data packet received](/reference/radio/on-data-packet-received), [send number](/reference/radio/send-number), [on data received](/reference/radio/on-data-received) +[on received number](/reference/radio/on-received-number), [send number](/reference/radio/send-number), [on data received](/reference/radio/on-data-received) ```package radio diff --git a/docs/reference/radio/send-buffer.md b/docs/reference/radio/send-buffer.md new file mode 100644 index 00000000..5d4975de --- /dev/null +++ b/docs/reference/radio/send-buffer.md @@ -0,0 +1,59 @@ +# Send Buffer + +Sends a buffer to other @boardname@s in the area connected by radio. The +maximum buffer length is 19 bytes. + +```sig +radio.sendBuffer(pins.createBuffer(1)) +``` + +## Parameters + +* `msg` is a [buffer](/types/buffer) to send by radio. + + +## Example: Remote level + +If you load this program onto two @boardname@s, each board will send the level information to the other board. + +```typescript +let ax = 0; +let ay = 0; +basic.forever(() => { + ax = input.acceleration(Dimension.X); + ay = input.acceleration(Dimension.Y); + + // encode data in buffer + let buf = pins.createBuffer(4) + buf.setNumber(NumberFormat.Int16LE, 0, ax) + buf.setNumber(NumberFormat.Int16LE, 2, ay) + radio.sendBuffer(buf) +}) + +radio.onReceivedBuffer(function (receivedBuffer) { + // decode data from buffer + ax = receivedBuffer.getNumber(NumberFormat.Int16LE, 0); + ay = receivedBuffer.getNumber(NumberFormat.Int16LE, 2); + + // display + basic.clearScreen() + led.plot( + pins.map(ax, -1023, 1023, 0, 4), + pins.map(ay, -1023, 1023, 0, 4) + ) +}); +``` + +## ~hint + +A radio that can both transmit and receive is called a _transceiver_. + +## ~ + +## See also + +[on received buffer](/reference/radio/on-received-buffer) + +```package +radio +``` \ No newline at end of file diff --git a/docs/reference/radio/send-number.md b/docs/reference/radio/send-number.md index 5c655cf4..15303c6f 100644 --- a/docs/reference/radio/send-number.md +++ b/docs/reference/radio/send-number.md @@ -1,17 +1,26 @@ -# Send Number +# send Number -Broadcast a [number](/reference/types/number) to other @boardname@s connected via ``radio``. +Broadcast a [number](/types/number) to other @boardname@s connected via ``radio``. ```sig radio.sendNumber(0); ``` -### Parameters +## Parameters -* ``value`` - a [number](/reference/types/number) to send. +* **value**: a [number](/types/number) to send. +## ~ hint -### Example: Broadcasting acceleration +Watch this video to see how the radio hardware works on the @boardname@: + +https://www.youtube.com/watch?v=Re3H2ISfQE8 + +## ~ + +## Examples + +### Broadcasting acceleration This example broadcasts the value of your @boardname@'s ``acceleration`` in the `x` direction (left and right) to other @boardname@s. This kind @@ -27,7 +36,7 @@ input.onButtonPressed(Button.A, () => { This example broadcasts the level of the light around it. You can do some interesting things with it if you use it along with the -[on data packet received](/reference/radio/on-data-packet-received) example. +[on received number](/reference/radio/on-received-number) example. ```blocks radio.setGroup(99) @@ -37,9 +46,9 @@ basic.forever(() => { }) ``` -### See also +## See also -[on data packet received](/reference/radio/on-data-packet-received) +[on received number](/reference/radio/on-received-number) ```package radio diff --git a/docs/reference/radio/send-string.md b/docs/reference/radio/send-string.md index 53aa08a4..07211194 100644 --- a/docs/reference/radio/send-string.md +++ b/docs/reference/radio/send-string.md @@ -1,18 +1,25 @@ -# Send String +# send String Sends a string to other @boardname@s in the area connected by radio. The maximum string length is 19 characters. ```sig -radio.sendString("Hello!") +radio.sendString("hi!") ``` -### Parameters +## Parameters -* `msg` is a [string](/reference/types/string) to send by radio. +* **msg**: a [string](/types/string) to send by radio. +## ~ hint -### Example: Two-way radio +Watch this video to see how the radio hardware works on the @boardname@: + +https://www.youtube.com/watch?v=Re3H2ISfQE8 + +## ~ + +## Example: Two-way radio If you load this program onto two or more @boardname@s, you can send a code word from one of them to the others by pressing button `A`. The @@ -23,21 +30,20 @@ input.onButtonPressed(Button.A, () => { radio.sendString("Codeword: TRIMARAN") basic.showString("SENT"); }) - -radio.onDataPacketReceived(({ receivedString }) => { +radio.onReceivedString(function (receivedString) { basic.showString(receivedString); -}); +}) ``` -### ~hint +## ~hint A radio that can both transmit and receive is called a _transceiver_. -### ~ +## ~ -### See also +## See also -[on data packet received](/reference/radio/on-data-packet-received) +[on received string](/reference/radio/on-received-string) ```package radio diff --git a/docs/reference/radio/send-value.md b/docs/reference/radio/send-value.md index 5d991c93..b3737c1b 100644 --- a/docs/reference/radio/send-value.md +++ b/docs/reference/radio/send-value.md @@ -1,18 +1,26 @@ -# Send Value +# send Value Send a [string]() and [number]() together by ``radio`` to other @boardname@s. -The maximum [string]() length is 12 characters. +The maximum [string]() length is 8 characters. ```sig radio.sendValue("name", 0); ``` -### Parameters +## Parameters -* ``name`` is a [string](/reference/types/string) to send by radio -* ``value`` a [number](/reference/types/number) to send by radio +* **name**: a [string](/types/string) that is the name of the value to send. +* **value**: a [number](/types/number) that is the value to send. -### Example: Broadcasting acceleration +## ~ hint + +Watch this video to see how the radio hardware works on the @boardname@: + +https://www.youtube.com/watch?v=Re3H2ISfQE8 + +## ~ + +## Example: Broadcasting acceleration This program sends your @boardname@'s **acceleration** (amount it is speeding up or slowing down) in the `x` direction (left and right) to @@ -31,15 +39,15 @@ Then it shows them on the LED screen. ```blocks radio.setGroup(99) -radio.onDataPacketReceived(({ receivedString, receivedNumber }) => { - basic.showString(receivedString); - basic.showNumber(receivedNumber); +radio.onReceivedValue(function (name, value) { + basic.showString(name); + basic.showNumber(value); }); ``` -### See also +## See also -[on data packet received](/reference/radio/on-data-packet-received) +[on received value](/reference/radio/on-received-value) ```package radio diff --git a/docs/reference/radio/set-frequency-band.md b/docs/reference/radio/set-frequency-band.md new file mode 100644 index 00000000..eaa5662c --- /dev/null +++ b/docs/reference/radio/set-frequency-band.md @@ -0,0 +1,34 @@ +# set Frequency Band + +Change the transmission and reception band of the radio to the given channel. Default is 7. + +```sig +radio.setFrequencyBand(50); +``` + +## Parameters + +* ``band`` is a [number](/types/number) between ``0`` and ``83``. Each step is 1MHz wide, based at 2400MHz. + +## Simulator + +This function only works on the @boardname@, not in browsers. + +## Example + +This program makes the ``radio`` use frequency band 50. + +```blocks +radio.setFrequencyBand(50) +``` + +## See also + +[received packet](/reference/radio/received-packet), +[send number](/reference/radio/send-number), +[send value](/reference/radio/send-value), +[send string](/reference/radio/send-string) + +```package +radio +``` \ No newline at end of file diff --git a/docs/reference/radio/set-group.md b/docs/reference/radio/set-group.md index 02fd8c68..6c640441 100644 --- a/docs/reference/radio/set-group.md +++ b/docs/reference/radio/set-group.md @@ -1,7 +1,13 @@ -# Set Group +# set Group Make a program have the group ID you tell it for sending and receiving -with ``radio``. A group is like a cable channel (a @boardname@ can only +with radio. + +```sig +radio.setGroup(0); +``` + +A group is like a cable channel (a @boardname@ can only send or receive in one group at a time). A group ID is like the cable channel number. @@ -10,19 +16,15 @@ function, it will figure out its own group ID by itself. If you load the very same program onto two different @boardname@s, they will be able to talk to each other because they will have the same group ID. -```sig -radio.setGroup(0); -``` +## Parameters -### Parameters +* **id**: a [number](/types/number) from ``0`` to ``255``. -* ``id`` is a [number](/reference/types/number) from ``0`` to ``255``. - -### Simulator +## Simulator This function only works on the @boardname@, not in browsers. -### Example +## Example This program makes the group ID equal 128. @@ -30,9 +32,11 @@ This program makes the group ID equal 128. radio.setGroup(128) ``` -### See also +## See also -[on data packet received](/reference/radio/on-data-packet-received), +[on received number](/reference/radio/on-received-number), +[on received string](/reference/radio/on-received-string), +[on received value](/reference/radio/on-received-value), [send number](/reference/radio/send-number), [send value](/reference/radio/send-value), [send string](/reference/radio/send-string) diff --git a/docs/reference/radio/set-transmit-power.md b/docs/reference/radio/set-transmit-power.md index 6f68a528..b5143aa2 100644 --- a/docs/reference/radio/set-transmit-power.md +++ b/docs/reference/radio/set-transmit-power.md @@ -1,33 +1,33 @@ -# Set Transmit Power +# set Transmit Power Make the ``radio`` signal of the @boardname@ stronger or weaker. -It can be as weak as `0` and as strong as `7`. + +```sig +radio.setTransmitPower(7); +``` + +The signal can be as weak as `0` and as strong as `7`. Default is ``6``. The scientific name for the strength of the ``radio`` signal is **dBm**, or **decibel-milliwatts**. A signal strength of `0` can be measured as -30 dBm, and a strength of `7` can be measured as +4 dBm. -```sig -radio.setTransmitPower(7); -``` - -### Range +## Range If your @boardname@ is sending with a strength of `7`, and you are in an open area without many other computers around, the @boardname@ signal can reach as far as 70 meters (about 230 feet). -### Parameters +## Parameters -* ``power`` is a [number](/reference/types/number) between ``0`` and ``7`` that -means how strong the signal is. +* ``power`` is a [number](/types/number) between ``0`` and ``7`` that means how strong the signal is. -### Simulator +## Simulator This function only works on the @boardname@, not in browsers. -### Example +## Example This program makes the ``radio`` send at full strength. @@ -35,9 +35,9 @@ This program makes the ``radio`` send at full strength. radio.setTransmitPower(7) ``` -### See also +## See also -[on data packet received](/reference/radio/on-data-packet-received), +[received packet](/reference/radio/received-packet), [send number](/reference/radio/send-number), [send value](/reference/radio/send-value), [send string](/reference/radio/send-string) diff --git a/docs/reference/radio/set-transmit-serial-number.md b/docs/reference/radio/set-transmit-serial-number.md index bb8f3880..f52ce7cb 100644 --- a/docs/reference/radio/set-transmit-serial-number.md +++ b/docs/reference/radio/set-transmit-serial-number.md @@ -1,16 +1,16 @@ -# Set Transmit Serial Number +# set Transmit Serial Number -Make the ``radio`` packet embed the board serial number with each packet of data. +Make the radio packet embed the board serial number with each packet of data. ```sig radio.setTransmitSerialNumber(true); ``` -### Parameters +## Parameters -* ``transmit`` is a [boolean](/reference/types/boolean) that represents whether the serial number needs to be transmitted. +* **transmit**: a [boolean](/types/boolean) that, when ``true``, means that the board serial number is included in each transmitted packet. If ``false``, the serial number value is set to `0`. -### Example +## Example This program makes the ``radio`` send the serial number in each packet. @@ -18,9 +18,9 @@ This program makes the ``radio`` send the serial number in each packet. radio.setTransmitSerialNumber(true); ``` -### See also +## See also -[on data packet received](/reference/radio/on-data-packet-received), +[received packet property](/reference/radio/received-packet), [send number](/reference/radio/send-number), [send value](/reference/radio/send-value), [send string](/reference/radio/send-string) diff --git a/docs/reference/radio/write-received-packet-to-serial.md b/docs/reference/radio/write-received-packet-to-serial.md index 1290d1c9..26fc44b6 100644 --- a/docs/reference/radio/write-received-packet-to-serial.md +++ b/docs/reference/radio/write-received-packet-to-serial.md @@ -1,48 +1,66 @@ -# Write Received Packet To Serial +# write Received Packet To Serial Writes the last packet received by the ``radio`` to serial in JSON format. -Should be called within a callback to -[on data packet received](/reference/radio/on-data-packet-received). ```sig radio.writeReceivedPacketToSerial(); ``` -### Data received format +This should be called within a callback to +[on data packet received](/reference/radio/on-data-packet-received). -The format for received data printed to serial is as follows: +## Data received format + +The format for received data when these send functions are used: - [send number](/reference/radio/send-number): ```{v:ValueSent,t:MicrobitTimeAlive,s:SerialNumber}``` - [send value](/reference/radio/send-value): ```{v:ValueSent,t:MicrobitTimeAlive,s:SerialNumber,n:"Name"}``` - [send string](/reference/radio/send-string): ```{t:MicrobitTimeAlive,s:SerialNumber,n:"Text"}``` -### Examples +### ~hint + +The serial number value sent in the packet is set to `0` unless transmission of the serial number is enabled with ``||radio:radio set transmit serial number||``. + +### ~ + +## Example When ```radio``` data is received (after pressing the ``A`` button on -the second @boardname@), this program sends temperature data to -serial. +the second @boardname@), this program sends temperature data to the +serial port. ```blocks -input.onButtonPressed(Button.A, () => { - radio.sendNumber(input.temperature()); -}); -radio.onDataPacketReceived(() => { - radio.writeReceivedPacketToSerial(); -}); +input.onButtonPressed(Button.A, function () { + radio.sendNumber(input.temperature()) + radio.sendValue("temp", input.temperature()) + radio.sendString("It's warm now") +}) +radio.onReceivedNumber(function (receivedNumber) { + radio.writeReceivedPacketToSerial() +}) +radio.onReceivedValue(function (name, value) { + radio.writeReceivedPacketToSerial() +}) +radio.onReceivedString(function (receivedString) { + radio.writeReceivedPacketToSerial() +}) ``` Sample output to serial when ``A`` button pressed: -```Text -{v:27,t:323,s:0} +```json +{"t":323,"s":0,"v":27} +{"t":325,"s":0,"n":"temp","v":27} +{"t":326,"s":0,"n":"It's warm now"} ``` -### See also +## See also [send number](/reference/radio/send-number), [send value](/reference/radio/send-value), [send string](/reference/radio/send-string), -[on data packet received](/reference/radio/on-data-packet-received) +[on data packet received](/reference/radio/on-data-packet-received), +[set transmit serial number](/reference/radio/set-transmit-serial-number) ```package radio -``` \ No newline at end of file +``` diff --git a/docs/reference/radio/write-value-to-serial.md b/docs/reference/radio/write-value-to-serial.md index 051eb804..d3feb48e 100644 --- a/docs/reference/radio/write-value-to-serial.md +++ b/docs/reference/radio/write-value-to-serial.md @@ -1,14 +1,20 @@ -# Write Value To Serial +# write Value To Serial -> Note: This API has been deprecated! Use [write received packet to serial](/reference/radio/write-received-packet-to-serial) instead. - -Writes the data received by ``radio`` to serial in JSON format. +Write the data received by radio to serial in JSON format. ```sig radio.writeValueToSerial(); ``` -### Data received format +## ~ hint + +**Deprecated** + +This API has been deprecated! Use [write received packet to serial](/reference/radio/write-received-packet-to-serial) instead. + +## ~ + +## Data received format The format for received data printed to serial is as follows: @@ -16,7 +22,7 @@ The format for received data printed to serial is as follows: - [send value](/reference/radio/send-value): ```{v:ValueSent,t:MicrobitTimeAlive,s:SerialNumber,n:"Name"}``` - [send string](/reference/radio/send-string): ```{t:MicrobitTimeAlive,s:SerialNumber,n:"Text"}``` -### Examples +## Examples When ```radio``` data is received (after pressing the ``A`` button on the second @boardname@), this program sends temperature data to @@ -36,7 +42,7 @@ Sample output to serial when ``A`` button pressed: {v:27,t:323,s:0} ``` -### See also +## See also [send number](/reference/radio/send-number), [send value](/reference/radio/send-value), diff --git a/docs/reference/serial.md b/docs/reference/serial.md index ad8820e5..a59ed0ac 100644 --- a/docs/reference/serial.md +++ b/docs/reference/serial.md @@ -1,19 +1,37 @@ # Serial -Reading and writing data over a serial connection. +Read and write data over a serial connection. ```cards serial.writeLine(""); serial.writeNumber(0); serial.writeValue("x", 0); serial.writeString(""); +serial.writeNumbers([0]); serial.readUntil(","); serial.readLine(); serial.readString(); -serial.redirect(SerialPin.P0, SerialPin.P0, BaudRate.BaudRate115200); serial.onDataReceived(",", () => {}) ``` -### See Also +## Advanced -[writeLine](/reference/serial/write-line), [writeNumber](/reference/serial/write-number), [writeValue](/reference/serial/write-value), [writeString](/reference/serial/write-string), [readLine](/reference/serial/read-line), [redirect](/reference/serial/redirect-to) +```cards +serial.redirect(SerialPin.P0, SerialPin.P0, BaudRate.BaudRate115200); +serial.redirectToUSB(); +serial.writeBuffer(serial.readBuffer(64)); +serial.readBuffer(64); +serial.setRxBufferSize(64); +serial.setTxBufferSize(64); +``` + +## See Also + +[writeLine](/reference/serial/write-line), [writeNumber](/reference/serial/write-number), [writeValue](/reference/serial/write-value), +[writeString](/reference/serial/write-string), +[writeNumbers](/reference/serial/write-numbers), [readUntil](/reference/serial/read-until), [readLine](/reference/serial/read-line), +[readString](/reference/serial/read-string), [onDataReceived](/reference/serial/on-data-received), +[redirect](/reference/serial/redirect), [writeBuffer](/reference/serial/write-buffer), [readBuffer](/reference/serial/read-buffer), +[redirectToUSB](/reference/serial/redirect-to-usb), +[set rx buffer size](/reference/serial/set-rx-buffer-size), +[set tx buffer size](/reference/serial/set-tx-buffer-size) \ No newline at end of file diff --git a/docs/reference/serial/on-data-received.md b/docs/reference/serial/on-data-received.md index de2a6888..d8477bd4 100644 --- a/docs/reference/serial/on-data-received.md +++ b/docs/reference/serial/on-data-received.md @@ -7,11 +7,11 @@ Registers an event to be fired when one of the delimiter is matched. serial.onDataReceived(",", () => {}) ``` -### Parameters +## Parameters -* `delimiters` is a [string](/reference/types/string) containing any of the character to match +* `delimiters` is a [string](/types/string) containing any of the character to match -### Example +## Example Read values separated by `,`: @@ -21,7 +21,7 @@ serial.onDataReceived(serial.delimiters(Delimiters.Comma), () => { }) ``` -### See also +## See also [serial](/device/serial), [serial write line](/reference/serial/write-line), diff --git a/docs/reference/serial/read-buffer.md b/docs/reference/serial/read-buffer.md new file mode 100644 index 00000000..7a31fe33 --- /dev/null +++ b/docs/reference/serial/read-buffer.md @@ -0,0 +1,39 @@ +# read Buffer + +Read available serial data into a buffer. + +```sig +serial.readBuffer(64); +``` + +## Parameters + +* **length**: the [number](/types/number) of characters of serial data to read. + +## Returns + +* a [buffer](/types/buffer) containing input from the serial port. The length of the buffer may be smaller than the requested length. + +## ~hint +**Pause for more data** + +If the desired number of characters are available, **readBuffer** returns a buffer with the expected size. If not, the calling fiber (the part of your program calling the **readBuffer** function) sleeps until the desired number of characters are finally read into the buffer. + +The need to pause for more data is set by the @boardname@ **[serial mode](https://lancaster-university.github.io/microbit-docs/ubit/serial/#serial-modes)**. +## ~ + +## Example + +Read character data from the serial port one row at a time. Write the rows to an LED display connected to the I2C pins. + +```typescript +let rowData: Buffer = null; +for (let i = 0; i < 24; i++) { + rowData = serial.readBuffer(80); + pins.i2cWriteBuffer(65, rowData, false); +} +``` + +## See Also + +[write buffer](/reference/serial/write-buffer) diff --git a/docs/reference/serial/read-line.md b/docs/reference/serial/read-line.md index eb38402b..1f988789 100644 --- a/docs/reference/serial/read-line.md +++ b/docs/reference/serial/read-line.md @@ -6,19 +6,19 @@ Read a line of text from the serial port. serial.readLine(); ``` -#### ~hint +### ~hint This function expects the line it reads to be terminated with the `\r` character. If your terminal software does not terminate lines with `\r`, this function will probably never return a value. -#### ~ +### ~ -### Returns +## Returns -* a [string](/reference/types/string) containing input from the serial port, such as a response typed by a user +* a [string](/types/string) containing input from the serial port, such as a response typed by a user -### Example +## Example The following example requests the user's name, then repeats it to greet the user. @@ -31,7 +31,7 @@ basic.forever(() => { }); ``` -### See also +## See also [serial](/device/serial), [serial write line](/reference/serial/write-line), diff --git a/docs/reference/serial/read-string.md b/docs/reference/serial/read-string.md index 5f3861f5..281d0eef 100644 --- a/docs/reference/serial/read-string.md +++ b/docs/reference/serial/read-string.md @@ -1,16 +1,16 @@ # Serial Read String -Read the buffered serial data as a string +Read the buffered serial data as a string. ```sig serial.readString(); ``` -### Returns +## Returns -* a [string](/reference/types/string) containing input from the serial port. Empty if no data available. +* a [string](/types/string) containing input from the serial port. The string is empty if no data is available. -### Example +## Example The following program scrolls text on the screen as it arrives from serial. @@ -20,7 +20,7 @@ basic.forever(() => { }); ``` -### See also +## See also [serial](/device/serial), [serial write line](/reference/serial/write-line), diff --git a/docs/reference/serial/read-until.md b/docs/reference/serial/read-until.md new file mode 100644 index 00000000..484501f3 --- /dev/null +++ b/docs/reference/serial/read-until.md @@ -0,0 +1,28 @@ +# Serial Read Until + +Read a text from the serial port until a delimiter is found. + +```sig +serial.readUntil(","); +``` + +## Returns + +* a [string](/types/string) containing input from the serial port, such as a response typed by a user + +## Example + +The following example reads strings separated by commands (``,``). + +```blocks +basic.forever(() => { + let answer = serial.readUntil(","); + serial.writeLine(answer); +}); +``` + +## See also + +[serial](/device/serial), +[serial write line](/reference/serial/write-line), +[serial write value](/reference/serial/write-value) diff --git a/docs/reference/serial/redirect-to-usb.md b/docs/reference/serial/redirect-to-usb.md new file mode 100644 index 00000000..e03c8993 --- /dev/null +++ b/docs/reference/serial/redirect-to-usb.md @@ -0,0 +1,14 @@ +# redirect To USB + +Direct the serial input and output to use the USB connection. + +The @boardname@ is set to use the USB connection for serial data by default. If serial data is currently redirected, using [redirect](/reference/serial/redirect), to the pins, you can set it back to use USB. + +```sig +serial.redirectToUSB() +``` + +## See also + +[serial](/device/serial), +[redirect](/reference/serial/redirect) diff --git a/docs/reference/serial/redirect-to.md b/docs/reference/serial/redirect-to.md deleted file mode 100644 index 0cfb6671..00000000 --- a/docs/reference/serial/redirect-to.md +++ /dev/null @@ -1,31 +0,0 @@ -# Serial Redirect To - -Dynamically configure the serial instance to use pins other than -``USBTX`` and ``USBRX``. - -```sig -serial.redirect(SerialPin.P0, SerialPin.P0, BaudRate.BaudRate115200); -``` - -### Parameters - -* ``tx``: the [serial pin](/device/pins) on which to transmit data -* ``rx``: the [serial pin](/device/pins) on which to receive data -* ``rate``: the baud rate at which to transmit and receive data (either `9600` or ``115200``) - -### Example - -When button ``A`` is pressed, the following example reconfigures the -serial instance. The new configuration uses pin ``P1`` to transmit and -``P2`` to receive, at a baud rate of `9600`. - -```blocks -input.onButtonPressed(Button.A, () => { - serial.redirect(SerialPin.P1, SerialPin.P2, BaudRate.BaudRate9600); -}); -``` - -### See also - -[serial](/device/serial) - diff --git a/docs/reference/serial/redirect.md b/docs/reference/serial/redirect.md new file mode 100644 index 00000000..4563c646 --- /dev/null +++ b/docs/reference/serial/redirect.md @@ -0,0 +1,44 @@ +# redirect + +Configure the serial port to use the pins instead of USB. + +```sig +serial.redirect(SerialPin.P0, SerialPin.P0, BaudRate.BaudRate115200); +``` +The default connection for the serial port is over a USB cable. You can have the serial data go across wires connected to pins on the @boardname@ instead. To set the input and output for the serial connection to be on the pins, you redirect it to the pins. Also, you decide how fast you want to send and receive the data on the pins by choosing a _baud_ rate. + +## Parameters + +* **tx**: the transmit [pin](/device/pins) to send serial data on. +* **rx**: the receive [pin](/device/pins) to receive serial data on. +* **rate**: the baud rate for transmitting and receiving data. Baud rates you can choose from are: +>`300`, `1200`, `2400`, `4800`, `9600`, `14400`, `19200,`, `28800`, `31250`, `38400`, `57600`, or `115200` + +## ~hint +**Baud rate** + +Serial communication transmits data by sending one bit of a [digital number](/types/buffer/number-format) (usually a byte sized number), at a time. So, the data bytes are sent as a series of their bits. Serial communication uses just one wire to send these bits so only one bit can travel across the wire at a time. + +When pins on your @boardname@ are configured for serial communication, they make a serial port for data. The port switches the voltage on the pins to represent a new bit to send on the wire. A series of these voltage changes eventually sends a complete byte of data. The speed at which the voltage changes create a signal to communicate the bits is called the _baud_ rate. + +You will typically use `9600` or `115200` for your baud rate. Sometimes the device you connect to can figure out what your baud rate is. Most of the time though, you need to make sure the device you connect to is set to match your baud rate. + +## ~ + +## Example + +Change where serial data is sent to and received from. When button **A** is pressed, reconfigure the +serial port to use the pins. The new configuration uses pin ``P1`` to transmit and +``P2`` to receive. The baud rate is set to `9600`. + +```blocks +input.onButtonPressed(Button.A, () => { + serial.redirect(SerialPin.P1, SerialPin.P2, BaudRate.BaudRate9600); +}); +``` + +## See also + +[serial](/device/serial), +[redirectToUSB](/reference/serial/redirect-to-usb) + diff --git a/docs/reference/serial/set-rx-buffer-size.md b/docs/reference/serial/set-rx-buffer-size.md new file mode 100644 index 00000000..1fc58aa4 --- /dev/null +++ b/docs/reference/serial/set-rx-buffer-size.md @@ -0,0 +1,23 @@ +# set Rx Buffer Size + +Sets the length of the serial reception buffer in bytes. + +```sig +serial.setRxBufferSize(10) +``` + +## Parameters + +* **size**: desired length of the reception buffer + +## Example + +Allocates 64 bytes for the reception buffer. + +```typescript +serial.setRxBufferSize(64) +``` + +## See also + +[set tx buffer size](/reference/serial/set-tx-buffer-size) \ No newline at end of file diff --git a/docs/reference/serial/set-tx-buffer-size.md b/docs/reference/serial/set-tx-buffer-size.md new file mode 100644 index 00000000..31b69b9a --- /dev/null +++ b/docs/reference/serial/set-tx-buffer-size.md @@ -0,0 +1,23 @@ +# set Tx Buffer Size + +Sets the length of the serial transmission buffer in bytes. + +```sig +serial.setTxBufferSize(10) +``` + +## Parameters + +* **size**: desired length of the transmission buffer + +## Example + +Allocates 64 bytes for the transmission buffer. + +```typescript +serial.setTxBufferSize(64) +``` + +## See also + +[set rx buffer size](/reference/serial/set-rx-buffer-size) \ No newline at end of file diff --git a/docs/reference/serial/write-buffer.md b/docs/reference/serial/write-buffer.md new file mode 100644 index 00000000..d9c3c6fb --- /dev/null +++ b/docs/reference/serial/write-buffer.md @@ -0,0 +1,27 @@ +# write Buffer + +Write a buffer to the [serial](/device/serial) port. + +```sig +serial.writeBuffer(pins.createBuffer(0)); +``` + +You place your data characters into an existing buffer. All of the data, the length of the buffer, is written to the serial port. + +## Parameters + +* **buffer**: a [buffer](/types/buffer) to write to the serial port. + +## Example + +Read some characters of data from a device connected to the I2C pins. Write the data to the serial port. + +```typescript +pins.i2cWriteNumber(132, NumberFormat.UInt8LE, 0); +let i2cBuffer = pins.i2cReadBuffer(132, 16, false); +serial.writeBuffer(i2cBuffer); +``` + +## See also + +[read buffer](/reference/serial/read-buffer) \ No newline at end of file diff --git a/docs/reference/serial/write-line.md b/docs/reference/serial/write-line.md index c9b3171d..7e37741f 100644 --- a/docs/reference/serial/write-line.md +++ b/docs/reference/serial/write-line.md @@ -1,19 +1,21 @@ # Serial Write Line -Write a string to the [serial](/device/serial) port and start a new line of text +Write a string to the [serial](/device/serial) port and start a new line of text by writing `\r\n`. ```sig serial.writeLine(""); ``` -### Parameters +## Parameters -* `text` is the [string](/reference/types/string) to write to the serial port +* `text` is the [string](/types/string) to write to the serial port -### Example: simple serial +## Examples -This program writes the word `BOFFO` to the serial port repeatedly. +### Simple serial + +Write the word `BOFFO` to the serial port repeatedly. ```blocks basic.forever(() => { @@ -22,29 +24,37 @@ basic.forever(() => { }); ``` -### Example: streaming data +### Streaming data -This program checks the -[compass heading](/reference/input/compass-heading) and sends the -direction to the serial port repeatedly. +Check the [compass heading](/reference/input/compass-heading) and show the direction on the screen. Also, send both the direction and degree heading to the serial port. ```blocks +let degrees = 0 +let direction = "" basic.forever(() => { - let heading = input.compassHeading() - if (heading < 45) { - serial.writeLine("N"); - } else if (heading < 135) { - serial.writeLine("E"); - } - else if (heading < 225) { - serial.writeLine("S"); - } - else { - serial.writeLine("W"); + degrees = input.compassHeading() + if (degrees < 45) { + basic.showArrow(ArrowNames.North) + direction = "North" + } else if (degrees < 135) { + basic.showArrow(ArrowNames.East) + direction = "East" + } else if (degrees < 225) { + basic.showArrow(ArrowNames.South) + direction = "South" + } else if (degrees < 315) { + basic.showArrow(ArrowNames.West) + direction = "West" + } else { + basic.showArrow(ArrowNames.North) + direction = "North" } + serial.writeLine(direction + " @ " + degrees + " degrees") + basic.pause(500) }) ``` -### See also + +## See also [serial](/device/serial), [serial write number](/reference/serial/write-number), diff --git a/docs/reference/serial/write-number.md b/docs/reference/serial/write-number.md index 7e29cfbc..8e73eacd 100644 --- a/docs/reference/serial/write-number.md +++ b/docs/reference/serial/write-number.md @@ -6,22 +6,22 @@ Write a number to the [serial](/device/serial) port. serial.writeNumber(0); ``` -### Parameters +## Parameters -* `value` is the [number](/reference/types/number) to write to the serial port +* `value` is the [number](/types/number) to write to the serial port -### Example: one through ten +## Example: one two three -This program repeatedly writes a 10-digit number to the serial port. +This program repeatedly writes a 3-digit number to the serial port. ```blocks basic.forever(() => { - serial.writeNumber(1234567890); + serial.writeNumber(123); basic.pause(5000); }); ``` -### Example: plot bar graph does serial +## Example: plot bar graph does serial If you use the ``led.plotBarGraph`` function, it writes the number being plotted to the serial port too. @@ -33,9 +33,10 @@ basic.forever(() => { }) ``` -### See also +## See also [serial](/device/serial), [serial write line](/reference/serial/write-line), -[serial write value](/reference/serial/write-value) +[serial write value](/reference/serial/write-value), +[serial write numbers](/reference/serial/write-numbers) diff --git a/docs/reference/serial/write-numbers.md b/docs/reference/serial/write-numbers.md new file mode 100644 index 00000000..dbe0eb56 --- /dev/null +++ b/docs/reference/serial/write-numbers.md @@ -0,0 +1,45 @@ +# Serial Write Numbers + +Write an array of numbers to the [serial](/device/serial) port. + +```sig +serial.writeNumbers([0, 1, 2]); +``` + +Instead of writing a single number at a time using [write number](/reference/serial/write-number), you can write multiple numbers to the serial port at once. They are written as _Comma Separated Values (CSV)_. + +You can write the numbers `0` through `5` together and they will appear as one line of serial output: + +``0,1,2,3,4,5`` + +This makes a line of CSV data where the commas between the numbers are the separators for each value. + +## Parameters + +* `values`: the array of [numbers](/types/number) to write to the serial port + +## Example: one two three + +This program repeatedly writes a 3-number array to the serial port. + +```blocks +basic.forever(() => { + serial.writeNumbers([1, 2, 3]); + basic.pause(5000); +}); +``` + +## Example: plot temperature and light + +```blocks +serial.writeLine("temp,light") +basic.forever(() => { + serial.writeNumbers([input.temperature(), input.lightLevel()]) +}) +``` + +## See also + +[serial](/device/serial), +[serial write line](/reference/serial/write-line), +[serial write value](/reference/serial/write-value) diff --git a/docs/reference/serial/write-string.md b/docs/reference/serial/write-string.md index 4c673ff4..0e9f4941 100644 --- a/docs/reference/serial/write-string.md +++ b/docs/reference/serial/write-string.md @@ -7,11 +7,11 @@ without starting a new line afterward. serial.writeString(""); ``` -### Parameters +## Parameters -* `text` is the [string](/reference/types/string) to write to the serial port +* `text` is the [string](/types/string) to write to the serial port -### Example: simple serial +## Example: simple serial This program writes the word `JUMBO` to the serial port repeatedly, without any new lines. @@ -23,7 +23,7 @@ basic.forever(() => { }); ``` -### See also +## See also [serial](/device/serial), [serial write line](/reference/serial/write-line), diff --git a/docs/reference/serial/write-value.md b/docs/reference/serial/write-value.md index f19b706a..e10fb546 100644 --- a/docs/reference/serial/write-value.md +++ b/docs/reference/serial/write-value.md @@ -1,20 +1,31 @@ -# Write Value +# write Value -Write a name/value pair and a newline character (`\r\n`) to the [serial](/device/serial) port. +Write a **name:value** pair and a newline character (`\r\n`) to the [serial](/device/serial) port. ```sig serial.writeValue("x", 0); ``` -### Parameters +It is common when reporting or recording data to use a _Name Value Pair_ (NVP). They appear as a text output string in the form of a _name_ and a _value_ together. The name and the value are separated in the string with a _colon_, `:`. A name value pair reporting a temperature of `-15` degrees could look like: -* `name` is the [string](/reference/types/string) to write to the serial port -* `value` is the [number](/reference/types/number) to write to the serial port +``temperature:-15`` +Associating a name with a value helps to identify related data when different data sources are recorded. For example, if you're reporting both temperature and light intensity, the _name:value_ format helps spreadsheets or other data analysis programs distinguish between them and group the same types of values together properly. Reporting two data sources might look like this in the output: +``` +temperature:-15 +temperature:-12 +light:154 +temperature:-11 +light:152 +``` +## Parameters -### Example: streaming data +* `name` is the [string](/types/string) to write to the serial port +* `value` is the [number](/types/number) to write to the serial port + +## Example: streaming data Every 10 seconds, the example below sends the temperature and light level to the serial port. @@ -27,15 +38,15 @@ basic.forever(() => { }) ``` -#### ~hint +### ~hint The [send value](/reference/radio/send-value) function broadcasts string/number pairs. You can use a second @boardname@ to receive them, and then send them directly to the serial port with ``write value``. -#### ~ +### ~ -### See also +## See also [serial](/device/serial), [serial write line](/reference/serial/write-line), diff --git a/docs/reference/text.md b/docs/reference/text.md new file mode 100644 index 00000000..a7832884 --- /dev/null +++ b/docs/reference/text.md @@ -0,0 +1,18 @@ +# Text + +Functions to combine, split, search, and convert text strings. + +```cards +"".charAt(0); +"".compare(""); +"".substr(0, 0); +parseFloat(""); +parseInt(""); +convertToText(0); +``` + +## See also + +[char at](/reference/text/char-at), [compare](/reference/text/compare), +[substr](/reference/text/substr), [parse int](/reference/text/parse-int), +[parse float](/reference/text/parse-float), [convert to text](/reference/text/convert-text) \ No newline at end of file diff --git a/docs/reference/text/convert-to-text.md b/docs/reference/text/convert-to-text.md new file mode 100644 index 00000000..5cf823c2 --- /dev/null +++ b/docs/reference/text/convert-to-text.md @@ -0,0 +1,34 @@ +# convert to text + +Change the value of any [type](/types) into a text [string](/types/string). + +```sig +convertToText(123) +``` + +## Parameters + +* **value**: a value of some [type](/types) to convert to a [string](/types/string). + +## Returns + +* a [string](/types/string) that is a text representation of **value**. + +## Example #example + +Convert a boolean and a number value into strings and join them in a sentence. + +```blocks +let myBoolean = false +let myNumber = 0 + +myBoolean = true +myNumber = 123 + +let myString = "It is " + convertToText(myBoolean) + " that " + convertToText(myNumber) + " is now a string!" +``` + +## Sea also #seealso + +[parse int](/reference/text/parse-int), +[parse float](/reference/text/parse-float) diff --git a/docs/reference/toc.md b/docs/reference/toc.md deleted file mode 100644 index 7df807db..00000000 --- a/docs/reference/toc.md +++ /dev/null @@ -1,195 +0,0 @@ -acceleration - -analog-pitch - -analog-read-pin - -analog-set-period - -analog-set-pitch-pin - -analog-write-pin - -assign - -boolean - -brightness - -button-is-pressed - -change - -change-score-by - -change-tempo-by - -change-var - -clear - -clear-screen - -compass-heading - -create-image - -digital-read-pin - -digital-write-pin - -fade-in - -fade-out - -for - -forever - -game-over - -if - -image - -in-background - -light-level - -magnetic-force - -map - -math - -move - -number - -[on button pressed](/reference/input/on-button-pressed) - -on-data-received - -on-gamepad-button - -on-gesture - -on-pin-pressed - -on-signal-strength-changed - -pause - -pin-is-pressed - -pixel - -play-tone - -plot - -plot-all - -plot-bar-graph - -plot-frame - -plot-image - -plot-leds - -point - -position - -raise-alert-to - -receive-number - -receive-number - -repeat - -reports - -reset - -rest - -ring-tone - -rotation - -running-time - -score - -screenshot - -scroll-image - -send-number - -servo-set-pulse - -servo-write-pin - -set-brightness - -set-display-mode - -set-group - -set-pixel - -set-tempo - -show-animation - -show-frame - -show-image - -show-leds - -show-number - -show-string - -signal-strength - -start-countdown - -stop-animation - -string - -tell-camera-to - -tell-microphone-to - -tell-remote-control-to - -temperature - -tempo - -toggle - -toggle-all - -touching - -turn - -unplot - -var - -while - -width - -write-line - -write-value diff --git a/docs/reference/types.md b/docs/reference/types.md deleted file mode 100644 index ab6fbcbf..00000000 --- a/docs/reference/types.md +++ /dev/null @@ -1,11 +0,0 @@ -# types - -A *type* refers to a class of data and the operations permitted on that class of data. -The following built-in types are supported for the @boardname@: - -* **[String](/reference/types/string)**: a sequence of characters -* **[Number](/reference/types/number)**: an integer number (32-bit signed) -* **[Boolean](/blocks/logic/boolean)**: true or false -* **[Image](/reference/images/image)**: a collection of [@boardname@ LED states](/device/screen) (on/off) - -TypeScript allows you to create user-defined classes of data. diff --git a/docs/reference/types/boolean.md b/docs/reference/types/boolean.md deleted file mode 100644 index b538ddc9..00000000 --- a/docs/reference/types/boolean.md +++ /dev/null @@ -1,16 +0,0 @@ -# Boolean - -true or false. - -A Boolean has one of two possible values: `true`; `false`. Boolean (logical) operators (*and*, *or*, *not*) take Boolean inputs and yields a Boolean value. Comparison operators on other types ([numbers](/reference/types/number), [strings](/reference/types/string) yields a Boolean value. - -The following blocks represent the true and false Boolean values, which can be plugged in anywhere a Boolean value is expected: - -```blocks -true; -false; -``` - -### See Also - -[boolean (blocks)](/blocks/logic/boolean) diff --git a/docs/reference/types/number.md b/docs/reference/types/number.md deleted file mode 100644 index ecddb249..00000000 --- a/docs/reference/types/number.md +++ /dev/null @@ -1,71 +0,0 @@ -# Number - -An integer number. - -### @parent blocks/language - -A *Number* is an integer such as `42` or `-42`. More precisely, a *Number* is a signed 32-bit integer (two's complement). - -### Declare a number variable - -You can assign a number to a variable: - -```blocks -let num = 42; -basic.showNumber(42); -``` - -### Arithmetic operators - -The following arithmetic operators work on numbers and return a [Number](/reference/types/number): - -* addition: `1 + 3` -* subtraction: `1 - 3 ` -* multiplication: `3 * 2` -* integer division: `7 / 3` -* modulo is available through the [math library](/blocks/math) - -### Relational operators - -The following relational operators work on numbers and return a [Boolean](/blocks/logic/boolean): - -* equality: `(3 + 1) = 4` -* inequality: `3 != 4` -* less or equal than: `3 <= 4` -* less than: `3 < 4` -* greater or equal than : `4 >= 3` -* greater than: `4 > 3` - -### Show number - -The [show number](/reference/basic/show-number) function displays a number on the [LED screen](/device/screen). -For example, this code displays the number 42: - -```blocks -basic.showNumber(42); -``` - -### Functions that return a number - -Some functions return a number, which you can store in a variable. -For example the following code gets the display brightness -(using the [brightness function](/reference/led/brightness)) and stores the value in a variable named `brightness`: - -```blocks -let brightness = led.brightness() -``` - -### Math functions - -The [math library](/blocks/math) includes math related functions. -For example, the `absolute` function returns the returns the absolute value of input parameter `x`: - -```blocks -let abs = Math.abs(-42); -basic.showNumber(abs); -``` - -### See also - -[math](/blocks/math), [var](/blocks/variables/var), [Boolean](/blocks/logic/boolean), [show number](/reference/basic/show-number) - diff --git a/docs/reference/types/string-functions.md b/docs/reference/types/string-functions.md deleted file mode 100644 index f546ce1c..00000000 --- a/docs/reference/types/string-functions.md +++ /dev/null @@ -1,3 +0,0 @@ -# String functions - -TBD \ No newline at end of file diff --git a/docs/reference/types/string.md b/docs/reference/types/string.md deleted file mode 100644 index a9d7ca9a..00000000 --- a/docs/reference/types/string.md +++ /dev/null @@ -1,45 +0,0 @@ -# String - -a piece of text. - -### @parent blocks/language - -A *String* is a sequence of characters. For the @boardname@, ASCII character codes 32 to 126 are supported; letters, digits, punctuation marks, and a few symbols. All other character codes appear as a ? on the [LED screen](/device/screen). - -### Create a string variable - -```block -let salutation = "Hello"; -``` - -To create a variable that holds a string: - -1. Click `Variables` (in the Block drawer). - -2. Type a name for your new string variable by clicking the down arrow, then click New Variable. Then type the variable name "salutation" - -2. Drag a string block on the right side of the operator. - -3. Click `"Hello"` and then type a string like `hello`. - -Your code should look something like this: - -```block -let salutation = "Hello"; -``` - -### The function `show string` - -Use [show string](/reference/basic/show-string) to display a string on the [LED screen](/device/screen). -If the string is multiple characters, the string scrolls right to left. The following example displays `Hello world!` on the @boardname@ screen: - -```block -basic.showString("Hello world!"); -``` - -The parameter of `show string` specifies the string - -### See also - -[string functions](/reference/types/string-functions), [Number](/reference/types/number), [show string](/reference/basic/show-string) - diff --git a/docs/stable-ref.json b/docs/stable-ref.json new file mode 100644 index 00000000..0821d1dd --- /dev/null +++ b/docs/stable-ref.json @@ -0,0 +1,3 @@ +{ + "appref": "v2.0.10" +} diff --git a/docs/static/bluetooth/Bluetooth_SIG.png b/docs/static/bluetooth/Bluetooth_SIG.png deleted file mode 100755 index 5479e652..00000000 Binary files a/docs/static/bluetooth/Bluetooth_SIG.png and /dev/null differ diff --git a/docs/static/bluetooth/gatt_hierarchy.png b/docs/static/bluetooth/gatt_hierarchy.png deleted file mode 100755 index d5171d3a..00000000 Binary files a/docs/static/bluetooth/gatt_hierarchy.png and /dev/null differ diff --git a/docs/static/bluetooth/microbit_accelerometer.png b/docs/static/bluetooth/microbit_accelerometer.png deleted file mode 100755 index 47de394b..00000000 Binary files a/docs/static/bluetooth/microbit_accelerometer.png and /dev/null differ diff --git a/docs/static/bluetooth/microbit_button.png b/docs/static/bluetooth/microbit_button.png deleted file mode 100755 index c43675a8..00000000 Binary files a/docs/static/bluetooth/microbit_button.png and /dev/null differ diff --git a/docs/static/bluetooth/microbit_led.png b/docs/static/bluetooth/microbit_led.png deleted file mode 100755 index 4b5c57cd..00000000 Binary files a/docs/static/bluetooth/microbit_led.png and /dev/null differ diff --git a/docs/static/bluetooth/microbit_magnetometer.png b/docs/static/bluetooth/microbit_magnetometer.png deleted file mode 100755 index 662424ed..00000000 Binary files a/docs/static/bluetooth/microbit_magnetometer.png and /dev/null differ diff --git a/docs/static/bluetooth/microbit_on_connected.png b/docs/static/bluetooth/microbit_on_connected.png deleted file mode 100755 index 2a409f54..00000000 Binary files a/docs/static/bluetooth/microbit_on_connected.png and /dev/null differ diff --git a/docs/static/bluetooth/microbit_on_disconnected.png b/docs/static/bluetooth/microbit_on_disconnected.png deleted file mode 100755 index 47ea81ee..00000000 Binary files a/docs/static/bluetooth/microbit_on_disconnected.png and /dev/null differ diff --git a/docs/static/bluetooth/microbit_pin_io.png b/docs/static/bluetooth/microbit_pin_io.png deleted file mode 100755 index e262587f..00000000 Binary files a/docs/static/bluetooth/microbit_pin_io.png and /dev/null differ diff --git a/docs/static/bluetooth/microbit_temperature.png b/docs/static/bluetooth/microbit_temperature.png deleted file mode 100755 index dda6488f..00000000 Binary files a/docs/static/bluetooth/microbit_temperature.png and /dev/null differ diff --git a/docs/static/bluetooth/services_and_GATT.png b/docs/static/bluetooth/services_and_GATT.png deleted file mode 100755 index 7fd212d0..00000000 Binary files a/docs/static/bluetooth/services_and_GATT.png and /dev/null differ diff --git a/docs/static/coding-cards/balance-card.jpg b/docs/static/coding-cards/balance-card.jpg new file mode 100644 index 00000000..6b23939c Binary files /dev/null and b/docs/static/coding-cards/balance-card.jpg differ diff --git a/docs/static/coding-cards/dice-card.jpg b/docs/static/coding-cards/dice-card.jpg new file mode 100644 index 00000000..94fac1a0 Binary files /dev/null and b/docs/static/coding-cards/dice-card.jpg differ diff --git a/docs/static/coding-cards/games-nervous.jpg b/docs/static/coding-cards/games-nervous.jpg new file mode 100644 index 00000000..772ddd24 Binary files /dev/null and b/docs/static/coding-cards/games-nervous.jpg differ diff --git a/docs/static/coding-cards/games-reaction.jpg b/docs/static/coding-cards/games-reaction.jpg new file mode 100644 index 00000000..a2e50f68 Binary files /dev/null and b/docs/static/coding-cards/games-reaction.jpg differ diff --git a/docs/static/coding-cards/games-shake.jpg b/docs/static/coding-cards/games-shake.jpg new file mode 100644 index 00000000..2f4a51bf Binary files /dev/null and b/docs/static/coding-cards/games-shake.jpg differ diff --git a/docs/static/coding-cards/games-sprite.jpg b/docs/static/coding-cards/games-sprite.jpg new file mode 100644 index 00000000..caa6533e Binary files /dev/null and b/docs/static/coding-cards/games-sprite.jpg differ diff --git a/docs/static/coding-cards/games-zen.jpg b/docs/static/coding-cards/games-zen.jpg new file mode 100644 index 00000000..9677eb37 Binary files /dev/null and b/docs/static/coding-cards/games-zen.jpg differ diff --git a/docs/static/coding-cards/trundlewheel-card.jpg b/docs/static/coding-cards/trundlewheel-card.jpg new file mode 100644 index 00000000..c3ae03f5 Binary files /dev/null and b/docs/static/coding-cards/trundlewheel-card.jpg differ diff --git a/docs/static/configurations/chrome-version.png b/docs/static/configurations/chrome-version.png deleted file mode 100644 index b7a4db67..00000000 Binary files a/docs/static/configurations/chrome-version.png and /dev/null differ diff --git a/docs/static/configurations/edge-version.png b/docs/static/configurations/edge-version.png deleted file mode 100644 index f9c9095a..00000000 Binary files a/docs/static/configurations/edge-version.png and /dev/null differ diff --git a/docs/static/configurations/firefox-version.png b/docs/static/configurations/firefox-version.png deleted file mode 100644 index d9b5684c..00000000 Binary files a/docs/static/configurations/firefox-version.png and /dev/null differ diff --git a/docs/static/configurations/ie-version.png b/docs/static/configurations/ie-version.png deleted file mode 100644 index 3fbc6e7c..00000000 Binary files a/docs/static/configurations/ie-version.png and /dev/null differ diff --git a/docs/static/configurations/osx-version.png b/docs/static/configurations/osx-version.png deleted file mode 100644 index 9457d7e4..00000000 Binary files a/docs/static/configurations/osx-version.png and /dev/null differ diff --git a/docs/static/configurations/safari-version.png b/docs/static/configurations/safari-version.png deleted file mode 100644 index 70d1d871..00000000 Binary files a/docs/static/configurations/safari-version.png and /dev/null differ diff --git a/docs/static/configurations/windows-version.png b/docs/static/configurations/windows-version.png deleted file mode 100644 index 06847ede..00000000 Binary files a/docs/static/configurations/windows-version.png and /dev/null differ diff --git a/docs/static/download/connect.png b/docs/static/download/connect.png new file mode 100644 index 00000000..af9fbd0e Binary files /dev/null and b/docs/static/download/connect.png differ diff --git a/docs/static/download/firmware.png b/docs/static/download/firmware.png new file mode 100644 index 00000000..c2280fb2 Binary files /dev/null and b/docs/static/download/firmware.png differ diff --git a/docs/static/download/pair.png b/docs/static/download/pair.png new file mode 100644 index 00000000..1dcf5851 Binary files /dev/null and b/docs/static/download/pair.png differ diff --git a/docs/static/download/transfer.png b/docs/static/download/transfer.png new file mode 100644 index 00000000..9f18101a Binary files /dev/null and b/docs/static/download/transfer.png differ diff --git a/docs/static/electron-dmg.png b/docs/static/electron-dmg.png new file mode 100644 index 00000000..cdefcb8f Binary files /dev/null and b/docs/static/electron-dmg.png differ diff --git a/docs/static/electron-dmg@2x.png b/docs/static/electron-dmg@2x.png new file mode 100644 index 00000000..a313c6ec Binary files /dev/null and b/docs/static/electron-dmg@2x.png differ diff --git a/docs/static/electron-icon.icns b/docs/static/electron-icon.icns new file mode 100644 index 00000000..80fd5c8d Binary files /dev/null and b/docs/static/electron-icon.icns differ diff --git a/docs/static/embed/blogger.png b/docs/static/embed/blogger.png deleted file mode 100644 index 80e6e60b..00000000 Binary files a/docs/static/embed/blogger.png and /dev/null differ diff --git a/docs/static/embed/embed-info.png b/docs/static/embed/embed-info.png deleted file mode 100644 index 6cd32872..00000000 Binary files a/docs/static/embed/embed-info.png and /dev/null differ diff --git a/docs/static/embed/project-page.png b/docs/static/embed/project-page.png deleted file mode 100644 index 31037d05..00000000 Binary files a/docs/static/embed/project-page.png and /dev/null differ diff --git a/docs/static/embed/publish.png b/docs/static/embed/publish.png deleted file mode 100644 index cc9dd0b8..00000000 Binary files a/docs/static/embed/publish.png and /dev/null differ diff --git a/docs/static/embed/squarespace-code.png b/docs/static/embed/squarespace-code.png deleted file mode 100644 index d377b112..00000000 Binary files a/docs/static/embed/squarespace-code.png and /dev/null differ diff --git a/docs/static/embed/squarespace-insert.png b/docs/static/embed/squarespace-insert.png deleted file mode 100644 index f7ac999c..00000000 Binary files a/docs/static/embed/squarespace-insert.png and /dev/null differ diff --git a/docs/static/filelogo.svg b/docs/static/filelogo.svg new file mode 100644 index 00000000..f3011103 --- /dev/null +++ b/docs/static/filelogo.svg @@ -0,0 +1,145 @@ + + + +image/svg+xml \ No newline at end of file diff --git a/docs/static/fonts/Roboto_400_normal.svg b/docs/static/fonts/Roboto_400_normal.svg new file mode 100644 index 00000000..627f5a36 --- /dev/null +++ b/docs/static/fonts/Roboto_400_normal.svg @@ -0,0 +1,308 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/static/fonts/Roboto_400_normal.ttf b/docs/static/fonts/Roboto_400_normal.ttf new file mode 100644 index 00000000..45d1e376 Binary files /dev/null and b/docs/static/fonts/Roboto_400_normal.ttf differ diff --git a/docs/static/fonts/Roboto_400_normal.woff b/docs/static/fonts/Roboto_400_normal.woff new file mode 100644 index 00000000..296609e0 Binary files /dev/null and b/docs/static/fonts/Roboto_400_normal.woff differ diff --git a/docs/static/fonts/fonts.css b/docs/static/fonts/fonts.css new file mode 100644 index 00000000..87fc735a --- /dev/null +++ b/docs/static/fonts/fonts.css @@ -0,0 +1,11 @@ +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 400; + src: url(Roboto_400_normal.eot); /* {{embedded-opentype-gf-url}} */ + src: local('☺'), + url(Roboto_400_normal.eot?#iefix) format('embedded-opentype'), /* {{embedded-opentype-gf-url}} */ + url(Roboto_400_normal.woff) format('woff'), /* http://fonts.gstatic.com/s/roboto/v16/2UX7WLTfW3W8TclTUvlFyQ.woff */ + url(Roboto_400_normal.ttf) format('truetype'), /* http://fonts.gstatic.com/s/roboto/v16/QHD8zigcbDB8aPfIoaupKOvvDin1pK8aKteLpeZ5c0A.ttf */ + url(Roboto_400_normal.svg#Roboto_400_normal) format('svg'); /* http://fonts.gstatic.com/l/font?kit=_YZOZaQ9UBZzaxiLBLcgZg&skey=a0a0114a1dcab3ac&v=v16#Roboto */ +} diff --git a/docs/static/githubfilelogo.svg b/docs/static/githubfilelogo.svg new file mode 100644 index 00000000..6a37ff01 --- /dev/null +++ b/docs/static/githubfilelogo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/static/hero.png b/docs/static/hero.png new file mode 100644 index 00000000..84f556ef Binary files /dev/null and b/docs/static/hero.png differ diff --git a/docs/static/icons/android-chrome-144x144.png b/docs/static/icons/android-chrome-144x144.png deleted file mode 100644 index 4f21365d..00000000 Binary files a/docs/static/icons/android-chrome-144x144.png and /dev/null differ diff --git a/docs/static/icons/android-chrome-192x192.png b/docs/static/icons/android-chrome-192x192.png index 38c59f87..ff399b13 100644 Binary files a/docs/static/icons/android-chrome-192x192.png and b/docs/static/icons/android-chrome-192x192.png differ diff --git a/docs/static/icons/android-chrome-256x256.png b/docs/static/icons/android-chrome-256x256.png deleted file mode 100644 index 1d717fb0..00000000 Binary files a/docs/static/icons/android-chrome-256x256.png and /dev/null differ diff --git a/docs/static/icons/android-chrome-36x36.png b/docs/static/icons/android-chrome-36x36.png deleted file mode 100644 index c0b0cfc3..00000000 Binary files a/docs/static/icons/android-chrome-36x36.png and /dev/null differ diff --git a/docs/static/icons/android-chrome-384x384.png b/docs/static/icons/android-chrome-384x384.png deleted file mode 100644 index 0136026b..00000000 Binary files a/docs/static/icons/android-chrome-384x384.png and /dev/null differ diff --git a/docs/static/icons/android-chrome-48x48.png b/docs/static/icons/android-chrome-48x48.png deleted file mode 100644 index 292b7308..00000000 Binary files a/docs/static/icons/android-chrome-48x48.png and /dev/null differ diff --git a/docs/static/icons/android-chrome-512x512.png b/docs/static/icons/android-chrome-512x512.png index cf5dc1f6..66b87f4f 100644 Binary files a/docs/static/icons/android-chrome-512x512.png and b/docs/static/icons/android-chrome-512x512.png differ diff --git a/docs/static/icons/android-chrome-72x72.png b/docs/static/icons/android-chrome-72x72.png deleted file mode 100644 index 9e4e5087..00000000 Binary files a/docs/static/icons/android-chrome-72x72.png and /dev/null differ diff --git a/docs/static/icons/android-chrome-96x96.png b/docs/static/icons/android-chrome-96x96.png deleted file mode 100644 index fe761e5e..00000000 Binary files a/docs/static/icons/android-chrome-96x96.png and /dev/null differ diff --git a/docs/static/icons/apple-touch-icon-114x114-precomposed.png b/docs/static/icons/apple-touch-icon-114x114-precomposed.png deleted file mode 100644 index 7288a4b8..00000000 Binary files a/docs/static/icons/apple-touch-icon-114x114-precomposed.png and /dev/null differ diff --git a/docs/static/icons/apple-touch-icon-114x114.png b/docs/static/icons/apple-touch-icon-114x114.png deleted file mode 100644 index ca342a66..00000000 Binary files a/docs/static/icons/apple-touch-icon-114x114.png and /dev/null differ diff --git a/docs/static/icons/apple-touch-icon-120x120-precomposed.png b/docs/static/icons/apple-touch-icon-120x120-precomposed.png deleted file mode 100644 index 42283d9a..00000000 Binary files a/docs/static/icons/apple-touch-icon-120x120-precomposed.png and /dev/null differ diff --git a/docs/static/icons/apple-touch-icon-120x120.png b/docs/static/icons/apple-touch-icon-120x120.png deleted file mode 100644 index 16f23115..00000000 Binary files a/docs/static/icons/apple-touch-icon-120x120.png and /dev/null differ diff --git a/docs/static/icons/apple-touch-icon-144x144-precomposed.png b/docs/static/icons/apple-touch-icon-144x144-precomposed.png deleted file mode 100644 index 29ee8f57..00000000 Binary files a/docs/static/icons/apple-touch-icon-144x144-precomposed.png and /dev/null differ diff --git a/docs/static/icons/apple-touch-icon-144x144.png b/docs/static/icons/apple-touch-icon-144x144.png deleted file mode 100644 index 4329adfd..00000000 Binary files a/docs/static/icons/apple-touch-icon-144x144.png and /dev/null differ diff --git a/docs/static/icons/apple-touch-icon-152x152-precomposed.png b/docs/static/icons/apple-touch-icon-152x152-precomposed.png deleted file mode 100644 index 01ff569c..00000000 Binary files a/docs/static/icons/apple-touch-icon-152x152-precomposed.png and /dev/null differ diff --git a/docs/static/icons/apple-touch-icon-152x152.png b/docs/static/icons/apple-touch-icon-152x152.png deleted file mode 100644 index 04a2bf01..00000000 Binary files a/docs/static/icons/apple-touch-icon-152x152.png and /dev/null differ diff --git a/docs/static/icons/apple-touch-icon-180x180-precomposed.png b/docs/static/icons/apple-touch-icon-180x180-precomposed.png deleted file mode 100644 index e7b313c8..00000000 Binary files a/docs/static/icons/apple-touch-icon-180x180-precomposed.png and /dev/null differ diff --git a/docs/static/icons/apple-touch-icon-180x180.png b/docs/static/icons/apple-touch-icon-180x180.png deleted file mode 100644 index caa027e5..00000000 Binary files a/docs/static/icons/apple-touch-icon-180x180.png and /dev/null differ diff --git a/docs/static/icons/apple-touch-icon-57x57-precomposed.png b/docs/static/icons/apple-touch-icon-57x57-precomposed.png deleted file mode 100644 index 3029d3bc..00000000 Binary files a/docs/static/icons/apple-touch-icon-57x57-precomposed.png and /dev/null differ diff --git a/docs/static/icons/apple-touch-icon-57x57.png b/docs/static/icons/apple-touch-icon-57x57.png deleted file mode 100644 index dea8718f..00000000 Binary files a/docs/static/icons/apple-touch-icon-57x57.png and /dev/null differ diff --git a/docs/static/icons/apple-touch-icon-60x60-precomposed.png b/docs/static/icons/apple-touch-icon-60x60-precomposed.png deleted file mode 100644 index a8a601e7..00000000 Binary files a/docs/static/icons/apple-touch-icon-60x60-precomposed.png and /dev/null differ diff --git a/docs/static/icons/apple-touch-icon-60x60.png b/docs/static/icons/apple-touch-icon-60x60.png deleted file mode 100644 index fa7cf816..00000000 Binary files a/docs/static/icons/apple-touch-icon-60x60.png and /dev/null differ diff --git a/docs/static/icons/apple-touch-icon-72x72-precomposed.png b/docs/static/icons/apple-touch-icon-72x72-precomposed.png deleted file mode 100644 index f2f4ba79..00000000 Binary files a/docs/static/icons/apple-touch-icon-72x72-precomposed.png and /dev/null differ diff --git a/docs/static/icons/apple-touch-icon-72x72.png b/docs/static/icons/apple-touch-icon-72x72.png deleted file mode 100644 index b339cc46..00000000 Binary files a/docs/static/icons/apple-touch-icon-72x72.png and /dev/null differ diff --git a/docs/static/icons/apple-touch-icon-76x76-precomposed.png b/docs/static/icons/apple-touch-icon-76x76-precomposed.png deleted file mode 100644 index 5ce8c3ad..00000000 Binary files a/docs/static/icons/apple-touch-icon-76x76-precomposed.png and /dev/null differ diff --git a/docs/static/icons/apple-touch-icon-76x76.png b/docs/static/icons/apple-touch-icon-76x76.png deleted file mode 100644 index 79616b48..00000000 Binary files a/docs/static/icons/apple-touch-icon-76x76.png and /dev/null differ diff --git a/docs/static/icons/apple-touch-icon-precomposed.png b/docs/static/icons/apple-touch-icon-precomposed.png deleted file mode 100644 index dc606f5a..00000000 Binary files a/docs/static/icons/apple-touch-icon-precomposed.png and /dev/null differ diff --git a/docs/static/icons/apple-touch-icon.png b/docs/static/icons/apple-touch-icon.png index 298a5419..a8677b6c 100644 Binary files a/docs/static/icons/apple-touch-icon.png and b/docs/static/icons/apple-touch-icon.png differ diff --git a/docs/static/icons/browserconfig.xml b/docs/static/icons/browserconfig.xml index 7e8a26a6..5aecc916 100644 --- a/docs/static/icons/browserconfig.xml +++ b/docs/static/icons/browserconfig.xml @@ -1,16 +1,9 @@ - - - - - - -<<<<<<< HEAD - #da532c -======= - #9f00a7 ->>>>>>> microbit/master - - + + + + #00aba9 + + diff --git a/docs/static/icons/favicon-16x16.png b/docs/static/icons/favicon-16x16.png index 28caab92..63dc7ec9 100644 Binary files a/docs/static/icons/favicon-16x16.png and b/docs/static/icons/favicon-16x16.png differ diff --git a/docs/static/icons/favicon-32x32.png b/docs/static/icons/favicon-32x32.png index 909e8ff1..c26e80b8 100644 Binary files a/docs/static/icons/favicon-32x32.png and b/docs/static/icons/favicon-32x32.png differ diff --git a/docs/static/icons/favicon.ico b/docs/static/icons/favicon.ico index 16625b1f..ae354412 100644 Binary files a/docs/static/icons/favicon.ico and b/docs/static/icons/favicon.ico differ diff --git a/docs/static/icons/manifest.json b/docs/static/icons/manifest.json index 659f2f9a..339e99ba 100644 --- a/docs/static/icons/manifest.json +++ b/docs/static/icons/manifest.json @@ -1,5 +1,5 @@ { - "name": "Calliope mini", + "name": "makecode.microbit.org", "icons": [ { "src": "\/android-chrome-36x36.png", diff --git a/docs/static/icons/mstile-144x144.png b/docs/static/icons/mstile-144x144.png deleted file mode 100644 index e7999906..00000000 Binary files a/docs/static/icons/mstile-144x144.png and /dev/null differ diff --git a/docs/static/icons/mstile-150x150.png b/docs/static/icons/mstile-150x150.png index f7396c3b..614e5911 100644 Binary files a/docs/static/icons/mstile-150x150.png and b/docs/static/icons/mstile-150x150.png differ diff --git a/docs/static/icons/mstile-310x150.png b/docs/static/icons/mstile-310x150.png deleted file mode 100644 index b246769f..00000000 Binary files a/docs/static/icons/mstile-310x150.png and /dev/null differ diff --git a/docs/static/icons/mstile-310x310.png b/docs/static/icons/mstile-310x310.png deleted file mode 100644 index 5cc42c85..00000000 Binary files a/docs/static/icons/mstile-310x310.png and /dev/null differ diff --git a/docs/static/icons/mstile-70x70.png b/docs/static/icons/mstile-70x70.png deleted file mode 100644 index bfe97023..00000000 Binary files a/docs/static/icons/mstile-70x70.png and /dev/null differ diff --git a/docs/static/icons/safari-pinned-tab.svg b/docs/static/icons/safari-pinned-tab.svg index 3a988d95..8e668a10 100644 --- a/docs/static/icons/safari-pinned-tab.svg +++ b/docs/static/icons/safari-pinned-tab.svg @@ -9,35 +9,18 @@ Created by potrace 1.11, written by Peter Selinger 2001-2013 - + diff --git a/docs/static/logo_texture.png b/docs/static/logo_texture.png new file mode 100644 index 00000000..7d92d326 Binary files /dev/null and b/docs/static/logo_texture.png differ diff --git a/docs/static/logo_texture2.png b/docs/static/logo_texture2.png new file mode 100644 index 00000000..80e1cab5 Binary files /dev/null and b/docs/static/logo_texture2.png differ diff --git a/docs/static/logo_texture3.png b/docs/static/logo_texture3.png new file mode 100644 index 00000000..a0b0e7cc Binary files /dev/null and b/docs/static/logo_texture3.png differ diff --git a/docs/static/mb/acc.png b/docs/static/mb/acc.png deleted file mode 100644 index 7e4310e5..00000000 Binary files a/docs/static/mb/acc.png and /dev/null differ diff --git a/docs/static/mb/acc2.png b/docs/static/mb/acc2.png deleted file mode 100644 index 07c68713..00000000 Binary files a/docs/static/mb/acc2.png and /dev/null differ diff --git a/docs/static/mb/analyze1.png b/docs/static/mb/analyze1.png deleted file mode 100644 index 4c5b6ba3..00000000 Binary files a/docs/static/mb/analyze1.png and /dev/null differ diff --git a/docs/static/mb/analyze3.png b/docs/static/mb/analyze3.png deleted file mode 100644 index fac50a40..00000000 Binary files a/docs/static/mb/analyze3.png and /dev/null differ diff --git a/docs/static/mb/blocks/contents-0.png b/docs/static/mb/blocks/contents-0.png deleted file mode 100644 index 5dd3fe48..00000000 Binary files a/docs/static/mb/blocks/contents-0.png and /dev/null differ diff --git a/docs/static/mb/blocks/image-0.png b/docs/static/mb/blocks/image-0.png deleted file mode 100644 index 53fc0fbb..00000000 Binary files a/docs/static/mb/blocks/image-0.png and /dev/null differ diff --git a/docs/static/mb/blocks/lessons/graphics-0.png b/docs/static/mb/blocks/lessons/graphics-0.png deleted file mode 100644 index 577c6478..00000000 Binary files a/docs/static/mb/blocks/lessons/graphics-0.png and /dev/null differ diff --git a/docs/static/mb/blocks/lessons/graphics-4.png b/docs/static/mb/blocks/lessons/graphics-4.png deleted file mode 100644 index 89175a07..00000000 Binary files a/docs/static/mb/blocks/lessons/graphics-4.png and /dev/null differ diff --git a/docs/static/mb/blocks/lessons/loops-0.png b/docs/static/mb/blocks/lessons/loops-0.png deleted file mode 100644 index f2f02da1..00000000 Binary files a/docs/static/mb/blocks/lessons/loops-0.png and /dev/null differ diff --git a/docs/static/mb/blocks/lessons/loops-1.png b/docs/static/mb/blocks/lessons/loops-1.png deleted file mode 100644 index bd455405..00000000 Binary files a/docs/static/mb/blocks/lessons/loops-1.png and /dev/null differ diff --git a/docs/static/mb/blocks/lessons/loops-2.png b/docs/static/mb/blocks/lessons/loops-2.png deleted file mode 100644 index 8a9fe3ab..00000000 Binary files a/docs/static/mb/blocks/lessons/loops-2.png and /dev/null differ diff --git a/docs/static/mb/blocks/lessons/loops-3.png b/docs/static/mb/blocks/lessons/loops-3.png deleted file mode 100644 index 0fe89bc0..00000000 Binary files a/docs/static/mb/blocks/lessons/loops-3.png and /dev/null differ diff --git a/docs/static/mb/blocks/lessons/screen-wipe-4.png b/docs/static/mb/blocks/lessons/screen-wipe-4.png deleted file mode 100644 index d4602738..00000000 Binary files a/docs/static/mb/blocks/lessons/screen-wipe-4.png and /dev/null differ diff --git a/docs/static/mb/blocks/lessons/smiley-4.png b/docs/static/mb/blocks/lessons/smiley-4.png deleted file mode 100644 index 81644a43..00000000 Binary files a/docs/static/mb/blocks/lessons/smiley-4.png and /dev/null differ diff --git a/docs/static/mb/blocks/lessons/smiley-6.png b/docs/static/mb/blocks/lessons/smiley-6.png deleted file mode 100644 index c773cc86..00000000 Binary files a/docs/static/mb/blocks/lessons/smiley-6.png and /dev/null differ diff --git a/docs/static/mb/blocks/lessons/variables-0.png b/docs/static/mb/blocks/lessons/variables-0.png deleted file mode 100644 index d6c398bf..00000000 Binary files a/docs/static/mb/blocks/lessons/variables-0.png and /dev/null differ diff --git a/docs/static/mb/blocks/lessons/variables-1.png b/docs/static/mb/blocks/lessons/variables-1.png deleted file mode 100644 index 2be74cb7..00000000 Binary files a/docs/static/mb/blocks/lessons/variables-1.png and /dev/null differ diff --git a/docs/static/mb/chart_title.png b/docs/static/mb/chart_title.png deleted file mode 100644 index 25dba72b..00000000 Binary files a/docs/static/mb/chart_title.png and /dev/null differ diff --git a/docs/static/mb/crocodile-clips-2.jpg b/docs/static/mb/crocodile-clips-2.jpg deleted file mode 100644 index 633738dd..00000000 Binary files a/docs/static/mb/crocodile-clips-2.jpg and /dev/null differ diff --git a/docs/static/mb/csv.png b/docs/static/mb/csv.png deleted file mode 100644 index b54464e4..00000000 Binary files a/docs/static/mb/csv.png and /dev/null differ diff --git a/docs/static/mb/data-0.png b/docs/static/mb/data-0.png deleted file mode 100644 index b47e728c..00000000 Binary files a/docs/static/mb/data-0.png and /dev/null differ diff --git a/docs/static/mb/data2.png b/docs/static/mb/data2.png deleted file mode 100644 index 32ef1ca5..00000000 Binary files a/docs/static/mb/data2.png and /dev/null differ diff --git a/docs/static/mb/data3.png b/docs/static/mb/data3.png deleted file mode 100644 index c312cf1c..00000000 Binary files a/docs/static/mb/data3.png and /dev/null differ diff --git a/docs/static/mb/data4.png b/docs/static/mb/data4.png deleted file mode 100644 index e9923003..00000000 Binary files a/docs/static/mb/data4.png and /dev/null differ diff --git a/docs/static/mb/data7.png b/docs/static/mb/data7.png deleted file mode 100644 index c13f8474..00000000 Binary files a/docs/static/mb/data7.png and /dev/null differ diff --git a/docs/static/mb/device-0.png b/docs/static/mb/device-0.png deleted file mode 100644 index b7c7358b..00000000 Binary files a/docs/static/mb/device-0.png and /dev/null differ diff --git a/docs/static/mb/device-1.jpg b/docs/static/mb/device-1.jpg deleted file mode 100644 index ae9f8ec6..00000000 Binary files a/docs/static/mb/device-1.jpg and /dev/null differ diff --git a/docs/static/mb/device/croc-clips/badclamp.jpg b/docs/static/mb/device/croc-clips/badclamp.jpg deleted file mode 100644 index 315d4efe..00000000 Binary files a/docs/static/mb/device/croc-clips/badclamp.jpg and /dev/null differ diff --git a/docs/static/mb/device/croc-clips/crocclipsclamped.jpg b/docs/static/mb/device/croc-clips/crocclipsclamped.jpg deleted file mode 100644 index 97c0a42a..00000000 Binary files a/docs/static/mb/device/croc-clips/crocclipsclamped.jpg and /dev/null differ diff --git a/docs/static/mb/device/croc-clips/foilcircuit.jpg b/docs/static/mb/device/croc-clips/foilcircuit.jpg deleted file mode 100644 index a2f8a1af..00000000 Binary files a/docs/static/mb/device/croc-clips/foilcircuit.jpg and /dev/null differ diff --git a/docs/static/mb/device/croc-clips/foilcut.jpg b/docs/static/mb/device/croc-clips/foilcut.jpg deleted file mode 100644 index ea6dc2f0..00000000 Binary files a/docs/static/mb/device/croc-clips/foilcut.jpg and /dev/null differ diff --git a/docs/static/mb/device/croc-clips/frontclamp.jpg b/docs/static/mb/device/croc-clips/frontclamp.jpg deleted file mode 100644 index eca31b20..00000000 Binary files a/docs/static/mb/device/croc-clips/frontclamp.jpg and /dev/null differ diff --git a/docs/static/mb/device/croc-clips/groundconnected.jpg b/docs/static/mb/device/croc-clips/groundconnected.jpg deleted file mode 100644 index 43f64c9a..00000000 Binary files a/docs/static/mb/device/croc-clips/groundconnected.jpg and /dev/null differ diff --git a/docs/static/mb/device/croc-clips/jackconnect.jpg b/docs/static/mb/device/croc-clips/jackconnect.jpg deleted file mode 100644 index ac84336b..00000000 Binary files a/docs/static/mb/device/croc-clips/jackconnect.jpg and /dev/null differ diff --git a/docs/static/mb/device/croc-clips/jackground.jpg b/docs/static/mb/device/croc-clips/jackground.jpg deleted file mode 100644 index b791178b..00000000 Binary files a/docs/static/mb/device/croc-clips/jackground.jpg and /dev/null differ diff --git a/docs/static/mb/device/croc-clips/microbitattached.jpg b/docs/static/mb/device/croc-clips/microbitattached.jpg deleted file mode 100644 index 35c88ecf..00000000 Binary files a/docs/static/mb/device/croc-clips/microbitattached.jpg and /dev/null differ diff --git a/docs/static/mb/device/croc-clips/microbitconnect.jpg b/docs/static/mb/device/croc-clips/microbitconnect.jpg deleted file mode 100644 index 5c7532df..00000000 Binary files a/docs/static/mb/device/croc-clips/microbitconnect.jpg and /dev/null differ diff --git a/docs/static/mb/device/croc-clips/sideclamp.jpg b/docs/static/mb/device/croc-clips/sideclamp.jpg deleted file mode 100644 index 24db12cc..00000000 Binary files a/docs/static/mb/device/croc-clips/sideclamp.jpg and /dev/null differ diff --git a/docs/static/mb/device/pano.jpg b/docs/static/mb/device/pano.jpg deleted file mode 100644 index df4c95a1..00000000 Binary files a/docs/static/mb/device/pano.jpg and /dev/null differ diff --git a/docs/static/mb/device/pins-0.png b/docs/static/mb/device/pins-0.png deleted file mode 100644 index 64c6ccff..00000000 Binary files a/docs/static/mb/device/pins-0.png and /dev/null differ diff --git a/docs/static/mb/device/reactive-0.png b/docs/static/mb/device/reactive-0.png deleted file mode 100644 index ca6fdf5d..00000000 Binary files a/docs/static/mb/device/reactive-0.png and /dev/null differ diff --git a/docs/static/mb/device/reactive-1.png b/docs/static/mb/device/reactive-1.png deleted file mode 100644 index 724cf676..00000000 Binary files a/docs/static/mb/device/reactive-1.png and /dev/null differ diff --git a/docs/static/mb/device/reactive-3.png b/docs/static/mb/device/reactive-3.png deleted file mode 100644 index 163122fb..00000000 Binary files a/docs/static/mb/device/reactive-3.png and /dev/null differ diff --git a/docs/static/mb/device/usb-generic.jpg b/docs/static/mb/device/usb-generic.jpg deleted file mode 100644 index e605c8d9..00000000 Binary files a/docs/static/mb/device/usb-generic.jpg and /dev/null differ diff --git a/docs/static/mb/device/usb-mac.jpg b/docs/static/mb/device/usb-mac.jpg deleted file mode 100644 index 48570d3e..00000000 Binary files a/docs/static/mb/device/usb-mac.jpg and /dev/null differ diff --git a/docs/static/mb/device/usb-osx-chrome.png b/docs/static/mb/device/usb-osx-chrome.png deleted file mode 100644 index b4533195..00000000 Binary files a/docs/static/mb/device/usb-osx-chrome.png and /dev/null differ diff --git a/docs/static/mb/device/usb-osx-copy-file-error.png b/docs/static/mb/device/usb-osx-copy-file-error.png deleted file mode 100644 index 7e20ec90..00000000 Binary files a/docs/static/mb/device/usb-osx-copy-file-error.png and /dev/null differ diff --git a/docs/static/mb/device/usb-osx-device.png b/docs/static/mb/device/usb-osx-device.png deleted file mode 100644 index 16ee59aa..00000000 Binary files a/docs/static/mb/device/usb-osx-device.png and /dev/null differ diff --git a/docs/static/mb/device/usb-osx-dnd.png b/docs/static/mb/device/usb-osx-dnd.png deleted file mode 100644 index cd213349..00000000 Binary files a/docs/static/mb/device/usb-osx-dnd.png and /dev/null differ diff --git a/docs/static/mb/device/usb-osx-firefox-1.jpg b/docs/static/mb/device/usb-osx-firefox-1.jpg deleted file mode 100644 index eea0fad3..00000000 Binary files a/docs/static/mb/device/usb-osx-firefox-1.jpg and /dev/null differ diff --git a/docs/static/mb/device/usb-osx-firefox-2.png b/docs/static/mb/device/usb-osx-firefox-2.png deleted file mode 100644 index 97c38a68..00000000 Binary files a/docs/static/mb/device/usb-osx-firefox-2.png and /dev/null differ diff --git a/docs/static/mb/device/usb-thin.jpg b/docs/static/mb/device/usb-thin.jpg deleted file mode 100644 index 051cb493..00000000 Binary files a/docs/static/mb/device/usb-thin.jpg and /dev/null differ diff --git a/docs/static/mb/device/usb-windows-chrome.png b/docs/static/mb/device/usb-windows-chrome.png deleted file mode 100644 index 89eb9a94..00000000 Binary files a/docs/static/mb/device/usb-windows-chrome.png and /dev/null differ diff --git a/docs/static/mb/device/usb-windows-copy-file-error.jpg b/docs/static/mb/device/usb-windows-copy-file-error.jpg deleted file mode 100644 index 05a55a1f..00000000 Binary files a/docs/static/mb/device/usb-windows-copy-file-error.jpg and /dev/null differ diff --git a/docs/static/mb/device/usb-windows-device.jpg b/docs/static/mb/device/usb-windows-device.jpg deleted file mode 100644 index ea3c2d68..00000000 Binary files a/docs/static/mb/device/usb-windows-device.jpg and /dev/null differ diff --git a/docs/static/mb/device/usb-windows-edge-1.png b/docs/static/mb/device/usb-windows-edge-1.png deleted file mode 100644 index 07831fdc..00000000 Binary files a/docs/static/mb/device/usb-windows-edge-1.png and /dev/null differ diff --git a/docs/static/mb/device/usb-windows-edge-2.png b/docs/static/mb/device/usb-windows-edge-2.png deleted file mode 100644 index aad1cae9..00000000 Binary files a/docs/static/mb/device/usb-windows-edge-2.png and /dev/null differ diff --git a/docs/static/mb/device/usb-windows-firefox-1.png b/docs/static/mb/device/usb-windows-firefox-1.png deleted file mode 100644 index 83a7c17d..00000000 Binary files a/docs/static/mb/device/usb-windows-firefox-1.png and /dev/null differ diff --git a/docs/static/mb/device/usb-windows-firefox-2.jpg b/docs/static/mb/device/usb-windows-firefox-2.jpg deleted file mode 100644 index 416e42ed..00000000 Binary files a/docs/static/mb/device/usb-windows-firefox-2.jpg and /dev/null differ diff --git a/docs/static/mb/device/usb-windows-ie11-1.png b/docs/static/mb/device/usb-windows-ie11-1.png deleted file mode 100644 index 5a3e3bfd..00000000 Binary files a/docs/static/mb/device/usb-windows-ie11-1.png and /dev/null differ diff --git a/docs/static/mb/device/usb-windows-ie11-2.png b/docs/static/mb/device/usb-windows-ie11-2.png deleted file mode 100644 index d18c8dbe..00000000 Binary files a/docs/static/mb/device/usb-windows-ie11-2.png and /dev/null differ diff --git a/docs/static/mb/device/usb-windows-sendto.jpg b/docs/static/mb/device/usb-windows-sendto.jpg deleted file mode 100644 index 5ffb02b4..00000000 Binary files a/docs/static/mb/device/usb-windows-sendto.jpg and /dev/null differ diff --git a/docs/static/mb/elements_styles_filters.png b/docs/static/mb/elements_styles_filters.png deleted file mode 100644 index f1ea55d5..00000000 Binary files a/docs/static/mb/elements_styles_filters.png and /dev/null differ diff --git a/docs/static/mb/empty-microbit.png b/docs/static/mb/empty-microbit.png deleted file mode 100644 index 18299903..00000000 Binary files a/docs/static/mb/empty-microbit.png and /dev/null differ diff --git a/docs/static/mb/image-0.png b/docs/static/mb/image-0.png deleted file mode 100644 index 07759140..00000000 Binary files a/docs/static/mb/image-0.png and /dev/null differ diff --git a/docs/static/mb/js/basicFuns.png b/docs/static/mb/js/basicFuns.png deleted file mode 100644 index c5bc257c..00000000 Binary files a/docs/static/mb/js/basicFuns.png and /dev/null differ diff --git a/docs/static/mb/js/basicIntell.png b/docs/static/mb/js/basicIntell.png deleted file mode 100644 index 67d095d1..00000000 Binary files a/docs/static/mb/js/basicIntell.png and /dev/null differ diff --git a/docs/static/mb/js/forIntell.png b/docs/static/mb/js/forIntell.png deleted file mode 100644 index 687e55e3..00000000 Binary files a/docs/static/mb/js/forIntell.png and /dev/null differ diff --git a/docs/static/mb/lessons/analyze.png b/docs/static/mb/lessons/analyze.png deleted file mode 100644 index 0d97742a..00000000 Binary files a/docs/static/mb/lessons/analyze.png and /dev/null differ diff --git a/docs/static/mb/lessons/analyze1.png b/docs/static/mb/lessons/analyze1.png deleted file mode 100644 index 4c5b6ba3..00000000 Binary files a/docs/static/mb/lessons/analyze1.png and /dev/null differ diff --git a/docs/static/mb/lessons/analyze16.png b/docs/static/mb/lessons/analyze16.png deleted file mode 100644 index 83125563..00000000 Binary files a/docs/static/mb/lessons/analyze16.png and /dev/null differ diff --git a/docs/static/mb/lessons/analyze19.png b/docs/static/mb/lessons/analyze19.png deleted file mode 100644 index ddfc06be..00000000 Binary files a/docs/static/mb/lessons/analyze19.png and /dev/null differ diff --git a/docs/static/mb/lessons/analyze2.png b/docs/static/mb/lessons/analyze2.png deleted file mode 100644 index 4634507e..00000000 Binary files a/docs/static/mb/lessons/analyze2.png and /dev/null differ diff --git a/docs/static/mb/lessons/analyze20.png b/docs/static/mb/lessons/analyze20.png deleted file mode 100644 index e51f66d6..00000000 Binary files a/docs/static/mb/lessons/analyze20.png and /dev/null differ diff --git a/docs/static/mb/lessons/analyze3.png b/docs/static/mb/lessons/analyze3.png deleted file mode 100644 index fac50a40..00000000 Binary files a/docs/static/mb/lessons/analyze3.png and /dev/null differ diff --git a/docs/static/mb/lessons/analyze5.png b/docs/static/mb/lessons/analyze5.png deleted file mode 100644 index dc11a8af..00000000 Binary files a/docs/static/mb/lessons/analyze5.png and /dev/null differ diff --git a/docs/static/mb/lessons/analyze6.png b/docs/static/mb/lessons/analyze6.png deleted file mode 100644 index 83125563..00000000 Binary files a/docs/static/mb/lessons/analyze6.png and /dev/null differ diff --git a/docs/static/mb/lessons/analyze7.png b/docs/static/mb/lessons/analyze7.png deleted file mode 100644 index 1b612c4d..00000000 Binary files a/docs/static/mb/lessons/analyze7.png and /dev/null differ diff --git a/docs/static/mb/lessons/analyze8.png b/docs/static/mb/lessons/analyze8.png deleted file mode 100644 index 446b68c8..00000000 Binary files a/docs/static/mb/lessons/analyze8.png and /dev/null differ diff --git a/docs/static/mb/lessons/analyze9.png b/docs/static/mb/lessons/analyze9.png deleted file mode 100644 index 7aba0082..00000000 Binary files a/docs/static/mb/lessons/analyze9.png and /dev/null differ diff --git a/docs/static/mb/lessons/answering-machine-0.png b/docs/static/mb/lessons/answering-machine-0.png deleted file mode 100644 index d29260a0..00000000 Binary files a/docs/static/mb/lessons/answering-machine-0.png and /dev/null differ diff --git a/docs/static/mb/lessons/answering-machine-1.png b/docs/static/mb/lessons/answering-machine-1.png deleted file mode 100644 index 10c8f632..00000000 Binary files a/docs/static/mb/lessons/answering-machine-1.png and /dev/null differ diff --git a/docs/static/mb/lessons/answering-machine-2.png b/docs/static/mb/lessons/answering-machine-2.png deleted file mode 100644 index 30a82735..00000000 Binary files a/docs/static/mb/lessons/answering-machine-2.png and /dev/null differ diff --git a/docs/static/mb/lessons/answering-machine-4.png b/docs/static/mb/lessons/answering-machine-4.png deleted file mode 100644 index 15fa4c34..00000000 Binary files a/docs/static/mb/lessons/answering-machine-4.png and /dev/null differ diff --git a/docs/static/mb/lessons/banana-keyboard-0.png b/docs/static/mb/lessons/banana-keyboard-0.png deleted file mode 100644 index a9b218ee..00000000 Binary files a/docs/static/mb/lessons/banana-keyboard-0.png and /dev/null differ diff --git a/docs/static/mb/lessons/banana-keyboard-1.png b/docs/static/mb/lessons/banana-keyboard-1.png deleted file mode 100644 index 9ddb8832..00000000 Binary files a/docs/static/mb/lessons/banana-keyboard-1.png and /dev/null differ diff --git a/docs/static/mb/lessons/banana-keyboard-10.png b/docs/static/mb/lessons/banana-keyboard-10.png deleted file mode 100644 index 9e982914..00000000 Binary files a/docs/static/mb/lessons/banana-keyboard-10.png and /dev/null differ diff --git a/docs/static/mb/lessons/banana-keyboard-11.png b/docs/static/mb/lessons/banana-keyboard-11.png deleted file mode 100644 index bb6ae2cd..00000000 Binary files a/docs/static/mb/lessons/banana-keyboard-11.png and /dev/null differ diff --git a/docs/static/mb/lessons/banana-keyboard-12.png b/docs/static/mb/lessons/banana-keyboard-12.png deleted file mode 100644 index 020a11bd..00000000 Binary files a/docs/static/mb/lessons/banana-keyboard-12.png and /dev/null differ diff --git a/docs/static/mb/lessons/banana-keyboard-2.png b/docs/static/mb/lessons/banana-keyboard-2.png deleted file mode 100644 index e3983d0b..00000000 Binary files a/docs/static/mb/lessons/banana-keyboard-2.png and /dev/null differ diff --git a/docs/static/mb/lessons/banana-keyboard-3.png b/docs/static/mb/lessons/banana-keyboard-3.png deleted file mode 100644 index 4c261f3b..00000000 Binary files a/docs/static/mb/lessons/banana-keyboard-3.png and /dev/null differ diff --git a/docs/static/mb/lessons/banana-keyboard-4.png b/docs/static/mb/lessons/banana-keyboard-4.png deleted file mode 100644 index c1be8631..00000000 Binary files a/docs/static/mb/lessons/banana-keyboard-4.png and /dev/null differ diff --git a/docs/static/mb/lessons/banana-keyboard-5.png b/docs/static/mb/lessons/banana-keyboard-5.png deleted file mode 100644 index c20ea3b3..00000000 Binary files a/docs/static/mb/lessons/banana-keyboard-5.png and /dev/null differ diff --git a/docs/static/mb/lessons/banana-keyboard-6.png b/docs/static/mb/lessons/banana-keyboard-6.png deleted file mode 100644 index f5edaeed..00000000 Binary files a/docs/static/mb/lessons/banana-keyboard-6.png and /dev/null differ diff --git a/docs/static/mb/lessons/banana-keyboard-7.png b/docs/static/mb/lessons/banana-keyboard-7.png deleted file mode 100644 index 54793044..00000000 Binary files a/docs/static/mb/lessons/banana-keyboard-7.png and /dev/null differ diff --git a/docs/static/mb/lessons/banana-keyboard-8.png b/docs/static/mb/lessons/banana-keyboard-8.png deleted file mode 100644 index 14739ed6..00000000 Binary files a/docs/static/mb/lessons/banana-keyboard-8.png and /dev/null differ diff --git a/docs/static/mb/lessons/banana-keyboard-9.png b/docs/static/mb/lessons/banana-keyboard-9.png deleted file mode 100644 index ba760b3e..00000000 Binary files a/docs/static/mb/lessons/banana-keyboard-9.png and /dev/null differ diff --git a/docs/static/mb/lessons/blink-0.png b/docs/static/mb/lessons/blink-0.png deleted file mode 100644 index 4e1c4aeb..00000000 Binary files a/docs/static/mb/lessons/blink-0.png and /dev/null differ diff --git a/docs/static/mb/lessons/blink-1.png b/docs/static/mb/lessons/blink-1.png deleted file mode 100644 index 1639a3fd..00000000 Binary files a/docs/static/mb/lessons/blink-1.png and /dev/null differ diff --git a/docs/static/mb/lessons/blink-2.png b/docs/static/mb/lessons/blink-2.png deleted file mode 100644 index b0222961..00000000 Binary files a/docs/static/mb/lessons/blink-2.png and /dev/null differ diff --git a/docs/static/mb/lessons/cascade-0.png b/docs/static/mb/lessons/cascade-0.png deleted file mode 100644 index bd8fe973..00000000 Binary files a/docs/static/mb/lessons/cascade-0.png and /dev/null differ diff --git a/docs/static/mb/lessons/cascade-1.png b/docs/static/mb/lessons/cascade-1.png deleted file mode 100644 index eecf6536..00000000 Binary files a/docs/static/mb/lessons/cascade-1.png and /dev/null differ diff --git a/docs/static/mb/lessons/cascade-2.png b/docs/static/mb/lessons/cascade-2.png deleted file mode 100644 index 37ba14c7..00000000 Binary files a/docs/static/mb/lessons/cascade-2.png and /dev/null differ diff --git a/docs/static/mb/lessons/catch-the-egg-game-0.png b/docs/static/mb/lessons/catch-the-egg-game-0.png deleted file mode 100644 index 54129445..00000000 Binary files a/docs/static/mb/lessons/catch-the-egg-game-0.png and /dev/null differ diff --git a/docs/static/mb/lessons/chart1.png b/docs/static/mb/lessons/chart1.png deleted file mode 100644 index 26f43c4e..00000000 Binary files a/docs/static/mb/lessons/chart1.png and /dev/null differ diff --git a/docs/static/mb/lessons/column-0.png b/docs/static/mb/lessons/column-0.png deleted file mode 100644 index 67ff1a07..00000000 Binary files a/docs/static/mb/lessons/column-0.png and /dev/null differ diff --git a/docs/static/mb/lessons/column-1.png b/docs/static/mb/lessons/column-1.png deleted file mode 100644 index 6323a67e..00000000 Binary files a/docs/static/mb/lessons/column-1.png and /dev/null differ diff --git a/docs/static/mb/lessons/counter-0.png b/docs/static/mb/lessons/counter-0.png deleted file mode 100644 index c2abb0f6..00000000 Binary files a/docs/static/mb/lessons/counter-0.png and /dev/null differ diff --git a/docs/static/mb/lessons/counter-1.png b/docs/static/mb/lessons/counter-1.png deleted file mode 100644 index 29448958..00000000 Binary files a/docs/static/mb/lessons/counter-1.png and /dev/null differ diff --git a/docs/static/mb/lessons/counter-2.png b/docs/static/mb/lessons/counter-2.png deleted file mode 100644 index b924b9fd..00000000 Binary files a/docs/static/mb/lessons/counter-2.png and /dev/null differ diff --git a/docs/static/mb/lessons/data3.png b/docs/static/mb/lessons/data3.png deleted file mode 100644 index c312cf1c..00000000 Binary files a/docs/static/mb/lessons/data3.png and /dev/null differ diff --git a/docs/static/mb/lessons/die-roll-0.png b/docs/static/mb/lessons/die-roll-0.png deleted file mode 100644 index 472d18bb..00000000 Binary files a/docs/static/mb/lessons/die-roll-0.png and /dev/null differ diff --git a/docs/static/mb/lessons/die-roll-1.png b/docs/static/mb/lessons/die-roll-1.png deleted file mode 100644 index 532bd452..00000000 Binary files a/docs/static/mb/lessons/die-roll-1.png and /dev/null differ diff --git a/docs/static/mb/lessons/die-roll-2.png b/docs/static/mb/lessons/die-roll-2.png deleted file mode 100644 index f6594952..00000000 Binary files a/docs/static/mb/lessons/die-roll-2.png and /dev/null differ diff --git a/docs/static/mb/lessons/die-roll-3.png b/docs/static/mb/lessons/die-roll-3.png deleted file mode 100644 index 1e582cac..00000000 Binary files a/docs/static/mb/lessons/die-roll-3.png and /dev/null differ diff --git a/docs/static/mb/lessons/digi-yoyo-0.png b/docs/static/mb/lessons/digi-yoyo-0.png deleted file mode 100644 index 917ce0e7..00000000 Binary files a/docs/static/mb/lessons/digi-yoyo-0.png and /dev/null differ diff --git a/docs/static/mb/lessons/flashing-heart-0.png b/docs/static/mb/lessons/flashing-heart-0.png deleted file mode 100644 index a8e04a87..00000000 Binary files a/docs/static/mb/lessons/flashing-heart-0.png and /dev/null differ diff --git a/docs/static/mb/lessons/flipping-bird-0.png b/docs/static/mb/lessons/flipping-bird-0.png deleted file mode 100644 index a28b2ea6..00000000 Binary files a/docs/static/mb/lessons/flipping-bird-0.png and /dev/null differ diff --git a/docs/static/mb/lessons/flipping-bird-1.png b/docs/static/mb/lessons/flipping-bird-1.png deleted file mode 100644 index 44abf050..00000000 Binary files a/docs/static/mb/lessons/flipping-bird-1.png and /dev/null differ diff --git a/docs/static/mb/lessons/glowing-pendulum-0.jpg b/docs/static/mb/lessons/glowing-pendulum-0.jpg deleted file mode 100644 index b5ad4ee4..00000000 Binary files a/docs/static/mb/lessons/glowing-pendulum-0.jpg and /dev/null differ diff --git a/docs/static/mb/lessons/glowing-pendulum-1.png b/docs/static/mb/lessons/glowing-pendulum-1.png deleted file mode 100644 index fc30a4df..00000000 Binary files a/docs/static/mb/lessons/glowing-pendulum-1.png and /dev/null differ diff --git a/docs/static/mb/lessons/guess-the-number-0.png b/docs/static/mb/lessons/guess-the-number-0.png deleted file mode 100644 index 979f06f6..00000000 Binary files a/docs/static/mb/lessons/guess-the-number-0.png and /dev/null differ diff --git a/docs/static/mb/lessons/hack-your-headphones-0.png b/docs/static/mb/lessons/hack-your-headphones-0.png deleted file mode 100644 index ba58df5a..00000000 Binary files a/docs/static/mb/lessons/hack-your-headphones-0.png and /dev/null differ diff --git a/docs/static/mb/lessons/hack-your-headphones-1.png b/docs/static/mb/lessons/hack-your-headphones-1.png deleted file mode 100644 index 42a68449..00000000 Binary files a/docs/static/mb/lessons/hack-your-headphones-1.png and /dev/null differ diff --git a/docs/static/mb/lessons/looper-0.png b/docs/static/mb/lessons/looper-0.png deleted file mode 100644 index eaf37d0d..00000000 Binary files a/docs/static/mb/lessons/looper-0.png and /dev/null differ diff --git a/docs/static/mb/lessons/looper-1.png b/docs/static/mb/lessons/looper-1.png deleted file mode 100644 index 4c832c21..00000000 Binary files a/docs/static/mb/lessons/looper-1.png and /dev/null differ diff --git a/docs/static/mb/lessons/looper-2.png b/docs/static/mb/lessons/looper-2.png deleted file mode 100644 index 3ae90577..00000000 Binary files a/docs/static/mb/lessons/looper-2.png and /dev/null differ diff --git a/docs/static/mb/lessons/looper-3.png b/docs/static/mb/lessons/looper-3.png deleted file mode 100644 index 701c0d3e..00000000 Binary files a/docs/static/mb/lessons/looper-3.png and /dev/null differ diff --git a/docs/static/mb/lessons/lucky-7-0.png b/docs/static/mb/lessons/lucky-7-0.png deleted file mode 100644 index e9c20c68..00000000 Binary files a/docs/static/mb/lessons/lucky-7-0.png and /dev/null differ diff --git a/docs/static/mb/lessons/lucky-7-1.png b/docs/static/mb/lessons/lucky-7-1.png deleted file mode 100644 index 05ed459f..00000000 Binary files a/docs/static/mb/lessons/lucky-7-1.png and /dev/null differ diff --git a/docs/static/mb/lessons/lucky-7-2.png b/docs/static/mb/lessons/lucky-7-2.png deleted file mode 100644 index 51bd9d80..00000000 Binary files a/docs/static/mb/lessons/lucky-7-2.png and /dev/null differ diff --git a/docs/static/mb/lessons/lucky-7-3.png b/docs/static/mb/lessons/lucky-7-3.png deleted file mode 100644 index 609e1895..00000000 Binary files a/docs/static/mb/lessons/lucky-7-3.png and /dev/null differ diff --git a/docs/static/mb/lessons/magic-logo-0.png b/docs/static/mb/lessons/magic-logo-0.png deleted file mode 100644 index 67bb4841..00000000 Binary files a/docs/static/mb/lessons/magic-logo-0.png and /dev/null differ diff --git a/docs/static/mb/lessons/night-light-0.png b/docs/static/mb/lessons/night-light-0.png deleted file mode 100644 index 8803fb65..00000000 Binary files a/docs/static/mb/lessons/night-light-0.png and /dev/null differ diff --git a/docs/static/mb/lessons/night-light-1.png b/docs/static/mb/lessons/night-light-1.png deleted file mode 100644 index 348e0382..00000000 Binary files a/docs/static/mb/lessons/night-light-1.png and /dev/null differ diff --git a/docs/static/mb/lessons/night-light-2.png b/docs/static/mb/lessons/night-light-2.png deleted file mode 100644 index 18299903..00000000 Binary files a/docs/static/mb/lessons/night-light-2.png and /dev/null differ diff --git a/docs/static/mb/lessons/offset-image-0.png b/docs/static/mb/lessons/offset-image-0.png deleted file mode 100644 index ba2a9afe..00000000 Binary files a/docs/static/mb/lessons/offset-image-0.png and /dev/null differ diff --git a/docs/static/mb/lessons/offset-image-1.png b/docs/static/mb/lessons/offset-image-1.png deleted file mode 100644 index 9c1827b8..00000000 Binary files a/docs/static/mb/lessons/offset-image-1.png and /dev/null differ diff --git a/docs/static/mb/lessons/ornament-chain-0.jpg b/docs/static/mb/lessons/ornament-chain-0.jpg deleted file mode 100644 index 45b7a1d5..00000000 Binary files a/docs/static/mb/lessons/ornament-chain-0.jpg and /dev/null differ diff --git a/docs/static/mb/lessons/ornament-chain-1.jpg b/docs/static/mb/lessons/ornament-chain-1.jpg deleted file mode 100644 index dd9242cf..00000000 Binary files a/docs/static/mb/lessons/ornament-chain-1.jpg and /dev/null differ diff --git a/docs/static/mb/lessons/ornament-chain-2.png b/docs/static/mb/lessons/ornament-chain-2.png deleted file mode 100644 index 07ce9637..00000000 Binary files a/docs/static/mb/lessons/ornament-chain-2.png and /dev/null differ diff --git a/docs/static/mb/lessons/ornament-chain-3.png b/docs/static/mb/lessons/ornament-chain-3.png deleted file mode 100644 index fe2ed067..00000000 Binary files a/docs/static/mb/lessons/ornament-chain-3.png and /dev/null differ diff --git a/docs/static/mb/lessons/ornament-chain-4.png b/docs/static/mb/lessons/ornament-chain-4.png deleted file mode 100644 index fb4d9882..00000000 Binary files a/docs/static/mb/lessons/ornament-chain-4.png and /dev/null differ diff --git a/docs/static/mb/lessons/ornament-chain-5.png b/docs/static/mb/lessons/ornament-chain-5.png deleted file mode 100644 index c9739202..00000000 Binary files a/docs/static/mb/lessons/ornament-chain-5.png and /dev/null differ diff --git a/docs/static/mb/lessons/ornament-chain-6.png b/docs/static/mb/lessons/ornament-chain-6.png deleted file mode 100644 index 24d1442c..00000000 Binary files a/docs/static/mb/lessons/ornament-chain-6.png and /dev/null differ diff --git a/docs/static/mb/lessons/ornament-chain-7.png b/docs/static/mb/lessons/ornament-chain-7.png deleted file mode 100644 index 707cb208..00000000 Binary files a/docs/static/mb/lessons/ornament-chain-7.png and /dev/null differ diff --git a/docs/static/mb/lessons/ornament-chain-8.png b/docs/static/mb/lessons/ornament-chain-8.png deleted file mode 100644 index b8537355..00000000 Binary files a/docs/static/mb/lessons/ornament-chain-8.png and /dev/null differ diff --git a/docs/static/mb/lessons/prank-wifi-0.png b/docs/static/mb/lessons/prank-wifi-0.png deleted file mode 100644 index dbdbe244..00000000 Binary files a/docs/static/mb/lessons/prank-wifi-0.png and /dev/null differ diff --git a/docs/static/mb/lessons/rotation-animation-0.png b/docs/static/mb/lessons/rotation-animation-0.png deleted file mode 100644 index 96352e44..00000000 Binary files a/docs/static/mb/lessons/rotation-animation-0.png and /dev/null differ diff --git a/docs/static/mb/lessons/rotation-animation-1.png b/docs/static/mb/lessons/rotation-animation-1.png deleted file mode 100644 index ba98236a..00000000 Binary files a/docs/static/mb/lessons/rotation-animation-1.png and /dev/null differ diff --git a/docs/static/mb/lessons/rotation-animation-2.png b/docs/static/mb/lessons/rotation-animation-2.png deleted file mode 100644 index 3953500c..00000000 Binary files a/docs/static/mb/lessons/rotation-animation-2.png and /dev/null differ diff --git a/docs/static/mb/lessons/rotation-animation-3.png b/docs/static/mb/lessons/rotation-animation-3.png deleted file mode 100644 index 488b3b02..00000000 Binary files a/docs/static/mb/lessons/rotation-animation-3.png and /dev/null differ diff --git a/docs/static/mb/lessons/screen-wipe-0.png b/docs/static/mb/lessons/screen-wipe-0.png deleted file mode 100644 index a1f7855c..00000000 Binary files a/docs/static/mb/lessons/screen-wipe-0.png and /dev/null differ diff --git a/docs/static/mb/lessons/seis_challenge01.png b/docs/static/mb/lessons/seis_challenge01.png deleted file mode 100644 index 0168a79f..00000000 Binary files a/docs/static/mb/lessons/seis_challenge01.png and /dev/null differ diff --git a/docs/static/mb/lessons/seis_challenge02.png b/docs/static/mb/lessons/seis_challenge02.png deleted file mode 100644 index a06111be..00000000 Binary files a/docs/static/mb/lessons/seis_challenge02.png and /dev/null differ diff --git a/docs/static/mb/lessons/seis_challenge04.png b/docs/static/mb/lessons/seis_challenge04.png deleted file mode 100644 index 3373604c..00000000 Binary files a/docs/static/mb/lessons/seis_challenge04.png and /dev/null differ diff --git a/docs/static/mb/lessons/seis_challenge05.png b/docs/static/mb/lessons/seis_challenge05.png deleted file mode 100644 index 47e2c79d..00000000 Binary files a/docs/static/mb/lessons/seis_challenge05.png and /dev/null differ diff --git a/docs/static/mb/lessons/seis_challenge06.png b/docs/static/mb/lessons/seis_challenge06.png deleted file mode 100644 index c0f69793..00000000 Binary files a/docs/static/mb/lessons/seis_challenge06.png and /dev/null differ diff --git a/docs/static/mb/lessons/seis_challenge07.png b/docs/static/mb/lessons/seis_challenge07.png deleted file mode 100644 index c9b233ad..00000000 Binary files a/docs/static/mb/lessons/seis_challenge07.png and /dev/null differ diff --git a/docs/static/mb/lessons/seismograph0.png b/docs/static/mb/lessons/seismograph0.png deleted file mode 100644 index 35b8ce7d..00000000 Binary files a/docs/static/mb/lessons/seismograph0.png and /dev/null differ diff --git a/docs/static/mb/lessons/seismograph1.png b/docs/static/mb/lessons/seismograph1.png deleted file mode 100644 index 45dba342..00000000 Binary files a/docs/static/mb/lessons/seismograph1.png and /dev/null differ diff --git a/docs/static/mb/lessons/seismograph10.png b/docs/static/mb/lessons/seismograph10.png deleted file mode 100644 index 322fd6a4..00000000 Binary files a/docs/static/mb/lessons/seismograph10.png and /dev/null differ diff --git a/docs/static/mb/lessons/seismograph11.png b/docs/static/mb/lessons/seismograph11.png deleted file mode 100644 index 5eafa75d..00000000 Binary files a/docs/static/mb/lessons/seismograph11.png and /dev/null differ diff --git a/docs/static/mb/lessons/seismograph22.png b/docs/static/mb/lessons/seismograph22.png deleted file mode 100644 index 6730eedf..00000000 Binary files a/docs/static/mb/lessons/seismograph22.png and /dev/null differ diff --git a/docs/static/mb/lessons/seismograph3.png b/docs/static/mb/lessons/seismograph3.png deleted file mode 100644 index 1208a67a..00000000 Binary files a/docs/static/mb/lessons/seismograph3.png and /dev/null differ diff --git a/docs/static/mb/lessons/seismograph32.png b/docs/static/mb/lessons/seismograph32.png deleted file mode 100644 index 6730eedf..00000000 Binary files a/docs/static/mb/lessons/seismograph32.png and /dev/null differ diff --git a/docs/static/mb/lessons/seismograph33.png b/docs/static/mb/lessons/seismograph33.png deleted file mode 100644 index 1208a67a..00000000 Binary files a/docs/static/mb/lessons/seismograph33.png and /dev/null differ diff --git a/docs/static/mb/lessons/seismograph5.png b/docs/static/mb/lessons/seismograph5.png deleted file mode 100644 index f5b0b98d..00000000 Binary files a/docs/static/mb/lessons/seismograph5.png and /dev/null differ diff --git a/docs/static/mb/lessons/seismograph6.png b/docs/static/mb/lessons/seismograph6.png deleted file mode 100644 index b26b8e22..00000000 Binary files a/docs/static/mb/lessons/seismograph6.png and /dev/null differ diff --git a/docs/static/mb/lessons/seismograph7.png b/docs/static/mb/lessons/seismograph7.png deleted file mode 100644 index 884c0c2d..00000000 Binary files a/docs/static/mb/lessons/seismograph7.png and /dev/null differ diff --git a/docs/static/mb/lessons/seismograph8.png b/docs/static/mb/lessons/seismograph8.png deleted file mode 100644 index efdb7d78..00000000 Binary files a/docs/static/mb/lessons/seismograph8.png and /dev/null differ diff --git a/docs/static/mb/lessons/seismograph9.png b/docs/static/mb/lessons/seismograph9.png deleted file mode 100644 index 322fd6a4..00000000 Binary files a/docs/static/mb/lessons/seismograph9.png and /dev/null differ diff --git a/docs/static/mb/lessons/smiley-0.png b/docs/static/mb/lessons/smiley-0.png deleted file mode 100644 index b2c5452f..00000000 Binary files a/docs/static/mb/lessons/smiley-0.png and /dev/null differ diff --git a/docs/static/mb/lessons/snowflake-fall-0.png b/docs/static/mb/lessons/snowflake-fall-0.png deleted file mode 100644 index 9c295dee..00000000 Binary files a/docs/static/mb/lessons/snowflake-fall-0.png and /dev/null differ diff --git a/docs/static/mb/lessons/snowflake-fall-1.png b/docs/static/mb/lessons/snowflake-fall-1.png deleted file mode 100644 index 92467302..00000000 Binary files a/docs/static/mb/lessons/snowflake-fall-1.png and /dev/null differ diff --git a/docs/static/mb/lessons/snowflake-fall-2.png b/docs/static/mb/lessons/snowflake-fall-2.png deleted file mode 100644 index 005c2da5..00000000 Binary files a/docs/static/mb/lessons/snowflake-fall-2.png and /dev/null differ diff --git a/docs/static/mb/lessons/speed-button-0.png b/docs/static/mb/lessons/speed-button-0.png deleted file mode 100644 index b98310ba..00000000 Binary files a/docs/static/mb/lessons/speed-button-0.png and /dev/null differ diff --git a/docs/static/mb/lessons/speed-button-1.png b/docs/static/mb/lessons/speed-button-1.png deleted file mode 100644 index 44abf050..00000000 Binary files a/docs/static/mb/lessons/speed-button-1.png and /dev/null differ diff --git a/docs/static/mb/lessons/speed-button-2.png b/docs/static/mb/lessons/speed-button-2.png deleted file mode 100644 index b00ec1eb..00000000 Binary files a/docs/static/mb/lessons/speed-button-2.png and /dev/null differ diff --git a/docs/static/mb/lessons/spinner-0.png b/docs/static/mb/lessons/spinner-0.png deleted file mode 100644 index 9c0b9390..00000000 Binary files a/docs/static/mb/lessons/spinner-0.png and /dev/null differ diff --git a/docs/static/mb/lessons/spinner-1.png b/docs/static/mb/lessons/spinner-1.png deleted file mode 100644 index 17c121d3..00000000 Binary files a/docs/static/mb/lessons/spinner-1.png and /dev/null differ diff --git a/docs/static/mb/lessons/telegraph-0.png b/docs/static/mb/lessons/telegraph-0.png deleted file mode 100644 index d5ebfdc5..00000000 Binary files a/docs/static/mb/lessons/telegraph-0.png and /dev/null differ diff --git a/docs/static/mb/lessons/the-watch-0.png b/docs/static/mb/lessons/the-watch-0.png deleted file mode 100644 index 177037e1..00000000 Binary files a/docs/static/mb/lessons/the-watch-0.png and /dev/null differ diff --git a/docs/static/mb/lessons/the-watch-1.png b/docs/static/mb/lessons/the-watch-1.png deleted file mode 100644 index d017662f..00000000 Binary files a/docs/static/mb/lessons/the-watch-1.png and /dev/null differ diff --git a/docs/static/mb/lessons/the-watch-10.png b/docs/static/mb/lessons/the-watch-10.png deleted file mode 100644 index c61ca460..00000000 Binary files a/docs/static/mb/lessons/the-watch-10.png and /dev/null differ diff --git a/docs/static/mb/lessons/the-watch-11.png b/docs/static/mb/lessons/the-watch-11.png deleted file mode 100644 index c8481af4..00000000 Binary files a/docs/static/mb/lessons/the-watch-11.png and /dev/null differ diff --git a/docs/static/mb/lessons/the-watch-12.png b/docs/static/mb/lessons/the-watch-12.png deleted file mode 100644 index 3d6a1f6b..00000000 Binary files a/docs/static/mb/lessons/the-watch-12.png and /dev/null differ diff --git a/docs/static/mb/lessons/the-watch-13.png b/docs/static/mb/lessons/the-watch-13.png deleted file mode 100644 index 1203b54f..00000000 Binary files a/docs/static/mb/lessons/the-watch-13.png and /dev/null differ diff --git a/docs/static/mb/lessons/the-watch-14.png b/docs/static/mb/lessons/the-watch-14.png deleted file mode 100644 index 6e810b19..00000000 Binary files a/docs/static/mb/lessons/the-watch-14.png and /dev/null differ diff --git a/docs/static/mb/lessons/the-watch-15.png b/docs/static/mb/lessons/the-watch-15.png deleted file mode 100644 index 96d036ec..00000000 Binary files a/docs/static/mb/lessons/the-watch-15.png and /dev/null differ diff --git a/docs/static/mb/lessons/the-watch-16.png b/docs/static/mb/lessons/the-watch-16.png deleted file mode 100644 index 9f7cbbde..00000000 Binary files a/docs/static/mb/lessons/the-watch-16.png and /dev/null differ diff --git a/docs/static/mb/lessons/the-watch-17.png b/docs/static/mb/lessons/the-watch-17.png deleted file mode 100644 index e0832e26..00000000 Binary files a/docs/static/mb/lessons/the-watch-17.png and /dev/null differ diff --git a/docs/static/mb/lessons/the-watch-18.png b/docs/static/mb/lessons/the-watch-18.png deleted file mode 100644 index 5af57520..00000000 Binary files a/docs/static/mb/lessons/the-watch-18.png and /dev/null differ diff --git a/docs/static/mb/lessons/the-watch-19.png b/docs/static/mb/lessons/the-watch-19.png deleted file mode 100644 index ad5e73bc..00000000 Binary files a/docs/static/mb/lessons/the-watch-19.png and /dev/null differ diff --git a/docs/static/mb/lessons/the-watch-2.png b/docs/static/mb/lessons/the-watch-2.png deleted file mode 100644 index 4cf5127c..00000000 Binary files a/docs/static/mb/lessons/the-watch-2.png and /dev/null differ diff --git a/docs/static/mb/lessons/the-watch-20.png b/docs/static/mb/lessons/the-watch-20.png deleted file mode 100644 index 8be6874f..00000000 Binary files a/docs/static/mb/lessons/the-watch-20.png and /dev/null differ diff --git a/docs/static/mb/lessons/the-watch-21.png b/docs/static/mb/lessons/the-watch-21.png deleted file mode 100644 index e241b25f..00000000 Binary files a/docs/static/mb/lessons/the-watch-21.png and /dev/null differ diff --git a/docs/static/mb/lessons/the-watch-22.png b/docs/static/mb/lessons/the-watch-22.png deleted file mode 100644 index a9e28360..00000000 Binary files a/docs/static/mb/lessons/the-watch-22.png and /dev/null differ diff --git a/docs/static/mb/lessons/the-watch-23.png b/docs/static/mb/lessons/the-watch-23.png deleted file mode 100644 index b2705794..00000000 Binary files a/docs/static/mb/lessons/the-watch-23.png and /dev/null differ diff --git a/docs/static/mb/lessons/the-watch-3.png b/docs/static/mb/lessons/the-watch-3.png deleted file mode 100644 index f8072ef2..00000000 Binary files a/docs/static/mb/lessons/the-watch-3.png and /dev/null differ diff --git a/docs/static/mb/lessons/the-watch-4.png b/docs/static/mb/lessons/the-watch-4.png deleted file mode 100644 index 86c539e1..00000000 Binary files a/docs/static/mb/lessons/the-watch-4.png and /dev/null differ diff --git a/docs/static/mb/lessons/the-watch-5.png b/docs/static/mb/lessons/the-watch-5.png deleted file mode 100644 index 0681a2db..00000000 Binary files a/docs/static/mb/lessons/the-watch-5.png and /dev/null differ diff --git a/docs/static/mb/lessons/the-watch-6.png b/docs/static/mb/lessons/the-watch-6.png deleted file mode 100644 index 1fd6c191..00000000 Binary files a/docs/static/mb/lessons/the-watch-6.png and /dev/null differ diff --git a/docs/static/mb/lessons/the-watch-7.png b/docs/static/mb/lessons/the-watch-7.png deleted file mode 100644 index 3ef7ec9a..00000000 Binary files a/docs/static/mb/lessons/the-watch-7.png and /dev/null differ diff --git a/docs/static/mb/lessons/the-watch-8.png b/docs/static/mb/lessons/the-watch-8.png deleted file mode 100644 index 6614bf5b..00000000 Binary files a/docs/static/mb/lessons/the-watch-8.png and /dev/null differ diff --git a/docs/static/mb/lessons/the-watch-9.png b/docs/static/mb/lessons/the-watch-9.png deleted file mode 100644 index 44aa930e..00000000 Binary files a/docs/static/mb/lessons/the-watch-9.png and /dev/null differ diff --git a/docs/static/mb/lessons/truth-or-dare-0.png b/docs/static/mb/lessons/truth-or-dare-0.png deleted file mode 100644 index 7a01002a..00000000 Binary files a/docs/static/mb/lessons/truth-or-dare-0.png and /dev/null differ diff --git a/docs/static/mb/line_chart.png b/docs/static/mb/line_chart.png deleted file mode 100644 index 05c14ef2..00000000 Binary files a/docs/static/mb/line_chart.png and /dev/null differ diff --git a/docs/static/mb/offline-2.png b/docs/static/mb/offline-2.png deleted file mode 100644 index e5a18bda..00000000 Binary files a/docs/static/mb/offline-2.png and /dev/null differ diff --git a/docs/static/mb/projects/a1-display.png b/docs/static/mb/projects/a1-display.png deleted file mode 100644 index bd3236c8..00000000 Binary files a/docs/static/mb/projects/a1-display.png and /dev/null differ diff --git a/docs/static/mb/projects/a10-watch.png b/docs/static/mb/projects/a10-watch.png deleted file mode 100644 index 9781b759..00000000 Binary files a/docs/static/mb/projects/a10-watch.png and /dev/null differ diff --git a/docs/static/mb/projects/a2-buttons.png b/docs/static/mb/projects/a2-buttons.png deleted file mode 100644 index 668a5a46..00000000 Binary files a/docs/static/mb/projects/a2-buttons.png and /dev/null differ diff --git a/docs/static/mb/projects/a3-pins.png b/docs/static/mb/projects/a3-pins.png deleted file mode 100644 index 5e811541..00000000 Binary files a/docs/static/mb/projects/a3-pins.png and /dev/null differ diff --git a/docs/static/mb/projects/a4-motion.png b/docs/static/mb/projects/a4-motion.png deleted file mode 100644 index 49b5a6cb..00000000 Binary files a/docs/static/mb/projects/a4-motion.png and /dev/null differ diff --git a/docs/static/mb/projects/a5-compass.png b/docs/static/mb/projects/a5-compass.png deleted file mode 100644 index d3e34ce8..00000000 Binary files a/docs/static/mb/projects/a5-compass.png and /dev/null differ diff --git a/docs/static/mb/projects/a6-music.png b/docs/static/mb/projects/a6-music.png deleted file mode 100644 index 6a1e39f1..00000000 Binary files a/docs/static/mb/projects/a6-music.png and /dev/null differ diff --git a/docs/static/mb/projects/a7-conductive.png b/docs/static/mb/projects/a7-conductive.png deleted file mode 100644 index 1c3ab640..00000000 Binary files a/docs/static/mb/projects/a7-conductive.png and /dev/null differ diff --git a/docs/static/mb/projects/a8-network.png b/docs/static/mb/projects/a8-network.png deleted file mode 100644 index de76df32..00000000 Binary files a/docs/static/mb/projects/a8-network.png and /dev/null differ diff --git a/docs/static/mb/projects/a9-radio.png b/docs/static/mb/projects/a9-radio.png deleted file mode 100644 index d8cf0f40..00000000 Binary files a/docs/static/mb/projects/a9-radio.png and /dev/null differ diff --git a/docs/static/mb/projects/all10.png b/docs/static/mb/projects/all10.png deleted file mode 100644 index e2aa6663..00000000 Binary files a/docs/static/mb/projects/all10.png and /dev/null differ diff --git a/docs/static/mb/projects/guitar.png b/docs/static/mb/projects/guitar.png deleted file mode 100644 index 6866549b..00000000 Binary files a/docs/static/mb/projects/guitar.png and /dev/null differ diff --git a/docs/static/mb/projects/guitar/accelleration_axis.png b/docs/static/mb/projects/guitar/accelleration_axis.png deleted file mode 100644 index 9e620d6b..00000000 Binary files a/docs/static/mb/projects/guitar/accelleration_axis.png and /dev/null differ diff --git a/docs/static/mb/projects/guitar/connectmicrobit.jpg b/docs/static/mb/projects/guitar/connectmicrobit.jpg deleted file mode 100644 index 8f22e8e5..00000000 Binary files a/docs/static/mb/projects/guitar/connectmicrobit.jpg and /dev/null differ diff --git a/docs/static/mb/projects/guitar/crocclipintoboard.jpg b/docs/static/mb/projects/guitar/crocclipintoboard.jpg deleted file mode 100644 index 23f46b69..00000000 Binary files a/docs/static/mb/projects/guitar/crocclipintoboard.jpg and /dev/null differ diff --git a/docs/static/mb/projects/guitar/crocclips.jpg b/docs/static/mb/projects/guitar/crocclips.jpg deleted file mode 100644 index 7acdd656..00000000 Binary files a/docs/static/mb/projects/guitar/crocclips.jpg and /dev/null differ diff --git a/docs/static/mb/projects/guitar/headphones.jpg b/docs/static/mb/projects/guitar/headphones.jpg deleted file mode 100644 index 9b05f0b4..00000000 Binary files a/docs/static/mb/projects/guitar/headphones.jpg and /dev/null differ diff --git a/docs/static/mb/projects/guitar/jacktocrocs.jpg b/docs/static/mb/projects/guitar/jacktocrocs.jpg deleted file mode 100644 index 4f6520f1..00000000 Binary files a/docs/static/mb/projects/guitar/jacktocrocs.jpg and /dev/null differ diff --git a/docs/static/mb/projects/guitar/map_analogy.png b/docs/static/mb/projects/guitar/map_analogy.png deleted file mode 100644 index 1235e679..00000000 Binary files a/docs/static/mb/projects/guitar/map_analogy.png and /dev/null differ diff --git a/docs/static/mb/projects/guitar/mapanalogy.JPG b/docs/static/mb/projects/guitar/mapanalogy.JPG deleted file mode 100644 index 53b2c65e..00000000 Binary files a/docs/static/mb/projects/guitar/mapanalogy.JPG and /dev/null differ diff --git a/docs/static/mb/projects/guitar/materials.jpg b/docs/static/mb/projects/guitar/materials.jpg deleted file mode 100644 index 9df09e04..00000000 Binary files a/docs/static/mb/projects/guitar/materials.jpg and /dev/null differ diff --git a/docs/static/mb/projects/guitar/microbit.jpg b/docs/static/mb/projects/guitar/microbit.jpg deleted file mode 100644 index 4d4b0495..00000000 Binary files a/docs/static/mb/projects/guitar/microbit.jpg and /dev/null differ diff --git a/docs/static/mb/projects/guitar/otherdesigns.jpg b/docs/static/mb/projects/guitar/otherdesigns.jpg deleted file mode 100644 index 7bc0d3a1..00000000 Binary files a/docs/static/mb/projects/guitar/otherdesigns.jpg and /dev/null differ diff --git a/docs/static/mb/projects/guitar/usbcable.jpg b/docs/static/mb/projects/guitar/usbcable.jpg deleted file mode 100644 index 4ec68d1a..00000000 Binary files a/docs/static/mb/projects/guitar/usbcable.jpg and /dev/null differ diff --git a/docs/static/mb/projects/magic-button-trick.png b/docs/static/mb/projects/magic-button-trick.png deleted file mode 100644 index 6e19d321..00000000 Binary files a/docs/static/mb/projects/magic-button-trick.png and /dev/null differ diff --git a/docs/static/mb/projects/magic-button-trick/magnets.jpg b/docs/static/mb/projects/magic-button-trick/magnets.jpg deleted file mode 100644 index 4b146bef..00000000 Binary files a/docs/static/mb/projects/magic-button-trick/magnets.jpg and /dev/null differ diff --git a/docs/static/mb/projects/timing-gates.jpg b/docs/static/mb/projects/timing-gates.jpg deleted file mode 100644 index a299040b..00000000 Binary files a/docs/static/mb/projects/timing-gates.jpg and /dev/null differ diff --git a/docs/static/mb/projects/timing-gates/carfoil.jpg b/docs/static/mb/projects/timing-gates/carfoil.jpg deleted file mode 100644 index 6365abfd..00000000 Binary files a/docs/static/mb/projects/timing-gates/carfoil.jpg and /dev/null differ diff --git a/docs/static/mb/projects/timing-gates/connectcrocs.jpg b/docs/static/mb/projects/timing-gates/connectcrocs.jpg deleted file mode 100644 index 69eec45d..00000000 Binary files a/docs/static/mb/projects/timing-gates/connectcrocs.jpg and /dev/null differ diff --git a/docs/static/mb/projects/timing-gates/connectsensor.jpg b/docs/static/mb/projects/timing-gates/connectsensor.jpg deleted file mode 100644 index 637a0b0b..00000000 Binary files a/docs/static/mb/projects/timing-gates/connectsensor.jpg and /dev/null differ diff --git a/docs/static/mb/projects/timing-gates/materials.jpg b/docs/static/mb/projects/timing-gates/materials.jpg deleted file mode 100644 index b2c22a27..00000000 Binary files a/docs/static/mb/projects/timing-gates/materials.jpg and /dev/null differ diff --git a/docs/static/mb/projects/timing-gates/sensor2.jpg b/docs/static/mb/projects/timing-gates/sensor2.jpg deleted file mode 100644 index 2a27a5ef..00000000 Binary files a/docs/static/mb/projects/timing-gates/sensor2.jpg and /dev/null differ diff --git a/docs/static/mb/projects/timing-gates/sensordone.jpg b/docs/static/mb/projects/timing-gates/sensordone.jpg deleted file mode 100644 index 519dc0b2..00000000 Binary files a/docs/static/mb/projects/timing-gates/sensordone.jpg and /dev/null differ diff --git a/docs/static/mb/projects/timing-gates/sensormicrobit2.jpg b/docs/static/mb/projects/timing-gates/sensormicrobit2.jpg deleted file mode 100644 index d95c33fc..00000000 Binary files a/docs/static/mb/projects/timing-gates/sensormicrobit2.jpg and /dev/null differ diff --git a/docs/static/mb/projects/timing-gates/sketchgate1.jpg b/docs/static/mb/projects/timing-gates/sketchgate1.jpg deleted file mode 100644 index 9c841577..00000000 Binary files a/docs/static/mb/projects/timing-gates/sketchgate1.jpg and /dev/null differ diff --git a/docs/static/mb/projects/timing-gates/sketchgate2.jpg b/docs/static/mb/projects/timing-gates/sketchgate2.jpg deleted file mode 100644 index 5b9878f9..00000000 Binary files a/docs/static/mb/projects/timing-gates/sketchgate2.jpg and /dev/null differ diff --git a/docs/static/mb/projects/timing-gates/sketchgates.jpg b/docs/static/mb/projects/timing-gates/sketchgates.jpg deleted file mode 100644 index 7e8383e6..00000000 Binary files a/docs/static/mb/projects/timing-gates/sketchgates.jpg and /dev/null differ diff --git a/docs/static/mb/projects/timing-gates/sketchmath.jpg b/docs/static/mb/projects/timing-gates/sketchmath.jpg deleted file mode 100644 index 947d1236..00000000 Binary files a/docs/static/mb/projects/timing-gates/sketchmath.jpg and /dev/null differ diff --git a/docs/static/mb/projects/timing-gates/spreadfoil.jpg b/docs/static/mb/projects/timing-gates/spreadfoil.jpg deleted file mode 100644 index 2e4042c3..00000000 Binary files a/docs/static/mb/projects/timing-gates/spreadfoil.jpg and /dev/null differ diff --git a/docs/static/mb/projects/timing-gates/stickfoil.jpg b/docs/static/mb/projects/timing-gates/stickfoil.jpg deleted file mode 100644 index 001eb38e..00000000 Binary files a/docs/static/mb/projects/timing-gates/stickfoil.jpg and /dev/null differ diff --git a/docs/static/mb/projects/timing-gates/tape.jpg b/docs/static/mb/projects/timing-gates/tape.jpg deleted file mode 100644 index ea5449af..00000000 Binary files a/docs/static/mb/projects/timing-gates/tape.jpg and /dev/null differ diff --git a/docs/static/mb/projects/wallet.png b/docs/static/mb/projects/wallet.png deleted file mode 100644 index 02f34ed7..00000000 Binary files a/docs/static/mb/projects/wallet.png and /dev/null differ diff --git a/docs/static/mb/projects/wallet/fold1.jpg b/docs/static/mb/projects/wallet/fold1.jpg deleted file mode 100644 index ac54a1c3..00000000 Binary files a/docs/static/mb/projects/wallet/fold1.jpg and /dev/null differ diff --git a/docs/static/mb/projects/wallet/fold2.jpg b/docs/static/mb/projects/wallet/fold2.jpg deleted file mode 100644 index caeab3aa..00000000 Binary files a/docs/static/mb/projects/wallet/fold2.jpg and /dev/null differ diff --git a/docs/static/mb/projects/wallet/fold3.jpg b/docs/static/mb/projects/wallet/fold3.jpg deleted file mode 100644 index 75bbe52f..00000000 Binary files a/docs/static/mb/projects/wallet/fold3.jpg and /dev/null differ diff --git a/docs/static/mb/projects/wallet/fold4.jpg b/docs/static/mb/projects/wallet/fold4.jpg deleted file mode 100644 index 69db16eb..00000000 Binary files a/docs/static/mb/projects/wallet/fold4.jpg and /dev/null differ diff --git a/docs/static/mb/projects/wallet/fold5.jpg b/docs/static/mb/projects/wallet/fold5.jpg deleted file mode 100644 index d85aa2ec..00000000 Binary files a/docs/static/mb/projects/wallet/fold5.jpg and /dev/null differ diff --git a/docs/static/mb/projects/wallet/fold6.jpg b/docs/static/mb/projects/wallet/fold6.jpg deleted file mode 100644 index 0bc5e64a..00000000 Binary files a/docs/static/mb/projects/wallet/fold6.jpg and /dev/null differ diff --git a/docs/static/mb/projects/wallet/fold7.jpg b/docs/static/mb/projects/wallet/fold7.jpg deleted file mode 100644 index 8472a7f8..00000000 Binary files a/docs/static/mb/projects/wallet/fold7.jpg and /dev/null differ diff --git a/docs/static/mb/projects/wallet/hole1.jpg b/docs/static/mb/projects/wallet/hole1.jpg deleted file mode 100644 index 261848b3..00000000 Binary files a/docs/static/mb/projects/wallet/hole1.jpg and /dev/null differ diff --git a/docs/static/mb/projects/wallet/hole2.jpg b/docs/static/mb/projects/wallet/hole2.jpg deleted file mode 100644 index 1bfd33c2..00000000 Binary files a/docs/static/mb/projects/wallet/hole2.jpg and /dev/null differ diff --git a/docs/static/mb/projects/wallet/hole3.jpg b/docs/static/mb/projects/wallet/hole3.jpg deleted file mode 100644 index 863efdf1..00000000 Binary files a/docs/static/mb/projects/wallet/hole3.jpg and /dev/null differ diff --git a/docs/static/mb/projects/wallet/hole4.jpg b/docs/static/mb/projects/wallet/hole4.jpg deleted file mode 100644 index 15523a21..00000000 Binary files a/docs/static/mb/projects/wallet/hole4.jpg and /dev/null differ diff --git a/docs/static/mb/projects/wallet/hole5.jpg b/docs/static/mb/projects/wallet/hole5.jpg deleted file mode 100644 index e3ec9aa4..00000000 Binary files a/docs/static/mb/projects/wallet/hole5.jpg and /dev/null differ diff --git a/docs/static/mb/projects/wallet/hole6.jpg b/docs/static/mb/projects/wallet/hole6.jpg deleted file mode 100644 index 322f09ab..00000000 Binary files a/docs/static/mb/projects/wallet/hole6.jpg and /dev/null differ diff --git a/docs/static/mb/projects/wallet/materials.jpg b/docs/static/mb/projects/wallet/materials.jpg deleted file mode 100644 index 66d6702f..00000000 Binary files a/docs/static/mb/projects/wallet/materials.jpg and /dev/null differ diff --git a/docs/static/mb/projects/wallet/mbhole1.jpg b/docs/static/mb/projects/wallet/mbhole1.jpg deleted file mode 100644 index 735715bb..00000000 Binary files a/docs/static/mb/projects/wallet/mbhole1.jpg and /dev/null differ diff --git a/docs/static/mb/projects/wallet/mbhole10.jpg b/docs/static/mb/projects/wallet/mbhole10.jpg deleted file mode 100644 index e50e449b..00000000 Binary files a/docs/static/mb/projects/wallet/mbhole10.jpg and /dev/null differ diff --git a/docs/static/mb/projects/wallet/mbhole11.jpg b/docs/static/mb/projects/wallet/mbhole11.jpg deleted file mode 100644 index 1b7db863..00000000 Binary files a/docs/static/mb/projects/wallet/mbhole11.jpg and /dev/null differ diff --git a/docs/static/mb/projects/wallet/mbhole12.jpg b/docs/static/mb/projects/wallet/mbhole12.jpg deleted file mode 100644 index 4e1b1aab..00000000 Binary files a/docs/static/mb/projects/wallet/mbhole12.jpg and /dev/null differ diff --git a/docs/static/mb/projects/wallet/mbhole13.jpg b/docs/static/mb/projects/wallet/mbhole13.jpg deleted file mode 100644 index e85a2c42..00000000 Binary files a/docs/static/mb/projects/wallet/mbhole13.jpg and /dev/null differ diff --git a/docs/static/mb/projects/wallet/mbhole14.jpg b/docs/static/mb/projects/wallet/mbhole14.jpg deleted file mode 100644 index 9118ad4e..00000000 Binary files a/docs/static/mb/projects/wallet/mbhole14.jpg and /dev/null differ diff --git a/docs/static/mb/projects/wallet/mbhole2.jpg b/docs/static/mb/projects/wallet/mbhole2.jpg deleted file mode 100644 index 7f969653..00000000 Binary files a/docs/static/mb/projects/wallet/mbhole2.jpg and /dev/null differ diff --git a/docs/static/mb/projects/wallet/mbhole3.jpg b/docs/static/mb/projects/wallet/mbhole3.jpg deleted file mode 100644 index f99cdf3b..00000000 Binary files a/docs/static/mb/projects/wallet/mbhole3.jpg and /dev/null differ diff --git a/docs/static/mb/projects/wallet/mbhole4.jpg b/docs/static/mb/projects/wallet/mbhole4.jpg deleted file mode 100644 index 9fe28a8d..00000000 Binary files a/docs/static/mb/projects/wallet/mbhole4.jpg and /dev/null differ diff --git a/docs/static/mb/projects/wallet/mbhole5.jpg b/docs/static/mb/projects/wallet/mbhole5.jpg deleted file mode 100644 index 69dd7159..00000000 Binary files a/docs/static/mb/projects/wallet/mbhole5.jpg and /dev/null differ diff --git a/docs/static/mb/projects/wallet/mbhole6.jpg b/docs/static/mb/projects/wallet/mbhole6.jpg deleted file mode 100644 index 35f03fbb..00000000 Binary files a/docs/static/mb/projects/wallet/mbhole6.jpg and /dev/null differ diff --git a/docs/static/mb/projects/wallet/mbhole7.jpg b/docs/static/mb/projects/wallet/mbhole7.jpg deleted file mode 100644 index 5da85874..00000000 Binary files a/docs/static/mb/projects/wallet/mbhole7.jpg and /dev/null differ diff --git a/docs/static/mb/projects/wallet/mbhole8.jpg b/docs/static/mb/projects/wallet/mbhole8.jpg deleted file mode 100644 index 2aeca562..00000000 Binary files a/docs/static/mb/projects/wallet/mbhole8.jpg and /dev/null differ diff --git a/docs/static/mb/projects/wallet/mbhole9.jpg b/docs/static/mb/projects/wallet/mbhole9.jpg deleted file mode 100644 index 0befb9e3..00000000 Binary files a/docs/static/mb/projects/wallet/mbhole9.jpg and /dev/null differ diff --git a/docs/static/mb/projects/wallet/rug1.jpg b/docs/static/mb/projects/wallet/rug1.jpg deleted file mode 100644 index ff0083f5..00000000 Binary files a/docs/static/mb/projects/wallet/rug1.jpg and /dev/null differ diff --git a/docs/static/mb/projects/wallet/rug2.jpg b/docs/static/mb/projects/wallet/rug2.jpg deleted file mode 100644 index 93053062..00000000 Binary files a/docs/static/mb/projects/wallet/rug2.jpg and /dev/null differ diff --git a/docs/static/mb/projects/wallet/sheet1.jpg b/docs/static/mb/projects/wallet/sheet1.jpg deleted file mode 100644 index 805e995a..00000000 Binary files a/docs/static/mb/projects/wallet/sheet1.jpg and /dev/null differ diff --git a/docs/static/mb/projects/wallet/sheet2.jpg b/docs/static/mb/projects/wallet/sheet2.jpg deleted file mode 100644 index 575527db..00000000 Binary files a/docs/static/mb/projects/wallet/sheet2.jpg and /dev/null differ diff --git a/docs/static/mb/projects/wallet/sheet3.jpg b/docs/static/mb/projects/wallet/sheet3.jpg deleted file mode 100644 index c1759197..00000000 Binary files a/docs/static/mb/projects/wallet/sheet3.jpg and /dev/null differ diff --git a/docs/static/mb/projects/wallet/sheet4.jpg b/docs/static/mb/projects/wallet/sheet4.jpg deleted file mode 100644 index 8092bb3a..00000000 Binary files a/docs/static/mb/projects/wallet/sheet4.jpg and /dev/null differ diff --git a/docs/static/mb/projects/wallet/sheet5.jpg b/docs/static/mb/projects/wallet/sheet5.jpg deleted file mode 100644 index c373b61b..00000000 Binary files a/docs/static/mb/projects/wallet/sheet5.jpg and /dev/null differ diff --git a/docs/static/mb/projects/wallet/sheet6.jpg b/docs/static/mb/projects/wallet/sheet6.jpg deleted file mode 100644 index bb6b45a0..00000000 Binary files a/docs/static/mb/projects/wallet/sheet6.jpg and /dev/null differ diff --git a/docs/static/mb/projects/wallet/wallet.jpg b/docs/static/mb/projects/wallet/wallet.jpg deleted file mode 100644 index 714618d6..00000000 Binary files a/docs/static/mb/projects/wallet/wallet.jpg and /dev/null differ diff --git a/docs/static/mb/quick-start-0.png b/docs/static/mb/quick-start-0.png deleted file mode 100644 index 223a9cec..00000000 Binary files a/docs/static/mb/quick-start-0.png and /dev/null differ diff --git a/docs/static/mb/seismograph9.png b/docs/static/mb/seismograph9.png deleted file mode 100644 index 322fd6a4..00000000 Binary files a/docs/static/mb/seismograph9.png and /dev/null differ diff --git a/docs/static/mb/serial-library-0.png b/docs/static/mb/serial-library-0.png deleted file mode 100644 index c00882ab..00000000 Binary files a/docs/static/mb/serial-library-0.png and /dev/null differ diff --git a/docs/static/mb/serial-library-1.png b/docs/static/mb/serial-library-1.png deleted file mode 100644 index 86cc6596..00000000 Binary files a/docs/static/mb/serial-library-1.png and /dev/null differ diff --git a/docs/static/mb/show-leds-1.png b/docs/static/mb/show-leds-1.png deleted file mode 100644 index f8ba3c12..00000000 Binary files a/docs/static/mb/show-leds-1.png and /dev/null differ diff --git a/docs/static/mb/vscode.png b/docs/static/mb/vscode.png deleted file mode 100644 index 035686f8..00000000 Binary files a/docs/static/mb/vscode.png and /dev/null differ diff --git a/docs/static/packages/bluetooth/icon.png b/docs/static/packages/bluetooth/icon.png new file mode 100644 index 00000000..cb967d40 Binary files /dev/null and b/docs/static/packages/bluetooth/icon.png differ diff --git a/docs/static/packages/bluetooth/icon.svg b/docs/static/packages/bluetooth/icon.svg new file mode 100644 index 00000000..9363f9d4 --- /dev/null +++ b/docs/static/packages/bluetooth/icon.svg @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + diff --git a/docs/static/packages/devices/icon.png b/docs/static/packages/devices/icon.png new file mode 100644 index 00000000..d900a7d6 Binary files /dev/null and b/docs/static/packages/devices/icon.png differ diff --git a/docs/static/packages/devices/icon.svg b/docs/static/packages/devices/icon.svg new file mode 100644 index 00000000..5ddc36e4 --- /dev/null +++ b/docs/static/packages/devices/icon.svg @@ -0,0 +1,1948 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/static/packages/packageicon.svg b/docs/static/packages/packageicon.svg new file mode 100644 index 00000000..24954311 --- /dev/null +++ b/docs/static/packages/packageicon.svg @@ -0,0 +1,1948 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/static/packages/radio/icon.png b/docs/static/packages/radio/icon.png new file mode 100644 index 00000000..e211d6eb Binary files /dev/null and b/docs/static/packages/radio/icon.png differ diff --git a/docs/static/packages/radio/icon.svg b/docs/static/packages/radio/icon.svg new file mode 100644 index 00000000..7ff5d6a4 --- /dev/null +++ b/docs/static/packages/radio/icon.svg @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + diff --git a/docs/static/uploader/screenshot.png b/docs/static/uploader/screenshot.png deleted file mode 100644 index 4fb518d6..00000000 Binary files a/docs/static/uploader/screenshot.png and /dev/null differ diff --git a/docs/static/uploader/tooltip.png b/docs/static/uploader/tooltip.png deleted file mode 100644 index ee623bd0..00000000 Binary files a/docs/static/uploader/tooltip.png and /dev/null differ diff --git a/docs/types/buffer.md b/docs/types/buffer.md new file mode 100644 index 00000000..4d5bbce3 --- /dev/null +++ b/docs/types/buffer.md @@ -0,0 +1,121 @@ +# Buffer + +Memory used as a temporary location for data in a program is commonly called a _buffer_. It's a transfer stop for data coming from some source like a network or pins operation. A program can read the data from the buffer when it's ready to work with it. Also, programs put their data in a buffer to make it ready for a transfer to a device or to somewhere else in memory on the @boardname@. + +## Create a new buffer + +Sending and receiving data over the pins might need a buffer if you use your own form of data. The **Pins** category contains a function to create buffers for this purpose. + +A buffer is created with the **createBuffer** function by choosing a buffer size as a number of bytes. + +```typescript-ignore +let bufr = pins.createBuffer(16); +``` + +## Get number value from a buffer + +You can get a number value from a particular place in a buffer using **getNumber**. To do it, you have to say how big each of your number values are. The size of the number values is set using a [NumberFormat](/types/buffer/number-format#number-format-types) type. You use an _offset_ value which is the position in the buffer where the number value you want is at. + +```typescript-ignore +let num = bufr.getNumber(NumberFormat.Int8LE, 5) +``` + +## Put a number value into a buffer +A number is placed in a buffer with **setNumber**. You use a number format like with **getNumber**. A new value to goes into the buffer at the position you select. + +```typescript-ignore +let val = 15; +bufr.setNumber(NumberFormat.Int8LE, 5, val); +``` + +## Get the length of the buffer + +The buffer **length** property tells how big the buffer is in size as number of bytes. + +```typescript-ignore +let bufrLength = bufr.length; +``` + +## Fill the buffer + +You can fill an entire buffer so that every byte in the buffer has the same value. You use the +**fill** function to initialize or reset the buffer contents to a default value. Typically the number `0`. + +```typescript-ignore +bufr.fill(0); +``` + +## Make two buffers from one + +A new smaller buffer is created from an original larger one using the **slice** function. You tell what position you want to start from in the original buffer and how many bytes from that position you want to copy. + +```typescript-ignore +let newBufr = bufr.slice(32, 64); +``` + +## Shift the buffer contents + +The contents of a buffer are shifted left or right by some amount of bytes with the **shift** function. A positive shift number moves the data to the left (to a lower position in the buffer). A negative number moves the data to the right (to a higher position in the buffer). Any data that is moved past the first or last position in the buffer is lost. Locations in the buffer where data is shifted out of are filled with `0` values. + +```typescript-ignore +bufr.shift(8); +``` +Here's an example of shifting a buffer to the left (higher positions to lower positions). The original buffer contains: + +||||||||| +|-|-|-|-|-|-|-|-| +|0|1|1|1|0|1|0|0| +|1|0|1|0|1|0|1|0| +|1|1|0|0|1|1|0|0| +|1|1|1|0|1|1|1|0| +|1|1|1|0|1|1|1|1| +
+After shifting by 2 bytes using **shift(2)**... + +||||||||| +|-|-|-|-|-|-|-|-| +|1|1|0|0|1|1|0|0| +|1|1|1|0|1|1|1|0| +|1|1|1|0|1|1|1|1| +|0|0|0|0|0|0|0|0| +|0|0|0|0|0|0|0|0| + +## Rotate the buffer contents + +The contents of a buffer are rotated left or right by some amount of bytes with the **rotate** function. A positive rotate number rotates the data to the left (to a lower position in the buffer). A negative number moves the data to the right (to a higher position in the buffer). Any data that is moved past the first or last position in the buffer is placed back in the buffer at the location where the rotation ended. + +```typescript-ignore +bufr.rotate(6); +``` +Here's an example of rotating a buffer to the left (higher positions to lower positions). The original buffer contains: + +||||||||| +|-|-|-|-|-|-|-|-| +|0|1|1|1|0|1|0|0| +|1|0|1|0|1|0|1|0| +|1|1|0|0|1|1|0|0| +|1|1|1|0|1|1|1|0| +|1|1|1|0|1|1|1|1| +
+After shifting by 3 bytes using **rotate(3)**... + +||||||||| +|-|-|-|-|-|-|-|-| +|1|1|1|0|1|1|1|0| +|1|1|1|0|1|1|1|1| +|0|1|1|1|0|1|0|0| +|1|0|1|0|1|0|1|0| +|1|1|0|0|1|1|0|0| + +## Copy one buffer into another + +The contents of another buffer are copied to a location in the current buffer using the **write** function. You say where (what position) in the current buffer you want to write the contents to and include the other buffer as the second parameter. + +```typescript-ignore +let sourceBufr = serial.readBuffer(32); +bufr.write(128, sourceBufr); +``` + +## See also + + [using buffers](/types/buffer/using-buffers), [number format](/types/buffer/number-format) \ No newline at end of file diff --git a/docs/types/buffer/number-format.md b/docs/types/buffer/number-format.md new file mode 100644 index 00000000..cf7c2c12 --- /dev/null +++ b/docs/types/buffer/number-format.md @@ -0,0 +1,79 @@ +# Number format + +Numbers get stored at some place in memory. They have a certain memory size (spaces in memory) and an arrangement for their bytes. + +## Digital numbers + +The data stored in memory is just a lot of tiny electronic connections in the circuits of the @boardname@. A number is the most basic type of data and other types of data are made using numbers (number are even used to act as text characters in memory). A number is made with combination of electronic connections that are either on and off. One connection is called a _bit_ and this is used as a single digit for computer numbers. A single bit can mean one of two numbers, 0 or 1. Two bits can mean one of four numbers, 00, 01, 10, or 11. We use decimal numbers normally so we give the decimal names to the computer numbers. So, for the two bit numbers, their decimal names are: 00 = 0, 01 = 1, 10 = 2, and 11 = 3. When you see numbers with ones and zeros, they are called _binary_ numbers. + +## The 'byte' + +The smallest amount of bits normally used to store a number in a computer is a combination of 8 bits. A group of 8 bits is called a _byte_. A byte looks like `10010010`. This binary number, for example, represents the number `162` in decimal. + +The maximum absolute value for a number contained in a byte is `255`. You couldn't store the decimal number of `2552` in one byte, you need to use two bytes together. So, `2552` as a binary number is `00001001 11111000` using two bytes. + +## Number formats on the @boardname@ + +Numbers are stored in memory in different ways. They can use one or more bytes, have a positive or negative value, and have their bytes switched around. + +### Signed numbers + +If you want a number that can have a positive value or a negative value, then you use a _signed_ number. This means that one bit of all the bits than make up the number value is treated as a plus sign or a minus sign. A bit value of `0` means a plus and a bit value of `1` means minus. Using one of the bits of the number for a sign means that the maximum possible value for a number gets reduced by about half. + +As an example, the decimal numbers of `1` and `-1` are `00000001` and `11111111` in binary. You see that the bit on the left of the second binary number is a `1`. That bit is used as the minus sign (-) for the `-1`. + +### ~hint +**Two's complement** + +You might think that the binary number for a decimal `-1` would be `10000001` if the left bit is a `1` for the minus sign. The binary number for a decimal `-1` is actually `11111111`. That's because computers and electronic devices use a special trick when working with negative numbers. The trick is called _two's complement_. + +Making a negative number from a positive number is a two step process. The first step is the _one's complement_ of the number. This step switches all the bits in the number that are `1` to `0` and all the bits that are `0` to `1` (invert the bits). Then, the twos's complement step adds the value of `1` to the one's complement value. Here's how it works: + +Start with the positive binary number for a decimal `1` which is `00000001`. +1. The **one's complement** switches the bits, the binary number is now `11111110`. +2. The **two's complement** adds a binary `1` to the one's complement value. + +>`11111110` + `00000001` = `11111111` +### ~ + +### Unsigned numbers + +Signed numbers use all of their bits for the value itself and are always positive values. + +### Big end and little end (endian) + +Earlier you saw that the decimal number `2552` needs two bytes in memory. The order in which these two bytes are placed in memory is called _endian_ order or _endianness_. Funny word, right? This comes from the idea that the byte with the larger part of the value is called the big end and the byte with smaller part of the value is called the little end. + +For `2552` its binary number uses two bytes which are: `00001001 11111000`. The two parts (ends) of this number are: + +* Big end: `00001001` +* Little end: `11111000` + +If the big end of the number is stored in memory first, before the little end, the number is a _big endian_ number. Then, of course, if the little end of the number is stored in memory first, before the big end, the number is a _little endian_ number. + +### Number format types + +Sometimes you need to have your program tell what type of numbers it will store in memory. This often necessary when you use [pin](/reference/pins) operations with a [buffer](/types/buffer). + +The formats for numbers stored on the @boardname@ are: + +* `Int8LE`: one byte, signed, little endian +* `UInt8LE`: one byte, unsigned, little endian +* `Int8BE`: one byte, signed, big endian +* `UInt8BE`: one byte, unsigned, big endian +* `Int16LE`: two bytes, signed, little endian +* `UInt16LE`: two bytes, unsigned, little endian +* `Int16BE`: two bytes, signed, big endian +* `UInt16BE`: two bytes, unsigned, big endian +* `Int32LE`: four bytes, signed, little endian +* `Int32BE`: four bytes, signed, big endian + +#### ~ hint + +The one byte formats really don't have endianness because there is no ordering needed for just one byte. They are given format types though so that they are consistent with the multi-byte formats. So, there is no difference between `Int8LE` and `Int8BE`, or `UInt8LE` and `UInt8BE`. + +#### ~ + +## See also + +[buffer](/types/buffer) diff --git a/docs/types/buffer/using-buffers.md b/docs/types/buffer/using-buffers.md new file mode 100644 index 00000000..352d2fd6 --- /dev/null +++ b/docs/types/buffer/using-buffers.md @@ -0,0 +1,114 @@ +# Using buffers + +Memory used as temporary location for data in a program is commonly called a _buffer_. It's a transfer stop for data coming from some source like a network or pins operation. A program can read the data from the buffer when it's ready to work with it. Also, programs put their data in a buffer to make it ready for a transfer to a device or to somewhere else in memory on the @boardname@. + +## Multiple data types in one place + +Much of the time you read and write [numbers](/types/number) and [strings](/types/string) to and from connected devices or to and from a part on the @boardname@. Sometimes, though, you need to transfer data that is more complicated just these simple types. Your data could be a combination of numbers and strings together, or just a lot of numbers together as a chunk. An example of where you might do this is if you have a external display module or a camera connected to the @boardname@. A buffer is kind of like an [array](/types/array) but it can have data of any type at any place in it. + +## Get a buffer + +Maybe we want to use a super accurate clock with our @boardname@. We can get an external Real Time Clock (RTC) device and connect it to the I2C pins. The time values returned from the RTC device come to us as a sequence of numbers (each number is one _byte_ of data, which means we use the number format of `UInt8LE`). The current time is read from the RTC in a buffer as 7 numbers of a time data (7 bytes). Here's an example of a function we can create to read the time and return the data in a buffer: + +```typescript-ignore +const rtcAddress = 104; + +function getTimeData() { + pins.i2cWriteNumber(rtcAddress, 0, NumberFormat.UInt8LE, false) + return pins.i2cReadBuffer(rtcAddress, pins.sizeOf(NumberFormat.UInt8LE) * 7) +} +``` + +The command to read the time uses just one number so we use [i2cWriteNumber](/reference/pins/i2c-write-number) to send this command. The time data that the RTC gives us comes back as a buffer from [i2cReadBuffer](/reference/pins/i2c-read-buffer). + +## Reading from a buffer + +Data items in buffers are located at _offsets_ inside the buffer. Like an _index_ in an [array](/types/array), an offset is the position number of some particular data in the buffer we want to access. + +In the previous example, our **getTimeData** function returned the current time to us in a buffer. The time data is 7 numbers all together. Remember, for this device the numbers are bytes which means we use `UInt8LE` as the format. The time is formatted where the first number is seconds, the next number is minutes, and so on. So, if we wanted to know what the current day is, we have to look at the 6th number. This is how we get the 6th number from the the buffer: + +```typescript-ignore +let timeBuf = getTimeData(); +let day = timeBuf.getNumber(NumberFormat.Int8LE, 6); +``` + +If we want to decode the data further, we can convert the day number to a name: + +```typescript-ignore +let dayNames = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]; +let timeBuf = getTimeData(); +let day = timeBuf.getNumber(NumberFormat.Int8LE, 6); +basic.showString(dayNames[day]); +``` + +## ~hint +**RTC module** + +Do you want to use a real RTC module and read accurate time data just like in the example? You can get a [precision RTC breakout](https://www.adafruit.com/product/3013) that connects on I2C. +## ~ + +## Writing to a buffer + +To write to a buffer, you need to use an existing buffer or create one. There is a function that is part of **Pins** that lets you create one. + +Let's say you want to see how quickly it gets dark in the evening over a period of 4 hours. You set the @boardname@ next to the window with the room lights off and record a light level reading once every minute. + +You could simply save the light measurements in an array like this: + +```blocks +let darkness: number[] = [] +input.onButtonPressed(Button.A, () => { + for (let i = 0; i < 60 * 4; i++) { + darkness.push(input.lightLevel()) + basic.pause(60000) + } +}) +``` + +This will save the light level measurements but we'd like to upload the data later to a laptop computer using the serial port. Also, we want the data to be compact and in the form of a file. We can use a buffer to do it. + +The **Pins** category has a special function called **createBuffer**. It makes a buffer that holds data with a size specified in bytes. Here it is: + +```typescript-ignore +let darkness = pins.createBuffer(60 * 4); +``` + +The code in blocks for recording the light level is modified to make our file data: + +```typescript-ignore +let darkness = pins.createBuffer(60 * 4); +input.onButtonPressed(Button.A, () => { + for (let i = 0; i < 60 * 4; i++) { + darkness.setNumber(NumberFormat.UInt8LE, i, input.lightLevel()) + basic.pause(60000) + } +}) +``` + +Later, we can upload the file to the laptop computer by pressing the **B** button: + +```typescript-ignore +let dataReady = false; +let darkness = pins.createBuffer(60 * 4); +input.onButtonPressed(Button.A, () => { + for (let i = 0; i < 60 * 4; i++) { + darkness.setNumber(NumberFormat.UInt8LE, i, input.lightLevel()) + basic.pause(60000) + } + dataReady = true; +}) + +input.onButtonPressed(Button.B, () => { + if (dataReady) { + serial.writeLine("Transferring file: DARKNESS, Length: " + darkness.length + " bytes..."); + serial.writeBuffer(darkness) + darkness.fill(0); + dataReady = false; + } +}) +``` + +## See also + +[buffer](/types/buffer), [number format](types/buffer/number-format), +[serial read buffer](/reference/serial/read-buffer), [serial write buffer](/reference/serial/write-buffer) \ No newline at end of file diff --git a/docs/types/number.md b/docs/types/number.md new file mode 100644 index 00000000..a8af5afc --- /dev/null +++ b/docs/types/number.md @@ -0,0 +1,26 @@ +# @extends + +## Show number #print + +The [show number](/reference/basic/show-number) function displays a number on the [LED screen](/device/screen). +For example, this code displays the number 42: + +```block +basic.showNumber(42); +``` + +### #declareexample + +```block +let num = 42; +basic.showNumber(42); +``` + +### #functionreturnexample + +For example the following code gets the display brightness +(using the [brightness function](/reference/led/brightness)) and stores the value in a variable named `brightness`: + +```block +let brightness = led.brightness() +``` diff --git a/docs/types/string.md b/docs/types/string.md new file mode 100644 index 00000000..11ae1da6 --- /dev/null +++ b/docs/types/string.md @@ -0,0 +1,9 @@ +# @extends + +## #intro + +## ~ hint + +For the @boardname@, ASCII character codes 32 to 126 are supported; letters, digits, punctuation marks, and a few symbols. All other character codes appear as a ? on the [LED screen](/device/screen). + +## ~ \ No newline at end of file diff --git a/docs/v0-beta-ref.json b/docs/v0-beta-ref.json new file mode 100644 index 00000000..7cefa36b --- /dev/null +++ b/docs/v0-beta-ref.json @@ -0,0 +1,3 @@ +{ + "appref": "v0" +} diff --git a/docs/v1-ref.json b/docs/v1-ref.json new file mode 100644 index 00000000..e2306939 --- /dev/null +++ b/docs/v1-ref.json @@ -0,0 +1,3 @@ +{ + "appref": "v1.2.13" +} diff --git a/docs/windows-app-web-link-ref.json b/docs/windows-app-web-link-ref.json new file mode 100644 index 00000000..03904058 --- /dev/null +++ b/docs/windows-app-web-link-ref.json @@ -0,0 +1,12 @@ +{ + "json": [ + { + "packageFamilyName": "MicrobitEducationalFounda.196216C47839B_e88r6s0b2swar", + "paths": [ + "/", + "/?????-?????-?????-?????" + ], + "excludePaths": [] + } + ] +} diff --git a/editor/dapjs.d.ts b/editor/dapjs.d.ts new file mode 100644 index 00000000..310acbc9 --- /dev/null +++ b/editor/dapjs.d.ts @@ -0,0 +1,421 @@ +declare namespace DapJS { + export interface IHID { + write(data: ArrayBuffer): Promise; + read(): Promise; + close(): Promise; + // sends each of commands and expects one packet in response + // this makes for better performance when HID access is proxied + sendMany?(commands: Uint8Array[]): Promise; + } + + export class DAP { + constructor(device: IHID); + reconnect(): Promise; + init(): Promise; + close(): Promise; + } + + /** + * # Memory Interface + * + * Controls access to the target's memory. + * + * ## Usage + * + * Using an instance of `CortexM`, as described before, we can simply read and + * write numbers to memory as follows: + * + * ```typescript + * const mem = core.memory; + * + * // NOTE: the address parameter must be word (4-byte) aligned. + * await mem.write32(0x200000, 12345); + * const val = await mem.read32(0x200000); + * + * // val === 12345 + * + * // NOTE: the address parameter must be half-word (2-byte) aligned + * await mem.write16(0x2000002, 65534); + * const val16 = await mem.read16(0x2000002); + * + * // val16 === 65534 + * ``` + * + * To write a larger block of memory, we can use `readBlock` and `writeBlock`. Again, + * these blocks must be written to word-aligned addresses in memory. + * + * ```typescript + * const data = new Uint32Array([0x1234, 0x5678, 0x9ABC, 0xDEF0]); + * await mem.writeBlock(0x200000, data); + * + * const readData = await mem.readBlock(0x200000, data.length, 0x100); + * ``` + * + * ## See also + * + * `PreparedMemoryCommand` provides an equivalent API with better performance (in some + * cases) by enabling batched memory operations. + */ + export class Memory { + private dev; + constructor(dev: DAP); + /** + * Write a 32-bit word to the specified (word-aligned) memory address. + * + * @param addr Memory address to write to + * @param data Data to write (values above 2**32 will be truncated) + */ + write32(addr: number, data: number): Promise; + /** + * Write a 16-bit word to the specified (half word-aligned) memory address. + * + * @param addr Memory address to write to + * @param data Data to write (values above 2**16 will be truncated) + */ + write16(addr: number, data: number): Promise; + /** + * Read a 32-bit word from the specified (word-aligned) memory address. + * + * @param addr Memory address to read from. + */ + read32(addr: number): Promise; + /** + * Read a 16-bit word from the specified (half word-aligned) memory address. + * + * @param addr Memory address to read from. + */ + read16(addr: number): Promise; + /** + * Reads a block of memory from the specified memory address. + * + * @param addr Address to read from + * @param words Number of words to read + * @param pageSize Memory page size + */ + readBlock(addr: number, words: number, pageSize: number): Promise; + /** + * Write a block of memory to the specified memory address. + * + * @param addr Memory address to write to. + * @param words Array of 32-bit words to write to memory. + */ + writeBlock(addr: number, words: Uint32Array): Promise; + private readBlockCore(addr, words); + private writeBlockCore(addr, words); + } + + /** + * # Cortex M + * + * Manages access to a CPU core, and its associated memory and debug functionality. + * + * > **NOTE:** all of the methods that involve interaction with the CPU core + * > are asynchronous, so must be `await`ed, or explicitly handled as a Promise. + * + * ## Usage + * + * First, let's create an instance of `CortexM`, using an associated _Debug Access + * Port_ (DAP) instance that we created earlier. + * + * ```typescript + * const core = new CortexM(dap); + * ``` + * + * Now, we can halt and resume the core just like this: + * + * > **NOTE:** If you're not using ES2017, you can replace the use of `async` and + * > `await` with direct use of Promises. These examples also need to be run within + * > an `async` function for `async` to be used. + * + * ```typescript + * await core.halt(); + * await core.resume(); + * ``` + * + * Resetting the core is just as easy: + * + * ```typescript + * await core.reset(); + * ``` + * + * You can even halt immediately after reset: + * + * ```typescript + * await core.reset(true); + * ``` + * + * We can also read and write 32-bit values to/from core registers: + * + * ```typescript + * const sp = await core.readCoreRegister(CortexReg.SP); + * + * await core.writeCoreRegister(CortexReg.R0, 0x1000); + * await core.writeCoreRegister(CortexReg.PC, 0x1234); + * ``` + * + * ### See also + * + * For details on debugging and memory features, see the documentation for + * `Debug` and `Memory`. + */ + export class CortexM { + /** + * Read and write to on-chip memory associated with this CPU core. + */ + memory: Memory; + /** + * Control the CPU's debugging features. + */ + debug: Debug; + /** + * Underlying Debug Access Port (DAP). + */ + private dev; + constructor(device: DAP); + /** + * Initialise the debug access port on the device, and read the device type. + */ + init(): Promise; + /** + * Read the current state of the CPU. + * + * @returns A member of the `CoreState` enum corresponding to the current status of the CPU. + */ + getState(): Promise; + + /** + * Read a core register from the CPU (e.g. r0...r15, pc, sp, lr, s0...) + * + * @param no Member of the `CortexReg` enum - an ARM Cortex CPU general-purpose register. + */ + readCoreRegister(no: CortexReg): Promise; + /** + * Write a 32-bit word to the specified CPU general-purpose register. + * + * @param no Member of the `CortexReg` enum - an ARM Cortex CPU general-purpose register. + * @param val Value to be written. + */ + writeCoreRegister(no: CortexReg, val: number): Promise; + /** + * Halt the CPU core. + */ + halt(): Promise; + /** + * Resume the CPU core. + */ + resume(): Promise; + /** + * Find out whether the CPU is halted. + */ + isHalted(): Promise; + /** + * Read the current status of the CPU. + * + * @returns Object containing the contents of the `DHCSR` register, the `DFSR` register, and a boolean value + * stating the current halted state of the CPU. + */ + status(): Promise<{ + dfsr: number; + dhscr: number; + isHalted: boolean; + }>; + /** + * Reset the CPU core. This currently does a software reset - it is also technically possible to perform a 'hard' + * reset using the reset pin from the debugger. + */ + reset(halt?: boolean): Promise; + /** + * Run specified machine code natively on the device. Assumes usual C calling conventions + * - returns the value of r0 once the program has terminated. The program _must_ terminate + * in order for this function to return. This can be achieved by placing a `bkpt` + * instruction at the end of the function. + * + * @param code array containing the machine code (32-bit words). + * @param address memory address at which to place the code. + * @param pc initial value of the program counter. + * @param lr initial value of the link register. + * @param sp initial value of the stack pointer. + * @param upload should we upload the code before running it. + * @param args set registers r0...rn before running code + * + * @returns A promise for the value of r0 on completion of the function call. + */ + runCode(code: Uint32Array, address: number, pc: number, lr: number, sp: number, upload: boolean, ...args: number[]): Promise; + /** + * Spin until the chip has halted. + */ + waitForHalt(timeout?: number): Promise; + + prepareCommand(): PreparedCortexMCommand; + + private softwareReset(); + } + + /** + * # Cortex M: Prepared Command + * + * Allows batching of Cortex M-related commands, such as writing to a register, + * halting and resuming the core. + * + * ## Example + * + * When preparing the sequence of commands, we can use the same API to prepare + * a command as we would to execute them immediately. + * + * ```typescript + * // Note that only the .go method is asynchronous. + * + * const prep = core.prepareCommand(); + * prep.writeCoreRegister(CortexReg.R0, 0x1000); + * prep.writeCoreRegister(CortexReg.R1, 0x0); + * prep.writeCoreRegister(CortexReg.PC, 0x2000000); + * prep.resume(); + * ``` + * + * We can then execute them as efficiently as possible by combining them together + * and executing them like so. + * + * ```typescript + * await prep.go(); + * ``` + * + * The code above is equivalent to the following _non-prepared_ command: + * + * ```typescript + * await core.writeCoreRegister(CortexReg.R0, 0x1000); + * await core.writeCoreRegister(CortexReg.R1, 0x0); + * await core.writeCoreRegister(CortexReg.PC, 0x2000000); + * await core.resume(); + * ``` + * + * Since the batched version of this code avoids making three round-trips to the + * target, we are able to significantly improve performance. This is especially + * noticable when uploading a binary to flash memory, where are large number of + * repetetive commands are being used. + * + * ## Explanation + * + * For a detailed explanation of why prepared commands are used in DAP.js, see the + * documentation for `PreparedDapCommand`. + */ + export class PreparedCortexMCommand { + private cmd; + constructor(dap: DAP); + /** + * Schedule a 32-bit integer to be written to a core register. + * + * @param no Core register to be written. + * @param val Value to write. + */ + writeCoreRegister(no: CortexReg, val: number): void; + /** + * Schedule a halt command to be written to the CPU. + */ + halt(): void; + /** + * Schedule a resume command to be written to the CPU. + */ + resume(): void; + /** + * Execute all scheduled commands. + */ + go(): Promise; + } + + + export const enum CortexReg { + R0 = 0, + R1 = 1, + R2 = 2, + R3 = 3, + R4 = 4, + R5 = 5, + R6 = 6, + R7 = 7, + R8 = 8, + R9 = 9, + R10 = 10, + R11 = 11, + R12 = 12, + SP = 13, + LR = 14, + PC = 15, + XPSR = 16, + MSP = 17, + PSP = 18, + PRIMASK = 20, + CONTROL = 20, + } + export const enum CoreState { + TARGET_RESET = 0, + TARGET_LOCKUP = 1, + TARGET_SLEEPING = 2, + TARGET_HALTED = 3, + TARGET_RUNNING = 4, + } + + + + /** + * # Debug Interface + * + * Keeps track of breakpoints set on the target, as well as deciding whether to + * use a hardware breakpoint or a software breakpoint. + * + * ## Usage + * + * ```typescript + * const dbg = core.debug; + * + * await dbg.setBreakpoint(0x123456); + * + * // resume the core and wait for the breakpoint + * await core.resume(); + * await core.waitForHalt(); + * + * // step forward one instruction + * await dbg.step(); + * + * // remove the breakpoint + * await dbg.deleteBreakpoint(0x123456); + * ``` + */ + export class Debug { + private core; + private breakpoints; + private availableHWBreakpoints; + private totalHWBreakpoints; + private enabled; + constructor(core: CortexM); + init(): Promise; + /** + * Enable debugging on the target CPU + */ + enable(): Promise; + /** + * Set breakpoints at specified memory addresses. + * + * @param addrs An array of memory addresses at which to set breakpoints. + */ + setBreakpoint(addr: number): Promise; + deleteBreakpoint(addr: number): Promise; + /** + * Step the processor forward by one instruction. + */ + step(): Promise; + /** + * Set up (and disable) the Flash Patch & Breakpoint unit. It will be enabled when + * the first breakpoint is set. + * + * Also reads the number of available hardware breakpoints. + */ + private setupFpb(); + /** + * Enable or disable the Flash Patch and Breakpoint unit (FPB). + * + * @param enabled + */ + private setFpbEnabled(enabled?); + } + +} \ No newline at end of file diff --git a/editor/extension.tsx b/editor/extension.tsx new file mode 100644 index 00000000..0c838415 --- /dev/null +++ b/editor/extension.tsx @@ -0,0 +1,1059 @@ +/// +/// +/// +/// +/// +/// +import * as React from "react"; + +const imul = (Math as any).imul; +const pageSize = 1024; +const numPages = 256; +const timeoutMessage = "timeout"; + +function murmur3_core(data: Uint8Array) { + let h0 = 0x2F9BE6CC; + let h1 = 0x1EC3A6C8; + + for (let i = 0; i < data.length; i += 4) { + let k = pxt.HF2.read32(data, i) >>> 0 + k = imul(k, 0xcc9e2d51); + k = (k << 15) | (k >>> 17); + k = imul(k, 0x1b873593); + + h0 ^= k; + h1 ^= k; + h0 = (h0 << 13) | (h0 >>> 19); + h1 = (h1 << 13) | (h1 >>> 19); + h0 = (imul(h0, 5) + 0xe6546b64) >>> 0; + h1 = (imul(h1, 5) + 0xe6546b64) >>> 0; + } + return [h0, h1] +} + +class DAPWrapper { + cortexM: DapJS.CortexM + packetIo: pxt.HF2.PacketIO; + cmsisdap: any; + flashing = true; + pbuf = new pxt.U.PromiseBuffer(); + private useSerial = true; + + constructor(h: pxt.HF2.PacketIO) { + this.packetIo = h; + + h.onData = buf => { + // console.log("RD: " + pxt.Util.toHex(buf)) + this.pbuf.push(buf); + } + + this.allocDAP() + + const readSerial = () => { + if (!this.useSerial) { + return + } + + if (this.flashing) { + setTimeout(readSerial, 300) + return + } + + this.cmsisdap.cmdNums(0x83, []) + .then((r: number[]) => { + const len = r[1] + let str = "" + for (let i = 2; i < len + 2; ++i) { + str += String.fromCharCode(r[i]) + } + if (str.length > 0) { + pxt.U.nextTick(readSerial) + window.postMessage({ + type: 'serial', + id: 'n/a', // TODO + data: str + }, "*") + // console.log("SERIAL: " + str) + } else + setTimeout(readSerial, 50) + }, (err: any) => { + setTimeout(readSerial, 1000) + }) + } + + readSerial() + } + + private allocDAP() { + /* + let sendMany = (cmds: Uint8Array[]) => { + return h.talksAsync(cmds.map(c => ({ cmd: 0, data: c }))); + } + + if (!h.talksAsync) + sendMany = null; + */ + + let dev = new DapJS.DAP({ + write: writeAsync, + close: this.disconnectAsync, + read: readAsync, + //sendMany: sendMany + }); + this.cmsisdap = (dev as any).dap; + this.cortexM = new DapJS.CortexM(dev); + + let h = this.packetIo + let pbuf = this.pbuf + + function writeAsync(data: ArrayBuffer) { + // console.log("WR: " + pxt.Util.toHex(new Uint8Array(data))); + return h.sendPacketAsync(new Uint8Array(data)); + } + + function readAsync() { + return pbuf.shiftAsync(); + } + } + + reconnectAsync(first: boolean) { + // configure serial at 115200 + let p = Promise.resolve(); + if (!first) { + p = this.packetIo.reconnectAsync() + .then(() => this.allocDAP()); + } + + return p + .then(() => this.cortexM.init()) + .then(() => { + return this.cmsisdap.cmdNums(0x82, [0x00, 0xC2, 0x01, 0x00]) + .then(() => { this.useSerial = true }, (err: any) => { this.useSerial = false; }); + }); + } + + disconnectAsync() { + return this.packetIo.disconnectAsync(); + } +} + +let packetIoPromise: Promise; +function initPacketIOAsync(): Promise { + if (!packetIoPromise) { + packetIoPromise = pxt.HF2.mkPacketIOAsync() + .catch(err => { + packetIoPromise = null; + return Promise.reject(err); + }); + return packetIoPromise; + } else { + let packetIo: pxt.HF2.PacketIO; + return packetIoPromise + .then((io) => { + packetIo = io; + return io.reconnectAsync(); + }) + .then(() => packetIo); + } +} + +let previousDapWrapper: DAPWrapper; +function dapAsync() { + if (previousDapWrapper) + return previousDapWrapper.reconnectAsync(false) // Always fully reconnect to handle device unplugged mid-session + .then(() => previousDapWrapper); + return Promise.resolve() + .then(() => { + if (previousDapWrapper) { + return previousDapWrapper.disconnectAsync() + .finally(() => { + previousDapWrapper = null; + }); + } + return Promise.resolve(); + }) + .then(() => initPacketIOAsync()) + .then(h => { + let w = new DAPWrapper(h) + previousDapWrapper = w; + return w.reconnectAsync(true) + .then(() => { + return w + }) + }) +} + +function canHID(): boolean { + let r = false + if (pxt.usb.isEnabled) { + r = true + } else if (pxt.U.isNodeJS) { + r = true + } else { + const forceHexDownload = /forceHexDownload/i.test(window.location.href); + const isUwp = !!(window as any).Windows; + if (pxt.BrowserUtils.isLocalHost() && pxt.Cloud.localToken && !forceHexDownload || isUwp) + r = true + } + return r; +} + +function initAsync() { + if (canHID()) { + return dapAsync(); + } else { + return Promise.reject(new Error("no HID")) + } +} + +function pageAlignBlocks(blocks: ts.pxtc.UF2.Block[], pageSize: number) { + pxt.U.assert(pageSize % 256 == 0) + let res: ts.pxtc.UF2.Block[] = [] + for (let i = 0; i < blocks.length;) { + let b0 = blocks[i] + let newbuf = new Uint8Array(pageSize) + let startPad = b0.targetAddr & (pageSize - 1) + let newAddr = b0.targetAddr - startPad + for (; i < blocks.length; ++i) { + let b = blocks[i] + if (b.targetAddr + b.payloadSize > newAddr + pageSize) + break + pxt.U.memcpy(newbuf, b.targetAddr - newAddr, b.data, 0, b.payloadSize) + } + let bb = pxt.U.flatClone(b0) + bb.data = newbuf + bb.targetAddr = newAddr + bb.payloadSize = pageSize + res.push(bb) + } + return res +} + +const flashPageBINquick = new Uint32Array([ + 0xbe00be00, // bkpt - LR is set to this + 0x2480b5f0, 0x00e42300, 0x58cd58c2, 0xd10342aa, 0x42a33304, 0xbdf0d1f8, + 0x4b162502, 0x509d4a16, 0x2d00591d, 0x24a1d0fc, 0x511800e4, 0x3cff3c09, + 0x591e0025, 0xd0fc2e00, 0x509c2400, 0x2c00595c, 0x2401d0fc, 0x509c2580, + 0x595c00ed, 0xd0fc2c00, 0x00ed2580, 0x002e2400, 0x5107590f, 0x2f00595f, + 0x3404d0fc, 0xd1f742ac, 0x50992100, 0x2a00599a, 0xe7d0d0fc, 0x4001e000, + 0x00000504, +]) + +// doesn't check if data is already there - for timing +const flashPageBIN = new Uint32Array([ + 0xbe00be00, // bkpt - LR is set to this + 0x2402b5f0, 0x4a174b16, 0x2480509c, 0x002500e4, 0x2e00591e, 0x24a1d0fc, + 0x511800e4, 0x2c00595c, 0x2400d0fc, 0x2480509c, 0x002500e4, 0x2e00591e, + 0x2401d0fc, 0x595c509c, 0xd0fc2c00, 0x00ed2580, 0x002e2400, 0x5107590f, + 0x2f00595f, 0x3404d0fc, 0xd1f742ac, 0x50992100, 0x2a00599a, 0xbdf0d0fc, + 0x4001e000, 0x00000504, +]) + +// void computeHashes(uint32_t *dst, uint8_t *ptr, uint32_t pageSize, uint32_t numPages) +const computeChecksums2 = new Uint32Array([ + 0x4c27b5f0, 0x44a52680, 0x22009201, 0x91004f25, 0x00769303, 0x24080013, + 0x25010019, 0x40eb4029, 0xd0002900, 0x3c01407b, 0xd1f52c00, 0x468c0091, + 0xa9044665, 0x506b3201, 0xd1eb42b2, 0x089b9b01, 0x23139302, 0x9b03469c, + 0xd104429c, 0x2000be2a, 0x449d4b15, 0x9f00bdf0, 0x4d149e02, 0x49154a14, + 0x3e01cf08, 0x2111434b, 0x491341cb, 0x405a434b, 0x4663405d, 0x230541da, + 0x4b10435a, 0x466318d2, 0x230541dd, 0x4b0d435d, 0x2e0018ed, 0x6002d1e7, + 0x9a009b01, 0x18d36045, 0x93003008, 0xe7d23401, 0xfffffbec, 0xedb88320, + 0x00000414, 0x1ec3a6c8, 0x2f9be6cc, 0xcc9e2d51, 0x1b873593, 0xe6546b64, +]) + +let startTime = 0 +function log(msg: string) { + let now = Date.now() + if (!startTime) startTime = now + now -= startTime + let ts = ("00000" + now).slice(-5) + pxt.log(`HID ${ts}: ${msg}`) +} + +const membase = 0x20000000 +const loadAddr = membase +const dataAddr = 0x20002000 +const stackAddr = 0x20001000 + +export const bufferConcat = (bufs: Uint8Array[]) => { + let len = 0; + for (const b of bufs) { + len += b.length; + } + const r = new Uint8Array(len); + len = 0; + for (const b of bufs) { + r.set(b, len); + len += b.length; + } + return r; +}; + +function fullVendorCommandFlashAsync(resp: pxtc.CompileResult, wrap: DAPWrapper): Promise { + const chunkSize = 62; + let aborted = false; + + return Promise.resolve() + .then(() => { + return wrap.cmsisdap.cmdNums(0x8A /* DAPLinkFlash.OPEN */, [1]); + }) + .then((res) => { + const hexUint8 = pxt.U.stringToUint8Array(resp.outfiles[pxtc.BINARY_HEX]); + const hexArray: number[] = Array.prototype.slice.call(hexUint8); + + const sendPages = (offset: number = 0): Promise => { + const end = Math.min(hexArray.length, offset + chunkSize); + const nextPage = hexArray.slice(offset, end); + nextPage.unshift(nextPage.length); + return wrap.cmsisdap.cmdNums(0x8C /* DAPLinkFlash.WRITE */, nextPage) + .then(() => { + if (!aborted && end < hexArray.length) { + return sendPages(end); + } + return Promise.resolve(); + }); + } + + return sendPages(); + }) + .then((res) => { + return wrap.cmsisdap.cmdNums(0x8B /* DAPLinkFlash.CLOSE */, []); + }) + .timeout(60000, timeoutMessage) + .catch((e) => { + aborted = true; + return wrap.cmsisdap.cmdNums(0x89 /* DAPLinkFlash.RESET */, []) + .catch((e2: any) => { + // Best effort reset, no-op if there's an error + }) + .then(() => { + return Promise.reject(e); + }); + }); +} + +function quickHidFlashAsync(resp: pxtc.CompileResult, wrap: DAPWrapper): Promise { + let logV = (msg: string) => { } + //let logV = log + let aborted = false; + + const runFlash = (b: ts.pxtc.UF2.Block, dataAddr: number) => { + const cmd = wrap.cortexM.prepareCommand(); + + cmd.halt(); + + cmd.writeCoreRegister(DapJS.CortexReg.PC, loadAddr + 4 + 1); + cmd.writeCoreRegister(DapJS.CortexReg.LR, loadAddr + 1); + cmd.writeCoreRegister(DapJS.CortexReg.SP, stackAddr); + + cmd.writeCoreRegister(0, b.targetAddr); + cmd.writeCoreRegister(1, dataAddr); + + return Promise.resolve() + .then(() => { + logV("setregs") + return cmd.go() + }) + .then(() => { + logV("dbg en") + // starts the program + return wrap.cortexM.debug.enable() + }) + } + + let checksums: Uint8Array + return getFlashChecksumsAsync(wrap) + .then(buf => { + checksums = buf; + log("write code"); + return wrap.cortexM.memory.writeBlock(loadAddr, flashPageBIN); + }) + .then(() => { + log("convert"); + // TODO this is seriously inefficient (130ms on a fast machine) + let uf2 = ts.pxtc.UF2.newBlockFile(); + ts.pxtc.UF2.writeHex(uf2, resp.outfiles[pxtc.BINARY_HEX].split(/\r?\n/)); + let bytes = pxt.U.stringToUint8Array(ts.pxtc.UF2.serializeFile(uf2)); + let parsed = ts.pxtc.UF2.parseFile(bytes); + + let aligned = pageAlignBlocks(parsed, pageSize); + log(`initial: ${aligned.length} pages`); + aligned = onlyChanged(aligned, checksums); + log(`incremental: ${aligned.length} pages`); + + return Promise.mapSeries(pxt.U.range(aligned.length), + i => { + if (aborted) return Promise.resolve(); + let b = aligned[i]; + if (b.targetAddr >= 0x10000000) + return Promise.resolve(); + + logV("about to write at 0x" + b.targetAddr.toString(16)); + + let writeBl = Promise.resolve(); + + let thisAddr = (i & 1) ? dataAddr : dataAddr + pageSize; + let nextAddr = (i & 1) ? dataAddr + pageSize : dataAddr; + + if (i == 0) { + let u32data = new Uint32Array(b.data.length / 4); + for (let i = 0; i < b.data.length; i += 4) + u32data[i >> 2] = pxt.HF2.read32(b.data, i); + writeBl = wrap.cortexM.memory.writeBlock(thisAddr, u32data); + } + + return writeBl + .then(() => runFlash(b, thisAddr)) + .then(() => { + let next = aligned[i + 1]; + if (!next) + return Promise.resolve(); + logV("write next"); + let buf = new Uint32Array(next.data.buffer); + return wrap.cortexM.memory.writeBlock(nextAddr, buf); + }) + .then(() => { + logV("wait"); + return wrap.cortexM.waitForHalt(500); + }) + .then(() => { + logV("done block"); + }); + }) + .then(() => { + log("flash done"); + pxt.tickEvent("hid.flash.done"); + return wrap.cortexM.reset(false); + }) + .then(() => { + wrap.flashing = false; + }); + }) + .timeout(25000, timeoutMessage) + .catch((e) => { + aborted = true; + return Promise.reject(e); + }); +} + +function flashAsync(resp: pxtc.CompileResult, d: pxt.commands.DeployOptions = {}): Promise { + startTime = 0 + let wrap: DAPWrapper + log("init") + + d.showNotification(pxt.U.lf("Downloading...")); + pxt.tickEvent("hid.flash.start"); + return Promise.resolve() + .then(() => { + if (previousDapWrapper) { + previousDapWrapper.flashing = true; + return Promise.delay(100); + } + return Promise.resolve(); + }) + .then(initAsync) + .then(w => { + wrap = w + log("reset"); + return wrap.cortexM.init() + .then(() => wrap.cortexM.reset(true)) + .catch(e => { + log("trying re-connect"); + return wrap.reconnectAsync(false) + .then(() => wrap.cortexM.reset(true)); + }); + }) + .then(() => wrap.cortexM.memory.readBlock(0x10001014, 1, pageSize)) + .then(v => { + if (pxt.HF2.read32(v, 0) != 0x3C000) { + pxt.tickEvent("hid.flash.uicrfail"); + return fullVendorCommandFlashAsync(resp, wrap); + } + return quickHidFlashAsync(resp, wrap); + }) + .catch(e => { + pxt.log(`flash error: ${e.type}`); + if (e.type === "devicenotfound" && d.reportDeviceNotFoundAsync) { + pxt.tickEvent("hid.flash.devicenotfound"); + return d.reportDeviceNotFoundAsync("/device/windows-app/troubleshoot", resp); + } else if (e.message === timeoutMessage) { + pxt.tickEvent("hid.flash.timeout"); + return previousDapWrapper.reconnectAsync(true) + .catch((e) => { }) + .then(() => { + // Best effort disconnect; at this point we don't even know the state of the device + pxt.reportException(e); + return resp.confirmAsync({ + header: lf("Something went wrong..."), + body: lf("One-click download took too long. Please disconnect your {0} from your computer and reconnect it, then manually download your program using drag and drop.", pxt.appTarget.appTheme.boardName || lf("device")), + agreeLbl: lf("Ok"), + hideCancel: true + }); + }) + .then(() => { + return pxt.commands.saveOnlyAsync(resp); + }); + } else if (e.isUserError) { + d.reportError(e.message); + return Promise.resolve(); + } else { + pxt.tickEvent("hid.flash.unknownerror"); + pxt.reportException(e); + return resp.confirmAsync({ + header: pxt.U.lf("Something went wrong..."), + body: pxt.U.lf("Please manually download your program to your device using drag and drop. One-click download might work afterwards."), + agreeLbl: lf("Ok"), + hideCancel: true + }) + .then(() => { + return pxt.commands.saveOnlyAsync(resp); + }); + } + }); +} + +function getFlashChecksumsAsync(wrap: DAPWrapper) { + log("getting existing flash checksums") + let pages = numPages + return wrap.cortexM.runCode(computeChecksums2, loadAddr, loadAddr + 1, 0xffffffff, stackAddr, true, + dataAddr, 0, pageSize, pages) + .then(() => wrap.cortexM.memory.readBlock(dataAddr, pages * 2, pageSize)) +} + +function onlyChanged(blocks: ts.pxtc.UF2.Block[], checksums: Uint8Array) { + return blocks.filter(b => { + let idx = b.targetAddr / pageSize + pxt.U.assert((idx | 0) == idx) + pxt.U.assert(b.data.length == pageSize) + if (idx * 8 + 8 > checksums.length) + return true // out of range? + let c0 = pxt.HF2.read32(checksums, idx * 8) + let c1 = pxt.HF2.read32(checksums, idx * 8 + 4) + let ch = murmur3_core(b.data) + if (c0 == ch[0] && c1 == ch[1]) + return false + return true + }) +} + +function uwpDeployCoreAsync(resp: pxtc.CompileResult, d: pxt.commands.DeployOptions = {}): Promise { + // Go straight to flashing + return flashAsync(resp, d); +} + +function deployCoreAsync(resp: pxtc.CompileResult, d: pxt.commands.DeployOptions = {}): Promise { + return pxt.usb.isPairedAsync() + .then(isPaired => { + if (isPaired) { + // Already paired from earlier in the session or from previous session + return flashAsync(resp, d); + } + + // try bluetooth if device is paired + if (pxt.webBluetooth.isPaired()) + return pxt.webBluetooth.flashAsync(resp, d) + .catch(e => pxt.commands.saveOnlyAsync(resp)); + + // No device paired, prompt user + return pxt.commands.saveOnlyAsync(resp); + }); +} + +/** + * + FALSE + FALSE + FALSE + FALSE + FALSE + FALSE + FALSE + FALSE + TRUE + FALSE + FALSE + FALSE + FALSE + FALSE + FALSE + FALSE + TRUE + FALSE + FALSE + FALSE + FALSE + FALSE + FALSE + FALSE + FALSE + + + to + + ` + # # # # # + . . . . # + . . . . . + . . . . # + . . . . # + ` + + + */ + +function patchBlocks(pkgTargetVersion: string, dom: Element) { + // is this a old script? + if (pxt.semver.majorCmp(pkgTargetVersion || "0.0.0", "1.0.0") >= 0) return; + + // showleds + const nodes = pxt.U.toArray(dom.querySelectorAll("block[type=device_show_leds]")) + .concat(pxt.U.toArray(dom.querySelectorAll("block[type=device_build_image]"))) + .concat(pxt.U.toArray(dom.querySelectorAll("shadow[type=device_build_image]"))) + .concat(pxt.U.toArray(dom.querySelectorAll("block[type=device_build_big_image]"))) + .concat(pxt.U.toArray(dom.querySelectorAll("shadow[type=device_build_big_image]"))); + nodes.forEach(node => { + // don't rewrite if already upgraded, eg. field LEDS already present + if (pxt.U.toArray(node.children).filter(child => child.tagName == "field" && "LEDS" == child.getAttribute("name"))[0]) + return; + // read LEDxx value and assmebly into a new field + const leds: string[][] = [[], [], [], [], []]; + pxt.U.toArray(node.children) + .filter(child => child.tagName == "field" && /^LED\d+$/.test(child.getAttribute("name"))) + .forEach(lednode => { + let n = lednode.getAttribute("name"); + let col = parseInt(n[3]); + let row = parseInt(n[4]); + leds[row][col] = lednode.innerHTML == "TRUE" ? "#" : "."; + // remove node + node.removeChild(lednode); + }); + // add new field + const f = node.ownerDocument.createElement("field"); + f.setAttribute("name", "LEDS"); + const s = '`\n' + leds.map(row => row.join('')).join('\n') + '\n`'; + f.appendChild(node.ownerDocument.createTextNode(s)); + node.insertBefore(f, null); + }); + + // radio + /* + + +receivedNumber + + + +name +value + + + +receivedString + + +converts to + + +receivedNumber + + +name +value + + +receivedString + +*/ + const varids: pxt.Map = {}; + + function addField(node: Element, renameMap: pxt.Map, name: string) { + const f = node.ownerDocument.createElement("field"); + f.setAttribute("name", "HANDLER_" + name) + f.setAttribute("id", varids[renameMap[name] || name]); + f.appendChild(node.ownerDocument.createTextNode(name)); + node.appendChild(f); + } + + pxt.U.toArray(dom.querySelectorAll("variable")).forEach(node => varids[node.innerHTML] = node.getAttribute("id")); + pxt.U.toArray(dom.querySelectorAll("block[type=radio_on_packet]")) + .forEach(node => { + const mutation = node.querySelector("mutation"); + if (!mutation) return; + const renameMap = JSON.parse(node.getAttribute("renamemap") || "{}"); + const props = mutation.getAttribute("callbackproperties"); + + if (props) { + const parts = props.split(","); + + // It's tempting to generate radio_on_number if parts.length === 0 but + // that would create a variable named "receivedNumber" and possibly shadow + // an existing variable in the user's program. It's safer to stick to the + // old block. + if (parts.length === 1) { + if (parts[0] === "receivedNumber") { + node.setAttribute("type", "radio_on_number"); + node.removeChild(node.querySelector("field[name=receivedNumber]")); + addField(node, renameMap, "receivedNumber"); + } + else if (parts[0] === "receivedString") { + node.setAttribute("type", "radio_on_string"); + node.removeChild(node.querySelector("field[name=receivedString]")); + addField(node, renameMap, "receivedString"); + } + else { + return; + } + node.removeChild(mutation); + } + else if (parts.length === 2 && parts.indexOf("receivedNumber") !== -1 && parts.indexOf("receivedString") !== -1) { + node.setAttribute("type", "radio_on_value"); + node.removeChild(node.querySelector("field[name=receivedNumber]")); + node.removeChild(node.querySelector("field[name=receivedString]")); + addField(node, renameMap, "name"); + addField(node, renameMap, "value"); + node.removeChild(mutation); + } + } + }) + + + // device_random now refers to randomRange() so we need to add the missing lower bound argument + pxt.U.toArray(dom.querySelectorAll("block[type=device_random]")) + .concat(pxt.U.toArray(dom.querySelectorAll("shadow[type=device_random]"))) + .forEach(node => { + if (getValue(node, "min")) return; + const v = node.ownerDocument.createElement("value"); + v.setAttribute("name", "min"); + addNumberShadow(v); + node.appendChild(v); + }); + + /* + + DIVIDE + + 0 + 2 + + + 1 + 3 + + + */ + pxt.U.toArray(dom.querySelectorAll("block[type=math_arithmetic]")) + .concat(pxt.U.toArray(dom.querySelectorAll("shadow[type=math_arithmetic]"))) + .forEach(node => { + const op = getField(node, "OP"); + if (!op || op.textContent.trim() !== "DIVIDE") return; + + // Convert to integer division + /* + + + idiv + + 0 + + + 0 + + + */ + + node.setAttribute("type", "math_js_op"); + op.textContent = "idiv"; + + const mutation = node.ownerDocument.createElement("mutation"); + mutation.setAttribute("op-type", "infix"); + // mutation has to be first or Blockly will drop the second argument + node.insertBefore(mutation, node.firstChild); + + const a = getValue(node, "A"); + if (a) a.setAttribute("name", "ARG0"); + + const b = getValue(node, "B"); + if (b) b.setAttribute("name", "ARG1"); + }); + + renameField(dom, "math_number_minmax", "NUM", "SLIDER"); + renameField(dom, "device_note", "note", "name"); +} + +function renameField(dom: Element, blockType: string, oldName: string, newName: string) { + pxt.U.toArray(dom.querySelectorAll(`block[type=${blockType}]`)) + .concat(pxt.U.toArray(dom.querySelectorAll(`shadow[type=${blockType}]`))) + .forEach(node => { + const thefield = getField(node, oldName); + if (thefield) { + thefield.setAttribute("name", newName); + } + }); +} + +pxt.editor.initExtensionsAsync = function (opts: pxt.editor.ExtensionOptions): Promise { + pxt.debug('loading microbit target extensions...') + + function cantImportAsync(project: pxt.editor.IProjectView) { + // this feature is support in v0 only + return project.showModalDialogAsync({ + header: lf("Can't import microbit.co.uk scripts..."), + body: lf("Importing microbit.co.uk programs is not supported in this editor anymore. Please open this script in the https://makecode.microbit.org/v0 editor."), + buttons: [ + { + label: lf("Go to the old editor"), + url: `https://makecode.microbit.org/v0` + } + ] + }).then(() => project.openHome()) + } + + const manyAny = Math as any; + if (!manyAny.imul) + manyAny.imul = function (a: number, b: number): number { + const ah = (a >>> 16) & 0xffff; + const al = a & 0xffff; + const bh = (b >>> 16) & 0xffff; + const bl = b & 0xffff; + // the shift by 0 fixes the sign on the high part + // the final |0 converts the unsigned value into a signed value + return ((al * bl) + (((ah * bl + al * bh) << 16) >>> 0) | 0); + }; + + const res: pxt.editor.ExtensionResult = { + hexFileImporters: [{ + id: "blockly", + canImport: data => data.meta.cloudId == "microbit.co.uk" && data.meta.editor == "blockly", + importAsync: (project, data) => { + pxt.tickEvent('import.legacyblocks.redirect'); + return cantImportAsync(project); + } + }, { + id: "td", + canImport: data => data.meta.cloudId == "microbit.co.uk" && data.meta.editor == "touchdevelop", + importAsync: (project, data) => { + pxt.tickEvent('import.legacytd.redirect'); + return cantImportAsync(project); + } + }] + }; + + pxt.usb.setFilters([{ + vendorId: 0x0D28, + productId: 0x0204, + classCode: 0xff, + subclassCode: 0x03 + }]) + + const isUwp = !!(window as any).Windows; + if (isUwp) + pxt.commands.deployCoreAsync = uwpDeployCoreAsync; + else if ((canHID() || pxt.webBluetooth.hasPartialFlash()) && !pxt.BrowserUtils.isPxtElectron()) + pxt.commands.deployCoreAsync = deployCoreAsync; + + res.blocklyPatch = patchBlocks; + res.showUploadInstructionsAsync = showUploadInstructionsAsync; + res.webUsbPairDialogAsync = webUsbPairDialogAsync; + return Promise.resolve(res); +} + +function getField(parent: Element, name: string) { + return getFieldOrValue(parent, name, true); +} + +function getValue(parent: Element, name: string) { + return getFieldOrValue(parent, name, false); +} + +function getFieldOrValue(parent: Element, name: string, isField: boolean) { + const nodeType = isField ? "field" : "value"; + for (let i = 0; i < parent.children.length; i++) { + const child = parent.children.item(i); + if (child.tagName === nodeType && child.getAttribute("name") === name) { + return child; + } + } + return undefined; +} + +function addNumberShadow(valueNode: Element) { + const s = valueNode.ownerDocument.createElement("shadow"); + s.setAttribute("type", "math_number"); + + const f = valueNode.ownerDocument.createElement("field"); + f.setAttribute("name", "NUM"); + f.textContent = "0"; + + s.appendChild(f); + valueNode.appendChild(s); +} + +function webUsbPairDialogAsync(confirmAsync: (options: any) => Promise): Promise { + const boardName = pxt.appTarget.appTheme.boardName || "???"; + const docUrl = pxt.appTarget.appTheme.usbDocs; + const jsx = +
+
+
{lf("First time here?")}
+ {lf("You must have version 0249 or above of the firmware")} +
+ +
+ {lf("Check your firmware version here and update if needed")} +
+
+
+
+
+
+
+
+
+ +
+
+
+ 1 + {lf("Connect the {0} to your computer with a USB cable", boardName)} +
+ {lf("Use the microUSB port on the top of the {0}", boardName)} +
+
+
+
+
+
+
+ +
+
+
+ 2 + {lf("Pair your {0}", boardName)} +
+ {lf("Click 'Pair device' below and select Calliope Mini CMSIS-DAP or DAPLink CMSIS-DAP from the list")} +
+
+
+
+
+
+
+
+
+
; + + const buttons: any[] = []; + if (docUrl) { + buttons.push({ + label: lf("Help"), + icon: "help", + className: "lightgrey", + url: `${docUrl}/webusb` + }); + } + + return confirmAsync({ + header: lf("Pair device for one-click downloads"), + jsx, + hasCloseIcon: true, + agreeLbl: lf("Pair device"), + agreeIcon: "usb", + hideCancel: true, + className: 'downloaddialog', + buttons + }); +} + +function showUploadInstructionsAsync(fn: string, url: string, confirmAsync: (options: any) => Promise) { + const boardName = pxt.appTarget.appTheme.boardName || "???"; + const boardDriveName = pxt.appTarget.appTheme.driveDisplayName || pxt.appTarget.compile.driveName || "???"; + + // https://msdn.microsoft.com/en-us/library/cc848897.aspx + // "For security reasons, data URIs are restricted to downloaded resources. + // Data URIs cannot be used for navigation, for scripting, or to populate frame or iframe elements" + const userDownload = pxt.BrowserUtils.isBrowserDownloadWithinUserContext(); + const downloadAgain = !pxt.BrowserUtils.isIE() && !pxt.BrowserUtils.isEdge(); + const docUrl = pxt.appTarget.appTheme.usbDocs; + + const body = + userDownload + ? lf("Click 'Download' to open the {0} app.", pxt.appTarget.appTheme.boardName || "") + : undefined; + const jsx = !userDownload ? +
+
+
+
+
+
+
+
+
+ +
+
+
+ 1 + {lf("Connect the {0} to your computer with a USB cable", boardName)} +
+ {lf("Use the microUSB port on the top of the {0}", boardName)} +
+
+
+
+
+
+
+ +
+
+
+ 2 + {lf("Move the .hex file to the {0}", boardName)} +
+ {lf("Locate the downloaded .hex file and drag it to the {0} drive", boardDriveName)} +
+
+
+
+
+
+
+
+
+
: undefined; + + const buttons: any[] = []; + + if (downloadAgain) { + buttons.push({ + label: userDownload ? lf("Download") : fn, + icon: "download", + class: `${userDownload ? "primary" : "lightgrey"}`, + url, + fileName: fn + }); + } + + if (docUrl) { + buttons.push({ + label: lf("Help"), + icon: "help", + className: "lightgrey", + url: docUrl + }); + } + + return confirmAsync({ + header: lf("Download to your {0}", pxt.appTarget.appTheme.boardName), + body, + jsx, + hasCloseIcon: true, + hideCancel: true, + hideAgree: true, + className: 'downloaddialog', + buttons + //timeout: 20000 + }).then(() => { }); +} \ No newline at end of file diff --git a/editor/prepend/dapjs.js b/editor/prepend/dapjs.js new file mode 100644 index 00000000..9521a736 --- /dev/null +++ b/editor/prepend/dapjs.js @@ -0,0 +1,3038 @@ +var DapJS = +/******/ (function(modules) { // webpackBootstrap +/******/ // The module cache +/******/ var installedModules = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ +/******/ // Check if module is in cache +/******/ if(installedModules[moduleId]) { +/******/ return installedModules[moduleId].exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = installedModules[moduleId] = { +/******/ i: moduleId, +/******/ l: false, +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); +/******/ +/******/ // Flag the module as loaded +/******/ module.l = true; +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = modules; +/******/ +/******/ // expose the module cache +/******/ __webpack_require__.c = installedModules; +/******/ +/******/ // define getter function for harmony exports +/******/ __webpack_require__.d = function(exports, name, getter) { +/******/ if(!__webpack_require__.o(exports, name)) { +/******/ Object.defineProperty(exports, name, { +/******/ configurable: false, +/******/ enumerable: true, +/******/ get: getter +/******/ }); +/******/ } +/******/ }; +/******/ +/******/ // getDefaultExport function for compatibility with non-harmony modules +/******/ __webpack_require__.n = function(module) { +/******/ var getter = module && module.__esModule ? +/******/ function getDefault() { return module['default']; } : +/******/ function getModuleExports() { return module; }; +/******/ __webpack_require__.d(getter, 'a', getter); +/******/ return getter; +/******/ }; +/******/ +/******/ // Object.prototype.hasOwnProperty.call +/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; +/******/ +/******/ // __webpack_public_path__ +/******/ __webpack_require__.p = ""; +/******/ +/******/ // Load entry module and return exports +/******/ return __webpack_require__(__webpack_require__.s = 4); +/******/ }) +/************************************************************************/ +/******/ ([ +/* 0 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (_) try { + if (f = 1, y && (t = y[op[0] & 2 ? "return" : op[0] ? "throw" : "next"]) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [0, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +var _this = this; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.readUInt32LE = function (b, idx) { + return (b[idx] | + (b[idx + 1] << 8) | + (b[idx + 2] << 16) | + (b[idx + 3] << 24)) >>> 0; +}; +exports.bufferConcat = function (bufs) { + var len = 0; + for (var _i = 0, bufs_1 = bufs; _i < bufs_1.length; _i++) { + var b = bufs_1[_i]; + len += b.length; + } + var r = new Uint8Array(len); + len = 0; + for (var _a = 0, bufs_2 = bufs; _a < bufs_2.length; _a++) { + var b = bufs_2[_a]; + r.set(b, len); + len += b.length; + } + return r; +}; +exports.delay = function (t) { return __awaiter(_this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/, new Promise(function (resolve) { + setTimeout(resolve, t); + })]; + }); +}); }; +exports.addInt32 = function (arr, val) { + if (!arr) { + arr = []; + } + arr.push(val & 0xff, (val >> 8) & 0xff, (val >> 16) & 0xff, (val >> 24) & 0xff); + return arr; +}; +exports.hex = function (v) { + return "0x" + v.toString(16); +}; +exports.rid = function (v) { + var m = [ + "DP_0x0", + "DP_0x4", + "DP_0x8", + "DP_0xC", + "AP_0x0", + "AP_0x4", + "AP_0x8", + "AP_0xC", + ]; + return m[v] || "?"; +}; +exports.bank = function (addr) { + var APBANKSEL = 0x000000f0; + return (addr & APBANKSEL) | (addr & 0xff000000); +}; +exports.apReg = function (r, mode) { + var v = r | mode | 1 /* AP_ACC */; + return (4 + ((v & 0x0c) >> 2)); +}; +exports.bufToUint32Array = function (buf) { + exports.assert((buf.length & 3) === 0); + var r = []; + if (!buf.length) { + return r; + } + r[buf.length / 4 - 1] = 0; + for (var i = 0; i < r.length; ++i) { + r[i] = exports.readUInt32LE(buf, i << 2); + } + return r; +}; +exports.assert = function (cond) { + if (!cond) { + throw new Error("assertion failed"); + } +}; +exports.regRequest = function (regId, isWrite) { + if (isWrite === void 0) { isWrite = false; } + var request = !isWrite ? 2 /* READ */ : 0 /* WRITE */; + if (regId < 4) { + request |= 0 /* DP_ACC */; + } + else { + request |= 1 /* AP_ACC */; + } + request |= (regId & 3) << 2; + return request; +}; +exports.hexBytes = function (bytes) { + var chk = 0; + var r = ":"; + bytes.forEach(function (b) { return chk += b; }); + bytes.push((-chk) & 0xff); + bytes.forEach(function (b) { return r += ("0" + b.toString(16)).slice(-2); }); + return r.toUpperCase(); +}; +exports.hex2bin = function (hexstr) { + var array = new Uint8Array(hexstr.length / 2); + for (var i = 0; i < hexstr.length / 2; i++) { + array[i] = parseInt(hexstr.substr(2 * i, 2), 16); + } + return array; +}; + + +/***/ }), +/* 1 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (_) try { + if (f = 1, y && (t = y[op[0] & 2 ? "return" : op[0] ? "throw" : "next"]) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [0, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +Object.defineProperty(exports, "__esModule", { value: true }); +/** + * # Prepared Memory Command + * + * Allows multiple memory operations to be batched together to improve HID + * interface utilisation. + * + * ## Usage + * + * Similarly to `CortexMPreparedCommand` and `DapPreparedCommand`, a convenience + * function exists to quickly create a prepared memory command: + * + * ```typescript + * const prep = core.memory.prepareCommand(); + * ``` + * + * You can then construct the sequence of commands using the same API as `Memory`. + * + * ```typescript + * prep.write32(0x20000, 1234); + * prep.write32(0x12344, 5678); + * prep.write16(0x12346, 123); + * ``` + * + * And then dispatch the prepared commands asynchronously: + * + * ```typescript + * await prep.go(); + * ``` + */ +var PreparedMemoryCommand = (function () { + function PreparedMemoryCommand(dap) { + this.cmd = dap.prepareCommand(); + } + /** + * Schedule a 32-bit memory write operation. + * + * @param addr Word-aligned memory address to write to. + * @param data Number to be written. + */ + PreparedMemoryCommand.prototype.write32 = function (addr, data) { + this.cmd.writeAp(0 /* CSW */, 587202640 /* CSW_VALUE */ | 2 /* CSW_SIZE32 */); + this.cmd.writeAp(4 /* TAR */, addr); + this.cmd.writeAp(12 /* DRW */, data); + }; + /** + * Schedule a 16-bit memory write operation. + * + * @param addr Half word-aligned memory address to write to. + * @param data Number to be written. + */ + PreparedMemoryCommand.prototype.write16 = function (addr, data) { + data = data << ((addr & 0x02) << 3); + this.cmd.writeAp(0 /* CSW */, 587202640 /* CSW_VALUE */ | 1 /* CSW_SIZE16 */); + this.cmd.writeAp(4 /* TAR */, addr); + this.cmd.writeAp(12 /* DRW */, data); + }; + /** + * Schedule a 32-bit memory read operation. + * + * @param addr Word-aligned memory address to read from. + */ + PreparedMemoryCommand.prototype.read32 = function (addr) { + this.cmd.writeAp(0 /* CSW */, 587202640 /* CSW_VALUE */ | 2 /* CSW_SIZE32 */); + this.cmd.writeAp(4 /* TAR */, addr); + this.cmd.readAp(12 /* DRW */); + }; + /** + * Schedule a 16-bit memory read operation. + * + * FIXME: the values need to be shifted after being read. + * + * @param addr Half word-aligned memory address to read from. + */ + PreparedMemoryCommand.prototype.read16 = function (addr) { + this.cmd.writeAp(0 /* CSW */, 587202640 /* CSW_VALUE */ | 1 /* CSW_SIZE16 */); + this.cmd.writeAp(4 /* TAR */, addr); + this.cmd.readAp(12 /* DRW */); + }; + /** + * Execute all commands asynchronously. + */ + PreparedMemoryCommand.prototype.go = function () { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/, this.cmd.go()]; + }); + }); + }; + return PreparedMemoryCommand; +}()); +exports.PreparedMemoryCommand = PreparedMemoryCommand; + + +/***/ }), +/* 2 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (_) try { + if (f = 1, y && (t = y[op[0] & 2 ? "return" : op[0] ? "throw" : "next"]) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [0, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +Object.defineProperty(exports, "__esModule", { value: true }); +var debug_1 = __webpack_require__(5); +var memory_1 = __webpack_require__(7); +var prepared_1 = __webpack_require__(1); +var util_1 = __webpack_require__(0); +var constants_1 = __webpack_require__(3); +var prepared_2 = __webpack_require__(8); +/** + * # Cortex M + * + * Manages access to a CPU core, and its associated memory and debug functionality. + * + * > **NOTE:** all of the methods that involve interaction with the CPU core + * > are asynchronous, so must be `await`ed, or explicitly handled as a Promise. + * + * ## Usage + * + * First, let's create an instance of `CortexM`, using an associated _Debug Access + * Port_ (DAP) instance that we created earlier. + * + * ```typescript + * const core = new CortexM(dap); + * ``` + * + * Now, we can halt and resume the core just like this: + * + * > **NOTE:** If you're not using ES2017, you can replace the use of `async` and + * > `await` with direct use of Promises. These examples also need to be run within + * > an `async` function for `async` to be used. + * + * ```typescript + * await core.halt(); + * await core.resume(); + * ``` + * + * Resetting the core is just as easy: + * + * ```typescript + * await core.reset(); + * ``` + * + * You can even halt immediately after reset: + * + * ```typescript + * await core.reset(true); + * ``` + * + * We can also read and write 32-bit values to/from core registers: + * + * ```typescript + * const sp = await core.readCoreRegister(CortexReg.SP); + * + * await core.writeCoreRegister(CortexReg.R0, 0x1000); + * await core.writeCoreRegister(CortexReg.PC, 0x1234); + * ``` + * + * ### See also + * + * For details on debugging and memory features, see the documentation for + * `Debug` and `Memory`. + */ +var CortexM = (function () { + function CortexM(device) { + this.dev = device; + this.memory = new memory_1.Memory(device); + this.debug = new debug_1.Debug(this); + } + /** + * Initialise the debug access port on the device, and read the device type. + */ + CortexM.prototype.init = function () { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, this.dev.init()]; + case 1: + _a.sent(); + // FIXME: don't run this if security is enabled on the K64F + return [4 /*yield*/, this.debug.init()]; + case 2: + // FIXME: don't run this if security is enabled on the K64F + _a.sent(); + return [4 /*yield*/, this.readCoreType()]; + case 3: + _a.sent(); + return [2 /*return*/]; + } + }); + }); + }; + /** + * Read the current state of the CPU. + * + * @returns A member of the `CoreState` enum corresponding to the current status of the CPU. + */ + CortexM.prototype.getState = function () { + return __awaiter(this, void 0, void 0, function () { + var dhcsr, newDHCSR; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, this.memory.read32(3758157296 /* DHCSR */)]; + case 1: + dhcsr = _a.sent(); + if (!(dhcsr & 33554432 /* S_RESET_ST */)) return [3 /*break*/, 3]; + return [4 /*yield*/, this.memory.read32(3758157296 /* DHCSR */)]; + case 2: + newDHCSR = _a.sent(); + if (newDHCSR & 33554432 /* S_RESET_ST */ && !(newDHCSR & 16777216 /* S_RETIRE_ST */)) { + return [2 /*return*/, 0 /* TARGET_RESET */]; + } + _a.label = 3; + case 3: + if (dhcsr & 524288 /* S_LOCKUP */) { + return [2 /*return*/, 1 /* TARGET_LOCKUP */]; + } + else if (dhcsr & 262144 /* S_SLEEP */) { + return [2 /*return*/, 2 /* TARGET_SLEEPING */]; + } + else if (dhcsr & 131072 /* S_HALT */) { + return [2 /*return*/, 3 /* TARGET_HALTED */]; + } + else { + return [2 /*return*/, 4 /* TARGET_RUNNING */]; + } + return [2 /*return*/]; + } + }); + }); + }; + /** + * Read the CPUID register from the CPU, and interpret its meaning in terms of implementer, + * architecture and core type. + */ + CortexM.prototype.readCoreType = function () { + return __awaiter(this, void 0, void 0, function () { + var cpuid, implementer, arch, coreType; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, this.memory.read32(3758157056 /* CPUID */)]; + case 1: + cpuid = _a.sent(); + implementer = ((cpuid & constants_1.CPUID_IMPLEMENTER_MASK) >> constants_1.CPUID_IMPLEMENTER_POS); + arch = ((cpuid & constants_1.CPUID_ARCHITECTURE_MASK) >> constants_1.CPUID_ARCHITECTURE_POS); + coreType = ((cpuid & constants_1.CPUID_PARTNO_MASK) >> constants_1.CPUID_PARTNO_POS); + console.debug("Found an ARM " + constants_1.CoreNames.get(coreType)); + return [2 /*return*/, [implementer, arch, coreType]]; + } + }); + }); + }; + CortexM.prototype.prepareCommand = function () { + return new prepared_2.PreparedCortexMCommand(this.dev); + }; + /** + * Read a core register from the CPU (e.g. r0...r15, pc, sp, lr, s0...) + * + * @param no Member of the `CortexReg` enum - an ARM Cortex CPU general-purpose register. + */ + CortexM.prototype.readCoreRegister = function (no) { + return __awaiter(this, void 0, void 0, function () { + var v; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, this.memory.write32(3758157300 /* DCRSR */, no)]; + case 1: + _a.sent(); + return [4 /*yield*/, this.memory.read32(3758157296 /* DHCSR */)]; + case 2: + v = _a.sent(); + util_1.assert(v & 65536 /* S_REGRDY */); + return [4 /*yield*/, this.memory.read32(3758157304 /* DCRDR */)]; + case 3: return [2 /*return*/, _a.sent()]; + } + }); + }); + }; + /** + * Write a 32-bit word to the specified CPU general-purpose register. + * + * @param no Member of the `CortexReg` enum - an ARM Cortex CPU general-purpose register. + * @param val Value to be written. + */ + CortexM.prototype.writeCoreRegister = function (no, val) { + return __awaiter(this, void 0, void 0, function () { + var prep, v; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + prep = new prepared_1.PreparedMemoryCommand(this.dev); + prep.write32(3758157304 /* DCRDR */, val); + prep.write32(3758157300 /* DCRSR */, no | 65536 /* DCRSR_REGWnR */); + prep.read32(3758157296 /* DHCSR */); + return [4 /*yield*/, prep.go()]; + case 1: + v = (_a.sent())[0]; + util_1.assert(v & 65536 /* S_REGRDY */); + return [2 /*return*/]; + } + }); + }); + }; + /** + * Halt the CPU core. + */ + CortexM.prototype.halt = function () { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/, this.memory.write32(3758157296 /* DHCSR */, -1604386816 /* DBGKEY */ | 1 /* C_DEBUGEN */ | 2 /* C_HALT */)]; + }); + }); + }; + /** + * Resume the CPU core. + */ + CortexM.prototype.resume = function () { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, this.isHalted()]; + case 1: + if (!_a.sent()) return [3 /*break*/, 4]; + return [4 /*yield*/, this.memory.write32(3758157104 /* DFSR */, 4 /* DFSR_DWTTRAP */ | 2 /* DFSR_BKPT */ | 1 /* DFSR_HALTED */)]; + case 2: + _a.sent(); + return [4 /*yield*/, this.debug.enable()]; + case 3: + _a.sent(); + _a.label = 4; + case 4: return [2 /*return*/]; + } + }); + }); + }; + /** + * Find out whether the CPU is halted. + */ + CortexM.prototype.isHalted = function () { + return __awaiter(this, void 0, void 0, function () { + var s; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, this.status()]; + case 1: + s = _a.sent(); + return [2 /*return*/, s.isHalted]; + } + }); + }); + }; + /** + * Read the current status of the CPU. + * + * @returns Object containing the contents of the `DHCSR` register, the `DFSR` register, and a boolean value + * stating the current halted state of the CPU. + */ + CortexM.prototype.status = function () { + return __awaiter(this, void 0, void 0, function () { + var prep, results, dhcsr, dfsr; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + prep = new prepared_1.PreparedMemoryCommand(this.dev); + prep.read32(3758157296 /* DHCSR */); + prep.read32(3758157104 /* DFSR */); + return [4 /*yield*/, prep.go()]; + case 1: + results = _a.sent(); + dhcsr = results[0]; + dfsr = results[1]; + return [2 /*return*/, { + dfsr: dfsr, + dhscr: dhcsr, + isHalted: !!(dhcsr & 131072 /* S_HALT */), + }]; + } + }); + }); + }; + /** + * Reset the CPU core. This currently does a software reset - it is also technically possible to perform a 'hard' + * reset using the reset pin from the debugger. + */ + CortexM.prototype.reset = function (halt) { + if (halt === void 0) { halt = false; } + return __awaiter(this, void 0, void 0, function () { + var demcr; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + if (!halt) return [3 /*break*/, 7]; + return [4 /*yield*/, this.halt()]; + case 1: + _a.sent(); + return [4 /*yield*/, this.memory.read32(3758157308 /* DEMCR */)]; + case 2: + demcr = _a.sent(); + return [4 /*yield*/, this.memory.write32(3758157308 /* DEMCR */, demcr | 1 /* DEMCR_VC_CORERESET */)]; + case 3: + _a.sent(); + return [4 /*yield*/, this.softwareReset()]; + case 4: + _a.sent(); + return [4 /*yield*/, this.waitForHalt()]; + case 5: + _a.sent(); + // Unset the VC_CORERESET bit + return [4 /*yield*/, this.memory.write32(3758157308 /* DEMCR */, demcr)]; + case 6: + // Unset the VC_CORERESET bit + _a.sent(); + return [3 /*break*/, 9]; + case 7: return [4 /*yield*/, this.softwareReset()]; + case 8: + _a.sent(); + _a.label = 9; + case 9: return [2 /*return*/]; + } + }); + }); + }; + /** + * Run specified machine code natively on the device. Assumes usual C calling conventions + * - returns the value of r0 once the program has terminated. The program _must_ terminate + * in order for this function to return. This can be achieved by placing a `bkpt` + * instruction at the end of the function. + * + * @param code array containing the machine code (32-bit words). + * @param address memory address at which to place the code. + * @param pc initial value of the program counter. + * @param lr initial value of the link register. + * @param sp initial value of the stack pointer. + * @param upload should we upload the code before running it. + * @param args set registers r0...rn before running code + * + * @returns A promise for the value of r0 on completion of the function call. + */ + CortexM.prototype.runCode = function (code, address, pc, lr, sp, upload) { + var args = []; + for (var _i = 6; _i < arguments.length; _i++) { + args[_i - 6] = arguments[_i]; + } + return __awaiter(this, void 0, void 0, function () { + var cmd, i; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + cmd = this.prepareCommand(); + cmd.halt(); + // Point the program counter to the start of the program + cmd.writeCoreRegister(15 /* PC */, pc); + cmd.writeCoreRegister(14 /* LR */, lr); + cmd.writeCoreRegister(13 /* SP */, sp); + for (i = 0; i < args.length; i++) { + cmd.writeCoreRegister(i, args[i]); + } + return [4 /*yield*/, cmd.go()]; + case 1: + _a.sent(); + if (!upload) return [3 /*break*/, 3]; + return [4 /*yield*/, this.memory.writeBlock(address, code)]; + case 2: + _a.sent(); + _a.label = 3; + case 3: + // Run the program and wait for halt + return [4 /*yield*/, this.resume()]; + case 4: + // Run the program and wait for halt + _a.sent(); + return [4 /*yield*/, this.waitForHalt(constants_1.DEFAULT_RUNCODE_TIMEOUT)]; + case 5: + _a.sent(); // timeout after 10s + return [4 /*yield*/, this.readCoreRegister(0 /* R0 */)]; + case 6: return [2 /*return*/, _a.sent()]; + } + }); + }); + }; + /** + * Spin until the chip has halted. + */ + CortexM.prototype.waitForHalt = function (timeout) { + if (timeout === void 0) { timeout = 0; } + return __awaiter(this, void 0, void 0, function () { + var _this = this; + return __generator(this, function (_a) { + return [2 /*return*/, new Promise(function (resolve, reject) { return __awaiter(_this, void 0, void 0, function () { + var running, _a; + return __generator(this, function (_b) { + switch (_b.label) { + case 0: + running = true; + if (timeout > 0) { + setTimeout(function () { + if (running) { + reject("waitForHalt timed out."); + running = false; + } + }, timeout); + } + _b.label = 1; + case 1: + _a = running; + if (!_a) return [3 /*break*/, 3]; + return [4 /*yield*/, this.isHalted()]; + case 2: + _a = !(_b.sent()); + _b.label = 3; + case 3: + if (!_a) return [3 /*break*/, 4]; + return [3 /*break*/, 1]; + case 4: + if (running) { + running = false; + resolve(); + } + return [2 /*return*/]; + } + }); + }); })]; + }); + }); + }; + CortexM.prototype.softwareReset = function () { + return __awaiter(this, void 0, void 0, function () { + var dhcsr; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, this.memory.write32(3758157068 /* NVIC_AIRCR */, 100270080 /* NVIC_AIRCR_VECTKEY */ | 4 /* NVIC_AIRCR_SYSRESETREQ */)]; + case 1: + _a.sent(); + return [4 /*yield*/, this.memory.read32(3758157296 /* DHCSR */)]; + case 2: + dhcsr = _a.sent(); + _a.label = 3; + case 3: + if (!((dhcsr & 33554432 /* S_RESET_ST */) !== 0)) return [3 /*break*/, 5]; + return [4 /*yield*/, this.memory.read32(3758157296 /* DHCSR */)]; + case 4: + dhcsr = _a.sent(); + return [3 /*break*/, 3]; + case 5: return [2 /*return*/]; + } + }); + }); + }; + return CortexM; +}()); +exports.CortexM = CortexM; + + +/***/ }), +/* 3 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +exports.DEFAULT_RUNCODE_TIMEOUT = 10000 /* ms */; +exports.CPUID_IMPLEMENTER_MASK = 0xff000000; +exports.CPUID_IMPLEMENTER_POS = 24; +exports.CPUID_VARIANT_MASK = 0x00f00000; +exports.CPUID_VARIANT_POS = 20; +exports.CPUID_ARCHITECTURE_MASK = 0x000f0000; +exports.CPUID_ARCHITECTURE_POS = 16; +exports.CPUID_PARTNO_MASK = 0x0000fff0; +exports.CPUID_PARTNO_POS = 4; +exports.CPUID_REVISION_MASK = 0x0000000f; +exports.CPUID_REVISION_POS = 0; +exports.ISANames = new Map(); +exports.ISANames.set(12 /* ARMv6M */, "ARMv6M"); +exports.ISANames.set(15 /* ARMv7M */, "ARMv7M"); +exports.CoreNames = new Map(); +exports.CoreNames.set(3104 /* CortexM0 */, "Cortex-M0"); +exports.CoreNames.set(3105 /* CortexM1 */, "Cortex-M1"); +exports.CoreNames.set(3107 /* CortexM3 */, "Cortex-M3"); +exports.CoreNames.set(3108 /* CortexM4 */, "Cortex-M4"); +exports.CoreNames.set(3168 /* CortexM0p */, "Cortex-M0+"); + + +/***/ }), +/* 4 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +var cortex_1 = __webpack_require__(2); +exports.CortexM = cortex_1.CortexM; +var constants_1 = __webpack_require__(3); +exports.CoreNames = constants_1.CoreNames; +exports.ISANames = constants_1.ISANames; +var dap_1 = __webpack_require__(9); +exports.DAP = dap_1.default; +var FlashTarget_1 = __webpack_require__(12); +exports.FlashTargets = FlashTarget_1.FlashTargets; +exports.FlashTarget = FlashTarget_1.FlashTarget; +var FlashProgram_1 = __webpack_require__(15); +exports.FlashProgram = FlashProgram_1.FlashProgram; + + +/***/ }), +/* 5 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (_) try { + if (f = 1, y && (t = y[op[0] & 2 ? "return" : op[0] ? "throw" : "next"]) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [0, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +Object.defineProperty(exports, "__esModule", { value: true }); +var breakpoint_1 = __webpack_require__(6); +/** + * # Debug Interface + * + * Keeps track of breakpoints set on the target, as well as deciding whether to + * use a hardware breakpoint or a software breakpoint. + * + * ## Usage + * + * ```typescript + * const dbg = core.debug; + * + * await dbg.setBreakpoint(0x123456); + * + * // resume the core and wait for the breakpoint + * await core.resume(); + * await core.waitForHalt(); + * + * // step forward one instruction + * await dbg.step(); + * + * // remove the breakpoint + * await dbg.deleteBreakpoint(0x123456); + * ``` + */ +var Debug = (function () { + function Debug(core) { + this.core = core; + this.enabled = false; + this.availableHWBreakpoints = []; + this.breakpoints = new Map(); + } + Debug.prototype.init = function () { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, this.setupFpb()]; + case 1: + _a.sent(); + return [2 /*return*/]; + } + }); + }); + }; + /** + * Enable debugging on the target CPU + */ + Debug.prototype.enable = function () { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, this.core.memory.write32(3758157296 /* DHCSR */, -1604386816 /* DBGKEY */ | 1 /* C_DEBUGEN */)]; + case 1: + _a.sent(); + return [2 /*return*/]; + } + }); + }); + }; + /** + * Set breakpoints at specified memory addresses. + * + * @param addrs An array of memory addresses at which to set breakpoints. + */ + Debug.prototype.setBreakpoint = function (addr) { + return __awaiter(this, void 0, void 0, function () { + var breakpoint, bkpt, regAddr; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + if (this.breakpoints.has(addr)) { + breakpoint = this.breakpoints.get(addr); + if (typeof breakpoint !== "number") { + // already enabled + console.warn("Breakpoint at " + addr.toString(16) + " already enabled."); + return [2 /*return*/]; + } + } + if (!(addr < 0x20000000)) return [3 /*break*/, 5]; + if (!(this.availableHWBreakpoints.length > 0)) return [3 /*break*/, 3]; + if (!!this.enabled) return [3 /*break*/, 2]; + console.log("enabling fpb"); + return [4 /*yield*/, this.setFpbEnabled(true)]; + case 1: + _a.sent(); + _a.label = 2; + case 2: + regAddr = this.availableHWBreakpoints.pop(); + console.log("using regAddr=" + regAddr.toString(16)); + bkpt = new breakpoint_1.HWBreakpoint(regAddr, this.core, addr); + return [3 /*break*/, 4]; + case 3: + bkpt = new breakpoint_1.SWBreakpoint(this.core, addr); + _a.label = 4; + case 4: return [3 /*break*/, 6]; + case 5: + bkpt = new breakpoint_1.SWBreakpoint(this.core, addr); + _a.label = 6; + case 6: return [4 /*yield*/, bkpt.set()]; + case 7: + _a.sent(); + this.breakpoints.set(addr, bkpt); + return [2 /*return*/]; + } + }); + }); + }; + Debug.prototype.deleteBreakpoint = function (addr) { + return __awaiter(this, void 0, void 0, function () { + var bkpt; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + if (!this.breakpoints.has(addr)) return [3 /*break*/, 3]; + bkpt = this.breakpoints.get(addr); + if (!(typeof bkpt !== "number")) return [3 /*break*/, 2]; + return [4 /*yield*/, bkpt.clear()]; + case 1: + _a.sent(); + if (bkpt instanceof breakpoint_1.HWBreakpoint) { + // return the register address to the pool + this.availableHWBreakpoints.push(bkpt.regAddr); + } + _a.label = 2; + case 2: + this.breakpoints.delete(addr); + return [3 /*break*/, 4]; + case 3: + console.warn("Breakpoint at " + addr.toString(16) + " does not exist."); + _a.label = 4; + case 4: return [2 /*return*/]; + } + }); + }); + }; + /** + * Step the processor forward by one instruction. + */ + Debug.prototype.step = function () { + return __awaiter(this, void 0, void 0, function () { + var dhcsr, interruptsMasked; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, this.core.memory.read32(3758157296 /* DHCSR */)]; + case 1: + dhcsr = _a.sent(); + if (!(dhcsr & (4 /* C_STEP */ | 2 /* C_HALT */))) { + console.error("Target is not halted."); + return [2 /*return*/]; + } + interruptsMasked = (8 /* C_MASKINTS */ & dhcsr) !== 0; + if (!!interruptsMasked) return [3 /*break*/, 3]; + return [4 /*yield*/, this.core.memory.write32(3758157296 /* DHCSR */, -1604386816 /* DBGKEY */ | + 1 /* C_DEBUGEN */ | + 2 /* C_HALT */ | + 8 /* C_MASKINTS */)]; + case 2: + _a.sent(); + _a.label = 3; + case 3: return [4 /*yield*/, this.core.memory.write32(3758157296 /* DHCSR */, -1604386816 /* DBGKEY */ | + 1 /* C_DEBUGEN */ | + 8 /* C_MASKINTS */ | + 4 /* C_STEP */)]; + case 4: + _a.sent(); + return [4 /*yield*/, this.core.waitForHalt()]; + case 5: + _a.sent(); + return [4 /*yield*/, this.core.memory.write32(3758157296 /* DHCSR */, -1604386816 /* DBGKEY */ | + 1 /* C_DEBUGEN */ | + 2 /* C_HALT */)]; + case 6: + _a.sent(); + return [2 /*return*/]; + } + }); + }); + }; + /** + * Set up (and disable) the Flash Patch & Breakpoint unit. It will be enabled when + * the first breakpoint is set. + * + * Also reads the number of available hardware breakpoints. + */ + Debug.prototype.setupFpb = function () { + return __awaiter(this, void 0, void 0, function () { + var fpcr, nbCode, nbLit, i; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, this.core.memory.read32(3758104576 /* FP_CTRL */)]; + case 1: + fpcr = _a.sent(); + nbCode = ((fpcr >> 8) & 0x70) | ((fpcr >> 4) & 0xf); + nbLit = (fpcr >> 7) & 0xf; + this.totalHWBreakpoints = nbCode; + console.debug(nbCode + " hardware breakpoints, " + nbLit + " literal comparators"); + return [4 /*yield*/, this.setFpbEnabled(false)]; + case 2: + _a.sent(); + i = 0; + _a.label = 3; + case 3: + if (!(i < nbCode)) return [3 /*break*/, 6]; + this.availableHWBreakpoints.push(3758104584 /* FP_COMP0 */ + (4 * i)); + return [4 /*yield*/, this.core.memory.write32(3758104584 /* FP_COMP0 */ + (i * 4), 0)]; + case 4: + _a.sent(); + _a.label = 5; + case 5: + i++; + return [3 /*break*/, 3]; + case 6: return [2 /*return*/]; + } + }); + }); + }; + /** + * Enable or disable the Flash Patch and Breakpoint unit (FPB). + * + * @param enabled + */ + Debug.prototype.setFpbEnabled = function (enabled) { + if (enabled === void 0) { enabled = true; } + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + this.enabled = enabled; + return [4 /*yield*/, this.core.memory.write32(3758104576 /* FP_CTRL */, 2 /* FP_CTRL_KEY */ | (enabled ? 1 : 0))]; + case 1: + _a.sent(); + return [2 /*return*/]; + } + }); + }); + }; + return Debug; +}()); +exports.Debug = Debug; + + +/***/ }), +/* 6 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (_) try { + if (f = 1, y && (t = y[op[0] & 2 ? "return" : op[0] ? "throw" : "next"]) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [0, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +Object.defineProperty(exports, "__esModule", { value: true }); +var HWBreakpoint = (function () { + function HWBreakpoint(regAddr, parent, addr) { + this.regAddr = regAddr; + this.parent = parent; + this.addr = addr; + } + HWBreakpoint.prototype.set = function () { + return __awaiter(this, void 0, void 0, function () { + var bpMatch; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + bpMatch = ((this.addr & 0x2) ? 2 : 1) << 30; + return [4 /*yield*/, this.parent.memory.write32(this.regAddr, this.addr & 0x1ffffffc | bpMatch | 1)]; + case 1: + _a.sent(); + return [2 /*return*/]; + } + }); + }); + }; + HWBreakpoint.prototype.clear = function () { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + /* clear hardware breakpoint */ + return [4 /*yield*/, this.parent.memory.write32(this.regAddr, 0)]; + case 1: + /* clear hardware breakpoint */ + _a.sent(); + return [2 /*return*/]; + } + }); + }); + }; + return HWBreakpoint; +}()); +exports.HWBreakpoint = HWBreakpoint; +var SWBreakpoint = (function () { + function SWBreakpoint(parent, addr) { + this.parent = parent; + this.addr = addr; + } + SWBreakpoint.prototype.set = function () { + return __awaiter(this, void 0, void 0, function () { + var _a; + return __generator(this, function (_b) { + switch (_b.label) { + case 0: + // read the instruction from the CPU... + _a = this; + return [4 /*yield*/, this.parent.memory.read16(this.addr)]; + case 1: + // read the instruction from the CPU... + _a.instruction = _b.sent(); + return [4 /*yield*/, this.parent.memory.write16(this.addr, SWBreakpoint.BKPT_INSTRUCTION)]; + case 2: + _b.sent(); + return [2 /*return*/]; + } + }); + }); + }; + SWBreakpoint.prototype.clear = function () { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + /* clear hardware breakpoint */ + return [4 /*yield*/, this.parent.memory.write16(this.addr, this.instruction)]; + case 1: + /* clear hardware breakpoint */ + _a.sent(); + return [2 /*return*/]; + } + }); + }); + }; + SWBreakpoint.BKPT_INSTRUCTION = 0xbe00; + return SWBreakpoint; +}()); +exports.SWBreakpoint = SWBreakpoint; + + +/***/ }), +/* 7 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (_) try { + if (f = 1, y && (t = y[op[0] & 2 ? "return" : op[0] ? "throw" : "next"]) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [0, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +Object.defineProperty(exports, "__esModule", { value: true }); +var util_1 = __webpack_require__(0); +var prepared_1 = __webpack_require__(1); +/** + * # Memory Interface + * + * Controls access to the target's memory. + * + * ## Usage + * + * Using an instance of `CortexM`, as described before, we can simply read and + * write numbers to memory as follows: + * + * ```typescript + * const mem = core.memory; + * + * // NOTE: the address parameter must be word (4-byte) aligned. + * await mem.write32(0x200000, 12345); + * const val = await mem.read32(0x200000); + * + * // val === 12345 + * + * // NOTE: the address parameter must be half-word (2-byte) aligned + * await mem.write16(0x2000002, 65534); + * const val16 = await mem.read16(0x2000002); + * + * // val16 === 65534 + * ``` + * + * To write a larger block of memory, we can use `readBlock` and `writeBlock`. Again, + * these blocks must be written to word-aligned addresses in memory. + * + * ```typescript + * const data = new Uint32Array([0x1234, 0x5678, 0x9ABC, 0xDEF0]); + * await mem.writeBlock(0x200000, data); + * + * const readData = await mem.readBlock(0x200000, data.length, 0x100); + * ``` + * + * ## See also + * + * `PreparedMemoryCommand` provides an equivalent API with better performance (in some + * cases) by enabling batched memory operations. + */ +var Memory = (function () { + function Memory(dev) { + this.dev = dev; + } + /** + * Write a 32-bit word to the specified (word-aligned) memory address. + * + * @param addr Memory address to write to + * @param data Data to write (values above 2**32 will be truncated) + */ + Memory.prototype.write32 = function (addr, data) { + return __awaiter(this, void 0, void 0, function () { + var prep; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + prep = this.dev.prepareCommand(); + prep.writeAp(0 /* CSW */, 587202640 /* CSW_VALUE */ | 2 /* CSW_SIZE32 */); + prep.writeAp(4 /* TAR */, addr); + prep.writeAp(12 /* DRW */, data); + return [4 /*yield*/, prep.go()]; + case 1: + _a.sent(); + return [2 /*return*/]; + } + }); + }); + }; + /** + * Write a 16-bit word to the specified (half word-aligned) memory address. + * + * @param addr Memory address to write to + * @param data Data to write (values above 2**16 will be truncated) + */ + Memory.prototype.write16 = function (addr, data) { + return __awaiter(this, void 0, void 0, function () { + var prep; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + data = data << ((addr & 0x02) << 3); + prep = this.dev.prepareCommand(); + prep.writeAp(0 /* CSW */, 587202640 /* CSW_VALUE */ | 1 /* CSW_SIZE16 */); + prep.writeAp(4 /* TAR */, addr); + prep.writeAp(12 /* DRW */, data); + return [4 /*yield*/, prep.go()]; + case 1: + _a.sent(); + return [2 /*return*/]; + } + }); + }); + }; + /** + * Read a 32-bit word from the specified (word-aligned) memory address. + * + * @param addr Memory address to read from. + */ + Memory.prototype.read32 = function (addr) { + return __awaiter(this, void 0, void 0, function () { + var prep, e_1; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + prep = this.dev.prepareCommand(); + prep.writeAp(0 /* CSW */, 587202640 /* CSW_VALUE */ | 2 /* CSW_SIZE32 */); + prep.writeAp(4 /* TAR */, addr); + prep.readAp(12 /* DRW */); + _a.label = 1; + case 1: + _a.trys.push([1, 3, , 6]); + return [4 /*yield*/, prep.go()]; + case 2: return [2 /*return*/, (_a.sent())[0]]; + case 3: + e_1 = _a.sent(); + // transfer wait, try again. + return [4 /*yield*/, util_1.delay(100)]; + case 4: + // transfer wait, try again. + _a.sent(); + return [4 /*yield*/, this.read32(addr)]; + case 5: return [2 /*return*/, _a.sent()]; + case 6: return [2 /*return*/]; + } + }); + }); + }; + /** + * Read a 16-bit word from the specified (half word-aligned) memory address. + * + * @param addr Memory address to read from. + */ + Memory.prototype.read16 = function (addr) { + return __awaiter(this, void 0, void 0, function () { + var prep, val, e_2; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + prep = this.dev.prepareCommand(); + prep.writeAp(0 /* CSW */, 587202640 /* CSW_VALUE */ | 1 /* CSW_SIZE16 */); + prep.writeAp(4 /* TAR */, addr); + prep.readAp(12 /* DRW */); + _a.label = 1; + case 1: + _a.trys.push([1, 3, , 6]); + return [4 /*yield*/, prep.go()]; + case 2: + val = (_a.sent())[0]; + return [3 /*break*/, 6]; + case 3: + e_2 = _a.sent(); + // transfer wait, try again. + return [4 /*yield*/, util_1.delay(100)]; + case 4: + // transfer wait, try again. + _a.sent(); + return [4 /*yield*/, this.read16(addr)]; + case 5: + val = _a.sent(); + return [3 /*break*/, 6]; + case 6: + val = (val >> ((addr & 0x02) << 3) & 0xffff); + return [2 /*return*/, val]; + } + }); + }); + }; + /** + * Reads a block of memory from the specified memory address. + * + * @param addr Address to read from + * @param words Number of words to read + * @param pageSize Memory page size + */ + Memory.prototype.readBlock = function (addr, words, pageSize) { + return __awaiter(this, void 0, void 0, function () { + var bufs, end, ptr, nextptr, len, _a, _b, result; + return __generator(this, function (_c) { + switch (_c.label) { + case 0: + bufs = []; + end = addr + words * 4; + ptr = addr; + _c.label = 1; + case 1: + if (!(ptr < end)) return [3 /*break*/, 3]; + nextptr = ptr + pageSize; + if (ptr === addr) { + nextptr &= ~(pageSize - 1); + } + len = Math.min(nextptr - ptr, end - ptr); + util_1.assert((len & 3) === 0); + _b = (_a = bufs).push; + return [4 /*yield*/, this.readBlockCore(ptr, len >> 2)]; + case 2: + _b.apply(_a, [_c.sent()]); + ptr = nextptr; + return [3 /*break*/, 1]; + case 3: + result = util_1.bufferConcat(bufs); + return [2 /*return*/, result.subarray(0, words * 4)]; + } + }); + }); + }; + /** + * Write a block of memory to the specified memory address. + * + * @param addr Memory address to write to. + * @param words Array of 32-bit words to write to memory. + */ + Memory.prototype.writeBlock = function (addr, words) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + if (words.length === 0) { + return [2 /*return*/]; + } + return [2 /*return*/, this.writeBlockCore(addr, words)]; + }); + }); + }; + Memory.prototype.prepareCommand = function () { + return new prepared_1.PreparedMemoryCommand(this.dev); + }; + Memory.prototype.readBlockCore = function (addr, words) { + return __awaiter(this, void 0, void 0, function () { + var prep, lastSize, blocks, i, b; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + prep = this.dev.prepareCommand(); + prep.writeAp(0 /* CSW */, 587202640 /* CSW_VALUE */ | 2 /* CSW_SIZE32 */); + prep.writeAp(4 /* TAR */, addr); + return [4 /*yield*/, prep.go()]; + case 1: + _a.sent(); + lastSize = words % 15; + if (lastSize === 0) { + lastSize = 15; + } + blocks = []; + i = 0; + _a.label = 2; + case 2: + if (!(i < Math.ceil(words / 15))) return [3 /*break*/, 5]; + return [4 /*yield*/, this.dev.readRegRepeat(util_1.apReg(12 /* DRW */, 2 /* READ */), i === blocks.length - 1 ? lastSize : 15)]; + case 3: + b = _a.sent(); + blocks.push(b); + _a.label = 4; + case 4: + i++; + return [3 /*break*/, 2]; + case 5: return [2 /*return*/, util_1.bufferConcat(blocks).subarray(0, words * 4)]; + } + }); + }); + }; + Memory.prototype.writeBlockCore = function (addr, words) { + return __awaiter(this, void 0, void 0, function () { + var prep, e_3; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + _a.trys.push([0, 2, , 7]); + prep = this.dev.prepareCommand(); + prep.writeAp(0 /* CSW */, 587202640 /* CSW_VALUE */ | 2 /* CSW_SIZE32 */); + prep.writeAp(4 /* TAR */, addr); + prep.writeRegRepeat(util_1.apReg(12 /* DRW */, 0 /* WRITE */), words); + return [4 /*yield*/, prep.go()]; + case 1: + _a.sent(); + return [3 /*break*/, 7]; + case 2: + e_3 = _a.sent(); + if (!e_3.dapWait) return [3 /*break*/, 5]; + console.debug("transfer wait, write block"); + return [4 /*yield*/, util_1.delay(100)]; + case 3: + _a.sent(); + return [4 /*yield*/, this.writeBlockCore(addr, words)]; + case 4: return [2 /*return*/, _a.sent()]; + case 5: throw e_3; + case 6: return [3 /*break*/, 7]; + case 7: return [2 /*return*/]; + } + }); + }); + }; + return Memory; +}()); +exports.Memory = Memory; + + +/***/ }), +/* 8 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (_) try { + if (f = 1, y && (t = y[op[0] & 2 ? "return" : op[0] ? "throw" : "next"]) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [0, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +Object.defineProperty(exports, "__esModule", { value: true }); +var prepared_1 = __webpack_require__(1); +/** + * # Cortex M: Prepared Command + * + * Allows batching of Cortex M-related commands, such as writing to a register, + * halting and resuming the core. + * + * ## Example + * + * When preparing the sequence of commands, we can use the same API to prepare + * a command as we would to execute them immediately. + * + * ```typescript + * // Note that only the .go method is asynchronous. + * + * const prep = core.prepareCommand(); + * prep.writeCoreRegister(CortexReg.R0, 0x1000); + * prep.writeCoreRegister(CortexReg.R1, 0x0); + * prep.writeCoreRegister(CortexReg.PC, 0x2000000); + * prep.resume(); + * ``` + * + * We can then execute them as efficiently as possible by combining them together + * and executing them like so. + * + * ```typescript + * await prep.go(); + * ``` + * + * The code above is equivalent to the following _non-prepared_ command: + * + * ```typescript + * await core.writeCoreRegister(CortexReg.R0, 0x1000); + * await core.writeCoreRegister(CortexReg.R1, 0x0); + * await core.writeCoreRegister(CortexReg.PC, 0x2000000); + * await core.resume(); + * ``` + * + * Since the batched version of this code avoids making three round-trips to the + * target, we are able to significantly improve performance. This is especially + * noticable when uploading a binary to flash memory, where are large number of + * repetetive commands are being used. + * + * ## Explanation + * + * For a detailed explanation of why prepared commands are used in DAP.js, see the + * documentation for `PreparedDapCommand`. + */ +var PreparedCortexMCommand = (function () { + function PreparedCortexMCommand(dap) { + this.cmd = new prepared_1.PreparedMemoryCommand(dap); + } + /** + * Schedule a 32-bit integer to be written to a core register. + * + * @param no Core register to be written. + * @param val Value to write. + */ + PreparedCortexMCommand.prototype.writeCoreRegister = function (no, val) { + this.cmd.write32(3758157304 /* DCRDR */, val); + this.cmd.write32(3758157300 /* DCRSR */, no | 65536 /* DCRSR_REGWnR */); + }; + /** + * Schedule a halt command to be written to the CPU. + */ + PreparedCortexMCommand.prototype.halt = function () { + this.cmd.write32(3758157296 /* DHCSR */, -1604386816 /* DBGKEY */ | 1 /* C_DEBUGEN */ | 2 /* C_HALT */); + }; + /** + * Schedule a resume command to be written to the CPU. + */ + PreparedCortexMCommand.prototype.resume = function () { + this.cmd.write32(3758157104 /* DFSR */, 4 /* DFSR_DWTTRAP */ | 2 /* DFSR_BKPT */ | 1 /* DFSR_HALTED */); + }; + /** + * Execute all scheduled commands. + */ + PreparedCortexMCommand.prototype.go = function () { + return __awaiter(this, void 0, void 0, function () { + var v; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, this.cmd.go()]; + case 1: + v = _a.sent(); + return [2 /*return*/]; + } + }); + }); + }; + return PreparedCortexMCommand; +}()); +exports.PreparedCortexMCommand = PreparedCortexMCommand; + + +/***/ }), +/* 9 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (_) try { + if (f = 1, y && (t = y[op[0] & 2 ? "return" : op[0] ? "throw" : "next"]) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [0, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +Object.defineProperty(exports, "__esModule", { value: true }); +var prepared_1 = __webpack_require__(10); +var cmsis_dap_1 = __webpack_require__(11); +var util_1 = __webpack_require__(0); +var DAP = (function () { + function DAP(device) { + this.device = device; + this.dap = new cmsis_dap_1.CMSISDAP(device); + } + DAP.prototype.reconnect = function () { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, this.dap.disconnect()]; + case 1: + _a.sent(); + return [4 /*yield*/, util_1.delay(100)]; + case 2: + _a.sent(); + return [4 /*yield*/, this.init()]; + case 3: + _a.sent(); + return [2 /*return*/]; + } + }); + }); + }; + DAP.prototype.init = function () { + return __awaiter(this, void 0, void 0, function () { + var n, prep, m, v; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, this.dap.connect()]; + case 1: + _a.sent(); + return [4 /*yield*/, this.readDp(0 /* IDCODE */)]; + case 2: + n = _a.sent(); + this.idcode = n; + prep = this.prepareCommand(); + prep.writeReg(0 /* DP_0x0 */, 1 << 2); // clear sticky error + prep.writeDp(2 /* SELECT */, 0); + prep.writeDp(1 /* CTRL_STAT */, 1073741824 /* CSYSPWRUPREQ */ | 268435456 /* CDBGPWRUPREQ */); + m = 536870912 /* CDBGPWRUPACK */ | 2147483648 /* CSYSPWRUPACK */; + prep.readDp(1 /* CTRL_STAT */); + return [4 /*yield*/, prep.go()]; + case 3: + v = (_a.sent())[0]; + _a.label = 4; + case 4: + if (!((v & m) !== m)) return [3 /*break*/, 6]; + return [4 /*yield*/, this.readDp(1 /* CTRL_STAT */)]; + case 5: + v = _a.sent(); + return [3 /*break*/, 4]; + case 6: + prep = this.prepareCommand(); + prep.writeDp(1 /* CTRL_STAT */, (1073741824 /* CSYSPWRUPREQ */ | + 268435456 /* CDBGPWRUPREQ */ | + 0 /* TRNNORMAL */ | + 3840 /* MASKLANE */)); + prep.writeDp(2 /* SELECT */, 0); + prep.readAp(252 /* IDR */); + return [4 /*yield*/, prep.go()]; + case 7: + _a.sent(); + return [2 /*return*/]; + } + }); + }); + }; + DAP.prototype.writeReg = function (regId, val) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/, this.regOp(regId, val)]; + }); + }); + }; + DAP.prototype.readReg = function (regId) { + return __awaiter(this, void 0, void 0, function () { + var buf, v; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, this.regOp(regId, null)]; + case 1: + buf = _a.sent(); + v = util_1.readUInt32LE(buf, 3); + return [2 /*return*/, v]; + } + }); + }); + }; + DAP.prototype.prepareCommand = function () { + return new prepared_1.PreparedDapCommand(this.dap); + }; + DAP.prototype.readDp = function (addr) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/, this.readReg(addr)]; + }); + }); + }; + DAP.prototype.readAp = function (addr) { + return __awaiter(this, void 0, void 0, function () { + var prep; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + prep = this.prepareCommand(); + prep.writeDp(2 /* SELECT */, util_1.bank(addr)); + prep.readReg(util_1.apReg(addr, 2 /* READ */)); + return [4 /*yield*/, prep.go()]; + case 1: return [2 /*return*/, (_a.sent())[0]]; + } + }); + }); + }; + DAP.prototype.writeDp = function (addr, data) { + if (addr === 2 /* SELECT */) { + if (data === this.dpSelect) { + return Promise.resolve(); + } + this.dpSelect = data; + } + return this.writeReg(addr, data); + }; + DAP.prototype.writeAp = function (addr, data) { + return __awaiter(this, void 0, void 0, function () { + var prep; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + if (addr === 0 /* CSW */) { + if (data === this.csw) { + return [2 /*return*/, Promise.resolve()]; + } + this.csw = data; + } + prep = this.prepareCommand(); + prep.writeDp(2 /* SELECT */, util_1.bank(addr)); + prep.writeReg(util_1.apReg(addr, 0 /* WRITE */), data); + return [4 /*yield*/, prep.go()]; + case 1: + _a.sent(); + return [2 /*return*/]; + } + }); + }); + }; + DAP.prototype.close = function () { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/, this.device.close()]; + }); + }); + }; + DAP.prototype.readRegRepeat = function (regId, cnt) { + return __awaiter(this, void 0, void 0, function () { + var request, sendargs, i, buf; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + util_1.assert(cnt <= 15); + request = util_1.regRequest(regId); + sendargs = [0, cnt]; + for (i = 0; i < cnt; ++i) { + sendargs.push(request); + } + return [4 /*yield*/, this.dap.cmdNums(5 /* DAP_TRANSFER */, sendargs)]; + case 1: + buf = _a.sent(); + if (buf[1] !== cnt) { + throw new Error(("(many) Bad #trans " + buf[1])); + } + else if (buf[2] !== 1) { + throw new Error(("(many) Bad transfer status " + buf[2])); + } + return [2 /*return*/, buf.subarray(3, 3 + cnt * 4)]; + } + }); + }); + }; + DAP.prototype.writeRegRepeat = function (regId, data) { + return __awaiter(this, void 0, void 0, function () { + var remainingLength, request, sendargs, buf; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + remainingLength = 64 - 1 - 1 - 2 - 1; + util_1.assert(data.length <= remainingLength / 4); + request = util_1.regRequest(regId, true); + sendargs = [0, data.length, 0, request]; + data.forEach(function (d) { + // separate d into bytes + util_1.addInt32(sendargs, d); + }); + return [4 /*yield*/, this.dap.cmdNums(6 /* DAP_TRANSFER_BLOCK */, sendargs)]; + case 1: + buf = _a.sent(); + if (buf[3] !== 1) { + throw new Error(("(many-wr) Bad transfer status " + buf[2])); + } + return [2 /*return*/]; + } + }); + }); + }; + DAP.prototype.regOp = function (regId, val) { + return __awaiter(this, void 0, void 0, function () { + var request, sendargs, buf; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + request = util_1.regRequest(regId, val !== null); + sendargs = [0, 1, request]; + if (val !== null) { + util_1.addInt32(sendargs, val); + } + return [4 /*yield*/, this.dap.cmdNums(5 /* DAP_TRANSFER */, sendargs)]; + case 1: + buf = _a.sent(); + if (buf[1] !== 1) { + console.error("Make sure you have initialised the DAP connection."); + throw new Error(("Bad #trans " + buf[1])); + } + else if (buf[2] !== 1) { + if (buf[2] === 2) { + throw new Error(("Transfer wait")); + } + throw new Error(("Bad transfer status " + buf[2])); + } + return [2 /*return*/, buf]; + } + }); + }); + }; + return DAP; +}()); +exports.default = DAP; + + +/***/ }), +/* 10 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (_) try { + if (f = 1, y && (t = y[op[0] & 2 ? "return" : op[0] ? "throw" : "next"]) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [0, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +Object.defineProperty(exports, "__esModule", { value: true }); +var util_1 = __webpack_require__(0); +/** + * # Prepared DAP Command + * + * Batches together multiple Debug Access Port (DAP) commands into one (or more) + * CMSIS-DAP Transfers that can be written together to improve link utilisation. + * + * > **NOTE:** this will not normally need to be used by applications or libraries + * > depending on DAP.js. + * + * ## Architecture + * + * - `PreparedDapCommand` keeps a list of CMSIS-DAP `Transfer` commands. + * - Every time an action is scheduled (writing to or reading from a DP or AP register), + * we check to see if there is any remaining room in the current batch, starting a new + * batch if none is available. + * - When `go` is called, the batches are executed sequentially (so DAP commands are + * executed in the order they were added). + * + * ### Reading Values + * + * Writing values to registers is relatively straight forward, however mixing register + * reads and writes together requires us to keep track of how many commands in + * each batch are read commands. + * + * Once data has successfully been read back from the target, the values read are assembled + * into an array, and returned in the order they requested. This allows `PreparedDapCommand`s + * to be used higher up the stack in places where multiple independent read operations take + * place sequentially. + * + * ### Constructing CMSIS-DAP Commands + * + * We keep track of the number of commands in each batch, so that we can fill in the command + * count field of the `DAP_Transfer`. + */ +var PreparedDapCommand = (function () { + function PreparedDapCommand(dap) { + this.dap = dap; + this.commands = [[0, 1]]; + this.commandCounts = [0]; + this.currentCommand = 0; + this.readCounts = [0]; + } + /** + * Schedule a value to be written to an AP or DP register. + * + * @param regId register ID to be written to + * @param value value to be written + */ + PreparedDapCommand.prototype.writeReg = function (regId, value) { + var request = util_1.regRequest(regId, true); + if (this.commands[this.currentCommand].length + 5 > 64) { + // start a new command + this.commands.push([0, 1]); + this.commandCounts.push(0); + this.readCounts.push(0); + this.currentCommand++; + } + this.commands[this.currentCommand].push(request); + util_1.addInt32(this.commands[this.currentCommand], value); + this.commandCounts[this.currentCommand]++; + }; + /** + * Schedule a value to be read from an AP or DP register. + * @param regId register to read from + */ + PreparedDapCommand.prototype.readReg = function (regId) { + var request = util_1.regRequest(regId, false); + if (this.commands[this.currentCommand].length + 1 > 64) { + // start a new command + this.commands.push([0, 1]); + this.commandCounts.push(0); + this.readCounts.push(0); + this.currentCommand++; + } + this.commands[this.currentCommand].push(request); + this.commandCounts[this.currentCommand]++; + this.readCounts[this.currentCommand]++; + }; + /** + * Schedule multiple values to be written to the same register. + * + * **TODO:** figure out dynamically whether it's better to use DAP_TransferBlock vs + * DAP_Transfer. We should be able to fill up the remaining space in a Transfer + * and then start a TransferBlock _if_ we can fit in _13 or more_ values into the + * TransferBlock. However, the gains from this are marginal unless we're using much + * larger packet sizes than 64 bytes. + * + * @param regId register to write to repeatedly + * @param data array of 32-bit values to be written + */ + PreparedDapCommand.prototype.writeRegRepeat = function (regId, data) { + var _this = this; + // fill up the rest of the command we have left + data.forEach(function (cmd) { + _this.writeReg(regId, cmd); + }); + }; + /** + * Asynchronously execute the commands scheduled. + */ + PreparedDapCommand.prototype.go = function () { + return __awaiter(this, void 0, void 0, function () { + var v, i, command, results, i, result, j; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + v = []; + for (i = 0; i < this.commands.length; i++) { + command = this.commands[i]; + command[1] = this.commandCounts[i]; + } + return [4 /*yield*/, this.dap.sendTransfers(this.commands)]; + case 1: + results = _a.sent(); + for (i = 0; i < this.commands.length; i++) { + result = results[i]; + for (j = 0; j < this.readCounts[i]; j++) { + v.push(util_1.readUInt32LE(result, 3 + 4 * j)); + } + } + return [2 /*return*/, v]; + } + }); + }); + }; + /** + * Schedule a value to be written to a DP register + * + * @param addr Address to write to + * @param data Data to be written + */ + PreparedDapCommand.prototype.writeDp = function (addr, data) { + if (addr === 2 /* SELECT */) { + if (data === this.dpSelect) { + return Promise.resolve(); + } + this.dpSelect = data; + } + return this.writeReg(addr, data); + }; + /** + * Schedule a value to be written to an AP register + * + * @param addr Address to write to + * @param data Data to be written + */ + PreparedDapCommand.prototype.writeAp = function (addr, data) { + this.writeDp(2 /* SELECT */, util_1.bank(addr)); + if (addr === 0 /* CSW */) { + if (data === this.csw) { + return Promise.resolve(); + } + this.csw = data; + } + this.writeReg(util_1.apReg(addr, 0 /* WRITE */), data); + }; + /** + * Schedule a DP register to read from + * + * @param addr Address to read from + */ + PreparedDapCommand.prototype.readDp = function (addr) { + return this.readReg(addr); + }; + /** + * Schedule an AP register to read from + * + * @param addr Address to read from + */ + PreparedDapCommand.prototype.readAp = function (addr) { + this.writeDp(2 /* SELECT */, util_1.bank(addr)); + return this.readReg(util_1.apReg(addr, 2 /* READ */)); + }; + return PreparedDapCommand; +}()); +exports.PreparedDapCommand = PreparedDapCommand; + + +/***/ }), +/* 11 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (_) try { + if (f = 1, y && (t = y[op[0] & 2 ? "return" : op[0] ? "throw" : "next"]) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [0, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +Object.defineProperty(exports, "__esModule", { value: true }); +var util_1 = __webpack_require__(0); +var CMSISDAP = (function () { + function CMSISDAP(hid) { + this.maxSent = 1; + this.hid = hid; + } + CMSISDAP.prototype.resetTarget = function () { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/, this.cmdNums(10 /* DAP_RESET_TARGET */, [])]; + }); + }); + }; + CMSISDAP.prototype.disconnect = function () { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/, this.cmdNums(3 /* DAP_DISCONNECT */, [])]; + }); + }); + }; + CMSISDAP.prototype.sendTransfers = function (commands) { + return __awaiter(this, void 0, void 0, function () { + var res, _i, commands_1, cmd, _a, _b; + return __generator(this, function (_c) { + switch (_c.label) { + case 0: + if (this.hid.sendMany) + return [2 /*return*/, this.hid.sendMany(commands.map(function (cmd) { + cmd.unshift(5 /* DAP_TRANSFER */); + return Uint8Array.from(cmd); + })).then(function (bufs) { + for (var _i = 0, bufs_1 = bufs; _i < bufs_1.length; _i++) { + var buf = bufs_1[_i]; + if (buf[0] != 5 /* DAP_TRANSFER */) + throw new Error("Bad response for Transfer (many) -> " + buf[0]); + } + return bufs; + })]; + res = []; + _i = 0, commands_1 = commands; + _c.label = 1; + case 1: + if (!(_i < commands_1.length)) return [3 /*break*/, 4]; + cmd = commands_1[_i]; + _b = (_a = res).push; + return [4 /*yield*/, this.cmdNums(5 /* DAP_TRANSFER */, cmd)]; + case 2: + _b.apply(_a, [_c.sent()]); + _c.label = 3; + case 3: + _i++; + return [3 /*break*/, 1]; + case 4: return [2 /*return*/, res]; + } + }); + }); + }; + CMSISDAP.prototype.cmdNums = function (op, data) { + return __awaiter(this, void 0, void 0, function () { + var buf; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + data.unshift(op); + return [4 /*yield*/, this.send(data)]; + case 1: + buf = _a.sent(); + if (buf[0] !== op) { + throw new Error("Bad response for " + op + " -> " + buf[0]); + } + switch (op) { + case 2 /* DAP_CONNECT */: + case 0 /* DAP_INFO */: + case 5 /* DAP_TRANSFER */: + case 6 /* DAP_TRANSFER_BLOCK */: + break; + default: + if (op < 0x80 && buf[1] !== 0) { + throw new Error("Bad status for " + op + " -> " + buf[1]); + } + } + return [2 /*return*/, buf]; + } + }); + }); + }; + CMSISDAP.prototype.connect = function () { + return __awaiter(this, void 0, void 0, function () { + var v, buf; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + console.log("Connecting..."); + return [4 /*yield*/, this.info(254 /* PACKET_COUNT */)]; + case 1: + v = _a.sent(); + if (v) { + this.maxSent = v; + } + else { + throw new Error("DAP_INFO returned invalid packet count."); + } + return [4 /*yield*/, this.cmdNums(17 /* DAP_SWJ_CLOCK */, util_1.addInt32(null, 10000000))]; + case 2: + _a.sent(); + return [4 /*yield*/, this.cmdNums(2 /* DAP_CONNECT */, [0])]; + case 3: + buf = _a.sent(); + if (buf[1] !== 1) { + throw new Error("SWD mode not enabled."); + } + return [4 /*yield*/, this.cmdNums(17 /* DAP_SWJ_CLOCK */, util_1.addInt32(null, 10000000))]; + case 4: + _a.sent(); + return [4 /*yield*/, this.cmdNums(4 /* DAP_TRANSFER_CONFIGURE */, [0, 0x50, 0, 0, 0])]; + case 5: + _a.sent(); + return [4 /*yield*/, this.cmdNums(19 /* DAP_SWD_CONFIGURE */, [0])]; + case 6: + _a.sent(); + return [4 /*yield*/, this.jtagToSwd()]; + case 7: + _a.sent(); + console.log("Connected"); + return [2 /*return*/]; + } + }); + }); + }; + CMSISDAP.prototype.jtagToSwd = function () { + return __awaiter(this, void 0, void 0, function () { + var arrs, _i, arrs_1, arr; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + arrs = [ + [56, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff], + [16, 0x9e, 0xe7], + [56, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff], + [8, 0x00], + ]; + _i = 0, arrs_1 = arrs; + _a.label = 1; + case 1: + if (!(_i < arrs_1.length)) return [3 /*break*/, 4]; + arr = arrs_1[_i]; + return [4 /*yield*/, this.swjSequence(arr)]; + case 2: + _a.sent(); + _a.label = 3; + case 3: + _i++; + return [3 /*break*/, 1]; + case 4: return [2 /*return*/]; + } + }); + }); + }; + CMSISDAP.prototype.swjSequence = function (data) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/, this.cmdNums(18 /* DAP_SWJ_SEQUENCE */, data)]; + }); + }); + }; + CMSISDAP.prototype.info = function (id) { + return __awaiter(this, void 0, void 0, function () { + var buf; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, this.cmdNums(0 /* DAP_INFO */, [id])]; + case 1: + buf = _a.sent(); + if (buf[1] === 0) { + return [2 /*return*/, null]; + } + switch (id) { + case 240 /* CAPABILITIES */: + case 254 /* PACKET_COUNT */: + case 255 /* PACKET_SIZE */: + if (buf[1] === 1) { + return [2 /*return*/, buf[2]]; + } + else if (buf[1] === 2) { + return [2 /*return*/, buf[3] << 8 | buf[2]]; + } + } + return [2 /*return*/, buf.subarray(2, buf[1] + 2 - 1)]; // .toString("utf8") + } + }); + }); + }; + CMSISDAP.prototype.send = function (command) { + return __awaiter(this, void 0, void 0, function () { + var array, response; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + array = Uint8Array.from(command); + return [4 /*yield*/, this.hid.write(array.buffer)]; + case 1: + _a.sent(); + return [4 /*yield*/, this.hid.read()]; + case 2: + response = _a.sent(); + return [2 /*return*/, new Uint8Array(response.buffer)]; + } + }); + }); + }; + return CMSISDAP; +}()); +exports.CMSISDAP = CMSISDAP; + + +/***/ }), +/* 12 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +var __extends = (this && this.__extends) || (function () { + var extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; + return function (d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (_) try { + if (f = 1, y && (t = y[op[0] & 2 ? "return" : op[0] ? "throw" : "next"]) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [0, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +Object.defineProperty(exports, "__esModule", { value: true }); +var cortex_1 = __webpack_require__(2); +var K64F_1 = __webpack_require__(13); +var NRF51_1 = __webpack_require__(14); +var analyzer = new Uint32Array([ + 0x2180468c, 0x2600b5f0, 0x4f2c2501, 0x447f4c2c, 0x1c2b0049, 0x425b4033, 0x40230872, 0x085a4053, + 0x425b402b, 0x40534023, 0x402b085a, 0x4023425b, 0x085a4053, 0x425b402b, 0x40534023, 0x402b085a, + 0x4023425b, 0x085a4053, 0x425b402b, 0x40534023, 0x402b085a, 0x4023425b, 0x085a4053, 0x425b402b, + 0x40534023, 0xc7083601, 0xd1d2428e, 0x2b004663, 0x4663d01f, 0x46b4009e, 0x24ff2701, 0x44844d11, + 0x1c3a447d, 0x88418803, 0x4351409a, 0xd0122a00, 0x22011856, 0x780b4252, 0x40533101, 0x009b4023, + 0x0a12595b, 0x42b1405a, 0x43d2d1f5, 0x4560c004, 0x2000d1e7, 0x2200bdf0, 0x46c0e7f8, 0x000000b6, + 0xedb88320, 0x00000044, +]); +var FlashTarget = (function (_super) { + __extends(FlashTarget, _super); + function FlashTarget(device, platform) { + var _this = _super.call(this, device) || this; + _this.platform = platform; + _this.inited = false; + return _this; + } + /** + * Initialise the flash driver on the chip. Must be called before any of the other + * flash-related methods. + */ + FlashTarget.prototype.flashInit = function () { + return __awaiter(this, void 0, void 0, function () { + var result; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + if (this.inited) { + return [2 /*return*/]; + } + // reset and halt + return [4 /*yield*/, this.reset(true)]; + case 1: + // reset and halt + _a.sent(); + // make sure we're in Thumb mode. + return [4 /*yield*/, this.writeCoreRegister(16 /* XPSR */, 1 << 24)]; + case 2: + // make sure we're in Thumb mode. + _a.sent(); + return [4 /*yield*/, this.writeCoreRegister(9 /* R9 */, this.platform.flashAlgo.staticBase)]; + case 3: + _a.sent(); + if (!this.platform.flashAlgo.analyzerSupported) return [3 /*break*/, 5]; + return [4 /*yield*/, this.memory.writeBlock(this.platform.flashAlgo.analyzerAddress, analyzer)]; + case 4: + _a.sent(); + _a.label = 5; + case 5: return [4 /*yield*/, this.runCode(this.platform.flashAlgo.instructions, this.platform.flashAlgo.loadAddress, this.platform.flashAlgo.pcInit, this.platform.flashAlgo.loadAddress + 1, this.platform.flashAlgo.stackPointer, true, 0, 0, 0, 0)]; + case 6: + result = _a.sent(); + this.inited = true; + return [2 /*return*/, result]; + } + }); + }); + }; + /** + * Erase _all_ data stored in flash on the chip. + */ + FlashTarget.prototype.eraseChip = function () { + return __awaiter(this, void 0, void 0, function () { + var result; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + if (!!this.inited) return [3 /*break*/, 2]; + return [4 /*yield*/, this.flashInit()]; + case 1: + _a.sent(); + _a.label = 2; + case 2: return [4 /*yield*/, this.runCode(this.platform.flashAlgo.instructions, this.platform.flashAlgo.loadAddress, this.platform.flashAlgo.pcEraseAll, this.platform.flashAlgo.loadAddress + 1, this.platform.flashAlgo.stackPointer, false, 0, 0, 0)]; + case 3: + result = _a.sent(); + return [2 /*return*/, result]; + } + }); + }); + }; + /** + * Upload a program to flash memory on the chip. + * TODO: add a callback to provide progress data + * + * @param data Array of 32-bit integers to write to flash. + */ + FlashTarget.prototype.flash = function (data, address, progressCb) { + return __awaiter(this, void 0, void 0, function () { + var pageSizeWords, bufferAddress, flashStart, ptr, wordPtr, pageData, flashAddress; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + if (!!this.inited) return [3 /*break*/, 2]; + return [4 /*yield*/, this.flashInit()]; + case 1: + _a.sent(); + _a.label = 2; + case 2: + pageSizeWords = this.platform.flashAlgo.pageSize / 4; + bufferAddress = this.platform.flashAlgo.pageBuffers[0]; + flashStart = address || this.platform.flashAlgo.flashStart; + ptr = 0; + _a.label = 3; + case 3: + if (!(ptr < data.byteLength)) return [3 /*break*/, 6]; + wordPtr = ptr / 4; + pageData = data.subarray(wordPtr, wordPtr + pageSizeWords); + flashAddress = flashStart + ptr; + return [4 /*yield*/, this.memory.writeBlock(bufferAddress, pageData)]; + case 4: + _a.sent(); + return [4 /*yield*/, this.runCode(this.platform.flashAlgo.instructions, this.platform.flashAlgo.loadAddress, this.platform.flashAlgo.pcProgramPage, // pc + this.platform.flashAlgo.loadAddress + 1, // lr + this.platform.flashAlgo.stackPointer, // sp + /* upload? */ + false, + /* args */ + flashAddress, this.platform.flashAlgo.pageSize, bufferAddress)]; + case 5: + _a.sent(); + if (progressCb) { + progressCb(ptr / data.byteLength); + } + ptr += pageData.byteLength; + return [3 /*break*/, 3]; + case 6: + if (progressCb) { + progressCb(1.0); + } + return [2 /*return*/]; + } + }); + }); + }; + FlashTarget.prototype.program = function (program, progressCb) { + return __awaiter(this, void 0, void 0, function () { + var totalBytes, cumulativeBytes, startTime, _loop_1, this_1, _i, _a, section, endTime, elapsedTime, transferRate; + return __generator(this, function (_b) { + switch (_b.label) { + case 0: return [4 /*yield*/, this.flashInit()]; + case 1: + _b.sent(); + return [4 /*yield*/, this.eraseChip()]; + case 2: + _b.sent(); + totalBytes = program.totalByteLength(); + cumulativeBytes = 0; + startTime = Date.now(); + _loop_1 = function (section) { + return __generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, this_1.flash(section.data, section.address, function (progress) { + var sectionBytes = section.data.byteLength * progress; + progressCb((cumulativeBytes + sectionBytes) / totalBytes); + })]; + case 1: + _a.sent(); + cumulativeBytes += section.data.byteLength; + return [2 /*return*/]; + } + }); + }; + this_1 = this; + _i = 0, _a = program.sections; + _b.label = 3; + case 3: + if (!(_i < _a.length)) return [3 /*break*/, 6]; + section = _a[_i]; + return [5 /*yield**/, _loop_1(section)]; + case 4: + _b.sent(); + _b.label = 5; + case 5: + _i++; + return [3 /*break*/, 3]; + case 6: + endTime = Date.now(); + elapsedTime = endTime - startTime; + transferRate = totalBytes / elapsedTime; + console.debug("Transfer took " + elapsedTime / 1000 + " s"); + console.debug("Transfered " + totalBytes + " bytes at " + transferRate + " kB/s"); + return [4 /*yield*/, this.flashUnInit()]; + case 7: + _b.sent(); + progressCb(1.0); + return [2 /*return*/]; + } + }); + }); + }; + FlashTarget.prototype.flashUnInit = function () { + this.inited = false; + }; + return FlashTarget; +}(cortex_1.CortexM)); +exports.FlashTarget = FlashTarget; +exports.FlashTargets = new Map(); +exports.FlashTargets.set("0240", new K64F_1.K64F()); +exports.FlashTargets.set("9900", new NRF51_1.NRF51()); + + +/***/ }), +/* 13 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +var K64F_FLASH_ALGO = { + analyzerAddress: 0x1ffff000, + analyzerSupported: true, + flashSize: 0x100000, + flashStart: 0x0, + // Flash algorithm as a hex string + instructions: new Uint32Array([ + 0xE00ABE00, 0x062D780D, 0x24084068, 0xD3000040, 0x1E644058, 0x1C49D1FA, 0x2A001E52, 0x4770D1F2, + 0x4604b570, 0x4616460d, 0x5020f24c, 0x81c84932, 0x1028f64d, 0x460881c8, 0xf0208800, 0x80080001, + 0x4448482e, 0xf8dcf000, 0x2001b108, 0x2000bd70, 0x4601e7fc, 0x47702000, 0x4929b510, 0x44484827, + 0xf8b8f000, 0xb92c4604, 0x48242100, 0xf0004448, 0x4604f9a9, 0xf837f000, 0xbd104620, 0x4604b570, + 0x4448481e, 0x46214b1e, 0xf00068c2, 0x4605f85d, 0x481ab93d, 0x23004448, 0x68c24621, 0xf946f000, + 0xf0004605, 0x4628f820, 0xb5febd70, 0x460c4605, 0x46234616, 0x46294632, 0x44484810, 0xf8f8f000, + 0xb9674607, 0x22012000, 0x2000e9cd, 0x46224633, 0x90024629, 0x44484809, 0xf984f000, 0xf0004607, + 0x4638f802, 0x4807bdfe, 0xf4206840, 0xf5000070, 0x49040070, 0x47706048, 0x40052000, 0x00000004, + 0x6b65666b, 0x4001f000, 0x4a0e2070, 0x20807010, 0xbf007010, 0x7800480b, 0x280009c0, 0x4809d0fa, + 0xf0017801, 0xb1080020, 0x47702067, 0x0010f001, 0x2068b108, 0xf001e7f9, 0xb1080001, 0xe7f42069, + 0xe7f22000, 0x40020000, 0x4df0e92d, 0x460d4604, 0x469a4690, 0xf0004650, 0x4606f891, 0x4630b116, + 0x8df0e8bd, 0x46422310, 0x46204629, 0xf86cf000, 0xb10e4606, 0xe7f34630, 0x0008eb05, 0x68e01e47, + 0xf1f0fbb7, 0x7011fb00, 0x68e0b140, 0xf0f0fbb7, 0x0b01f100, 0xfb0068e0, 0x1e47f00b, 0x480be011, + 0x68004478, 0x20096005, 0x71c84909, 0xffacf7ff, 0x69a04606, 0x69a0b108, 0xb1064780, 0x68e0e003, + 0x42bd4405, 0xbf00d9eb, 0xe7c94630, 0x000002ec, 0x40020000, 0x4604b570, 0x4628460d, 0xf84ef000, + 0xb10e4606, 0xbd704630, 0x2004b90c, 0x2044e7fb, 0x71c84902, 0xff88f7ff, 0x0000e7f5, 0x40020000, + 0xb9094601, 0x47702004, 0x6cc04826, 0x6003f3c0, 0x447b4b25, 0x0010f833, 0xb90a0302, 0xe7f22064, + 0x60082000, 0x2002604a, 0x02c06088, 0x200060c8, 0x61486108, 0xbf006188, 0x4602e7e5, 0x2004b90a, + 0x61914770, 0xe7fb2000, 0x4604b530, 0x2004b90c, 0x1e58bd30, 0xb9104008, 0x40101e58, 0x2065b108, + 0x6820e7f6, 0xd8054288, 0x0500e9d4, 0x188d4428, 0xd20142a8, 0xe7eb2066, 0xe7e92000, 0x480b4601, + 0xd0014281, 0x4770206b, 0xe7fc2000, 0xb90b4603, 0x47702004, 0xd801290f, 0xd0012a04, 0xe7f82004, + 0xe7f62000, 0x40048000, 0x0000025a, 0x6b65666b, 0x41f0e92d, 0x46884607, 0x461d4614, 0x2004b914, + 0x81f0e8bd, 0x462a2308, 0x46384641, 0xffbcf7ff, 0xb10e4606, 0xe7f34630, 0x4812e01f, 0x68004478, + 0x8000f8c0, 0x490fcc01, 0x390c4479, 0x60486809, 0x490ccc01, 0x39184479, 0x60886809, 0x490a2007, + 0xf7ff71c8, 0x4606ff01, 0xb10869b8, 0x478069b8, 0xe004b106, 0x0808f108, 0x2d003d08, 0xbf00d1dd, + 0xe7cd4630, 0x000001b0, 0x40020000, 0x4dffe92d, 0x4682b082, 0x2310460c, 0x46504621, 0xf7ff9a04, + 0x4683ff83, 0x0f00f1bb, 0x4658d003, 0xe8bdb006, 0xe9da8df0, 0xfbb00101, 0x4260f7f1, 0x40084279, + 0x42a54245, 0x443dd100, 0xe0229e04, 0x0804eba5, 0xd90045b0, 0xea4f46b0, 0x90011018, 0x4478480f, + 0x60046800, 0x490e2001, 0x980171c8, 0x72c80a00, 0x72889801, 0x72489805, 0xfeb6f7ff, 0xf1bb4683, + 0xd0010f00, 0xe7d14658, 0x0608eba6, 0x443d4444, 0x2e00bf00, 0x2000d1da, 0x0000e7c8, 0x0000010e, + 0x40020000, 0x4604b570, 0xb90c460d, 0xbd702004, 0x49032040, 0x460871c8, 0xf7ff7185, 0xe7f6fe95, + 0x40020000, 0x4dffe92d, 0x4617460c, 0xe9dd461d, 0xf8ddb80c, 0xb91da038, 0xb0042004, 0x8df0e8bd, + 0x463a2304, 0x98004621, 0xff1ef7ff, 0xb10e4606, 0xe7f24630, 0x4814e022, 0x68004478, 0x20026004, + 0x71c84912, 0xf8804608, 0x490fb00b, 0x39144479, 0x68096828, 0xf7ff6088, 0x4606fe67, 0xf1b8b15e, + 0xd0010f00, 0x4000f8c8, 0x0f00f1ba, 0x2000d002, 0x0000f8ca, 0x1f3fe004, 0x1d241d2d, 0xd1da2f00, + 0x4630bf00, 0x0000e7c9, 0x00000074, 0x40020000, 0x00000000, 0x00080000, 0x00100000, 0x00200000, + 0x00400000, 0x00800000, 0x01000000, 0x01000000, 0x40020004, 0x00000000, + ]), + loadAddress: 0x20000000, + pageBuffers: [0x20003000, 0x20004000], + pageSize: 0x1000, + // Relative function addresses + pcEraseAll: 0x20000059, + pcEraseSector: 0x2000007D, + pcInit: 0x20000021, + // pcUnInit: 0x49, + pcProgramPage: 0x200000AB, + stackPointer: 0x20001000, + staticBase: 0x20000000 + 0x20 + 0x474, +}; +var K64F = (function () { + function K64F() { + this.flashAlgo = K64F_FLASH_ALGO; + } + K64F.prototype.overrideSecurityBits = function (address, data) { + var u8data = new Uint8Array(data.buffer); + // Kinetis security values and addresses + var SECURITY_START = 0x400; + var SECURITY_SIZE = 16; + var FPROT_ADDR = 0x408; + var FPROT_ADDR_END = 0x40c; + var FPROT_SIZE = 4; + var FSEC_ADDR = 0x40c; + var FSEC_VAL = 0xFE; + var FOPT_ADDR = 0x40d; + var FOPT_VAL = 0xFF; + var FEPROT_ADDR = 0x40e; + var FEPROT_VAL = 0xFF; + var FDPROT_ADDR = 0x40f; + var FDPROT_VAL = 0xFF; + if (address <= SECURITY_START && address + u8data.byteLength > SECURITY_START + SECURITY_SIZE) { + for (var i = FPROT_ADDR; i < FPROT_ADDR_END; i++) { + if (u8data[i - address] !== 0xff) { + u8data[i - address] = 0xff; + console.debug("FCF[" + (i - FPROT_ADDR) + "] at addr " + i + " changed to " + u8data[i - address]); + } + } + if (u8data[FSEC_ADDR - address] !== FSEC_VAL) { + u8data[FSEC_ADDR - address] = FSEC_VAL; + console.debug("FSEC at addr " + FSEC_ADDR + " changed to " + FSEC_VAL); + } + if (u8data[FOPT_ADDR - address] === 0x00) { + console.debug("FOPT set to restricted value 0x00"); + } + if (u8data[FEPROT_ADDR - address] !== FEPROT_VAL) { + u8data[FEPROT_ADDR - address] = FEPROT_VAL; + console.debug("FEPROT at addr " + FEPROT_ADDR + " changed to " + FEPROT_VAL); + } + if (u8data[FDPROT_ADDR - address] !== FDPROT_VAL) { + u8data[FDPROT_ADDR - address] = FDPROT_VAL; + console.debug("FDPROT at addr " + FDPROT_ADDR + " changed to " + FDPROT_VAL); + } + } + }; + return K64F; +}()); +exports.K64F = K64F; + + +/***/ }), +/* 14 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +var NRF51_FLASH_ALGO = { + analyzerAddress: 0x20003000, + analyzerSupported: true, + beginData: 0x20002000, + flashSize: 0x40000, + flashStart: 0x0, + instructions: new Uint32Array([ + 0xE00ABE00, 0x062D780D, 0x24084068, 0xD3000040, 0x1E644058, 0x1C49D1FA, 0x2A001E52, 0x4770D1F2, + 0x47702000, 0x47702000, 0x4c26b570, 0x60602002, 0x60e02001, 0x68284d24, 0xd00207c0, 0x60602000, + 0xf000bd70, 0xe7f6f82c, 0x4c1eb570, 0x60612102, 0x4288491e, 0x2001d302, 0xe0006160, 0x4d1a60a0, + 0xf81df000, 0x07c06828, 0x2000d0fa, 0xbd706060, 0x4605b5f8, 0x4813088e, 0x46142101, 0x4f126041, + 0xc501cc01, 0x07c06838, 0x1e76d006, 0x480dd1f8, 0x60412100, 0xbdf84608, 0xf801f000, 0x480ce7f2, + 0x06006840, 0xd00b0e00, 0x6849490a, 0xd0072900, 0x4a0a4909, 0xd00007c3, 0x1d09600a, 0xd1f90840, + 0x00004770, 0x4001e500, 0x4001e400, 0x10001000, 0x40010400, 0x40010500, 0x40010600, 0x6e524635, + 0x00000000, + ]), + loadAddress: 0x20000000, + minProgramLength: 4, + pageBuffers: [0x20002000, 0x20002400], + pageSize: 0x400, + pcEraseAll: 0x20000029, + pcEraseSector: 0x20000049, + pcInit: 0x20000021, + pcProgramPage: 0x20000071, + stackPointer: 0x20001000, + staticBase: 0x20000170, +}; +var NRF51 = (function () { + function NRF51() { + this.flashAlgo = NRF51_FLASH_ALGO; + } + NRF51.prototype.overrideSecurityBits = function (address, data) { + /* empty */ + }; + return NRF51; +}()); +exports.NRF51 = NRF51; + + +/***/ }), +/* 15 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +var util_1 = __webpack_require__(0); +var FlashSection = (function () { + function FlashSection(address, data) { + this.address = address; + this.data = data; + /* empty */ + } + FlashSection.prototype.toString = function () { + return this.data.byteLength + " bytes @ " + this.address.toString(16); + }; + return FlashSection; +}()); +exports.FlashSection = FlashSection; +var FlashProgram = (function () { + function FlashProgram(sections) { + this.sections = sections; + } + FlashProgram.fromIntelHex = function (hex) { + var lines = hex.split(/\n/); + var upperAddr = 0; + var startAddr = 0; + var current = null; + var chunks = []; + for (var i = 0; i < lines.length; i++) { + var line = lines[i]; + if (line.substr(0, 1) !== ":") { + throw new Error("Invaild line in hex file: " + (i + 1)); + } + else { + var length_1 = parseInt(line.substr(1, 2), 16); + var addr = upperAddr + parseInt(line.substr(3, 4), 16); + var fieldType = parseInt(line.substr(7, 2), 16); + var data = line.substr(9, length_1 * 2); + if (fieldType === 0x00) { + if (current && addr !== startAddr + (current.length / 2)) { + // non-contiguous + var sectionData = util_1.hex2bin(current); + chunks.push(new FlashSection(startAddr, new Uint32Array(sectionData.buffer))); + current = ""; + startAddr = addr; + } + else if (!current) { + startAddr = addr; + current = ""; + } + current += data; + } + else if (fieldType === 0x01) { + // EOF + break; + } + else if (fieldType === 0x02) { + // extended segment address record + upperAddr = parseInt(data, 16) << 4; + } + else if (fieldType === 0x04) { + // extended linear address record + upperAddr = parseInt(data, 16) << 16; + } + } + } + return new FlashProgram(chunks); + }; + FlashProgram.fromBinary = function (addr, bin) { + return new FlashProgram([new FlashSection(addr, bin)]); + }; + FlashProgram.prototype.totalByteLength = function () { + return this.sections.map(function (s) { return s.data.byteLength; }).reduce(function (x, y) { return x + y; }); + }; + FlashProgram.prototype.toString = function () { + return this.sections.toString(); + }; + return FlashProgram; +}()); +exports.FlashProgram = FlashProgram; + + +/***/ }) +/******/ ]); +//# sourceMappingURL=dapjs.js.map \ No newline at end of file diff --git a/editor/tsconfig.json b/editor/tsconfig.json new file mode 100644 index 00000000..47c94f4a --- /dev/null +++ b/editor/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "target": "es5", + "noImplicitAny": true, + "noImplicitReturns": true, + "noImplicitThis": true, + "declaration": true, + "module": "commonjs", + "moduleResolution": "node", + "isolatedModules": false, + "outDir": "../built/editor", + "rootDir": ".", + "newLine": "LF", + "sourceMap": false, + "jsx": "react" + } +} diff --git a/electron/product.json b/electron/product.json new file mode 100644 index 00000000..7424cd56 --- /dev/null +++ b/electron/product.json @@ -0,0 +1,14 @@ +{ + "applicationName": "pxt-microbit-oss", + "dataFolderName": ".pxt-microbit-oss", + "darwinBundleIdentifier": "com.microsoft.pxtmicrobitoss", + "nameShort": "PXT microbit - OSS", + "nameLong": "PXT micro:bit - OSS", + "targetId": "pxt-microbit", + "win32AppId": "{{92db071a-6f58-4938-8c97-13c873f4da13}", + "win32AppUserModelId": "Microsoft.PXTmicrobitOss", + "win32DirName": "Microsoft PXT microbit - OSS", + "win32MutexName": "pxtmicrobitoss", + "win32NameVersion": "Microsoft PXT microbit-OSS", + "win32RegValueName": "PXTmicrobitOss" +} \ No newline at end of file diff --git a/electron/release.json b/electron/release.json new file mode 100644 index 00000000..e950d07e --- /dev/null +++ b/electron/release.json @@ -0,0 +1,9 @@ +{ + "versions": { + "0": { + "latest": "v0.9.15", + "banned": [], + "prompt": "v0.9.15" + } + } +} diff --git a/external/sha/.yotta.json b/external/sha/.yotta.json new file mode 100644 index 00000000..d7602538 --- /dev/null +++ b/external/sha/.yotta.json @@ -0,0 +1,6 @@ +{ + "build": { + "target": "bbc-microbit-classic-gcc,*", + "targetSetExplicitly": true + } +} diff --git a/external/sha/buildflash.sh b/external/sha/buildflash.sh new file mode 100644 index 00000000..ff40de0e --- /dev/null +++ b/external/sha/buildflash.sh @@ -0,0 +1,5 @@ +#!/bin/sh +yotta build +arm-none-eabi-objdump -d `find -name main.c.o` > disasm +node genapplet.js disasm Reset_Handler +rm disasm diff --git a/external/sha/genapplet.js b/external/sha/genapplet.js new file mode 100644 index 00000000..89fd3bee --- /dev/null +++ b/external/sha/genapplet.js @@ -0,0 +1,48 @@ +let fs = require("fs") +let s = fs.readFileSync(process.argv[2], "utf8") +let infun = false +let words = [] +for (let l of s.split(/\n/)) { + let m = /^00000000 <(.*)>:/.exec(l) + if (m && m[1] == process.argv[3]) infun = true + if (/^Disassembly/.test(l)) infun = false + if (!infun) continue + m = /^\s*[0-9a-f]+:\s+([0-9a-f]+)( ([0-9a-f]{4}))?\s+/.exec(l) + if (m) { + let n = m[1] + words.push(n) + if (m[3]) + words.push(m[3]) + if (n.length == 4 || n.length == 8) { + // ok + } else { + throw new Error() + } + } +} + +let ww = [] +let pref = "" +for (let w of words) { + if (w.length == 8) { + if (pref) throw new Error() + ww.push("0x" + w) + } else { + if (pref) { + ww.push("0x" + w + pref) + pref = "" + } else { + pref = w + } + } +} + +words = ww + +let r = "" +for (let i = 0; i < words.length; i++) { + if (i % 6 == 0) r += "\n" + r += words[i] + ", " +} + +console.log(r) \ No newline at end of file diff --git a/external/sha/module.json b/external/sha/module.json new file mode 100644 index 00000000..54dc0216 --- /dev/null +++ b/external/sha/module.json @@ -0,0 +1,9 @@ +{ + "name": "sha", + "version": "0.0.0", + "keywords": [], + "author": "", + "license": "MIT", + "dependencies": {}, + "bin": "./source" +} diff --git a/external/sha/source/main.c b/external/sha/source/main.c new file mode 100644 index 00000000..af00cfa9 --- /dev/null +++ b/external/sha/source/main.c @@ -0,0 +1,240 @@ +#include + +static const uint32_t sha256_k[] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, + 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, + 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, + 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, + 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, + 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2}; + +#define rotr(v, b) (((uint32_t)v >> b) | (v << (32 - b))) + +static inline void sha256round(uint32_t *hs, uint32_t *w) { + for (int i = 16; i < 64; ++i) { + uint32_t s0 = rotr(w[i - 15], 7) ^ rotr(w[i - 15], 18) ^ (w[i - 15] >> 3); + uint32_t s1 = rotr(w[i - 2], 17) ^ rotr(w[i - 2], 19) ^ (w[i - 2] >> 10); + w[i] = (w[i - 16] + s0 + w[i - 7] + s1) | 0; + } + + uint32_t a = hs[0]; + uint32_t b = hs[1]; + uint32_t c = hs[2]; + uint32_t d = hs[3]; + uint32_t e = hs[4]; + uint32_t f = hs[5]; + uint32_t g = hs[6]; + uint32_t h = hs[7]; + + for (int i = 0; i < 64; ++i) { + uint32_t s1 = rotr(e, 6) ^ rotr(e, 11) ^ rotr(e, 25); + uint32_t ch = (e & f) ^ (~e & g); + uint32_t temp1 = (h + s1 + ch + sha256_k[i] + w[i]); + uint32_t s0 = rotr(a, 2) ^ rotr(a, 13) ^ rotr(a, 22); + uint32_t maj = (a & b) ^ (a & c) ^ (b & c); + uint32_t temp2 = (s0 + maj); + + h = g; + g = f; + f = e; + e = (d + temp1); + d = c; + c = b; + b = a; + a = (temp1 + temp2); + } + + hs[0] += a; + hs[1] += b; + hs[2] += c; + hs[3] += d; + hs[4] += e; + hs[5] += f; + hs[6] += g; + hs[7] += h; +} + +#define INLINE __attribute__((always_inline)) static inline + +INLINE void sha256block(uint8_t *buf, uint32_t len, uint32_t *dst) { + uint32_t hs[] = {0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, + 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19}; + + uint32_t w[64]; + + for (uint32_t i = 0; i < len; i += 64) { + for (uint32_t j = 0; j < 16; j++) { + uint32_t off = (j << 2) + i; + w[j] = (buf[off] << 24) | (buf[off + 1] << 16) | (buf[off + 2] << 8) | + buf[off + 3]; + } + sha256round(hs, w); + } + + dst[0] = hs[0]; + dst[1] = hs[1]; +} + +#define POLYNOMIAL 0xEDB88320 + +INLINE void makeCRC32tab(uint32_t *table) { + for (uint32_t b = 0; b < 256; ++b) { + uint32_t r = b; + for (uint32_t j = 0; j < 8; ++j) { + if (r & 1) + r = (r >> 1) ^ POLYNOMIAL; + else + r = (r >> 1); + } + table[b] = r; + } +} + +INLINE uint32_t crc(const uint8_t *p, uint32_t len, uint32_t *crcTable) { + uint32_t crc = ~0U; + for (uint32_t i = 0; i < len; ++i) + crc = crcTable[*p++ ^ (crc & 0xff)] ^ (crc >> 8); + return (~crc); +} + +INLINE uint32_t murmur3_core(const uint8_t *data, uint32_t len) { + uint32_t h = 0x2F9BE6CC; + const uint32_t *data32 = (const uint32_t *)data; + uint32_t i = len >> 2; + do { + uint32_t k = *data32++; + k *= 0xcc9e2d51; + k = (k << 15) | (k >> 17); + k *= 0x1b873593; + h ^= k; + h = (h << 13) | (h >> 19); + h = (h * 5) + 0xe6546b64; + } while (--i); + return h; +} + +INLINE void murmur3_core_2(const uint8_t *data, uint32_t len, uint32_t *dst) { + // compute two hashes with different seeds in parallel, hopefully reducing + // collisions + uint32_t h0 = 0x2F9BE6CC; + uint32_t h1 = 0x1EC3A6C8; + const uint32_t *data32 = (const uint32_t *)data; + uint32_t i = len >> 2; + do { + uint32_t k = *data32++; + k *= 0xcc9e2d51; + k = (k << 15) | (k >> 17); + k *= 0x1b873593; + + h0 ^= k; + h1 ^= k; + h0 = (h0 << 13) | (h0 >> 19); + h1 = (h1 << 13) | (h1 >> 19); + h0 = (h0 * 5) + 0xe6546b64; + h1 = (h1 * 5) + 0xe6546b64; + } while (--i); + + dst[0] = h0; + dst[1] = h1; +} + +int Reset_Handler(uint32_t *dst, uint8_t *ptr, uint32_t pageSize, + uint32_t numPages) { + uint32_t crcTable[256]; + makeCRC32tab(crcTable); + + for (uint32_t i = 0; i < numPages; ++i) { +#if 0 + sha256block(ptr, pageSize, dst); +#elif 0 + dst[0] = crc(ptr, pageSize, crcTable); + dst[1] = murmur3_core(ptr, pageSize); +#else + murmur3_core_2(ptr, pageSize, dst); +#endif + dst += 2; + ptr += pageSize; + } +#ifdef __arm__ + __asm__("bkpt 42"); +#endif + return 0; +} + +#if 0 +#define PAGE_SIZE 0x400 +#define SIZE_IN_WORDS (PAGE_SIZE / 4) + +#define setConfig(v) \ + do { \ + NRF_NVMC->CONFIG = v; \ + while (NRF_NVMC->READY == NVMC_READY_READY_Busy) \ + ; \ + } while (0) + +void overwriteFlashPage(uint32_t *to, uint32_t *from) { + int same = 1; + for (int i = 0; i <= (SIZE_IN_WORDS - 1); i++) { + if (to[i] != from[i]) { + same = 0; + break; + } + } + if (same) + return; + + // Turn on flash erase enable and wait until the NVMC is ready: + setConfig(NVMC_CONFIG_WEN_Een << NVMC_CONFIG_WEN_Pos); + + // Erase page: + NRF_NVMC->ERASEPAGE = (uint32_t)to; + while (NRF_NVMC->READY == NVMC_READY_READY_Busy) + ; + + // Turn off flash erase enable and wait until the NVMC is ready: + setConfig(NVMC_CONFIG_WEN_Ren << NVMC_CONFIG_WEN_Pos); + + // Turn on flash write enable and wait until the NVMC is ready: + setConfig(NVMC_CONFIG_WEN_Wen << NVMC_CONFIG_WEN_Pos); + + for (int i = 0; i <= (SIZE_IN_WORDS - 1); i++) { + *(to + i) = *(from + i); + while (NRF_NVMC->READY == NVMC_READY_READY_Busy) + ; + } + + // Turn off flash write enable and wait until the NVMC is ready: + setConfig(NVMC_CONFIG_WEN_Ren << NVMC_CONFIG_WEN_Pos); +} + +#endif + +#ifndef __arm__ +#define PS 1024 +#define NP 10 + +#include +#include + +int main() { + + uint8_t buf[NP * PS]; + uint32_t sums[NP * 2]; + memset(buf, 0, sizeof(buf)); + for (int i = 0; i < PS; ++i) + buf[i] = i; + for (int i = 0; i < PS; ++i) + buf[i + PS] = 108; + Reset_Handler(sums, buf, PS, NP); + for (int i = 0; i < NP; ++i) { + printf("%08x %08x\n", sums[i * 2], sums[i * 2 + 1]); + } + + return 0; +} +#endif diff --git a/fieldeditors/extensions.ts b/fieldeditors/extensions.ts new file mode 100644 index 00000000..94c4bf5b --- /dev/null +++ b/fieldeditors/extensions.ts @@ -0,0 +1,15 @@ +/// +/// + +import { FieldGestures } from "./field_gestures"; + +pxt.editor.initFieldExtensionsAsync = function (opts: pxt.editor.FieldExtensionOptions): Promise { + pxt.debug('loading pxt-microbit field editors...') + const res: pxt.editor.FieldExtensionResult = { + fieldEditors: [{ + selector: "gestures", + editor: FieldGestures + }] + }; + return Promise.resolve(res); +} \ No newline at end of file diff --git a/fieldeditors/field_gestures.ts b/fieldeditors/field_gestures.ts new file mode 100644 index 00000000..5a257102 --- /dev/null +++ b/fieldeditors/field_gestures.ts @@ -0,0 +1,33 @@ +/// +/// +/// + +export interface FieldGesturesOptions extends pxtblockly.FieldImagesOptions { + columns?: string; + width?: string; +} + +export class FieldGestures extends pxtblockly.FieldImages implements Blockly.FieldCustom { + public isFieldCustom_ = true; + + constructor(text: string, options: FieldGesturesOptions, validator?: Function) { + super(text, options, validator); + + this.columns_ = parseInt(options.columns) || 4; + this.width_ = parseInt(options.width) || 350; + this.addLabel_ = true; + + this.setText = Blockly.FieldDropdown.prototype.setText; + this.updateSize_ = (Blockly.Field as any).prototype.updateSize_; + this.updateTextNode_ = Blockly.Field.prototype.updateTextNode_; + } + + trimOptions_() { + } + + protected buttonClick_ = function (e: any) { + let value = e.target.getAttribute('data-value'); + this.setValue(value); + Blockly.DropDownDiv.hide(); + }; +} \ No newline at end of file diff --git a/fieldeditors/tsconfig.json b/fieldeditors/tsconfig.json new file mode 100644 index 00000000..9f5342cb --- /dev/null +++ b/fieldeditors/tsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "target": "es5", + "noImplicitAny": false, + "noImplicitReturns": true, + "module": "commonjs", + "outDir": "../built/fieldeditors", + "rootDir": ".", + "newLine": "LF", + "sourceMap": false, + "allowSyntheticDefaultImports": true, + "declaration": true + } +} \ No newline at end of file diff --git a/libs/blocksprj/main.blocks b/libs/blocksprj/main.blocks index d809e7e4..9720ca4d 100644 --- a/libs/blocksprj/main.blocks +++ b/libs/blocksprj/main.blocks @@ -1,62 +1,4 @@ - - - -FALSE -FALSE -FALSE -FALSE -FALSE -FALSE -TRUE -FALSE -TRUE -FALSE -FALSE -FALSE -FALSE -FALSE -FALSE -TRUE -FALSE -FALSE -FALSE -TRUE -FALSE -TRUE -TRUE -TRUE -FALSE - - -FALSE -FALSE -FALSE -FALSE -FALSE -FALSE -FALSE -FALSE -FALSE -FALSE -FALSE -FALSE -FALSE -FALSE -FALSE -FALSE -FALSE -FALSE -FALSE -FALSE -FALSE -FALSE -FALSE -FALSE -FALSE - - - - - + + \ No newline at end of file diff --git a/libs/blocksprj/main.ts b/libs/blocksprj/main.ts index 4dfdb3a1..8b137891 100644 --- a/libs/blocksprj/main.ts +++ b/libs/blocksprj/main.ts @@ -1,16 +1 @@ -basic.forever(() => { - basic.showLeds(` - . # . # . - # . # . # - # . . . # - . # . # . - . . # . . - `) - basic.showLeds(` - . . . . . - . . . . . - . . . . . - . . . . . - . . . . . - `) -}) \ No newline at end of file + diff --git a/libs/bluetooth/BLEHF2Service.cpp b/libs/bluetooth/BLEHF2Service.cpp new file mode 100644 index 00000000..baa1a0ef --- /dev/null +++ b/libs/bluetooth/BLEHF2Service.cpp @@ -0,0 +1,50 @@ +#include "MicroBitConfig.h" +#include "ble/UUID.h" +#include "BLEHF2Service.h" +#include "MicroBitEvent.h" + +BLEHF2Service::BLEHF2Service(BLEDevice &_ble) : + ble(_ble) +{ + GattCharacteristic txCharacteristic(BLEHF2TxCharacteristicUUID, (uint8_t *)&txCharacteristicMessage, 0, + sizeof(txCharacteristicMessage), GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY); + + // Initialise our characteristic values. + memset(&txCharacteristicMessage, 0, sizeof(txCharacteristicMessage)); + + // Set default security requirements + txCharacteristic.requireSecurity(SecurityManager::MICROBIT_BLE_SECURITY_LEVEL); + + // setup GATT table + GattCharacteristic *characteristics[] = {&txCharacteristic}; + GattService service(BLEHF2ServiceUUID, characteristics, sizeof(characteristics) / sizeof(GattCharacteristic *)); + ble.addService(service); + + // retreive handles + txCharacteristicHandle = txCharacteristic.getValueHandle(); + + // initialize data + ble.gattServer().write(txCharacteristicHandle,(uint8_t *)&txCharacteristicMessage, sizeof(txCharacteristicMessage)); +} + +void BLEHF2Service::sendSerial(const char *data, int len, bool isError) { + if (ble.getGapState().connected) + { + int32_t sent = 0; + while(sent < len) { + int32_t n = min(BLEHF2_DATA_LENGTH, len - sent); + txCharacteristicMessage.command = (isError ? BLEHF2_FLAG_SERIAL_OUT : BLEHF2_FLAG_SERIAL_ERR) | n; + memcpy(&txCharacteristicMessage.data, data + sent, n); + ble.gattServer().notify(txCharacteristicHandle,(uint8_t *)&txCharacteristicMessage, sizeof(txCharacteristicMessage)); + sent += n; + } + } +} + +const uint8_t BLEHF2ServiceUUID[] = { + 0xb1,0x12,0xf5,0xe6,0x26,0x79,0x30,0xda,0xa2,0x6e,0x02,0x73,0xb6,0x04,0x38,0x49 +}; + +const uint8_t BLEHF2TxCharacteristicUUID[] = { + 0xb1,0x12,0xf5,0xe6,0x26,0x79,0x30,0xda,0xa2,0x6e,0x02,0x73,0xb6,0x04,0x38,0x4a +}; \ No newline at end of file diff --git a/libs/bluetooth/BLEHF2Service.h b/libs/bluetooth/BLEHF2Service.h new file mode 100644 index 00000000..20c67788 --- /dev/null +++ b/libs/bluetooth/BLEHF2Service.h @@ -0,0 +1,54 @@ +#ifndef BLE_HF2_SERVICE_H +#define BLE_HF2_SERVICE_H + +#include "MicroBitConfig.h" +#include "ble/BLE.h" +#include "MicroBitThermometer.h" +#include "EventModel.h" +#include "pxt.h" + +#define HF2_ID 9501 + +#define BLEHF2_FLAG_SERIAL_OUT 0x80 +#define BLEHF2_FLAG_SERIAL_ERR 0xC0 +#define BLEHF2_DATA_LENGTH 19 + +// UUIDs for our service and characteristics +extern const uint8_t BLEHF2ServiceUUID[]; +extern const uint8_t BLEHF2TxCharacteristicUUID[]; + +struct BLEHF2Packet { + uint8_t command; + uint8_t data[BLEHF2_DATA_LENGTH]; +}; + +class BLEHF2Service +{ + public: + + /** + * Constructor. + * Create a representation of the TemperatureService + * @param _ble The instance of a BLE device that we're running on. + */ + BLEHF2Service(BLEDevice &_ble); + + /** + * Sends text + */ + void sendSerial(const char *data, int len, bool isError); + + private: + + // Bluetooth stack we're running on. + BLEDevice &ble; + + // memory for buffers. + BLEHF2Packet txCharacteristicMessage; + + // Handles to access each characteristic when they are held by Soft Device. + GattAttribute::Handle_t txCharacteristicHandle; +}; + + +#endif \ No newline at end of file diff --git a/libs/bluetooth/_locales/bluetooth-jsdoc-strings.json b/libs/bluetooth/_locales/bluetooth-jsdoc-strings.json index 861244b8..925d5177 100644 --- a/libs/bluetooth/_locales/bluetooth-jsdoc-strings.json +++ b/libs/bluetooth/_locales/bluetooth-jsdoc-strings.json @@ -29,7 +29,10 @@ "bluetooth.startTemperatureService": "Starts the Bluetooth temperature service", "bluetooth.startUartService": "Starts the Bluetooth UART service", "bluetooth.stopAdvertising": "Stops advertising Eddystone end points", + "bluetooth.uartReadBuffer": "Reads buffered UART data into a buffer", "bluetooth.uartReadUntil": "Reads from the Bluetooth UART service buffer, returning its contents when the specified delimiter character is encountered.", + "bluetooth.uartWriteBuffer": "Sends a buffer of data via Bluetooth UART", + "bluetooth.uartWriteLine": "Writes to the Bluetooth UART service buffer. From there the data is transmitted over Bluetooth to a connected device.", "bluetooth.uartWriteNumber": "Prints a numeric value to the serial", "bluetooth.uartWriteString": "Writes to the Bluetooth UART service buffer. From there the data is transmitted over Bluetooth to a connected device.", "bluetooth.uartWriteValue": "Writes a ``name: value`` pair line to the serial.", diff --git a/libs/bluetooth/_locales/bluetooth-strings.json b/libs/bluetooth/_locales/bluetooth-strings.json index bf68a2dc..e63707af 100644 --- a/libs/bluetooth/_locales/bluetooth-strings.json +++ b/libs/bluetooth/_locales/bluetooth-strings.json @@ -14,6 +14,7 @@ "bluetooth.startUartService|block": "bluetooth uart service", "bluetooth.stopAdvertising|block": "bluetooth stop advertising", "bluetooth.uartReadUntil|block": "bluetooth uart|read until %del=serial_delimiter_conv", + "bluetooth.uartWriteLine|block": "bluetooth uart|write line %data", "bluetooth.uartWriteNumber|block": "bluetooth uart|write number %value", "bluetooth.uartWriteString|block": "bluetooth uart|write string %data", "bluetooth.uartWriteValue|block": "bluetooth uart|write value %name|= %value", diff --git a/libs/bluetooth/_locales/de/bluetooth-jsdoc-strings.json b/libs/bluetooth/_locales/de/bluetooth-jsdoc-strings.json deleted file mode 100644 index c39e2568..00000000 --- a/libs/bluetooth/_locales/de/bluetooth-jsdoc-strings.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "bluetooth": "Unterstützung für zusätzliche Bluetooth-Dienste.", - "bluetooth.onBluetoothConnected|param|body": "Code, der ausgeführt wird, wenn eine Bluetooth-Verbindung aufgebaut wurde", - "bluetooth.uartWriteNumber": "Gibt einen numerischen Wert an die serielle", - "bluetooth.uartWriteValue": "Schreibt ein ``Namen: Wert`` Wertepaar auf die serielle Schnittstelle.", - "bluetooth.uartWriteValue|param|name": "Name des Wertestreams, z.B.: x", - "bluetooth.uartWriteValue|param|value": "Schreiben" -} \ No newline at end of file diff --git a/libs/bluetooth/bluetooth.cpp b/libs/bluetooth/bluetooth.cpp index 4cafcaed..cb3efc5a 100644 --- a/libs/bluetooth/bluetooth.cpp +++ b/libs/bluetooth/bluetooth.cpp @@ -1,6 +1,7 @@ #include "pxt.h" #include "MESEvents.h" #include "MicroBitUARTService.h" +#include "BLEHF2Service.h" using namespace pxt; @@ -10,7 +11,14 @@ using namespace pxt; //% color=#0082FB weight=96 icon="\uf294" namespace bluetooth { MicroBitUARTService *uart = NULL; + BLEHF2Service* pHF2 = NULL; + //% + void __log(String msg) { + if (NULL == pHF2) + pHF2 = new BLEHF2Service(*uBit.ble); + pHF2->sendSerial(msg->getUTF8Data(), msg->getUTF8Size(), false); + } /** * Starts the Bluetooth accelerometer service @@ -88,26 +96,59 @@ namespace bluetooth { } //% - void uartWriteString(StringData *data) { + void uartWriteString(String data) { startUartService(); - uart->send(ManagedString(data)); + uart->send(MSTR(data)); } //% - StringData* uartReadUntil(StringData *del) { + String uartReadUntil(String del) { startUartService(); - return uart->readUntil(ManagedString(del)).leakData(); + return PSTR(uart->readUntil(MSTR(del))); } + + /** + * Sends a buffer of data via Bluetooth UART + */ + //% + void uartWriteBuffer(Buffer buffer) { + startUartService(); + uart->send(buffer->data, buffer->length); + } + + /** + * Reads buffered UART data into a buffer + */ + //% + Buffer uartReadBuffer() { + startUartService(); + int bytes = uart->rxBufferedSize(); + auto buffer = mkBuffer(NULL, bytes); + int read = uart->read(buffer->data, buffer->length); + // read failed + if (read < 0) { + decrRC(buffer); + return mkBuffer(NULL, 0); + } + // could not fill the buffer + if (read != buffer->length) { + auto tmp = mkBuffer(buffer->data, read); + decrRC(buffer); + buffer = tmp; + } + return buffer; + } + /** * Registers an event to be fired when one of the delimiter is matched. * @param delimiters the characters to match received characters against. */ //% help=bluetooth/on-uart-data-received //% weight=18 blockId=bluetooth_on_data_received block="bluetooth|on data received %delimiters=serial_delimiter_conv" - void onUartDataReceived(StringData* delimiters, Action body) { + void onUartDataReceived(String delimiters, Action body) { startUartService(); - uart->eventOn(ManagedString(delimiters)); + uart->eventOn(MSTR(delimiters)); registerWithDal(MICROBIT_ID_BLE_UART, MICROBIT_UART_S_EVT_DELIM_MATCH, body); } @@ -131,7 +172,7 @@ namespace bluetooth { //% parts="bluetooth" void onBluetoothDisconnected(Action body) { registerWithDal(MICROBIT_ID_BLE, MICROBIT_BLE_EVT_DISCONNECTED, body); - } + } const int8_t CALIBRATED_POWERS[] = {-49, -37, -33, -28, -25, -20, -15, -10}; /** @@ -143,11 +184,13 @@ namespace bluetooth { //% blockId=eddystone_advertise_url block="bluetooth advertise url %url|with power %power|connectable %connectable" //% parts=bluetooth weight=11 blockGap=8 //% help=bluetooth/advertise-url blockExternalInputs=1 - void advertiseUrl(StringData* url, int power, bool connectable) { + void advertiseUrl(String url, int power, bool connectable) { +#if CONFIG_ENABLED(MICROBIT_BLE_EDDYSTONE_URL) power = min(MICROBIT_BLE_POWER_LEVELS-1, max(0, power)); int8_t level = CALIBRATED_POWERS[power]; - uBit.bleManager.advertiseEddystoneUrl(ManagedString(url), level, connectable); + uBit.bleManager.advertiseEddystoneUrl(MSTR(url), level, connectable); uBit.bleManager.setTransmitPower(power); +#endif } /** @@ -158,14 +201,14 @@ namespace bluetooth { */ //% parts=bluetooth weight=12 advanced=true void advertiseUidBuffer(Buffer nsAndInstance, int power, bool connectable) { - ManagedBuffer buf(nsAndInstance); - if (buf.length() != 16) return; +#if CONFIG_ENABLED(MICROBIT_BLE_EDDYSTONE_UID) + auto buf = nsAndInstance; + if (buf->length != 16) return; power = min(MICROBIT_BLE_POWER_LEVELS-1, max(0, power)); int8_t level = CALIBRATED_POWERS[power]; - uint8_t uidNs[10]; buf.readBytes(uidNs, 0, 10); - uint8_t uidInst[6]; buf.readBytes(uidInst, 10, 6); - uBit.bleManager.advertiseEddystoneUid((const char*)uidNs, (const char*)uidInst, level, connectable); + uBit.bleManager.advertiseEddystoneUid((const char*)buf->data, (const char*)buf->data + 10, level, connectable); +#endif } /** @@ -186,5 +229,5 @@ namespace bluetooth { //% help=bluetooth/stop-advertising advanced=true void stopAdvertising() { uBit.bleManager.stopAdvertising(); - } + } } \ No newline at end of file diff --git a/libs/bluetooth/bluetooth.ts b/libs/bluetooth/bluetooth.ts index 343f24ba..49b76dff 100644 --- a/libs/bluetooth/bluetooth.ts +++ b/libs/bluetooth/bluetooth.ts @@ -1,8 +1,20 @@ +/// /** * Support for additional Bluetooth services. */ //% color=#0082FB weight=96 icon="\uf294" namespace bluetooth { + export let NEW_LINE = "\r\n"; + + /** + * Internal use + */ + //% shim=bluetooth::__log + export function __log(msg: string) { + return; + } + console.addListener(function (msg) { __log(msg) }); + /** * Writes to the Bluetooth UART service buffer. From there the data is transmitted over Bluetooth to a connected device. */ @@ -10,8 +22,17 @@ namespace bluetooth { //% blockId=bluetooth_uart_write block="bluetooth uart|write string %data" blockGap=8 //% parts="bluetooth" shim=bluetooth::uartWriteString advanced=true export function uartWriteString(data: string): void { - // dummy implementation for simulator - console.log("UART Write: " + data) + console.log(data) + } + + /** + * Writes to the Bluetooth UART service buffer. From there the data is transmitted over Bluetooth to a connected device. + */ + //% help=bluetooth/uart-write-line weight=79 + //% blockId=bluetooth_uart_line block="bluetooth uart|write line %data" blockGap=8 + //% parts="bluetooth" advanced=true + export function uartWriteLine(data: string): void { + uartWriteString(data + serial.NEW_LINE); } /** @@ -33,7 +54,7 @@ namespace bluetooth { //% help=bluetooth/uart-write-value advanced=true //% blockId=bluetooth_uart_writevalue block="bluetooth uart|write value %name|= %value" export function uartWriteValue(name: string, value: number): void { - uartWriteString(name + ":" + value + "\r\n"); + uartWriteString((name ? name + ":" : "") + value + NEW_LINE); } /** @@ -44,7 +65,7 @@ namespace bluetooth { //% parts="bluetooth" shim=bluetooth::uartReadUntil advanced=true export function uartReadUntil(del: string): string { // dummy implementation for simulator - return "???" + return "" } /** diff --git a/libs/bluetooth/pxt.json b/libs/bluetooth/pxt.json index ea5d704e..f5818816 100644 --- a/libs/bluetooth/pxt.json +++ b/libs/bluetooth/pxt.json @@ -7,8 +7,10 @@ "shims.d.ts", "bluetooth.ts", "bluetooth.cpp", - "_locales/de/bluetooth-jsdoc-strings.json" + "BLEHF2Service.h", + "BLEHF2Service.cpp" ], + "icon": "./static/packages/bluetooth/icon.png", "public": true, "dependencies": { "core": "file:../core" @@ -23,50 +25,10 @@ }, "optionalConfig": { "microbit-dal": { + "stack_size": 1280, "gatt_table_size": "0x700" } - }, - "userConfigs": [ - { - "description": "No Pairing Required: Anyone can connect via Bluetooth.", - "config": { - "microbit-dal": { - "bluetooth": { - "open": 1, - "pairing_mode": 0, - "whitelist": 0, - "security_level": null - } - } - } - }, - { - "description": "JustWorks pairing (default): Pairing is automatic once the pairing is initiated.", - "config": { - "microbit-dal": { - "bluetooth": { - "open": null, - "pairing_mode": null, - "whitelist": null, - "security_level": null - } - } - } - }, - { - "description": "Passkey pairing: Pairing requires 6 digit key to pair.", - "config": { - "microbit-dal": { - "bluetooth": { - "open": 0, - "pairing_mode": 1, - "whitelist": 1, - "security_level": "SECURITY_MODE_ENCRYPTION_WITH_MITM" - } - } - } - } - ] + } }, "installedVersion": "vzlhfd" } \ No newline at end of file diff --git a/libs/bluetooth/shims.d.ts b/libs/bluetooth/shims.d.ts index 5e35e3b7..46f84bf0 100644 --- a/libs/bluetooth/shims.d.ts +++ b/libs/bluetooth/shims.d.ts @@ -63,6 +63,18 @@ declare namespace bluetooth { //% parts="bluetooth" advanced=true shim=bluetooth::startUartService function startUartService(): void; + /** + * Sends a buffer of data via Bluetooth UART + */ + //% shim=bluetooth::uartWriteBuffer + function uartWriteBuffer(buffer: Buffer): void; + + /** + * Reads buffered UART data into a buffer + */ + //% shim=bluetooth::uartReadBuffer + function uartReadBuffer(): Buffer; + /** * Registers an event to be fired when one of the delimiter is matched. * @param delimiters the characters to match received characters against. @@ -98,7 +110,7 @@ declare namespace bluetooth { //% blockId=eddystone_advertise_url block="bluetooth advertise url %url|with power %power|connectable %connectable" //% parts=bluetooth weight=11 blockGap=8 //% help=bluetooth/advertise-url blockExternalInputs=1 shim=bluetooth::advertiseUrl - function advertiseUrl(url: string, power: number, connectable: boolean): void; + function advertiseUrl(url: string, power: int32, connectable: boolean): void; /** * Advertise an Eddystone UID @@ -107,7 +119,7 @@ declare namespace bluetooth { * @param connectable true to keep bluetooth connectable for other services, false otherwise. */ //% parts=bluetooth weight=12 advanced=true shim=bluetooth::advertiseUidBuffer - function advertiseUidBuffer(nsAndInstance: Buffer, power: number, connectable: boolean): void; + function advertiseUidBuffer(nsAndInstance: Buffer, power: int32, connectable: boolean): void; /** * Sets the bluetooth transmit power between 0 (minimal) and 7 (maximum). @@ -115,7 +127,7 @@ declare namespace bluetooth { */ //% parts=bluetooth weight=5 help=bluetooth/set-transmit-power advanced=true //% blockId=bluetooth_settransmitpower block="bluetooth set transmit power %power" shim=bluetooth::setTransmitPower - function setTransmitPower(power: number): void; + function setTransmitPower(power: int32): void; /** * Stops advertising Eddystone end points diff --git a/libs/bluetoothprj/main.blocks b/libs/bluetoothprj/main.blocks index d809e7e4..cf17f1bb 100644 --- a/libs/bluetoothprj/main.blocks +++ b/libs/bluetoothprj/main.blocks @@ -1,62 +1,3 @@ - - - -FALSE -FALSE -FALSE -FALSE -FALSE -FALSE -TRUE -FALSE -TRUE -FALSE -FALSE -FALSE -FALSE -FALSE -FALSE -TRUE -FALSE -FALSE -FALSE -TRUE -FALSE -TRUE -TRUE -TRUE -FALSE - - -FALSE -FALSE -FALSE -FALSE -FALSE -FALSE -FALSE -FALSE -FALSE -FALSE -FALSE -FALSE -FALSE -FALSE -FALSE -FALSE -FALSE -FALSE -FALSE -FALSE -FALSE -FALSE -FALSE -FALSE -FALSE - - - - - + \ No newline at end of file diff --git a/libs/bluetoothprj/main.ts b/libs/bluetoothprj/main.ts index 4dfdb3a1..8b137891 100644 --- a/libs/bluetoothprj/main.ts +++ b/libs/bluetoothprj/main.ts @@ -1,16 +1 @@ -basic.forever(() => { - basic.showLeds(` - . # . # . - # . # . # - # . . . # - . # . # . - . . # . . - `) - basic.showLeds(` - . . . . . - . . . . . - . . . . . - . . . . . - . . . . . - `) -}) \ No newline at end of file + diff --git a/libs/calliope-i2c/i2c.ts b/libs/calliope-i2c/i2c.ts deleted file mode 100644 index 0aa06b0e..00000000 --- a/libs/calliope-i2c/i2c.ts +++ /dev/null @@ -1,23 +0,0 @@ -import rgbw = basic.rgbw; -serial.writeLine("I2C"); -// send to 0x44, register 0x00, value 0x46 (RESET ISL29125) -pins.i2cWriteNumber(0x44, 0x0046, NumberFormat.UInt16BE); -// send to 0x44, register 0x01, value 0x05 (GRB SAMPLING) -pins.i2cWriteNumber(0x44, 0x0105, NumberFormat.UInt16BE); -basic.forever(() => { - serial.writeString("["); - pins.i2cWriteNumber(0x44, 0x0A, NumberFormat.Int8BE); - let g = pins.i2cReadNumber(0x44, NumberFormat.UInt8BE); - serial.writeNumber(r); - serial.writeString(","); - pins.i2cWriteNumber(0x44, 0x0C, NumberFormat.UInt8BE); - let r = pins.i2cReadNumber(0x44, NumberFormat.UInt8BE); - serial.writeNumber(g); - serial.writeString(","); - pins.i2cWriteNumber(0x44, 0x0E, NumberFormat.UInt8BE); - let b = pins.i2cReadNumber(0x44, NumberFormat.UInt8LE); - serial.writeNumber(b); - serial.writeLine("]"); - basic.setLedColor(basic.rgbw(r,g,b, 0)); - basic.pause(1000); -}); \ No newline at end of file diff --git a/libs/calliope-i2c/pxt.json b/libs/calliope-i2c/pxt.json deleted file mode 100644 index d5e66d31..00000000 --- a/libs/calliope-i2c/pxt.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "name": "calliope-i2c", - "description": "Calliope I2C test", - "files": [ - "i2c.ts" - ], - "public": true, - "dependencies": { - "core": "file:../core" - } -} diff --git a/libs/calliope-midi/midi.ts b/libs/calliope-midi/midi.ts deleted file mode 100644 index f384598b..00000000 --- a/libs/calliope-midi/midi.ts +++ /dev/null @@ -1,23 +0,0 @@ -serial.redirect( - SerialPin.P0, - SerialPin.P1, - 31250 -); - -basic.forever(() => { - for (let note = 0; note <= 90 - 1; note++) { - // Note on channel 1 (0x90), some note value (note), - // middle velocity (0x45): - serial.writeString(String.fromCharCode(144)); - serial.writeString(String.fromCharCode(note)); - serial.writeString(String.fromCharCode(69)); - basic.pause(100); - // Note on channel 1 (0x90), some note value (note), - // silent velocity (0x00): - serial.writeString(String.fromCharCode(144)); - serial.writeString(String.fromCharCode(note)); - serial.writeString("\0"); - basic.pause(100); - basic.pause(1000); - } -}); diff --git a/libs/calliope-midi/pxt.json b/libs/calliope-midi/pxt.json deleted file mode 100644 index 72fadda6..00000000 --- a/libs/calliope-midi/pxt.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "name": "midi", - "description": "MIDI Example via Serial", - "files": [ - "midi.ts" - ], - "public": true, - "dependencies": { - "core": "file:../core" - } -} diff --git a/libs/calliope-test/calliope.ts b/libs/calliope-test/calliope.ts deleted file mode 100644 index 5fa3f3b9..00000000 --- a/libs/calliope-test/calliope.ts +++ /dev/null @@ -1,173 +0,0 @@ -basic.showString("RGB"); -basic.setLedColor(Colors.Blue); -basic.pause(500); -basic.setLedColor(Colors.Red); -basic.pause(500); -basic.setLedColor(Colors.Green); -basic.pause(500); -basic.setLedColor(Colors.Violet); -basic.pause(500); -basic.setLedColor(0); -basic.showString("Gesten"); -input.onGesture(Gesture.Shake, () => { - basic.showString("S") -}); -input.onGesture(Gesture.LogoUp, () => { - basic.showString("U") -}); -input.onGesture(Gesture.LogoDown, () => { - basic.showString("D") -}); -input.onGesture(Gesture.ScreenUp, () => { - basic.showString("+") -}); -input.onGesture(Gesture.TiltRight, () => { - basic.showString("R") -}); -input.onGesture(Gesture.FreeFall, () => { - basic.showString("F") -}); -input.onGesture(Gesture.ScreenDown, () => { - basic.showString("-") -}); -input.onGesture(Gesture.TiltLeft, () => { - basic.showString("L") -}); -input.onGesture(Gesture.ThreeG, () => { - basic.showString("3") -}); -input.onGesture(Gesture.SixG, () => { - basic.showString("6") -}); -input.onPinPressed(TouchPin.P0, () => { - basic.showNumber(0) -}); -input.onPinPressed(TouchPin.P1, () => { - basic.showNumber(1) -}); -input.onPinPressed(TouchPin.P2, () => { - basic.showNumber(2) -}); -input.onPinPressed(TouchPin.P3, () => { - basic.showNumber(3) -}); - -basic.showString("Sound"); -music.setTempo(150); -let whole = music.beat(BeatFraction.Whole); -function note(n: Note, l: BeatFraction): number[] { - return [music.noteFrequency(n), music.beat(l)]; -} - -function getNoteName(frequency: number): string { - switch (frequency) { - case 262: - return "C"; - case 277: - return "CSharp"; - case 294: - return "D"; - case 311: - return "Eb"; - case 330: - return "E"; - case 349: - return "F"; - case 370: - return "FSharp"; - case 392: - return "G"; - case 415: - return "GSharp"; - case 440: - return "A"; - case 466: - return "Bb"; - case 494: - return "B"; - case 131: - return "C3"; - case 139: - return "CSharp3"; - case 147: - return "D3"; - case 156: - return "Eb3"; - case 165: - return "E3"; - case 175: - return "F3"; - case 185: - return "FSharp3"; - case 196: - return "G3"; - case 208: - return "GSharp3"; - case 220: - return "A3"; - case 233: - return "Bb3"; - case 247: - return "B3"; - case 523: - return "C5"; - case 555: - return "CSharp5"; - case 587: - return "D5"; - case 622: - return "Eb5"; - case 659: - return "E5"; - case 698: - return "F5"; - case 740: - return "FSharp5"; - case 784: - return "G5"; - case 831: - return "GSharp5"; - case 880: - return "A5"; - case 932: - return "Bb5"; - case 989: - return "B5"; - default: - return "?"; - } -} - -let notes = [ - note(Note.E, BeatFraction.Quarter), note(Note.E, BeatFraction.Quarter), note(Note.F, BeatFraction.Quarter), - note(Note.G, BeatFraction.Quarter), note(Note.G, BeatFraction.Quarter), note(Note.F, BeatFraction.Quarter), - note(Note.E, BeatFraction.Quarter), note(Note.D, BeatFraction.Quarter), note(Note.C, BeatFraction.Quarter), - note(Note.C, BeatFraction.Quarter), note(Note.D, BeatFraction.Quarter), note(Note.E, BeatFraction.Quarter), - note(Note.E, BeatFraction.Quarter + BeatFraction.Eighth), - note(Note.D, BeatFraction.Eighth), note(Note.D, BeatFraction.Half), - note(Note.E, BeatFraction.Quarter), note(Note.E, BeatFraction.Quarter), note(Note.F, BeatFraction.Quarter), - note(Note.G, BeatFraction.Quarter), note(Note.G, BeatFraction.Quarter), note(Note.F, BeatFraction.Quarter), - note(Note.E, BeatFraction.Quarter), note(Note.D, BeatFraction.Quarter), note(Note.C, BeatFraction.Quarter), - note(Note.C, BeatFraction.Quarter), note(Note.D, BeatFraction.Quarter), note(Note.E, BeatFraction.Quarter), - note(Note.D, BeatFraction.Quarter + BeatFraction.Eighth), - note(Note.C, BeatFraction.Eighth), note(Note.C, BeatFraction.Half), - note(Note.D, BeatFraction.Quarter), note(Note.D, BeatFraction.Quarter), note(Note.E, BeatFraction.Quarter), - note(Note.C, BeatFraction.Quarter), note(Note.D, BeatFraction.Quarter), - note(Note.E, BeatFraction.Eighth), note(Note.F, BeatFraction.Eighth), - note(Note.E, BeatFraction.Quarter), note(Note.C, BeatFraction.Quarter), note(Note.D, BeatFraction.Quarter), - note(Note.E, BeatFraction.Eighth), note(Note.F, BeatFraction.Eighth), - note(Note.E, BeatFraction.Quarter), note(Note.D, BeatFraction.Quarter), note(Note.C, BeatFraction.Quarter), - note(Note.D, BeatFraction.Quarter), note(Note.G3, BeatFraction.Quarter), note(Note.E, BeatFraction.Half), - note(Note.E, BeatFraction.Quarter), note(Note.F, BeatFraction.Quarter), note(Note.G, BeatFraction.Quarter), - note(Note.G, BeatFraction.Quarter), note(Note.F, BeatFraction.Quarter), note(Note.E, BeatFraction.Quarter), - note(Note.E, BeatFraction.Eighth), note(Note.F, BeatFraction.Eighth), - note(Note.C, BeatFraction.Quarter), note(Note.C, BeatFraction.Quarter), note(Note.D, BeatFraction.Quarter), - note(Note.E, BeatFraction.Quarter), note(Note.D, BeatFraction.Quarter + BeatFraction.Eighth), - note(Note.C, BeatFraction.Eighth), note(Note.C, BeatFraction.Half) -]; - -for (let t = 0; t < notes.length; t++) { - music.playTone(notes[t][0], notes[t][1]); - basic.showString(getNoteName(notes[t][0])); - music.rest(whole - notes[t][1]); -} diff --git a/libs/calliope-test/pxt.json b/libs/calliope-test/pxt.json deleted file mode 100644 index 917d19d8..00000000 --- a/libs/calliope-test/pxt.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "name": "calliope", - "description": "Test of Calliope Parts", - "files": [ - "calliope.ts" - ], - "public": true, - "dependencies": { - "core": "file:../core" - } -} diff --git a/libs/core/ManagedBuffer.cpp b/libs/core/ManagedBuffer.cpp deleted file mode 100644 index 25b9cb26..00000000 --- a/libs/core/ManagedBuffer.cpp +++ /dev/null @@ -1,373 +0,0 @@ -#include "MicroBit.h" -#include "ManagedBuffer.h" -#include - -static const char empty[] __attribute__ ((aligned (4))) = "\xff\xff\0\0\0"; - -/** - * Internal constructor helper. - * Configures this ManagedBuffer to refer to the static empty buffer. - */ -void ManagedBuffer::initEmpty() -{ - ptr = (BufferData*)(void*)empty; -} - -/** - * Default Constructor. - * Creates an empty ManagedBuffer. - * - * Example: - * @code - * ManagedBuffer p(); - * @endcode - */ -ManagedBuffer::ManagedBuffer() -{ - initEmpty(); -} - -/** - * Constructor. - * Creates an empty ManagedBuffer of the given size. - * - * @param length The length of the buffer to create. - * - * Example: - * @code - * ManagedBuffer p(16); // Creates a ManagedBuffer 16 bytes long. - * @endcode - */ -ManagedBuffer::ManagedBuffer(int length) -{ - this->init(NULL, length); -} - -/** - * Constructor. - * Creates a new ManagedBuffer of the given size, - * and fills it with the data provided. - * - * @param data The data with which to fill the buffer. - * @param length The length of the buffer to create. - * - * Example: - * @code - * uint8_t buf = {13,5,2}; - * ManagedBuffer p(buf, 3); // Creates a ManagedBuffer 3 bytes long. - * @endcode - */ -ManagedBuffer::ManagedBuffer(uint8_t *data, int length) -{ - this->init(data, length); -} - -/** - * Copy Constructor. - * Add ourselves as a reference to an existing ManagedBuffer. - * - * @param buffer The ManagedBuffer to reference. - * - * Example: - * @code - * ManagedBuffer p(); - * ManagedBuffer p2(i); // Refers to the same buffer as p. - * @endcode - */ -ManagedBuffer::ManagedBuffer(const ManagedBuffer &buffer) -{ - ptr = buffer.ptr; - ptr->incr(); -} - -/** - * Constructor. - * Create a buffer from a raw BufferData pointer. It will ptr->incr(). This is to be used by specialized runtimes. - * - * @param p The pointer to use. - */ -ManagedBuffer::ManagedBuffer(BufferData *p) -{ - ptr = p; - ptr->incr(); -} - -/** - * Internal constructor-initialiser. - * - * @param data The data with which to fill the buffer. - * @param length The length of the buffer to create. - * - */ -void ManagedBuffer::init(uint8_t *data, int length) -{ - if (length <= 0) { - initEmpty(); - return; - } - - ptr = (BufferData *) malloc(sizeof(BufferData) + length); - ptr->init(); - - ptr->length = length; - - // Copy in the data buffer, if provided. - if (data) - memcpy(ptr->payload, data, length); - else - memset(ptr->payload, 0, length); -} - -/** - * Destructor. - * Removes buffer resources held by the instance. - */ -ManagedBuffer::~ManagedBuffer() -{ - ptr->decr(); -} - -/** - * Copy assign operation. - * - * Called when one ManagedBuffer is assigned the value of another using the '=' operator. - * Decrements our reference count and free up the buffer as necessary. - * Then, update our buffer to refer to that of the supplied ManagedBuffer, - * and increase its reference count. - * - * @param p The ManagedBuffer to reference. - * - * Example: - * @code - * uint8_t buf = {13,5,2}; - * ManagedBuffer p1(16); - * ManagedBuffer p2(buf, 3); - * - * p1 = p2; - * @endcode - */ -ManagedBuffer& ManagedBuffer::operator = (const ManagedBuffer &p) -{ - if(ptr == p.ptr) - return *this; - - ptr->decr(); - ptr = p.ptr; - ptr->incr(); - - return *this; -} - -/** - * Equality operation. - * - * Called when one ManagedBuffer is tested to be equal to another using the '==' operator. - * - * @param p The ManagedBuffer to test ourselves against. - * @return true if this ManagedBuffer is identical to the one supplied, false otherwise. - * - * Example: - * @code - * - * uint8_t buf = {13,5,2}; - * ManagedBuffer p1(16); - * ManagedBuffer p2(buf, 3); - * - * if(p1 == p2) // will be true - * uBit.display.scroll("same!"); - * @endcode - */ -bool ManagedBuffer::operator== (const ManagedBuffer& p) -{ - if (ptr == p.ptr) - return true; - else - return (ptr->length == p.ptr->length && (memcmp(ptr->payload, p.ptr->payload, ptr->length)==0)); -} - -/** - * Sets the byte at the given index to value provided. - * @param position The index of the byte to change. - * @param value The new value of the byte (0-255). - * @return MICROBIT_OK, or MICROBIT_INVALID_PARAMETER. - * - * Example: - * @code - * ManagedBuffer p1(16); - * p1.setByte(0,255); // Sets the firts byte in the buffer to the value 255. - * @endcode - */ -int ManagedBuffer::setByte(int position, uint8_t value) -{ - if (0 <= position && position < ptr->length) - { - ptr->payload[position] = value; - return MICROBIT_OK; - } - else - { - return MICROBIT_INVALID_PARAMETER; - } -} - -/** - * Determines the value of the given byte in the buffer. - * - * @param position The index of the byte to read. - * @return The value of the byte at the given position, or MICROBIT_INVALID_PARAMETER. - * - * Example: - * @code - * ManagedBuffer p1(16); - * p1.setByte(0,255); // Sets the firts byte in the buffer to the value 255. - * p1.getByte(0); // Returns 255. - * @endcode - */ -int ManagedBuffer::getByte(int position) -{ - if (0 <= position && position < ptr->length) - return ptr->payload[position]; - else - return MICROBIT_INVALID_PARAMETER; -} - -/** - * Get current ptr, do not decr() it, and set the current instance to an empty buffer. - * This is to be used by specialized runtimes which pass BufferData around. - */ -BufferData *ManagedBuffer::leakData() -{ - BufferData* res = ptr; - initEmpty(); - return res; -} - - -int ManagedBuffer::fill(uint8_t value, int offset, int length) -{ - if (offset < 0 || offset > ptr->length) - return MICROBIT_INVALID_PARAMETER; - if (length < 0) - length = ptr->length; - length = min(length, ptr->length - offset); - - memset(ptr->payload + offset, value, length); - - return MICROBIT_OK; -} - -ManagedBuffer ManagedBuffer::slice(int offset, int length) const -{ - offset = min(ptr->length, offset); - if (length < 0) - length = ptr->length; - length = min(length, ptr->length - offset); - return ManagedBuffer(ptr->payload + offset, length); -} - -void ManagedBuffer::shift(int offset, int start, int len) -{ - if (len < 0) len = ptr->length - start; - if (start < 0 || start + len > ptr->length || start + len < start - || len == 0 || offset == 0 || offset == INT_MIN) return; - if (offset <= -len || offset >= len) { - fill(0); - return; - } - - uint8_t *data = ptr->payload + start; - if (offset < 0) { - offset = -offset; - memmove(data + offset, data, len - offset); - memset(data, 0, offset); - } else { - len = len - offset; - memmove(data, data + offset, len); - memset(data + len, 0, offset); - } -} - -void ManagedBuffer::rotate(int offset, int start, int len) -{ - if (len < 0) len = ptr->length - start; - if (start < 0 || start + len > ptr-> length || start + len < start - || len == 0 || offset == 0 || offset == INT_MIN) return; - - if (offset < 0) - offset += len << 8; // try to make it positive - offset %= len; - if (offset < 0) - offset += len; - - uint8_t *data = ptr->payload + start; - - uint8_t *n_first = data + offset; - uint8_t *first = data; - uint8_t *next = n_first; - uint8_t *last = data + len; - - while (first != next) { - uint8_t tmp = *first; - *first++ = *next; - *next++ = tmp; - if (next == last) { - next = n_first; - } else if (first == n_first) { - n_first = next; - } - } -} - -int ManagedBuffer::writeBuffer(int dstOffset, const ManagedBuffer &src, int srcOffset, int length) -{ - if (length < 0) - length = src.length(); - - if (srcOffset < 0 || dstOffset < 0 || dstOffset > ptr->length) - return MICROBIT_INVALID_PARAMETER; - - length = min(src.length() - srcOffset, ptr->length - dstOffset); - - if (length < 0) - return MICROBIT_INVALID_PARAMETER; - - if (ptr == src.ptr) { - memmove(getBytes() + dstOffset, src.ptr->payload + srcOffset, length); - } else { - memcpy(getBytes() + dstOffset, src.ptr->payload + srcOffset, length); - } - - return MICROBIT_OK; -} - -int ManagedBuffer::writeBytes(int offset, uint8_t *src, int length, bool swapBytes) -{ - if (offset < 0 || length < 0 || offset + length > ptr->length) - return MICROBIT_INVALID_PARAMETER; - - if (swapBytes) { - uint8_t *p = ptr->payload + offset + length; - for (int i = 0; i < length; ++i) - *--p = src[i]; - } else { - memcpy(ptr->payload + offset, src, length); - } - - return MICROBIT_OK; -} - -int ManagedBuffer::readBytes(uint8_t *dst, int offset, int length, bool swapBytes) const -{ - if (offset < 0 || length < 0 || offset + length > ptr->length) - return MICROBIT_INVALID_PARAMETER; - - if (swapBytes) { - uint8_t *p = ptr->payload + offset + length; - for (int i = 0; i < length; ++i) - dst[i] = *--p; - } else { - memcpy(dst, ptr->payload + offset, length); - } - - return MICROBIT_OK; -} diff --git a/libs/core/ManagedBuffer.h b/libs/core/ManagedBuffer.h deleted file mode 100644 index 991dd8d7..00000000 --- a/libs/core/ManagedBuffer.h +++ /dev/null @@ -1,257 +0,0 @@ -#ifndef MICROBIT_MANAGED_BUFFER_H -#define MICROBIT_MANAGED_BUFFER_H - -#include "mbed.h" -#include "RefCounted.h" - -struct BufferData : RefCounted -{ - uint16_t length; // The length of the payload in bytes - uint8_t payload[0]; // ManagedBuffer data -}; - -/** - * Class definition for a ManagedBuffer. - * A ManagedBuffer holds a series of bytes, used with MicroBitRadio channels and in other places. - * n.b. This is a mutable, managed type. - */ -class ManagedBuffer -{ - BufferData *ptr; // Pointer to payload data - - public: - - /** - * Default Constructor. - * Creates an empty ManagedBuffer. The 'ptr' field in all empty buffers is shared. - * - * Example: - * @code - * ManagedBuffer p(); - * @endcode - */ - ManagedBuffer(); - - /** - * Constructor. - * Creates a new ManagedBuffer of the given size. - * - * @param length The length of the buffer to create. - * - * Example: - * @code - * ManagedBuffer p(16); // Creates a ManagedBuffer 16 bytes long. - * @endcode - */ - ManagedBuffer(int length); - - /** - * Constructor. - * Creates an empty ManagedBuffer of the given size, - * and fills it with the data provided. - * - * @param data The data with which to fill the buffer. - * @param length The length of the buffer to create. - * - * Example: - * @code - * uint8_t buf[] = {13,5,2}; - * ManagedBuffer p(buf, 3); // Creates a ManagedBuffer 3 bytes long. - * @endcode - */ - ManagedBuffer(uint8_t *data, int length); - - /** - * Copy Constructor. - * Add ourselves as a reference to an existing ManagedBuffer. - * - * @param buffer The ManagedBuffer to reference. - * - * Example: - * @code - * ManagedBuffer p(); - * ManagedBuffer p2(i); // Refers to the same buffer as p. - * @endcode - */ - ManagedBuffer(const ManagedBuffer &buffer); - - /** - * Constructor. - * Create a buffer from a raw BufferData pointer. It will ptr->incr(). This is to be used by specialized runtimes. - * - * @param p The pointer to use. - */ - ManagedBuffer(BufferData *p); - - /** - * Internal constructor helper. - * Configures this ManagedBuffer to refer to the static empty buffer. - */ - void initEmpty(); - - /** - * Internal constructor-initialiser. - * - * @param data The data with which to fill the buffer. - * @param length The length of the buffer to create. - * - */ - void init(uint8_t *data, int length); - - /** - * Destructor. - * Removes buffer resources held by the instance. - */ - ~ManagedBuffer(); - - /** - * Provide an array containing the buffer data. - * @return The contents of this buffer, as an array of bytes. - */ - uint8_t *getBytes() - { - return ptr->payload; - } - - /** - * Get current ptr, do not decr() it, and set the current instance to an empty buffer. - * This is to be used by specialized runtimes which pass BufferData around. - */ - BufferData *leakData(); - - /** - * Copy assign operation. - * - * Called when one ManagedBuffer is assigned the value of another using the '=' operator. - * Decrements our reference count and free up the buffer as necessary. - * Then, update our buffer to refer to that of the supplied ManagedBuffer, - * and increase its reference count. - * - * @param p The ManagedBuffer to reference. - * - * Example: - * @code - * uint8_t buf = {13,5,2}; - * ManagedBuffer p1(16); - * ManagedBuffer p2(buf, 3); - * - * p1 = p2; - * @endcode - */ - ManagedBuffer& operator = (const ManagedBuffer& p); - - /** - * Array access operation (read). - * - * Called when a ManagedBuffer is dereferenced with a [] operation. - * Transparently map this through to the underlying payload for elegance of programming. - * - * Example: - * @code - * ManagedBuffer p1(16); - * uint8_t data = p1[0]; - * @endcode - */ - uint8_t operator [] (int i) const - { - return ptr->payload[i]; - } - - /** - * Array access operation (modify). - * - * Called when a ManagedBuffer is dereferenced with a [] operation. - * Transparently map this through to the underlying payload for elegance of programming. - * - * Example: - * @code - * ManagedBuffer p1(16); - * p1[0] = 42; - * @endcode - */ - uint8_t& operator [] (int i) - { - return ptr->payload[i]; - } - - /** - * Equality operation. - * - * Called when one ManagedBuffer is tested to be equal to another using the '==' operator. - * - * @param p The ManagedBuffer to test ourselves against. - * @return true if this ManagedBuffer is identical to the one supplied, false otherwise. - * - * Example: - * @code - * - * uint8_t buf = {13,5,2}; - * ManagedBuffer p1(16); - * ManagedBuffer p2(buf, 3); - * - * if(p1 == p2) // will be true - * uBit.display.scroll("same!"); - * @endcode - */ - bool operator== (const ManagedBuffer& p); - - /** - * Sets the byte at the given index to value provided. - * @param position The index of the byte to change. - * @param value The new value of the byte (0-255). - * @return MICROBIT_OK, or MICROBIT_INVALID_PARAMETER. - * - * Example: - * @code - * ManagedBuffer p1(16); - * p1.setByte(0,255); // Sets the first byte in the buffer to the value 255. - * @endcode - */ - int setByte(int position, uint8_t value); - - /** - * Determines the value of the given byte in the buffer. - * - * @param position The index of the byte to read. - * @return The value of the byte at the given position, or MICROBIT_INVALID_PARAMETER. - * - * Example: - * @code - * ManagedBuffer p1(16); - * p1.setByte(0,255); // Sets the first byte in the buffer to the value 255. - * p1.getByte(0); // Returns 255. - * @endcode - */ - int getByte(int position); - - /** - * Gets number of bytes in this buffer - * @return The size of the buffer in bytes. - * - * Example: - * @code - * ManagedBuffer p1(16); - * p1.length(); // Returns 16. - * @endcode - */ - int length() const { return ptr->length; } - - int fill(uint8_t value, int offset = 0, int length = -1); - - ManagedBuffer slice(int offset = 0, int length = -1) const; - - void shift(int offset, int start = 0, int length = -1); - - void rotate(int offset, int start = 0, int length = -1); - - int readBytes(uint8_t *dst, int offset, int length, bool swapBytes = false) const; - - int writeBytes(int dstOffset, uint8_t *src, int length, bool swapBytes = false); - - int writeBuffer(int dstOffset, const ManagedBuffer &src, int srcOffset = 0, int length = -1); - - bool isReadOnly() const { return ptr->isReadOnly(); } -}; - -#endif - diff --git a/libs/core/_locales/core-jsdoc-strings.json b/libs/core/_locales/core-jsdoc-strings.json index 7af391d7..6bf7d4c0 100644 --- a/libs/core/_locales/core-jsdoc-strings.json +++ b/libs/core/_locales/core-jsdoc-strings.json @@ -3,37 +3,39 @@ "AcceleratorRange.FourG": "The accelerator measures forces up to 4 gravity", "AcceleratorRange.OneG": "The accelerator measures forces up to 1 gravity", "AcceleratorRange.TwoG": "The accelerator measures forces up to 2 gravity", - "Array": "Add, remove, and replace items in lists.\n\nAdd, remove, and replace items in lists.", + "Array": "Add, remove, and replace items in lists.", + "Array.concat": "Concatenates the values with another array.", + "Array.concat|param|arr": "The other array that is being concatenated with", "Array.every": "Tests whether all elements in the array pass the test implemented by the provided function.", - "Array.every|param|callbackfn": "A function that accepts up to two arguments. The some method calls the callbackfn function one time for each element in the array.", + "Array.every|param|callbackfn": "A function that accepts up to two arguments. The every method calls the callbackfn function one time for each element in the array.", + "Array.fill": "Fills all the elements of an array from a start index to an end index with a static value. The end index is not included.", "Array.filter": "Return the elements of an array that meet the condition specified in a callback function.", "Array.filter|param|callbackfn": "A function that accepts up to two arguments. The filter method calls the callbackfn function one time for each element in the array.", + "Array.find": "Returns the value of the first element in the array that satisfies the provided testing function. Otherwise undefined is returned.", "Array.forEach": "Call a defined callback function on each element of an array.", "Array.forEach|param|callbackfn": "A function that accepts up to two arguments. The forEach method calls the callbackfn function one time for each element in the array.", - "Array.get": "Get the value at a particular index.", + "Array.get": "Get the value at a particular index", "Array.get|param|index": "the zero-based position in the list of the item, eg: 0", "Array.indexOf": "Return the index of the first occurrence of a value in an array.", "Array.indexOf|param|fromIndex": "The array index at which to begin the search. If fromIndex is omitted, the search starts at index 0.", "Array.indexOf|param|item": "The value to locate in the array.", - "Array.insertAt": "Insert the value at a particular index, increase the array length by 1.", + "Array.insertAt": "Insert the value at a particular index, increases length by 1", "Array.insertAt|param|index": "the zero-based position in the list to insert the value, eg: 0", - "Array.insertAt|param|value": "to insert, eg: 0", + "Array.isArray": "Check if a given object is an array.", "Array.join": "joins all elements of an array into a string and returns this string.", "Array.join|param|sep": "the string separator", - "Array.length": "Gets or sets the length of the array. This is a number one higher than the highest element defined in an array.", + "Array.length": "Get or set the length of an array. This number is one more than the index of the last element the array.", "Array.map": "Call a defined callback function on each element of an array, and return an array containing the results.", "Array.map|param|callbackfn": "A function that accepts up to two arguments. The map method calls the callbackfn function one time for each element in the array.", "Array.pop": "Remove the last element from an array and return it.", - "Array.push": "Append a new elements to an array.", - "Array.push|param|item": "to append to the Array.", + "Array.push": "Append a new element to an array.", "Array.reduce": "Call the specified callback function for all the elements in an array. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function.", "Array.reduce|param|callbackfn": "A function that accepts up to three arguments. The reduce method calls the callbackfn function one time for each element in the array.", "Array.reduce|param|initialValue": "Initial value to start the accumulation. The first call to the callbackfn function provides this value as an argument instead of an array value.", "Array.removeAt": "Remove the element at a certain index.", - "Array.removeAt|param|index": "the zero-based position in the list to remove the value from, eg: 0", - "Array.removeElement": "Remove the first occurence of an object. Return true if removed.", + "Array.removeElement": "Remove the first occurence of an object. Returns true if removed.", "Array.reverse": "Reverse the elements in an array. The first array element becomes the last, and the last array element becomes the first.", - "Array.set": "Store a value at a particular index.", + "Array.set": "Store a value at a particular index", "Array.set|param|index": "the zero-based position in the list to store the value, eg: 0", "Array.shift": "Remove the first element from an array and return it. This method changes the length of the array.", "Array.slice": "Return a section of an array.", @@ -46,21 +48,27 @@ "Array.splice|param|deleteCount": "The number of elements to remove. eg: 0", "Array.splice|param|start": "The zero-based location in the array from which to start removing elements. eg: 0", "Array.unshift": "Add one element to the beginning of an array and return the new length of the array.", - "Array.unshift|param|value": "to insert at the start of the Array.", + "Array@type": "Add, remove, and replace items in lists.", "Boolean.toString": "Returns a string representation of an object.", + "Buffer.concat": "Return concatenation of current buffer and the given buffer", "Buffer.fill": "Fill (a fragment) of the buffer with given value.", "Buffer.getNumber": "Read a number in specified format from the buffer.", + "Buffer.getUint8": "Reads an unsigned byte at a particular location", + "Buffer.indexOf": "Return position of other buffer in current buffer", "Buffer.length": "Returns the length of a Buffer object.", - "Buffer.rotate": "Rotate buffer left in place.", - "Buffer.rotate|param|length": "number of elements in buffer. If negative, length is set as the buffer length minus start. eg: -1", + "Buffer.rotate": "Rotate buffer left in place.\n\n\n\nstart. eg: -1", + "Buffer.rotate|param|length": "number of elements in buffer. If negative, length is set as the buffer length minus", "Buffer.rotate|param|offset": "number of bytes to shift; use negative value to shift right", "Buffer.rotate|param|start": "start offset in buffer. Default is 0.", "Buffer.setNumber": "Write a number in specified format in the buffer.", - "Buffer.shift": "Shift buffer left in place, with zero padding.", - "Buffer.shift|param|length": "number of elements in buffer. If negative, length is set as the buffer length minus start. eg: -1", + "Buffer.setUint8": "Writes an unsigned byte at a particular location", + "Buffer.shift": "Shift buffer left in place, with zero padding.\n\n\n\nstart. eg: -1", + "Buffer.shift|param|length": "number of elements in buffer. If negative, length is set as the buffer length minus", "Buffer.shift|param|offset": "number of bytes to shift; use negative value to shift right", "Buffer.shift|param|start": "start offset in buffer. Default is 0.", "Buffer.slice": "Return a copy of a fragment of a buffer.", + "Buffer.toHex": "Convert a buffer to its hexadecimal representation.", + "Buffer.toString": "Convert a buffer to string assuming UTF8 encoding", "Buffer.write": "Write contents of `src` at `dstOffset` in current buffer.", "Colors": "Well known colors", "EventCreationMode": "How to create the event.", @@ -81,8 +89,8 @@ "Image.height": "Gets the height in rows (always 5)", "Image.pixel": "Get the pixel state at position ``(x,y)``", "Image.pixelBrightness": "Gets the pixel brightness ([0..255]) at a given position", - "Image.pixel|param|x": "TODO", - "Image.pixel|param|y": "TODO", + "Image.pixel|param|x": "pixel column", + "Image.pixel|param|y": "pixel row", "Image.plotFrame": "Draws the ``index``-th frame of the image on the screen.", "Image.plotFrame|param|xOffset": "column index to start displaying the image", "Image.plotImage": "Plots the image at a given column to the screen", @@ -91,59 +99,112 @@ "Image.scrollImage|param|interval": "time between each animation step in milli seconds, eg: 200", "Image.setPixel": "Set a pixel state at position ``(x,y)``", "Image.setPixelBrightness": "Sets a specific pixel brightness at a given position", - "Image.setPixel|param|value": "TODO", - "Image.setPixel|param|x": "TODO", - "Image.setPixel|param|y": "TODO", - "Image.showFrame": "Shows a particular frame of the image strip.", - "Image.showFrame|param|frame": "TODO", + "Image.setPixel|param|value": "pixel state", + "Image.setPixel|param|x": "pixel column", + "Image.setPixel|param|y": "pixel row", + "Image.showFrame": "Show a particular frame of the image strip.", + "Image.showFrame|param|frame": "image frame to show", "Image.showImage": "Shows an frame from the image at offset ``x offset``.", "Image.showImage|param|xOffset": "column index to start displaying the image", "Image.width": "Gets the width in columns", + "Infinity": "Constant representing positive infinity.", "Math": "More complex operations with numbers.", "Math.abs": "Returns the absolute value of a number (the value without regard to whether it is positive or negative).\nFor example, the absolute value of -5 is the same as the absolute value of 5.", "Math.abs|param|x": "A numeric expression for which the absolute value is needed.", + "Math.acos": "Returns the arccosine (in radians) of a number", + "Math.acos|param|x": "A number", + "Math.asin": "Returns the arcsine (in radians) of a number", + "Math.asin|param|x": "A number", + "Math.atan": "Returns the arctangent (in radians) of a number", + "Math.atan2": "Returns the arctangent of the quotient of its arguments.", + "Math.atan2|param|x": "A number", + "Math.atan2|param|y": "A number", + "Math.atan|param|x": "A number", "Math.ceil": "Returns the smallest number greater than or equal to its numeric argument.", "Math.ceil|param|x": "A numeric expression.", + "Math.constrain": "Constrains a number to be within a range", + "Math.cos": "Returns the cosine of a number.", + "Math.cos|param|x": "An angle in radians", + "Math.exp": "Returns returns ``e^x``.", + "Math.exp|param|x": "A number", "Math.floor": "Returns the greatest number less than or equal to its numeric argument.", "Math.floor|param|x": "A numeric expression.", + "Math.icos": "Returns the cosine of an input angle. This is an 8-bit approximation.", + "Math.icos|param|theta": "input angle from 0-255", "Math.idiv": "Returns the value of integer signed 32 bit division of two numbers.", "Math.idiv|param|x": "The first number", "Math.idiv|param|y": "The second number", "Math.imul": "Returns the value of integer signed 32 bit multiplication of two numbers.", "Math.imul|param|x": "The first number", "Math.imul|param|y": "The second number", + "Math.isin": "Returns the sine of an input angle. This is an 8-bit approximation.", + "Math.isin|param|theta": "input angle from 0-255", + "Math.log": "Returns the natural logarithm (base e) of a number.", + "Math.log|param|x": "A number", + "Math.map": "Re-maps a number from one range to another. That is, a value of ``from low`` would get mapped to ``to low``, a value of ``from high`` to ``to high``, values in-between to values in-between, etc.", + "Math.map|param|fromHigh": "the upper bound of the value's current range, eg: 1023", + "Math.map|param|fromLow": "the lower bound of the value's current range", + "Math.map|param|toHigh": "the upper bound of the value's target range, eg: 4", + "Math.map|param|toLow": "the lower bound of the value's target range", + "Math.map|param|value": "value to map in ranges", "Math.max": "Returns the larger of two supplied numeric expressions.", "Math.min": "Returns the smaller of two supplied numeric expressions.", - "Math.pow": "Return the value of a base expression taken to a specified power.", + "Math.pow": "Returns the value of a base expression taken to a specified power.", "Math.pow|param|x": "The base value of the expression.", "Math.pow|param|y": "The exponent value of the expression.", - "Math.random": "Return a pseudorandom number between 0 and `limit`.", + "Math.random": "Returns a pseudorandom number between 0 and 1.", "Math.randomBoolean": "Generates a `true` or `false` value randomly, just like flipping a coin.", - "Math.random|param|limit": "the upper bound of the number generated, eg: 4", + "Math.randomRange": "Returns a pseudorandom number between min and max included.\nIf both numbers are integral, the result is integral.", + "Math.randomRange|param|max": "the upper inclusive bound, eg: 10", + "Math.randomRange|param|min": "the lower inclusive bound, eg: 0", "Math.round": "Returns a supplied numeric expression rounded to the nearest number.", + "Math.roundWithPrecision": "Rounds ``x`` to a number with the given number of ``digits``", + "Math.roundWithPrecision|param|digits": "the number of resulting digits", + "Math.roundWithPrecision|param|x": "the number to round", "Math.round|param|x": "The value to be rounded to the nearest number.", "Math.sign": "Returns the sign of the x, indicating whether x is positive, negative or zero.", "Math.sign|param|x": "The numeric expression to test", - "Math.sqrt": "Return the square root of a number.", + "Math.sin": "Returns the sine of a number.", + "Math.sin|param|x": "An angle in radians", + "Math.sqrt": "Returns the square root of a number.", "Math.sqrt|param|x": "A numeric expression.", + "Math.tan": "Returns the tangent of a number.", + "Math.tan|param|x": "An angle in radians", "Math.trunc": "Returns the number with the decimal part truncated.", "Math.trunc|param|x": "A numeric expression.", - "Number.toString": "Return a string representation of a number.", - "String": "Combine, split, and search text strings.\n\nCombine, split, and search text strings.", + "NaN": "Constant representing Not-A-Number.", + "Number.isNaN": "Check if a given value is of type Number and it is a NaN.", + "Number.toString": "Returns a string representation of a number.", + "Object.keys": "Return the field names in an object.", + "String": "Combine, split, and search text strings.", "String.charAt": "Return the character at the specified index.", - "String.charAt|param|index": "The zero-based index of the desired character, eg: 0", + "String.charAt|param|index": "The zero-based index of the desired character.", "String.charCodeAt": "Return the Unicode value of the character at the specified location.", "String.charCodeAt|param|index": "The zero-based index of the desired character. If there is no character at the specified index, NaN is returned.", "String.compare": "See how the order of characters in two strings is different (in ASCII encoding).", "String.compare|param|that": "String to compare to target string", "String.concat": "Returns a string that contains the concatenation of two or more strings.", - "String.concat|param|other": "The string to append to the end of the string, eg: \"add me!\"", + "String.concat|param|other": "The string to append to the end of the string.", "String.fromCharCode": "Make a string from the given ASCII character code.", + "String.includes": "Determines whether a string contains the characters of a specified string.", + "String.includes|param|searchValue": "the text to find", + "String.includes|param|start": "optional start index for the search", + "String.indexOf": "Returns the position of the first occurrence of a specified value in a string.", + "String.indexOf|param|searchValue": "the text to find", + "String.indexOf|param|start": "optional start index for the search", "String.isEmpty": "Returns a value indicating if the string is empty", - "String.length": "Return the length of a String object.", + "String.length": "Returns the length of a String object.", + "String.slice": "Return a substring of the current string.", + "String.slice|param|end": "one-past-last character index", + "String.slice|param|start": "first character index; can be negative from counting from the end, eg:0", + "String.split": "Splits the string according to the separators", + "String.split|param|separator": "@param limit ", "String.substr": "Return a substring of the current string.", - "String.substr|param|length": "number of characters to extract, eg: 3", - "String.substr|param|start": "first character index; can be negative from counting from the end, eg: 0", + "String.substr|param|length": "number of characters to extract", + "String.substr|param|start": "first character index; can be negative from counting from the end, eg:0", + "String.toLowerCase": "Converts the string to lower case characters.", + "String@type": "Combine, split, and search text strings.", + "StringMap": "A dictionary from string key to string values", "basic": "Provides access to basic micro:bit functionality.\n\nProvides access to basic micro:bit functionality.", "basic.clearScreen": "Turn off all LEDs", "basic.color": "Converts the color name to a number", @@ -161,11 +222,11 @@ "basic.showAnimation": "Shows a sequence of LED screens as an animation.", "basic.showAnimation|param|interval": "time in milliseconds between each redraw", "basic.showAnimation|param|leds": "pattern of LEDs to turn on/off", - "basic.showArrow": "Shows an arrow on screent", + "basic.showArrow": "Draws an arrow on the LED screen", "basic.showArrow|param|direction": "the direction of the arrow", "basic.showArrow|param|interval": "the amount of time (milliseconds) to show the icon. Default is 600.", "basic.showIcon": "Draws the selected icon on the LED screen", - "basic.showIcon|param|icon": "the predifined icon id", + "basic.showIcon|param|icon": "the predefined icon id", "basic.showIcon|param|interval": "the amount of time (milliseconds) to show the icon. Default is 600.", "basic.showLeds": "Draws an image on the LED screen.", "basic.showLeds|param|interval": "time in milliseconds to pause after drawing", @@ -174,17 +235,28 @@ "basic.showNumber|param|interval": "speed of scroll; eg: 150, 100, 200, -100", "basic.showString": "Display text on the display, one character at a time. If the string fits on the screen (i.e. is one letter), does not scroll.", "basic.showString|param|interval": "how fast to shift characters; eg: 150, 100, 200, -100", - "basic.showString|param|text": "the text to scroll on the screen, eg: \"Hello!\"", + "basic.showString|param|text": "the text to scroll on the screen, eg: \"hi!\"", + "basic.turnRgbLedOff": "Sets the color on the build-in LED. Set to 0 to turn off.", + "console": "Reading and writing data to the console output.", + "console.addListener": "Adds a listener for the log messages", + "console.log": "Write a line of text to the console output.", + "console.logValue": "Write a name:value pair as a line of text to the console output.", + "console.logValue|param|name": "name of the value stream, eg: \"x\"", + "console.logValue|param|value": "to write", "control": "Runtime and event utilities.", "control.assert": "If the condition is false, display msg on serial console, and panic with code 098.", - "control.deviceName": "Gets a friendly name for the device derived from the its serial number", + "control.createBuffer": "Create a new zero-initialized buffer.", + "control.createBufferFromUTF8": "Create a new buffer with UTF8-encoded string", + "control.createBufferFromUTF8|param|str": "the string to put in the buffer", + "control.createBuffer|param|size": "number of bytes in the buffer", + "control.deviceName": "Make a friendly name for the device based on its serial number", "control.deviceSerialNumber": "Derive a unique, consistent serial number of this device from internal data.", "control.eventSourceId": "Returns the value of a C++ runtime constant", "control.eventTimestamp": "Gets the timestamp of the last event executed on the bus", "control.eventValue": "Gets the value of the last event executed on the bus", "control.eventValueId": "Returns the value of a C++ runtime constant", "control.inBackground": "Schedules code that run in the background.", - "control.onEvent": "Raises an event in the event bus.", + "control.onEvent": "Registers an event handler.", "control.panic": "Display specified error code and stop the program.", "control.raiseEvent": "Raises an event in the event bus.", "control.raiseEvent|param|mode": "optional definition of how the event should be processed after construction (default is CREATE_AND_FIRE).", @@ -194,6 +266,8 @@ "control.runtimeWarning": "Display warning in the simulator.", "control.waitMicros": "Blocks the current fiber for the given microseconds", "control.waitMicros|param|micros": "number of micro-seconds to wait. eg: 4", + "convertToText": "Convert any value to text", + "convertToText|param|value": "value to be converted to text", "game": "A single-LED sprite game engine", "game.LedSprite": "A game sprite rendered as a single LED", "game.LedSprite.blink": "Reports the ``blink`` duration of a sprite", @@ -219,9 +293,10 @@ "game.LedSprite.goTo|param|x": "TODO", "game.LedSprite.goTo|param|y": "TODO", "game.LedSprite.ifOnEdgeBounce": "If touching the edge of the stage and facing towards it, then turn away.", + "game.LedSprite.isDeleted": "Reports whether the sprite has been deleted from the game engine.", "game.LedSprite.isTouching": "Reports true if sprite has the same position as specified sprite", "game.LedSprite.isTouchingEdge": "Reports true if sprite is touching an edge", - "game.LedSprite.isTouching|param|other": "TODO", + "game.LedSprite.isTouching|param|other": "the other sprite to check overlap or touch", "game.LedSprite.move": "Move a certain number of LEDs in the current direction", "game.LedSprite.move|param|leds": "number of leds to move, eg: 1, -1", "game.LedSprite.off": "Turns off the sprite (on by default)", @@ -232,7 +307,7 @@ "game.LedSprite.setBrightness": "Set the ``brightness`` of a sprite", "game.LedSprite.setBrightness|param|brightness": "the brightness from 0 (off) to 255 (on), eg: 255.", "game.LedSprite.setDirection": "Set the direction of the current sprite, rounded to the nearest multiple of 45", - "game.LedSprite.setDirection|param|degrees": "TODO", + "game.LedSprite.setDirection|param|degrees": "new direction in degrees", "game.LedSprite.setX": "Set the ``x`` position of a sprite", "game.LedSprite.setX|param|x": "TODO", "game.LedSprite.setY": "Set the ``y`` position of a sprite", @@ -247,8 +322,8 @@ "game.LedSprite.turn|param|direction": "left or right", "game.LedSprite.x": "Reports the ``x`` position of a sprite on the LED screen", "game.LedSprite.y": "Reports the ``y`` position of a sprite on the LED screen", - "game.addLife": "Adds life points to the current life", - "game.addLife|param|lives": "TODO", + "game.addLife": "Add life points to the current life amount", + "game.addLife|param|lives": "amount of lives to add", "game.addScore": "Adds points to the current score and shows an animation", "game.addScore|param|points": "amount of points to change, eg: 1", "game.createSprite": "Creates a new LED sprite pointing to the right.", @@ -257,38 +332,42 @@ "game.currentTime": "Gets the remaining time (since `start countdown`) or current time (since the device started or `start stopwatch`) in milliseconds.", "game.gameOver": "Displays a game over animation and the score.", "game.invalidSprite": "Gets an invalid sprite; used to initialize locals.", - "game.isGameOver": "Indicates if the game is display the game over sequence.", + "game.isGameOver": "Indicates if the game is over and displaying the game over sequence.", "game.isPaused": "Indicates if the game rendering is paused to allow other animations", - "game.isRunning": "Gets a value indicating if the game is still running. Returns `false` if game over.", + "game.isRunning": "Indicates if the game is still running. Returns `false` if the game is over or paused.", "game.level": "Gets the current level", "game.levelUp": "Increments the level and display a message.", "game.life": "Gets the current life", "game.pause": "Pauses the game rendering engine to allow other animations", - "game.removeLife": "Removes some life", - "game.removeLife|param|life": "TODO", + "game.removeLife": "Remove some life", + "game.removeLife|param|life": "amount of life to remove", "game.resume": "Resumes the game rendering engine", "game.score": "Gets the current score", "game.setLife": "Sets the current life value", - "game.setLife|param|value": "TODO", + "game.setLife|param|value": "current life value", "game.setScore": "Sets the current score value", "game.setScore|param|value": "new score value.", "game.showScore": "Displays the score on the screen.", "game.startCountdown": "Shows an animation, then starts a game countdown timer, which causes Game Over when it reaches 0", "game.startCountdown|param|ms": "countdown duration in milliseconds, eg: 10000", "game.startStopwatch": "Starts a stopwatch timer. `current time` will return the elapsed time.", + "hex": "Tagged hex literal converter", "images": "Creation, manipulation and display of LED images.", "images.createBigImage": "Creates an image with 2 frames.", "images.createImage": "Creates an image that fits on the LED screen.", "input": "Events and data from sensors", "input.acceleration": "Get the acceleration value in milli-gravitys (when the board is laying flat with the screen up, x=0, y=0 and z=-1024)", - "input.acceleration|param|dimension": "TODO", + "input.acceleration|param|dimension": "x, y, or z dimension, eg: Dimension.X", "input.buttonIsPressed": "Get the button state (pressed or not) for ``A`` and ``B``.", "input.buttonIsPressed|param|button": "the button to query the request, eg: Button.A", + "input.calibrate": "Obsolete, use input.calibrateCompass instead.", "input.calibrateCompass": "Obsolete, compass calibration is automatic.", "input.compassHeading": "Get the current compass heading in degrees.", + "input.isGesture": "Tests if a gesture is currently detected.", + "input.isGesture|param|gesture": "the type of gesture to detect, eg: Gesture.Shake", "input.lightLevel": "Reads the light level applied to the LED screen in a range from ``0`` (dark) to ``255`` bright.", "input.magneticForce": "Get the magnetic force value in ``micro-Teslas`` (``µT``). This function is not supported in the simulator.", - "input.magneticForce|param|dimension": "TODO", + "input.magneticForce|param|dimension": "the x, y, or z dimension, eg: Dimension.X", "input.onButtonPressed": "Do something when a button (A, B or both A+B) is pushed down and released again.", "input.onButtonPressed|param|body": "code to run when event is raised", "input.onButtonPressed|param|button": "the button that needs to be pressed", @@ -314,7 +393,7 @@ "input.pinIsPressed": "Get the pin state (pressed or not). Requires to hold the ground to close the circuit.", "input.pinIsPressed|param|name": "pin used to detect the touch, eg: TouchPin.P0", "input.rotation": "The pitch or roll of the device, rotation along the ``x-axis`` or ``y-axis``, in degrees.", - "input.rotation|param|kind": "TODO", + "input.rotation|param|kind": "pitch or roll", "input.runningTime": "Gets the number of milliseconds elapsed since power on.", "input.runningTimeMicros": "Gets the number of microseconds elapsed since power on.", "input.setAccelerometerRange": "Sets the accelerometer sample range in gravities.", @@ -325,9 +404,9 @@ "led.displayMode": "Gets the current display mode", "led.enable": "Turns on or off the display", "led.fadeIn": "Fades in the screen display.", - "led.fadeIn|param|ms": "TODO", + "led.fadeIn|param|ms": "fade time in milleseconds", "led.fadeOut": "Fades out the screen brightness.", - "led.fadeOut|param|ms": "TODO", + "led.fadeOut|param|ms": "fade time in milliseconds", "led.plot": "Turn on the specified LED using x, y coordinates (x is horizontal, y is vertical). (0,0) is upper left.", "led.plotAll": "Turns all LEDS on", "led.plotBarGraph": "Displays a vertical bar graph based on the `value` and `high` value.\nIf `high` is 0, the chart gets adjusted automatically.", @@ -340,8 +419,8 @@ "led.plot|param|x": "the horizontal coordinate of the LED starting at 0", "led.plot|param|y": "the vertical coordinate of the LED starting at 0", "led.point": "Get the on/off state of the specified LED using x, y coordinates. (0,0) is upper left.", - "led.point|param|x": "TODO", - "led.point|param|y": "TODO", + "led.point|param|x": "the horizontal coordinate of the LED", + "led.point|param|y": "the vertical coordinate of the LED", "led.screenshot": "Takes a screenshot of the LED screen and returns an image.", "led.setBrightness": "Set the screen brightness from 0 (off) to 255 (full bright).", "led.setBrightness|param|value": "the brightness value, eg:255, 127, 0", @@ -350,57 +429,65 @@ "led.stopAnimation": "Cancels the current animation and clears other pending animations.", "led.toggle": "Toggles a particular pixel", "led.toggleAll": "Inverts the current LED display", - "led.toggle|param|x": "TODO", - "led.toggle|param|y": "TODO", + "led.toggle|param|x": "pixel column", + "led.toggle|param|y": "pixel row", "led.unplot": "Turn off the specified LED using x, y coordinates (x is horizontal, y is vertical). (0,0) is upper left.", - "led.unplot|param|x": "TODO", - "led.unplot|param|y": "TODO", + "led.unplot|param|x": "the horizontal coordinate of the LED", + "led.unplot|param|y": "the vertical coordinate of the LED", "motors": "Blocks to control the onboard motors", "motors.dualMotorPower": "Controls two motors attached to the board. Switches to dual-motor mode!", "motors.motorCommand": "Send break, coast or sleep commands to the motor. Has no effect in dual-motor mode.", "motors.motorPower": "Turns on the motor at a certain percent of power. Switches to single motor mode!", "motors.motorPower|param|power": "%percent of power sent to the motor. Negative power goes backward. eg: 50", + "msgpack.packNumberArray": "Pack a number array into a buffer.", + "msgpack.packNumberArray|param|nums": "the numbers to be packed", + "msgpack.unpackNumberArray": "Unpacks a buffer into a number array.", "music": "Generation of music tones.", "music.beat": "Returns the duration of a beat in milli-seconds", "music.beginMelody": "Starts playing a melody.\nNotes are expressed as a string of characters with this format: NOTE[octave][:duration]", - "music.beginMelody|param|melodyArray": "the melody array to play, eg: ['g5:1']", + "music.beginMelody|param|melodyArray": "the melody array to play", "music.beginMelody|param|options": "melody options, once / forever, in the foreground / background", "music.builtInMelody": "Gets the melody array of a built-in melody.", "music.changeTempoBy": "Change the tempo by the specified amount", "music.changeTempoBy|param|bpm": "The change in beats per minute to the tempo, eg: 20", - "music.noteFrequency": "Gets the frequency of a note.", + "music.noteFrequency": "Get the frequency of a note.", "music.noteFrequency|param|name": "the note name, eg: Note.C", "music.onEvent": "Registers code to run on various melody events", "music.playTone": "Plays a tone through pin ``P0`` for the given duration.", - "music.playTone|param|frequency": "pitch of the tone to play in Hertz (Hz)", + "music.playTone|param|frequency": "pitch of the tone to play in Hertz (Hz), eg: Note.C", "music.playTone|param|ms": "tone duration in milliseconds (ms)", "music.rest": "Rests (plays nothing) for a specified time through pin ``P0``.", "music.rest|param|ms": "rest duration in milliseconds (ms)", "music.ringTone": "Plays a tone through pin ``P0``.", - "music.ringTone|param|frequency": "pitch of the tone to play in Hertz (Hz)", + "music.ringTone|param|frequency": "pitch of the tone to play in Hertz (Hz), eg: Note.C", "music.setPlayTone": "Sets a custom playTone function for playing melodies", "music.setTempo": "Sets the tempo to the specified amount", "music.setTempo|param|bpm": "The new tempo in beats per minute, eg: 120", "music.speakerPlayTone": "Plays a tone through ``speaker`` for the given duration.", "music.speakerPlayTone|param|frequency": "pitch of the tone to play in Hertz (Hz)", "music.speakerPlayTone|param|ms": "tone duration in milliseconds (ms)", + "music.stopMelody": "Stops the melodies", + "music.stopMelody|param|options": "which melody to stop", "music.tempo": "Returns the tempo in beats per minute. Tempo is the speed (bpm = beats per minute) at which notes play. The larger the tempo value, the faster the notes will play.", + "parseFloat": "Convert a string to a number.", "parseInt": "Convert a string to an integer.", "pins": "Control currents in Pins for analog/digital signals, servos, i2c, ...", - "pins.analogPitch": "Emits a Pulse-width modulation (PWM) signal to the current pitch pin. Use `analog set pitch pin` to define the pitch pin.", + "pins.analogPitch": "Emit a plse-width modulation (PWM) signal to the current pitch pin. Use `analog set pitch pin` to define the pitch pin.", "pins.analogPitch|param|frequency": "frequency to modulate in Hz.", "pins.analogPitch|param|ms": "duration of the pitch in milli seconds.", "pins.analogReadPin": "Read the connector value as analog, that is, as a value comprised between 0 and 1023.", "pins.analogReadPin|param|name": "pin to write to, eg: AnalogPin.P0", - "pins.analogSetPeriod": "Configures the Pulse-width modulation (PWM) of the analog output to the given value in **microseconds** or `1/1000` milliseconds.\nIf this pin is not configured as an analog output (using `analog write pin`), the operation has no effect.", + "pins.analogSetPeriod": "Configure the pulse-width modulation (PWM) period of the analog output in microseconds.\nIf this pin is not configured as an analog output (using `analog write pin`), the operation has no effect.", "pins.analogSetPeriod|param|micros": "period in micro seconds. eg:20000", "pins.analogSetPeriod|param|name": "analog pin to set period to, eg: AnalogPin.P0", - "pins.analogSetPitchPin": "Sets the pin used when using `analog pitch` or music.", + "pins.analogSetPitchPin": "Set the pin used when using analog pitch or music.", "pins.analogSetPitchPin|param|name": "pin to modulate pitch from", "pins.analogWritePin": "Set the connector value as analog. Value must be comprised between 0 and 1023.", "pins.analogWritePin|param|name": "pin name to write to, eg: AnalogPin.P0", "pins.analogWritePin|param|value": "value to write to the pin between ``0`` and ``1023``. eg:1023,0", "pins.createBuffer": "Create a new zero-initialized buffer.", + "pins.createBufferFromArray": "Create a new buffer initalized to bytes from given array.", + "pins.createBufferFromArray|param|bytes": "data to initalize with", "pins.createBuffer|param|size": "number of bytes in the buffer", "pins.digitalReadPin": "Read the specified pin or connector as either 0 or 1", "pins.digitalReadPin|param|name": "pin to read from, eg: DigitalPin.P0", @@ -411,56 +498,68 @@ "pins.i2cReadNumber": "Read one number from 7-bit I2C address.", "pins.i2cWriteBuffer": "Write bytes to a 7-bit I2C `address`.", "pins.i2cWriteNumber": "Write one number to a 7-bit I2C address.", - "pins.map": "Re-maps a number from one range to another. That is, a value of ``from low`` would get mapped to ``to low``, a value of ``from high`` to ``to high``, values in-between to values in-between, etc.", + "pins.map": "Map a number from one range to another. That is, a value of ``from low`` would get mapped to ``to low``, a value of ``from high`` to ``to high``, values in-between to values in-between, etc.", "pins.map|param|fromHigh": "the upper bound of the value's current range, eg: 1023", "pins.map|param|fromLow": "the lower bound of the value's current range", "pins.map|param|toHigh": "the upper bound of the value's target range, eg: 4", "pins.map|param|toLow": "the lower bound of the value's target range", "pins.map|param|value": "value to map in ranges", - "pins.onPulsed": "Configures this pin to a digital input, and generates events where the timestamp is the duration that this pin was either ``high`` or ``low``.", + "pins.onPulsed": "Configure the pin as a digital input and generate an event when the pin is pulsed either high or low.", "pins.onPulsed|param|name": "digital pin to register to, eg: DigitalPin.P0", "pins.onPulsed|param|pulse": "the value of the pulse, eg: PulseValue.High", - "pins.pulseDuration": "Gets the duration of the last pulse in micro-seconds. This function should be called from a ``onPulsed`` handler.", - "pins.pulseIn": "Returns the duration of a pulse in microseconds", + "pins.pulseDuration": "Get the duration of the last pulse in microseconds. This function should be called from a ``onPulsed`` handler.", + "pins.pulseIn": "Return the duration of a pulse at a pin in microseconds.", "pins.pulseIn|param|name": "the pin which measures the pulse, eg: DigitalPin.P0", "pins.pulseIn|param|value": "the value of the pulse, eg: PulseValue.High", - "pins.servoSetPulse": "Configures this IO pin as an analog/pwm output, configures the period to be 20 ms, and sets the pulse width, based on the value it is given **microseconds** or `1/1000` milliseconds.", + "pins.servoSetPulse": "Configure the IO pin as an analog/pwm output and set a pulse width. The period is 20 ms period and the pulse width is set based on the value given in **microseconds** or `1/1000` milliseconds.", "pins.servoSetPulse|param|micros": "pulse duration in micro seconds, eg:1500", "pins.servoSetPulse|param|name": "pin name", - "pins.servoWritePin": "Writes a value to the servo, controlling the shaft accordingly. On a standard servo, this will set the angle of the shaft (in degrees), moving the shaft to that orientation. On a continuous rotation servo, this will set the speed of the servo (with ``0`` being full-speed in one direction, ``180`` being full speed in the other, and a value near ``90`` being no movement).", + "pins.servoWritePin": "Write a value to the servo, controlling the shaft accordingly. On a standard servo, this will set the angle of the shaft (in degrees), moving the shaft to that orientation. On a continuous rotation servo, this will set the speed of the servo (with ``0`` being full-speed in one direction, ``180`` being full speed in the other, and a value near ``90`` being no movement).", "pins.servoWritePin|param|name": "pin to write to, eg: AnalogPin.P0", "pins.servoWritePin|param|value": "angle or rotation speed, eg:180,90,0", - "pins.setEvents": "Configures the events emitted by this pin. Events can be subscribed to\nusing ``control.onEvent()``.", + "pins.setEvents": "Configure the events emitted by this pin. Events can be subscribed to\nusing ``control.onEvent()``.", "pins.setEvents|param|name": "pin to set the event mode on, eg: DigitalPin.P0", "pins.setEvents|param|type": "the type of events for this pin to emit, eg: PinEventType.Edge", - "pins.setPull": "Configures the pull of this pin.", + "pins.setPull": "Configure the pull directiion of of a pin.", "pins.setPull|param|name": "pin to set the pull mode on, eg: DigitalPin.P0", "pins.setPull|param|pull": "one of the mbed pull configurations, eg: PinPullMode.PullUp", "pins.sizeOf": "Get the size in bytes of specified number format.", - "pins.spiFormat": "Sets the SPI bits and mode", + "pins.spiFormat": "Set the SPI bits and mode", "pins.spiFormat|param|bits": "the number of bits, eg: 8", "pins.spiFormat|param|mode": "the mode, eg: 3", - "pins.spiFrequency": "Sets the SPI frequency", + "pins.spiFrequency": "Set the SPI frequency", "pins.spiFrequency|param|frequency": "the clock frequency, eg: 1000000", - "pins.spiPins": "Sets the MOSI, MISO, SCK pins used by the SPI instance", + "pins.spiPins": "Set the MOSI, MISO, SCK pins used by the SPI connection", "pins.spiWrite": "Write to the SPI slave and return the response", "pins.spiWrite|param|value": "Data to be sent to the SPI slave", "serial": "Reading and writing data over a serial connection.", - "serial.delimiters": "Returns the delimiter corresponding string", - "serial.onDataReceived": "Registers an event to be fired when one of the delimiter is matched.", + "serial.NEW_LINE": "The string used to mark a new line, default is \\r\\n", + "serial.delimiters": "Return the corresponding delimiter string", + "serial.onDataReceived": "Register an event to be fired when one of the delimiter is matched.", "serial.onDataReceived|param|delimiters": "the characters to match received characters against.", - "serial.readLine": "Reads a line of text from the serial port.", - "serial.readString": "Reads the buffered received data as a string", - "serial.readUntil": "Reads a line of text from the serial port and returns the buffer when the delimiter is met.", + "serial.readBuffer": "Read multiple characters from the receive buffer. Pause until enough characters are present.", + "serial.readBuffer|param|length": "default buffer length, eg: 64", + "serial.readLine": "Read a line of text from the serial port.", + "serial.readString": "Read the buffered received data as a string", + "serial.readUntil": "Read a line of text from the serial port and return the buffer when the delimiter is met.", "serial.readUntil|param|delimiter": "text delimiter that separates each text chunk", - "serial.redirect": "Dynamically configuring the serial instance to use pins other than USBTX and USBRX.", + "serial.redirect": "Set the serial input and output to use pins instead of the USB connection.", + "serial.redirectToUSB": "Direct the serial input and output to use the USB connection.", "serial.redirect|param|rate": "the new baud rate. eg: 115200", "serial.redirect|param|rx": "the new reception pin, eg: SerialPin.P1", - "serial.redirect|param|tx": "the new transmission pins, eg: SerialPin.P0", - "serial.writeLine": "Prints a line of text to the serial", - "serial.writeNumber": "Prints a numeric value to the serial", - "serial.writeString": "Sends a piece of text through Serial connection.", - "serial.writeValue": "Writes a ``name: value`` pair line to the serial.", + "serial.redirect|param|tx": "the new transmission pin, eg: SerialPin.P0", + "serial.setRxBufferSize": "Sets the size of the RX buffer in bytes", + "serial.setRxBufferSize|param|size": "length of the rx buffer in bytes, eg: 32", + "serial.setTxBufferSize": "Sets the size of the TX buffer in bytes", + "serial.setTxBufferSize|param|size": "length of the tx buffer in bytes, eg: 32", + "serial.setWriteLinePadding": "Sets the padding length for lines sent with \"write line\".", + "serial.setWriteLinePadding|param|length": "the number of bytes alignment, eg: 0", + "serial.writeBuffer": "Send a buffer through serial connection", + "serial.writeLine": "Print a line of text to the serial port", + "serial.writeNumber": "Print a numeric value to the serial port", + "serial.writeNumbers": "Print an array of numeric values as CSV to the serial port", + "serial.writeString": "Send a piece of text through the serial connection.", + "serial.writeValue": "Write a name:value pair as a line to the serial port.", "serial.writeValue|param|name": "name of the value stream, eg: x", "serial.writeValue|param|value": "to write" } \ No newline at end of file diff --git a/libs/core/_locales/core-strings.json b/libs/core/_locales/core-strings.json index 17e0f04e..c662aa1f 100644 --- a/libs/core/_locales/core-strings.json +++ b/libs/core/_locales/core-strings.json @@ -26,7 +26,15 @@ "ArrowNames.South|block": "South", "ArrowNames.West|block": "West", "BaudRate.BaudRate115200|block": "115200", - "BaudRate.BaudRate56700|block": "57600", + "BaudRate.BaudRate1200|block": "1200", + "BaudRate.BaudRate14400|block": "14400", + "BaudRate.BaudRate19200|block": "19200", + "BaudRate.BaudRate2400|block": "2400", + "BaudRate.BaudRate28800|block": "28800", + "BaudRate.BaudRate31250|block": "31250", + "BaudRate.BaudRate38400|block": "38400", + "BaudRate.BaudRate4800|block": "4800", + "BaudRate.BaudRate57600|block": "57600", "BaudRate.BaudRate9600|block": "9600", "BeatFraction.Breve|block": "4", "BeatFraction.Double|block": "2", @@ -39,6 +47,7 @@ "Colors.Blue|block": "blue", "Colors.Green|block": "green", "Colors.Indigo|block": "indigo", + "Colors.Off|block": "off", "Colors.Orange|block": "orange", "Colors.Purple|block": "purple", "Colors.Red|block": "red", @@ -57,7 +66,7 @@ "Dimension.Z|block": "z", "Direction.Left|block": "left", "Direction.Right|block": "right", - "DisplayMode.BackAndWhite|block": "black and white", + "DisplayMode.BlackAndWhite|block": "black and white", "DisplayMode.Greyscale|block": "greyscale", "EventCreationMode.CreateAndFire": "MicroBitEvent is initialised, and its event handlers are immediately fired (not suitable for use in interrupts!).", "EventCreationMode.CreateOnly": "MicroBitEvent is initialised, and no further processing takes place.", @@ -123,15 +132,17 @@ "IconNames.Triangle|block": "triangle", "IconNames.Umbrella|block": "umbrella", "IconNames.Yes|block": "yes", - "Image.scrollImage|block": "scroll image %sprite|with offset %frameoffset|and interval (ms) %delay", - "Image.showImage|block": "show image %sprite|at offset %offset", + "Image.scrollImage|block": "scroll image %sprite(myImage)|with offset %frameoffset|and interval (ms) %delay", + "Image.showImage|block": "show image %sprite(myImage)|at offset %offset", "LedSpriteProperty.Blink|block": "blink", "LedSpriteProperty.Brightness|block": "brightness", "LedSpriteProperty.Direction|block": "direction", "LedSpriteProperty.X|block": "x", "LedSpriteProperty.Y|block": "y", + "Math.constrain|block": "constrain %value|between %low|and %high", + "Math.map|block": "map %value|from low %fromLow|high %fromHigh|to low %toLow|high %toHigh", "Math.randomBoolean|block": "pick random true or false", - "Math.random|block": "pick random 0 to %limit", + "Math.randomRange|block": "pick random %min|to %limit", "Math|block": "Math", "Melodies.BaDing|block": "ba ding", "Melodies.Baddy|block": "baddy", @@ -157,6 +168,9 @@ "MelodyOptions.Forever|block": "forever", "MelodyOptions.OnceInBackground|block": "once in background", "MelodyOptions.Once|block": "once", + "MelodyStopOptions.All|block": "all", + "MelodyStopOptions.Background|block": "background", + "MelodyStopOptions.Foreground|block": "foreground", "MesDpadButtonInfo.ADown|block": "A down", "MesDpadButtonInfo.AUp|block": "A up", "MesDpadButtonInfo.BDown|block": "B down", @@ -199,6 +213,8 @@ "Note.GSharp4|block": "G#4", "Note.GSharp5|block": "G#5", "Note.GSharp|block": "G#", + "Number|block": "Number", + "Object|block": "Object", "PinEventType.Edge|block": "edge", "PinEventType.None|block": "none", "PinEventType.Pulse|block": "pulse", @@ -206,12 +222,18 @@ "PinPullMode.PullDown|block": "down", "PinPullMode.PullNone|block": "none", "PinPullMode.PullUp|block": "up", + "PulseValue.High|block": "high", + "PulseValue.Low|block": "low", "Rotation.Pitch|block": "pitch", "Rotation.Roll|block": "roll", "String.charAt|block": "char from %this=text|at %pos", "String.compare|block": "compare %this=text| to %that", "String.fromCharCode|block": "text from char code %code", + "String.includes|block": "%this=text|includes %searchValue", + "String.indexOf|block": "%this=text|find index of %searchValue", + "String.isEmpty|block": "%this=text| is empty", "String.length|block": "length of %VALUE", + "String.split|block": "split %this=text|at %separator", "String.substr|block": "substring of %this=text|from %start|of length %length", "String|block": "String", "basic.clearScreen|block": "clear screen", @@ -219,13 +241,15 @@ "basic.forever|block": "forever", "basic.pause|block": "pause (ms) %pause", "basic.rgbw|block": "red %red|green %green|blue %blue|white %white", - "basic.setLedColor|block": "set led to %color=color_id", + "basic.setLedColor|block": "set led to %color=colorNumberPicker", "basic.showArrow|block": "show arrow %i=device_arrow", "basic.showIcon|block": "show icon %i", "basic.showLeds|block": "show leds", "basic.showNumber|block": "show|number %number", "basic.showString|block": "show|string %text", + "basic.turnRgbLedOff|block": "turn build-in LED off", "basic|block": "basic", + "console|block": "console", "control.deviceName|block": "device name", "control.deviceSerialNumber|block": "device serial number", "control.eventSourceId|block": "%id", @@ -238,21 +262,29 @@ "control.reset|block": "reset", "control.waitMicros|block": "wait (µs)%micros", "control|block": "control", + "convertToText|block": "convert $value=math_number to text", "game.LedSprite.change|block": "%sprite|change %property|by %value", - "game.LedSprite.delete|block": "delete %this", + "game.LedSprite.delete|block": "delete %this(sprite)", "game.LedSprite.get|block": "%sprite|%property", "game.LedSprite.ifOnEdgeBounce|block": "%sprite|if on edge, bounce", - "game.LedSprite.isTouchingEdge|block": "%sprite|touching edge?", - "game.LedSprite.isTouching|block": "%sprite|touching %other|?", + "game.LedSprite.isDeleted|block": "is %sprite|deleted", + "game.LedSprite.isTouchingEdge|block": "is %sprite|touching edge", + "game.LedSprite.isTouching|block": "is %sprite|touching %other", "game.LedSprite.move|block": "%sprite|move by %leds", "game.LedSprite.set|block": "%sprite|set %property|to %value", "game.LedSprite.turn|block": "%sprite|turn %direction|by (°) %degrees", + "game.addLife|block": "add life %lives", "game.addScore|block": "change score by|%points", "game.createSprite|block": "create sprite at|x: %x|y: %y", "game.gameOver|block": "game over", + "game.isGameOver|block": "is game over", + "game.isPaused|block": "is paused", + "game.isRunning|block": "is running", "game.pause|block": "pause", + "game.removeLife|block": "remove life %life", "game.resume|block": "resume", "game.score|block": "score", + "game.setLife|block": "set life %value", "game.setScore|block": "set score %points", "game.startCountdown|block": "start countdown|(ms) %duration", "game|block": "game", @@ -266,6 +298,7 @@ "input.buttonIsPressed|block": "button|%NAME|is pressed", "input.calibrateCompass|block": "calibrate compass", "input.compassHeading|block": "compass heading (°)", + "input.isGesture|block": "is %gesture gesture", "input.lightLevel|block": "light level", "input.magneticForce|block": "magnetic force (µT)|%NAME", "input.onButtonPressed|block": "on button|%NAME|pressed", @@ -281,11 +314,12 @@ "input|block": "input", "led.brightness|block": "brightness", "led.enable|block": "led enable %on", - "led.plotBarGraph|block": "plot bar graph of %value |up to %high", + "led.plotBarGraph|block": "plot bar graph of %value up to %high", "led.plotBrightness|block": "plot|x %x|y %y|brightness %brightness", "led.plot|block": "plot|x %x|y %y", "led.point|block": "point|x %x|y %y", "led.setBrightness|block": "set brightness %value", + "led.setDisplayMode|block": "set display mode $mode", "led.stopAnimation|block": "stop animation", "led.toggle|block": "toggle|x %x|y %y", "led.unplot|block": "unplot|x %x|y %y", @@ -294,18 +328,21 @@ "motors.motorCommand|block": "motor %command", "motors.motorPower|block": "motor on at %percent", "motors|block": "motors", + "msgpack|block": "msgpack", "music.beat|block": "%fraction|beat", "music.beginMelody|block": "start melody %melody=device_builtin_melody| repeating %options", "music.builtInMelody|block": "%melody", "music.changeTempoBy|block": "change tempo by (bpm)|%value", - "music.noteFrequency|block": "%note", + "music.noteFrequency|block": "%name", "music.onEvent|block": "music on %value", "music.playTone|block": "play|tone %note=device_note|for %duration=device_beat", "music.rest|block": "rest(ms)|%duration=device_beat", "music.ringTone|block": "ring tone (Hz)|%note=device_note", "music.setTempo|block": "set tempo to (bpm)|%value", + "music.stopMelody|block": "stop melody $options", "music.tempo|block": "tempo (bpm)", "music|block": "music", + "parseFloat|block": "parse to number %text", "parseInt|block": "parse to integer %text", "pins.analogPitch|block": "analog pitch %frequency|for (ms) %ms", "pins.analogReadPin|block": "analog read|pin %name", @@ -314,8 +351,8 @@ "pins.analogWritePin|block": "analog write|pin %name|to %value", "pins.digitalReadPin|block": "digital read|pin %name", "pins.digitalWritePin|block": "digital write|pin %name|to %value", - "pins.i2cReadNumber|block": "i2c read number|at address %address|of format %format=i2c_sizeof|repeat %repeat", - "pins.i2cWriteNumber|block": "i2c write number|at address %address|with value %value|of format %format=i2c_sizeof|repeat %repeat", + "pins.i2cReadNumber|block": "i2c read number|at address %address|of format %format|repeated %repeat", + "pins.i2cWriteNumber|block": "i2c write number|at address %address|with value %value|of format %format|repeated %repeat", "pins.map|block": "map %value|from low %fromLow|from high %fromHigh|to low %toLow|to high %toHigh", "pins.onPulsed|block": "on|pin %pin|pulsed %pulse", "pins.pulseDuration|block": "pulse duration (µs)", @@ -331,11 +368,18 @@ "pins|block": "pins", "serial.delimiters|block": "%del", "serial.onDataReceived|block": "serial|on data received %delimiters=serial_delimiter_conv", + "serial.readBuffer|block": "serial|read buffer %length", "serial.readLine|block": "serial|read line", "serial.readString|block": "serial|read string", "serial.readUntil|block": "serial|read until %delimiter=serial_delimiter_conv", + "serial.redirectToUSB|block": "serial|redirect to USB", "serial.redirect|block": "serial|redirect to|TX %tx|RX %rx|at baud rate %rate", + "serial.setRxBufferSize|block": "serial set rx buffer size to $size", + "serial.setTxBufferSize|block": "serial set tx buffer size to $size", + "serial.setWriteLinePadding|block": "serial set write line padding to $length", + "serial.writeBuffer|block": "serial|write buffer %buffer=serial_readbuffer", "serial.writeLine|block": "serial|write line %text", + "serial.writeNumbers|block": "serial|write numbers %values", "serial.writeNumber|block": "serial|write number %value", "serial.writeString|block": "serial|write string %text", "serial.writeValue|block": "serial|write value %name|= %value", @@ -347,6 +391,8 @@ "{id:category}Buffer": "Buffer", "{id:category}Console": "Console", "{id:category}Control": "Control", + "{id:category}Fx": "Fx", + "{id:category}Fx8": "Fx8", "{id:category}Game": "Game", "{id:category}Helpers": "Helpers", "{id:category}Image": "Image", @@ -355,8 +401,10 @@ "{id:category}Led": "Led", "{id:category}Math": "Math", "{id:category}Motors": "Motors", + "{id:category}Msgpack": "Msgpack", "{id:category}Music": "Music", "{id:category}Number": "Number", + "{id:category}Object": "Object", "{id:category}Pins": "Pins", "{id:category}Serial": "Serial", "{id:category}String": "String", diff --git a/libs/core/basic.cpp b/libs/core/basic.cpp index e0812e40..47a4341c 100644 --- a/libs/core/basic.cpp +++ b/libs/core/basic.cpp @@ -4,12 +4,13 @@ /** * Provides access to basic micro:bit functionality. */ -//% color=#54C9C9 weight=100 icon="\uf00a" +//% color=#1E90FF weight=116 icon="\uf00a" namespace basic { /** * Sets the color on the build-in LED. Set to 0 to turn off. */ - //% blockId=device_set_led_color block="set led to %color=color_id" + //% blockId=device_set_led_color + //% block="set led to %color=colorNumberPicker" //% weight=50 void setLedColor(int color) { if (!color) { @@ -25,24 +26,14 @@ namespace basic { uBit.rgb.setColour(r,g,b,w); } + /** - * Scroll a number on the screen. If the number fits on the screen (i.e. is a single digit), do not scroll. - * @param interval speed of scroll; eg: 150, 100, 200, -100 - */ - //% help=basic/show-number - //% weight=96 - //% blockId=device_show_number block="show|number %number" blockGap=8 - //% async - //% parts="ledmatrix" - void showNumber(int value, int interval = 150) { - if (interval <= 0) - interval = 1; - ManagedString t(value); - if (value < 0 || value >= 10) { - uBit.display.scroll(t, interval); - } else { - uBit.display.printChar(t.charAt(0), interval * 5); - } + * Sets the color on the build-in LED. Set to 0 to turn off. + */ + //% blockId=device_turn_rgb_led_off block="turn build-in LED off" + //% weight=50 + void turnRgbLedOff() { + uBit.rgb.off(); } /** @@ -56,33 +47,33 @@ namespace basic { //% blockId=device_show_leds //% block="show leds" icon="\uf00a" //% parts="ledmatrix" - void showLeds(ImageLiteral leds, int interval = 400) { + void showLeds(ImageLiteral_ leds, int interval = 400) { uBit.display.print(MicroBitImage(imageBytes(leds)), 0, 0, 0, interval); } /** * Display text on the display, one character at a time. If the string fits on the screen (i.e. is one letter), does not scroll. - * @param text the text to scroll on the screen, eg: "Hello!" + * @param text the text to scroll on the screen, eg: "hi!" * @param interval how fast to shift characters; eg: 150, 100, 200, -100 */ //% help=basic/show-string - //% weight=87 blockGap=8 + //% weight=87 blockGap=16 //% block="show|string %text" //% async //% blockId=device_print_message //% parts="ledmatrix" - void showString(StringData *text, int interval = 150) { + //% text.shadowOptions.toString=true + void showString(String text, int interval = 150) { if (interval <= 0) interval = 1; - ManagedString s(text); - int l = s.length(); + int l = text ? text->getUTF8Size() : 0; if (l == 0) { uBit.display.clear(); fiber_sleep(interval * 5); } else if (l > 1) { - uBit.display.scroll(s, interval); + uBit.display.scroll(MSTR(text), interval); } else { - uBit.display.print(s.charAt(0), interval * 5); + uBit.display.printChar(text->getUTF8Data()[0], interval * 5); } } @@ -104,7 +95,7 @@ namespace basic { */ //% help=basic/show-animation imageLiteral=1 async //% parts="ledmatrix" - void showAnimation(ImageLiteral leds, int interval = 400) { + void showAnimation(ImageLiteral_ leds, int interval = 400) { uBit.display.animate(MicroBitImage(imageBytes(leds)), interval, 5, 0, 0); } @@ -114,29 +105,19 @@ namespace basic { */ //% help=basic/plot-leds weight=80 //% parts="ledmatrix" - void plotLeds(ImageLiteral leds) { + void plotLeds(ImageLiteral_ leds) { MicroBitImage i(imageBytes(leds)); uBit.display.print(i, 0, 0, 0, 0); } - void forever_stub(void *a) { - while (true) { - runAction0((Action)a); - fiber_sleep(20); - } - } - /** * Repeats the code forever in the background. On each iteration, allows other codes to run. * @param body code to execute */ - //% help=basic/forever weight=55 blockGap=8 blockAllowMultiple=1 afterOnStart=true + //% help=basic/forever weight=55 blockGap=16 blockAllowMultiple=1 afterOnStart=true //% blockId=device_forever block="forever" icon="\uf01e" void forever(Action a) { - if (a != 0) { - incr(a); - create_fiber(forever_stub, (void*)a); - } + runForever(a); } /** @@ -144,8 +125,9 @@ namespace basic { * @param ms how long to pause for, eg: 100, 200, 500, 1000, 2000 */ //% help=basic/pause weight=54 - //% async block="pause (ms) %pause" + //% async block="pause (ms) %pause" blockGap=16 //% blockId=device_pause icon="\uf110" + //% pause.shadow=timePicker void pause(int ms) { fiber_sleep(ms); } diff --git a/libs/core/basic.ts b/libs/core/basic.ts index b0c881e0..a3d2fdb0 100644 --- a/libs/core/basic.ts +++ b/libs/core/basic.ts @@ -28,7 +28,10 @@ enum Colors { Purple = 0x00FF00FF, //% blockIdentity=basic.color //% block=white - White = 0xFF00000 + White = 0xFFFFFFFF, + //% blockIdentity=basic.color + //% block=off + Off = 0x00000000, } /** @@ -36,6 +39,7 @@ enum Colors { */ //% color=#54C9C9 weight=100 namespace basic { + /** * Converts the color name to a number */ @@ -56,4 +60,17 @@ namespace basic { export function rgbw(red: number, green: number, blue: number, white:number): number { return ((white & 0xFF) << 24) | ((red & 0xFF) << 16) | ((green & 0xFF) << 8) | (blue & 0xFF); } -} \ No newline at end of file + + /** + * Scroll a number on the screen. If the number fits on the screen (i.e. is a single digit), do not scroll. + * @param interval speed of scroll; eg: 150, 100, 200, -100 + */ + //% help=basic/show-number + //% weight=96 + //% blockId=device_show_number block="show|number %number" blockGap=8 + //% async + //% parts="ledmatrix" interval.defl=150 + export function showNumber(value: number, interval?: number) { + showString(Math.roundWithPrecision(value, 2).toString(), interval); + } +} diff --git a/libs/core/blocks-test/basic.blocks b/libs/core/blocks-test/basic.blocks new file mode 100644 index 00000000..8548c929 --- /dev/null +++ b/libs/core/blocks-test/basic.blocks @@ -0,0 +1,53 @@ + + + receivedNumber + + + + + + + 12 + + + + + IconNames.Umbrella + + + + + hi! + + + + + + + 100 + + + + + + + + + ArrowNames.South + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/libs/core/blocks-test/control.blocks b/libs/core/blocks-test/control.blocks new file mode 100644 index 00000000..5f6f4363 --- /dev/null +++ b/libs/core/blocks-test/control.blocks @@ -0,0 +1,66 @@ + + + item + + + + + + + + + 4 + + + + + + + + EventBusSource.MICROBIT_ID_BUTTON_A + + + + + + EventBusValue.MICROBIT_EVT_ANY + + + + + + + + + + + + + + EventBusSource.MICROBIT_ID_BUTTON_A + + + EventBusValue.MES_DPAD_BUTTON_C_UP + + + + + EventBusValue.MICROBIT_EVT_ANY + + + EventBusValue.MES_REMOTE_CONTROL_EVT_PLAY + + + + + item + + + 0 + + + + + + + \ No newline at end of file diff --git a/libs/core/blocks-test/game.blocks b/libs/core/blocks-test/game.blocks new file mode 100644 index 00000000..9b8ede84 --- /dev/null +++ b/libs/core/blocks-test/game.blocks @@ -0,0 +1,183 @@ + + + item + gdfgsdfg + + + + + + + + + 2 + + + + + 2 + + + + + + + + + item + + + + + 1 + + + + + Direction.Right + + + item + + + + + 45 + + + + + LedSpriteProperty.X + + + item + + + + + 1 + + + + + LedSpriteProperty.X + + + item + + + + + 0 + + + LedSpriteProperty.X + + + item + + + + + + + gdfgsdfg + + + 0 + + + + + item + + + + + item + + + + + + + gdfgsdfg + + + 0 + + + + + item + + + + + + + + + item + + + + + + + 1 + + + + + + + + 0 + + + + + + + 10000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + item + + + 0 + + + + + item + + \ No newline at end of file diff --git a/libs/core/blocks-test/image.blocks b/libs/core/blocks-test/image.blocks new file mode 100644 index 00000000..a6272f28 --- /dev/null +++ b/libs/core/blocks-test/image.blocks @@ -0,0 +1,46 @@ + + + item + + + + + + + IconNames.Heart + + + + + 0 + + + ArrowNames.South + + + + + + + ArrowNames.SouthWest + + + + + 1 + + + + + 200 + + + + + + + + + item + + \ No newline at end of file diff --git a/libs/core/blocks-test/input.blocks b/libs/core/blocks-test/input.blocks new file mode 100644 index 00000000..dce61b60 --- /dev/null +++ b/libs/core/blocks-test/input.blocks @@ -0,0 +1,132 @@ + + + item + sdfsadf + + + Button.AB + + + item + + + 0 + + + Button.B + + + + + item + + + 0 + + + TouchPin.P1 + + + + + sdfsadf + + + 0 + + + Dimension.Y + + + + + sdfsadf + + + 0 + + + + + + sdfsadf + + + 0 + + + + + + sdfsadf + + + 0 + + + + + + sdfsadf + + + 0 + + + Rotation.Roll + + + + + sdfsadf + + + 0 + + + Dimension.Z + + + + + sdfsadf + + + 0 + + + + + + AcceleratorRange.TwoG + + + + + + + + + + + + + + + + + + + + + + + Gesture.SixG + + + TouchPin.P2 + + + TouchPin.P2 + + \ No newline at end of file diff --git a/libs/core/blocks-test/led.blocks b/libs/core/blocks-test/led.blocks new file mode 100644 index 00000000..cd656d1f --- /dev/null +++ b/libs/core/blocks-test/led.blocks @@ -0,0 +1,114 @@ + + + + + + + 5 + + + + + 5 + + + + + + + 5 + + + + + 5 + + + + + + + 5 + + + + + 5 + + + + + + + 0 + + + + + 0 + + + + + + + 5 + + + + + 5 + + + + + + 5 + + + + + + + 5 + + + + + + + + + FALSE + + + + + 5 + + + + + 5 + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/libs/core/blocks-test/music.blocks b/libs/core/blocks-test/music.blocks new file mode 100644 index 00000000..96719219 --- /dev/null +++ b/libs/core/blocks-test/music.blocks @@ -0,0 +1,95 @@ + + + item + + + MusicEvent.BackgroundMelodyStarted + + + + + 175 + + + + + BeatFraction.Sixteenth + + + + + + + 147 + + + + + + + BeatFraction.Sixteenth + + + + + item + + + 0 + + + 466 + + + + + item + + + 0 + + + BeatFraction.Sixteenth + + + + + item + + + 0 + + + + + + + + 1242 + + + + + + + 5 + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/libs/core/blocks-test/pins.blocks b/libs/core/blocks-test/pins.blocks new file mode 100644 index 00000000..9e01d01c --- /dev/null +++ b/libs/core/blocks-test/pins.blocks @@ -0,0 +1,209 @@ + + + DigitalPin.P5 + PulseValue.Low + + + AnalogPin.P9 + + + 5 + + + + + AnalogPin.P10 + + + 20000 + + + + + DigitalPin.P6 + + + 5 + + + + + AnalogPin.P13 + + + 5 + + + + + AnalogPin.P8 + + + 1500 + + + + + 0 + + + NumberFormat.Int8BE + + + 0 + + + + + FALSE + + + + + + + 0 + + + DigitalPin.P9 + PulseValue.Low + + + + + 1023 + + + + + + 0 + + + + + 0 + + + + + + + 4 + + + + + + + NumberFormat.Int16BE + + + 0 + + + DigitalPin.P9 + + + + + 0 + + + AnalogPin.P9 + + + + + FALSE + + + + + DigitalPin.P11 + DigitalPin.P9 + DigitalPin.P10 + + + DigitalPin.P9 + PinPullMode.PullDown + + + + + 0 + + + + + 0 + + + + + DigitalPin.P8 + PinEventType.Touch + + + AnalogPin.P9 + + + + + 8 + + + + + 3 + + + + + + + 8 + + + + + 3 + + + + + + + 1000000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/libs/core/blocks-test/serial.blocks b/libs/core/blocks-test/serial.blocks new file mode 100644 index 00000000..f1edf86c --- /dev/null +++ b/libs/core/blocks-test/serial.blocks @@ -0,0 +1,94 @@ + + + item + + + + + Delimiters.Colon + + + + + + + + + + + + + + + + 0 + + + + + + + x + + + + + Delimiters.Colon + + + + + + + 0 + + + + + + + + + + + + + + item + + + + + SerialPin.P12 + SerialPin.P13 + BaudRate.BaudRate28800 + + + + + + + 64 + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/libs/core/blocks-test/test.blocks b/libs/core/blocks-test/test.blocks new file mode 100644 index 00000000..d1e1be1e --- /dev/null +++ b/libs/core/blocks-test/test.blocks @@ -0,0 +1,677 @@ + + + booltest + myImage + strtest + + + + + + + 123 + + + + + + ` + # . . # . + # . . # . + . # . . . + . # # . . + . . . . . + ` + + + + IconNames.Heart + + + + + 500 + + + + + + + + + ArrowNames.SouthEast + + + + + + + myImage + + + + + 0 + + + + + + + myImage + + + + + 1 + + + + + + 200 + + + + + strtest + + + 0 + + + + + Delimiters.Hash + + + + + + + strtest + + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + TouchPin.P2 + + + + + + 1 + + + + + + 2 + + + + + + + 5 + + + + + 45 + + + + + DisplayMode.Greyscale + + + AnalogPin.P4 + + + + 1023 + + + AnalogPin.P13 + + + + + DigitalPin.P10 + + + + 0 + + + DigitalPin.P15 + + + + + AnalogPin.P9 + + + 1234 + + + + + 0 + + + + + + 0 + + + + + + 1023 + + + Rotation.Roll + + + + + 0 + + + Dimension.Y + + + + + 4 + + + + + + + + AnalogPin.P20 + + + + 180 + + + Dimension.Z + + + + + AnalogPin.P14 + + + 1500 + + + + + + + + 220 + + + + + BeatFraction.Sixteenth + + + + + + + 659 + + + + + + + BeatFraction.Double + + + + + MelodyOptions.ForeverInBackground + + + Melodies.Ringtone + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Gesture.TiltLeft + + + + + + 1 + + + EventBusValue.MICROBIT_PIN_EVT_PULSE_HI + + + + + + 2 + + + + + + + + + 64 + + + + + + + + + + + + + booltest + + + 0 + + + Button.B + + + + + booltest + + + 0 + + + TouchPin.P2 + + + + + booltest + + + 0 + + + + + + 3 + + + + + + 4 + + + + + + + + + + + + + Button.AB + + + + + + 1 + + + BeatFraction.Sixteenth + + + + + + 2 + + + + + + + + 3 + + + + + + + 5 + + + + + + 255 + + + + + + + + + 255 + + + 440 + + + + + + + + + TRUE + + + + + + + + + + + + + + + + + + + + + + 4 + + + + + + + + EventBusSource.MICROBIT_ID_IO_P0 + + + + + EventBusValue.MES_ALERT_EVT_ALARM1 + + + + + + + + + TouchPin.P2 + + + AcceleratorRange.EightG + + + + + + + Delimiters.Colon + + + + + SerialPin.P12 + SerialPin.P14 + BaudRate.BaudRate19200 + + + + + + + + DigitalPin.P10 + PulseValue.Low + + + NumberFormat.UInt8BE + + + 0 + + + + + 0 + + + + + FALSE + + + + + + + 0 + + + + + 0 + + + + + DigitalPin.P0 + PinEventType.Touch + + + + + 1000000 + + + + + AnalogPin.P2 + + + DigitalPin.P2 + PinPullMode.PullDown + + + + + 8 + + + + + 3 + + + + + DigitalPin.P9 + DigitalPin.P14 + DigitalPin.P16 + + + + + + + + + + + + + + + + + + + + + + MusicEvent.BackgroundMelodyNotePlayed + + + + + 123 + + + + + + + + 12312312 + + + + + + + + + + + + + + + 0 + + + + + + + x + + + + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + EventBusSource.MICROBIT_ID_IO_P1 + + + + + EventBusValue.MES_ALERT_EVT_ALARM2 + + + + \ No newline at end of file diff --git a/libs/core/buffer.cpp b/libs/core/buffer.cpp deleted file mode 100644 index 1ccb5813..00000000 --- a/libs/core/buffer.cpp +++ /dev/null @@ -1,160 +0,0 @@ -#include "pxt.h" - -// keep in sync with github/pxt/pxtsim/libgeneric.ts -enum class NumberFormat { - Int8LE = 1, - UInt8LE, - Int16LE, - UInt16LE, - Int32LE, - Int8BE, - UInt8BE, - Int16BE, - UInt16BE, - Int32BE, - // UInt32, -}; - -//% indexerGet=BufferMethods::getByte indexerSet=BufferMethods::setByte -namespace BufferMethods { - //% - int getByte(Buffer buf, int off) { - return max(ManagedBuffer(buf).getByte(off), 0); - } - - //% - void setByte(Buffer buf, int off, int v) { - ManagedBuffer(buf).setByte(off, v); - } - - //% - uint8_t *getBytes(Buffer buf) { - return buf->payload; - } - - /** - * Write a number in specified format in the buffer. - */ - //% - void setNumber(Buffer buf, NumberFormat format, int offset, int value) - { - int8_t i8; - uint8_t u8; - int16_t i16; - uint16_t u16; - int32_t i32; - - ManagedBuffer b(buf); - - // Assume little endian - #define WRITEBYTES(isz, swap) isz = value; b.writeBytes(offset, (uint8_t*)&isz, sizeof(isz), swap); break - - switch (format) { - case NumberFormat::Int8LE: WRITEBYTES(i8, false); - case NumberFormat::UInt8LE: WRITEBYTES(u8, false); - case NumberFormat::Int16LE: WRITEBYTES(i16, false); - case NumberFormat::UInt16LE: WRITEBYTES(u16, false); - case NumberFormat::Int32LE: WRITEBYTES(i32, false); - case NumberFormat::Int8BE: WRITEBYTES(i8, true); - case NumberFormat::UInt8BE: WRITEBYTES(u8, true); - case NumberFormat::Int16BE: WRITEBYTES(i16, true); - case NumberFormat::UInt16BE: WRITEBYTES(u16, true); - case NumberFormat::Int32BE: WRITEBYTES(i32, true); - } - } - - /** - * Read a number in specified format from the buffer. - */ - //% - int getNumber(Buffer buf, NumberFormat format, int offset) - { - int8_t i8; - uint8_t u8; - int16_t i16; - uint16_t u16; - int32_t i32; - - ManagedBuffer b(buf); - - // Assume little endian - #define READBYTES(isz, swap) b.readBytes((uint8_t*)&isz, offset, sizeof(isz), swap); return isz - - switch (format) { - case NumberFormat::Int8LE: READBYTES(i8, false); - case NumberFormat::UInt8LE: READBYTES(u8, false); - case NumberFormat::Int16LE: READBYTES(i16, false); - case NumberFormat::UInt16LE: READBYTES(u16, false); - case NumberFormat::Int32LE: READBYTES(i32, false); - case NumberFormat::Int8BE: READBYTES(i8, true); - case NumberFormat::UInt8BE: READBYTES(u8, true); - case NumberFormat::Int16BE: READBYTES(i16, true); - case NumberFormat::UInt16BE: READBYTES(u16, true); - case NumberFormat::Int32BE: READBYTES(i32, true); - } - - return 0; - } - - /** Returns the length of a Buffer object. */ - //% property - int length(Buffer s) { - return s->length; - } - - /** - * Fill (a fragment) of the buffer with given value. - */ - //% - void fill(Buffer buf, int value, int offset = 0, int length = -1) - { - ManagedBuffer(buf).fill(value, offset, length); - } - - /** - * Return a copy of a fragment of a buffer. - */ - //% - Buffer slice(Buffer buf, int offset = 0, int length = -1) - { - return ManagedBuffer(buf).slice(offset, length).leakData(); - } - - /** - * Shift buffer left in place, with zero padding. - * @param offset number of bytes to shift; use negative value to shift right - * @param start start offset in buffer. Default is 0. - * @param length number of elements in buffer. If negative, length is set as the buffer length minus start. eg: -1 - */ - //% - void shift(Buffer buf, int offset, int start = 0, int length = -1) - { - ManagedBuffer(buf).shift(offset, start, length); - } - - /** - * Rotate buffer left in place. - * @param offset number of bytes to shift; use negative value to shift right - * @param start start offset in buffer. Default is 0. - * @param length number of elements in buffer. If negative, length is set as the buffer length minus start. eg: -1 - */ - //% - void rotate(Buffer buf, int offset, int start = 0, int length = -1) - { - ManagedBuffer(buf).rotate(offset, start, length); - } - - // int readBytes(uint8_t *dst, int offset, int length, bool swapBytes = false) const; - // int writeBytes(int dstOffset, uint8_t *src, int length, bool swapBytes = false); - - /** - * Write contents of `src` at `dstOffset` in current buffer. - */ - //% - void write(Buffer buf, int dstOffset, Buffer src) - { - //Not supported, we only do up to 4 args :/ - //void write(Buffer buf, int dstOffset, Buffer src, int srcOffset = 0, int length = -1) - ManagedBuffer(buf).writeBuffer(dstOffset, ManagedBuffer(src), 0, -1); - } -} diff --git a/libs/core/codal.cpp b/libs/core/codal.cpp new file mode 100644 index 00000000..a214ab00 --- /dev/null +++ b/libs/core/codal.cpp @@ -0,0 +1,280 @@ +#include "pxt.h" +#include + +PXT_ABI(__aeabi_dadd) +PXT_ABI(__aeabi_dcmplt) +PXT_ABI(__aeabi_dcmpgt) +PXT_ABI(__aeabi_dsub) +PXT_ABI(__aeabi_ddiv) +PXT_ABI(__aeabi_dmul) + +extern "C" void target_panic(int error_code) { + // wait for serial to flush + wait_us(300000); + microbit_panic(error_code); +} + +extern "C" void target_reset() { + microbit_reset(); +} + +uint32_t device_heap_size(uint8_t heap_index); // defined in microbit-dal + +namespace pxt { + +MicroBit uBit; +MicroBitEvent lastEvent; + +void platform_init() { + microbit_seed_random(); + seedRandom(microbit_random(0x7fffffff)); +} + +void initMicrobitGC() { + if (device_heap_size(1) > NON_GC_HEAP_RESERVATION + 4) + gcPreAllocateBlock(device_heap_size(1) - NON_GC_HEAP_RESERVATION); +} + +void platform_init(); +void usb_init(); + +struct FreeList { + FreeList *next; +}; + +static void initCodal() { + + uBit.init(); + + // repeat error 4 times and restart as needed + microbit_panic_timeout(4); +} + +void dumpDmesg() {} + +// --------------------------------------------------------------------------- +// An adapter for the API expected by the run-time. +// --------------------------------------------------------------------------- + +// We have the invariant that if [dispatchEvent] is registered against the DAL +// for a given event, then [handlersMap] contains a valid entry for that +// event. +void dispatchEvent(MicroBitEvent e) { + lastEvent = e; + + auto curr = findBinding(e.source, e.value); + auto value = fromInt(e.value); + if (curr) + runAction1(curr->action, value); + + curr = findBinding(e.source, DEVICE_EVT_ANY); + if (curr) + runAction1(curr->action, value); +} + +void registerWithDal(int id, int event, Action a, int flags) { + // first time? + if (!findBinding(id, event)) + uBit.messageBus.listen(id, event, dispatchEvent, flags); + setBinding(id, event, a); +} + +void fiberDone(void *a) { + decr((Action)a); + unregisterGCPtr((Action)a); + release_fiber(); +} + +void releaseFiber() { + release_fiber(); +} + +void sleep_ms(unsigned ms) { + fiber_sleep(ms); +} + +void sleep_us(uint64_t us) { + wait_us(us); +} + +void forever_stub(void *a) { + while (true) { + runAction0((Action)a); + fiber_sleep(20); + } +} + +void runForever(Action a) { + if (a != 0) { + incr(a); + registerGCPtr(a); + create_fiber(forever_stub, (void *)a); + } +} + +void runInParallel(Action a) { + if (a != 0) { + incr(a); + registerGCPtr(a); + create_fiber((void (*)(void *))runAction0, (void *)a, fiberDone); + } +} + +void waitForEvent(int id, int event) { + fiber_wait_for_event(id, event); +} + +void initRuntime() { + initCodal(); + platform_init(); +} + +//% +unsigned afterProgramPage() { + unsigned ptr = (unsigned)&bytecode[0]; + ptr += programSize(); + ptr = (ptr + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1); + return ptr; +} + +int current_time_ms() { + return system_timer_current_time(); +} + +static void logwriten(const char *msg, int l) { + uBit.serial.send((uint8_t *)msg, l); +} + +static void logwrite(const char *msg) { + logwriten(msg, strlen(msg)); +} + +static void writeNum(char *buf, uint32_t n, bool full) { + int i = 0; + int sh = 28; + while (sh >= 0) { + int d = (n >> sh) & 0xf; + if (full || d || sh == 0 || i) { + buf[i++] = d > 9 ? 'A' + d - 10 : '0' + d; + } + sh -= 4; + } + buf[i] = 0; +} + +static void logwritenum(uint32_t n, bool full, bool hex) { + char buff[20]; + + if (hex) { + writeNum(buff, n, full); + logwrite("0x"); + } else { + itoa(n, buff); + } + + logwrite(buff); +} + +void vdebuglog(const char *format, va_list ap) { + const char *end = format; + + while (*end) { + if (*end++ == '%') { + logwriten(format, end - format - 1); + uint32_t val = va_arg(ap, uint32_t); + switch (*end++) { + case 'c': + logwriten((const char *)&val, 1); + break; + case 'd': + logwritenum(val, false, false); + break; + case 'x': + logwritenum(val, false, true); + break; + case 'p': + case 'X': + logwritenum(val, true, true); + break; + case 's': + logwrite((char *)(void *)val); + break; + case '%': + logwrite("%"); + break; + default: + logwrite("???"); + break; + } + format = end; + } + } + logwriten(format, end - format); + logwrite("\n"); +} + +void debuglog(const char *format, ...) { + va_list arg; + va_start(arg, format); + vdebuglog(format, arg); + va_end(arg); +} + +void sendSerial(const char *data, int len) { + logwriten(data, len); +} + +#ifdef PXT_GC +ThreadContext *getThreadContext() { + if (!currentFiber) + return NULL; + return (ThreadContext *)currentFiber->user_data; +} + +void setThreadContext(ThreadContext *ctx) { + currentFiber->user_data = ctx; +} + +static void *threadAddressFor(Fiber *fib, void *sp) { + if (fib == currentFiber) + return sp; + return (uint8_t *)sp + ((uint8_t *)fib->stack_top - (uint8_t *)fib->tcb.stack_base); +} + +void gcProcessStacks(int flags) { + // check scheduler is initialized + if (!currentFiber) { + // make sure we allocate something to at least initalize the memory allocator + void * volatile p = xmalloc(1); + xfree(p); + return; + } + + int numFibers = list_fibers(NULL); + Fiber **fibers = (Fiber **)xmalloc(sizeof(Fiber *) * numFibers); + int num2 = list_fibers(fibers); + if (numFibers != num2) + oops(12); + int cnt = 0; + + for (int i = 0; i < numFibers; ++i) { + auto fib = fibers[i]; + auto ctx = (ThreadContext *)fib->user_data; + if (!ctx) + continue; + for (auto seg = &ctx->stack; seg; seg = seg->next) { + auto ptr = (TValue *)threadAddressFor(fib, seg->top); + auto end = (TValue *)threadAddressFor(fib, seg->bottom); + if (flags & 2) + DMESG("RS%d:%p/%d", cnt++, ptr, end - ptr); + // VLOG("mark: %p - %p", ptr, end); + while (ptr < end) { + gcProcess(*ptr++); + } + } + } + xfree(fibers); +} +#endif + +} // namespace pxt diff --git a/libs/core/console.ts b/libs/core/console.ts new file mode 100644 index 00000000..87ec98a2 --- /dev/null +++ b/libs/core/console.ts @@ -0,0 +1,53 @@ +/// + +/** + * Reading and writing data to the console output. + */ +//% weight=12 color=#002050 icon="\uf120" +//% advanced=true +namespace console { + type Listener = (text: string) => void; + + //% whenUsed + let listeners: Listener[] = undefined; + + /** + * Write a line of text to the console output. + * @param value to send + */ + //% weight=90 + //% help=console/log blockGap=8 + //% text.shadowOptions.toString=true + export function log(text: string): void { + // pad text on the 32byte boundar + text += "\r\n"; + control.__log(text); + // send to listeners + if (listeners) + for (let i = 0; i < listeners.length; ++i) + listeners[i](text); + } + + /** + * Write a name:value pair as a line of text to the console output. + * @param name name of the value stream, eg: "x" + * @param value to write + */ + //% weight=88 blockGap=8 + //% help=console/log-value + export function logValue(name: string, value: number): void { + log(name ? `${name}: ${value}` : `${value}`) + } + + /** + * Adds a listener for the log messages + * @param listener + */ + //% + export function addListener(listener: (text: string) => void) { + if (!listener) return; + if (!listeners) + listeners = []; + listeners.push(listener); + } +} \ No newline at end of file diff --git a/libs/core/control.cpp b/libs/core/control.cpp index a0e66297..0aff221f 100644 --- a/libs/core/control.cpp +++ b/libs/core/control.cpp @@ -71,8 +71,6 @@ enum EventBusSource { //% blockIdentity="control.eventSourceId" MICROBIT_ID_IO_P20_ = MICROBIT_ID_IO_P20, //% blockIdentity="control.eventSourceId" - MICROBIT_ID_IO_P21_ = MICROBIT_ID_IO_P21, - //% blockIdentity="control.eventSourceId" MES_DEVICE_INFO_ID_ = MES_DEVICE_INFO_ID, //% blockIdentity="control.eventSourceId" MES_SIGNAL_STRENGTH_ID_ = MES_SIGNAL_STRENGTH_ID, @@ -207,6 +205,15 @@ enum EventBusValue { MES_REMOTE_CONTROL_EVT_VOLUMEUP_ = MES_REMOTE_CONTROL_EVT_VOLUMEUP, }; +enum EventFlags { + //% + QueueIfBusy = MESSAGE_BUS_LISTENER_QUEUE_IF_BUSY, + //% + DropIfBusy = MESSAGE_BUS_LISTENER_DROP_IF_BUSY, + //% + Reentrant = MESSAGE_BUS_LISTENER_REENTRANT +}; + //% weight=1 color="#333333" //% advanced=true namespace control { @@ -222,7 +229,7 @@ namespace control { //% help=control/in-background blockAllowMultiple=1 afterOnStart=true //% blockId="control_in_background" block="run in background" blockGap=8 void inBackground(Action a) { - runInBackground(a); + runInParallel(a); } /** @@ -258,13 +265,14 @@ namespace control { } /** - * Raises an event in the event bus. + * Registers an event handler. */ //% weight=20 blockGap=8 blockId="control_on_event" block="on event|from %src=control_event_source_id|with value %value=control_event_value_id" //% help=control/on-event //% blockExternalInputs=1 - void onEvent(int src, int value, Action handler) { - registerWithDal(src, value, handler); + void onEvent(int src, int value, Action handler, int flags = 0) { + if (!flags) flags = EventFlags::QueueIfBusy; + registerWithDal(src, value, handler, (int)flags); } /** @@ -288,12 +296,12 @@ namespace control { } /** - * Gets a friendly name for the device derived from the its serial number + * Make a friendly name for the device based on its serial number */ //% blockId="control_device_name" block="device name" weight=10 blockGap=8 //% advanced=true - StringData* deviceName() { - return ManagedString(microbit_friendly_name()).leakData(); + String deviceName() { + return mkString(microbit_friendly_name(), -1); } /** @@ -304,4 +312,22 @@ namespace control { int deviceSerialNumber() { return microbit_serial_number(); } + + /** + * Informs simulator/runtime of a MIDI message + * Internal function to support the simulator. + */ + //% part=midioutput blockHidden=1 + void __midiSend(Buffer buffer) { + // this is a stub to support the simulator + } + + /** + * + */ + //% + void __log(String text) { + if (NULL == text) return; + pxt::sendSerial(text->getUTF8Data(), text->getUTF8Size()); + } } diff --git a/libs/core/control.ts b/libs/core/control.ts index 2eb382fb..a6f49206 100644 --- a/libs/core/control.ts +++ b/libs/core/control.ts @@ -4,47 +4,63 @@ //% weight=1 color="#42495F" icon="\uf233" //% advanced=true namespace control { - - /** - * Returns the value of a C++ runtime constant - */ - //% weight=2 weight=19 blockId="control_event_source_id" block="%id" blockGap=8 - //% shim=TD_ID advanced=true - export function eventSourceId(id: EventBusSource): number { - return id; - } - /** - * Returns the value of a C++ runtime constant - */ - //% weight=1 weight=19 blockId="control_event_value_id" block="%id" - //% shim=TD_ID advanced=true - export function eventValueId(id: EventBusValue): number { - return id; - } - - /** - * Display specified error code and stop the program. - */ - //% shim=pxtrt::panic - export function panic(code: number) { } - - /** - * If the condition is false, display msg on serial console, and panic with code 098. - */ - export function assert(condition: boolean, msg?: string) { - if (!condition) { - console.log("ASSERTION FAILED") - if (msg != null) { - console.log(msg) - } - panic(98) - } - } - - /** - * Display warning in the simulator. - */ - //% shim=pxtrt::runtimeWarning - export function runtimeWarning(message: string) { } + + /** + * Returns the value of a C++ runtime constant + */ + //% weight=2 weight=19 blockId="control_event_source_id" block="%id" blockGap=8 + //% shim=TD_ID advanced=true + export function eventSourceId(id: EventBusSource): number { + return id; } - \ No newline at end of file + /** + * Returns the value of a C++ runtime constant + */ + //% weight=1 weight=19 blockId="control_event_value_id" block="%id" + //% shim=TD_ID advanced=true + export function eventValueId(id: EventBusValue): number { + return id; + } + + /** + * Display specified error code and stop the program. + */ + //% shim=pxtrt::panic + export function panic(code: number) { } + + /** + * If the condition is false, display msg on serial console, and panic with code 098. + */ + export function assert(condition: boolean, msg?: string) { + if (!condition) { + console.log("ASSERTION FAILED") + if (msg != null) { + console.log(msg) + } + panic(98) + } + } + + export function fail(message: string) { + console.log("Fatal failure: ") + console.log(message) + panic(108) + } + + /** + * Display warning in the simulator. + */ + //% shim=pxtrt::runtimeWarning + export function runtimeWarning(message: string) { } +} + +/** + * Convert any value to text + * @param value value to be converted to text + */ +//% help=text/convert-to-text weight=1 +//% block="convert $value=math_number to text" +//% blockId=variable_to_text blockNamespace="text" +function convertToText(value: any): string { + return "" + value; +} diff --git a/libs/core/core.cpp b/libs/core/core.cpp deleted file mode 100644 index 2a026aa8..00000000 --- a/libs/core/core.cpp +++ /dev/null @@ -1,436 +0,0 @@ -#include "pxt.h" -#include - - -namespace String_ { - //% - StringData *charAt(StringData *s, int pos) { - return ManagedString((char)ManagedString(s).charAt(pos)).leakData(); - } - - //% - int charCodeAt(StringData *s, int index) { - return ManagedString(s).charAt(index); - } - - //% - StringData *concat(StringData *s, StringData *other) { - ManagedString a(s), b(other); - return (a + b).leakData(); - } - - //% - int compare(StringData *s, StringData *that) { - int compareResult = strcmp(s->data, that->data); - if (compareResult < 0) - return -1; - else if (compareResult > 0) - return 1; - return 0; - } - - //% - int compareDecr(StringData *s, StringData *that) { - int r = compare(s, that); - if (r == 0) - decr((uint32_t)that); - return r; - } - - - //% - int length(StringData *s) { return s->len; } - - //% - StringData *fromCharCode(int code) - { - return ManagedString((char)code).leakData(); - } - - //% - int toNumber(StringData *s) { - return atoi(s->data); - } - - //% - StringData *mkEmpty() - { - return ManagedString::EmptyString.leakData(); - } - - //% - StringData *substr(StringData *s, int start, int length) - { - if (length <= 0) - return mkEmpty(); - if (start < 0) - start = max(s->len + start, 0); - length = min(length, s->len - start); - ManagedString x(s); - return x.substring(start, length).leakData(); - } -} - - -namespace Boolean_ { - // Cache the string literals "true" and "false" when used. - // Note that the representation of booleans stays the usual C-one. - - static const char sTrue[] __attribute__ ((aligned (4))) = "\xff\xff\x04\x00" "true\0"; - static const char sFalse[] __attribute__ ((aligned (4))) = "\xff\xff\x05\x00" "false\0"; - - //% - StringData* toString(bool v) - { - if (v) { - return (StringData*)(void*)sTrue; - } else { - return (StringData*)(void*)sFalse; - } - } - - //% - bool bang(int v) { return v == 0; } -} - -namespace Number_ { - //% - StringData* toString(int n) - { - return ManagedString(n).leakData(); - } - - // +, - and friends are handled directly by assembly instructions - // The comparisons are here as they are more code-size efficient - - //% - bool lt(int x, int y) { return x < y; } - //% - bool le(int x, int y) { return x <= y; } - //% - bool neq(int x, int y) { return x != y; } - //% - bool eq(int x, int y) { return x == y; } - //% - bool gt(int x, int y) { return x > y; } - //% - bool ge(int x, int y) { return x >= y; } - - // These in fact call into C runtime on Cortex-M0 - //% - int div(int x, int y) { return x / y; } - //% - int mod(int x, int y) { return x % y; } - - //% - bool eqDecr(int x, int y) { - if(x == y) { - decr(y); - return true; - } - return false; - } -} - -namespace Math_ { - //% - int pow(int x, int y) - { - if (y < 0) - return 0; - int r = 1; - while (y) { - if (y & 1) - r *= x; - y >>= 1; - x *= x; - } - return r; - } - - //% - int random(int max) { - if (max == INT_MIN) - return -microbit_random(INT_MAX); - else if (max < 0) - return -microbit_random(-max); - else if (max == 0) - return 0; - else - return microbit_random(max); - } - - //% - int sqrt(int x) - { - return ::sqrt(x); - } -} - -namespace Array_ { - //% - RefCollection *mk(uint32_t flags) - { - return new RefCollection(flags); - } - //% - int length(RefCollection *c) { return c->length(); } - //% - void setLength(RefCollection *c, int newLength) { c->setLength(newLength); } - //% - void push(RefCollection *c, uint32_t x) { c->push(x); } - //% - uint32_t pop(RefCollection *c) { return c->pop(); } - //% - uint32_t getAt(RefCollection *c, int x) { return c->getAt(x); } - //% - void setAt(RefCollection *c, int x, uint32_t y) { c->setAt(x, y); } - //% - uint32_t removeAt(RefCollection *c, int x) { return c->removeAt(x); } - //% - void insertAt(RefCollection *c, int x, uint32_t value) { c->insertAt(x, value); } - //% - int indexOf(RefCollection *c, uint32_t x, int start) { return c->indexOf(x, start); } - //% - int removeElement(RefCollection *c, uint32_t x) { return c->removeElement(x); } -} - - -// Import some stuff directly -namespace pxt { - //% - void registerWithDal(int id, int event, Action a); - //% - uint32_t runAction3(Action a, int arg0, int arg1, int arg2); - //% - uint32_t runAction2(Action a, int arg0, int arg1); - //% - uint32_t runAction1(Action a, int arg0); - //% - uint32_t runAction0(Action a); - //% - Action mkAction(int reflen, int totallen, int startptr); - //% - RefRecord* mkClassInstance(int offset); - //% - void RefRecord_destroy(RefRecord *r); - //% - void RefRecord_print(RefRecord *r); - //% - void debugMemLeaks(); - //% - int incr(uint32_t e); - //% - void decr(uint32_t e); - //% - uint32_t *allocate(uint16_t sz); - //% - int templateHash(); - //% - int programHash(); - //% - void *ptrOfLiteral(int offset); - //% - int getNumGlobals(); - - //% - uint32_t programSize() { - return bytecode[17] * 2; - } - - //% - uint32_t afterProgramPage() { - uint32_t ptr = (uint32_t)&bytecode[0]; - ptr += programSize(); - if (ptr % PAGE_SIZE != 0) - ptr = (ptr & ~(PAGE_SIZE-1)) + PAGE_SIZE; - return ptr; - } -} - -namespace pxtrt { - //% - uint32_t ldloc(RefLocal *r) { - return r->v; - } - - //% - uint32_t ldlocRef(RefRefLocal *r) { - uint32_t tmp = r->v; - incr(tmp); - return tmp; - } - - //% - void stloc(RefLocal *r, uint32_t v) { - r->v = v; - } - - //% - void stlocRef(RefRefLocal *r, uint32_t v) { - decr(r->v); - r->v = v; - } - - //% - RefLocal *mkloc() { - return new RefLocal(); - } - - //% - RefRefLocal *mklocRef() { - return new RefRefLocal(); - } - - // All of the functions below unref() self. This is for performance reasons - - // the code emitter will not emit the unrefs for them. - - //% - uint32_t ldfld(RefRecord *r, int idx) { - auto tmp = r->ld(idx); - r->unref(); - return tmp; - } - - //% - uint32_t ldfldRef(RefRecord *r, int idx) { - auto tmp = r->ldref(idx); - r->unref(); - return tmp; - } - - //% - void stfld(RefRecord *r, int idx, uint32_t val) { - r->st(idx, val); - r->unref(); - } - - //% - void stfldRef(RefRecord *r, int idx, uint32_t val) { - r->stref(idx, val); - r->unref(); - } - - // Store a captured local in a closure. It returns the action, so it can be chained. - //% - RefAction *stclo(RefAction *a, int idx, uint32_t v) - { - //DBG("STCLO "); a->print(); DBG("@%d = %p\n", idx, (void*)v); - a->stCore(idx, v); - return a; - } - - //% - void panic(int code) - { - microbit_panic(code); - } - - //% - int stringToBool(StringData *s) { - if (s == NULL) return 0; - if (s->len == 0) { - s->decr(); - return 0; - } - s->decr(); - return 1; - } - - //% - StringData* emptyToNull(StringData *s) { - if (!s || s->len == 0) - return NULL; - return s; - } - - //% - int ptrToBool(uint32_t p) { - if (p) { - decr(p); - return 1; - } else { - return 0; - } - } - - //% - RefMap *mkMap() { - return new RefMap(); - } - - //% - uint32_t mapGet(RefMap *map, uint32_t key) { - int i = map->findIdx(key); - if (i < 0) { - map->unref(); - return 0; - } - uint32_t r = map->data[i].val; - map->unref(); - return r; - } - - //% - uint32_t mapGetRef(RefMap *map, uint32_t key) { - int i = map->findIdx(key); - if (i < 0) { - map->unref(); - return 0; - } - uint32_t r = incr(map->data[i].val); - map->unref(); - return r; - } - - //% - void mapSet(RefMap *map, uint32_t key, uint32_t val) { - int i = map->findIdx(key); - if (i < 0) { - map->data.push_back({ - key << 1, - val - }); - } else { - if (map->data[i].key & 1) { - decr(map->data[i].val); - map->data[i].key = key << 1; - } - map->data[i].val = val; - } - map->unref(); - } - - //% - void mapSetRef(RefMap *map, uint32_t key, uint32_t val) { - int i = map->findIdx(key); - if (i < 0) { - map->data.push_back({ - (key << 1) | 1, - val - }); - } else { - if (map->data[i].key & 1) { - decr(map->data[i].val); - } else { - map->data[i].key = (key << 1) | 1; - } - map->data[i].val = val; - } - map->unref(); - } - - // - // Debugger - // - - //% - void* getGlobalsPtr() { - return globals; - } - - //% - void runtimeWarning(StringData *s) { - // noop for now - } -} diff --git a/libs/core/dal.d.ts b/libs/core/dal.d.ts index 466fc550..7156889d 100644 --- a/libs/core/dal.d.ts +++ b/libs/core/dal.d.ts @@ -420,11 +420,11 @@ declare const enum DAL { MICROBIT_ACCELEROMETER_EVT_FACE_UP = 5, MICROBIT_ACCELEROMETER_EVT_FACE_DOWN = 6, MICROBIT_ACCELEROMETER_EVT_FREEFALL = 7, - MICROBIT_ACCELEROMETER_EVT_2G = 8, - MICROBIT_ACCELEROMETER_EVT_3G = 9, - MICROBIT_ACCELEROMETER_EVT_6G = 10, - MICROBIT_ACCELEROMETER_EVT_8G = 11, - MICROBIT_ACCELEROMETER_EVT_SHAKE = 12, + // MICROBIT_ACCELEROMETER_EVT_2G = 8, + MICROBIT_ACCELEROMETER_EVT_3G = 8, + MICROBIT_ACCELEROMETER_EVT_6G = 9, + MICROBIT_ACCELEROMETER_EVT_8G = 10, + MICROBIT_ACCELEROMETER_EVT_SHAKE = 11, MICROBIT_ACCELEROMETER_REST_TOLERANCE = 200, MICROBIT_ACCELEROMETER_TILT_TOLERANCE = 200, MICROBIT_ACCELEROMETER_FREEFALL_TOLERANCE = 400, @@ -641,4 +641,4 @@ declare const enum DAL { // built/yt/yotta_modules/microbit-dal/inc/types/MicroBitImage.h // built/yt/yotta_modules/microbit-dal/inc/types/PacketBuffer.h // built/yt/yotta_modules/microbit-dal/inc/types/RefCounted.h -} +} \ No newline at end of file diff --git a/libs/core/enums.d.ts b/libs/core/enums.d.ts index 8fe1de13..a0a8cb14 100644 --- a/libs/core/enums.d.ts +++ b/libs/core/enums.d.ts @@ -1,4 +1,30 @@ // Auto-generated. Do not edit. + + + declare const enum NumberFormat { + Int8LE = 1, + UInt8LE = 2, + Int16LE = 3, + UInt16LE = 4, + Int32LE = 5, + Int8BE = 6, + UInt8BE = 7, + Int16BE = 8, + UInt16BE = 9, + Int32BE = 10, + + UInt32LE = 11, + UInt32BE = 12, + Float32LE = 13, + Float64LE = 14, + Float32BE = 15, + Float64BE = 16, + } + + + declare const enum PerfCounters { + GC = 0, + } declare namespace images { } declare namespace basic { @@ -70,57 +96,68 @@ declare namespace basic { * Raised when shaken */ //% block=shake - Shake = 12, // MICROBIT_ACCELEROMETER_EVT_SHAKE + //% jres=gestures.shake + Shake = 11, // MICROBIT_ACCELEROMETER_EVT_SHAKE /** * Raised when the logo is upward and the screen is vertical */ //% block="logo up" + //% jres=gestures.tiltforward LogoUp = 1, // MICROBIT_ACCELEROMETER_EVT_TILT_UP /** * Raised when the logo is downward and the screen is vertical */ //% block="logo down" + //% jres=gestures.tiltbackwards LogoDown = 2, // MICROBIT_ACCELEROMETER_EVT_TILT_DOWN /** * Raised when the screen is pointing down and the board is horizontal */ //% block="screen up" + //% jres=gestures.frontsideup ScreenUp = 5, // MICROBIT_ACCELEROMETER_EVT_FACE_UP /** * Raised when the screen is pointing up and the board is horizontal */ //% block="screen down" + //% jres=gestures.backsideup ScreenDown = 6, // MICROBIT_ACCELEROMETER_EVT_FACE_DOWN /** * Raised when the screen is pointing left */ //% block="tilt left" + //% jres=gestures.tiltleft TiltLeft = 3, // MICROBIT_ACCELEROMETER_EVT_TILT_LEFT /** * Raised when the screen is pointing right */ //% block="tilt right" + //% jres=gestures.tiltright TiltRight = 4, // MICROBIT_ACCELEROMETER_EVT_TILT_RIGHT /** * Raised when the board is falling! */ //% block="free fall" + //% jres=gestures.freefall FreeFall = 7, // MICROBIT_ACCELEROMETER_EVT_FREEFALL /** * Raised when a 3G shock is detected */ //% block="3g" - ThreeG = 9, // MICROBIT_ACCELEROMETER_EVT_3G + //% jres=gestures.impact3g + ThreeG = 8, // MICROBIT_ACCELEROMETER_EVT_3G /** * Raised when a 6G shock is detected */ //% block="6g" - SixG = 10, // MICROBIT_ACCELEROMETER_EVT_6G + //% jres=gestures.impact6g + SixG = 9, // MICROBIT_ACCELEROMETER_EVT_6G /** * Raised when a 8G shock is detected */ //% block="8g" - EightG = 11, // MICROBIT_ACCELEROMETER_EVT_8G + //% jres=gestures.impact8g + EightG = 10, // MICROBIT_ACCELEROMETER_EVT_8G } @@ -230,8 +267,6 @@ declare namespace input { //% blockIdentity="control.eventSourceId" MICROBIT_ID_IO_P20 = 25, // MICROBIT_ID_IO_P20 //% blockIdentity="control.eventSourceId" - MICROBIT_ID_IO_P21 = 50, // MICROBIT_ID_IO_P21 - //% blockIdentity="control.eventSourceId" MES_DEVICE_INFO_ID = 1103, // MES_DEVICE_INFO_ID //% blockIdentity="control.eventSourceId" MES_SIGNAL_STRENGTH_ID = 1101, // MES_SIGNAL_STRENGTH_ID @@ -366,12 +401,24 @@ declare namespace input { //% blockIdentity="control.eventValueId" MES_REMOTE_CONTROL_EVT_VOLUMEUP = 8, // MES_REMOTE_CONTROL_EVT_VOLUMEUP } + + + declare const enum EventFlags { + //% + QueueIfBusy = 0x0010, // MESSAGE_BUS_LISTENER_QUEUE_IF_BUSY + //% + DropIfBusy = 0x0020, // MESSAGE_BUS_LISTENER_DROP_IF_BUSY + //% + Reentrant = 0x0008, // MESSAGE_BUS_LISTENER_REENTRANT + } declare namespace control { } declare const enum DisplayMode { //% block="black and white" + BlackAndWhite = 0, // DISPLAY_MODE_BLACK_AND_WHITE + //% blockHidden=true BackAndWhite = 0, // DISPLAY_MODE_BLACK_AND_WHITE //% block="greyscale" Greyscale = 1, // DISPLAY_MODE_GREYSCALE @@ -435,7 +482,9 @@ declare namespace motors { declare const enum PulseValue { + //% block=high High = 4, // MICROBIT_PIN_EVT_PULSE_HI + //% block=low Low = 5, // MICROBIT_PIN_EVT_PULSE_LO } @@ -463,12 +512,17 @@ declare namespace motors { declare const enum SerialPin { - C16 = 9, // MICROBIT_ID_IO_P2 - C17 = 15, // MICROBIT_ID_IO_P8 - P0 = 19, // MICROBIT_ID_IO_P12 - P1 = 7, // MICROBIT_ID_IO_P0 - P2 = 8, // MICROBIT_ID_IO_P1 - P3 = 23, // MICROBIT_ID_IO_P16 + P0 = 7, // MICROBIT_ID_IO_P0 + P1 = 8, // MICROBIT_ID_IO_P1 + P2 = 9, // MICROBIT_ID_IO_P2 + P8 = 15, // MICROBIT_ID_IO_P8 + P12 = 19, // MICROBIT_ID_IO_P12 + P13 = 20, // MICROBIT_ID_IO_P13 + P14 = 21, // MICROBIT_ID_IO_P14 + P15 = 22, // MICROBIT_ID_IO_P15 + P16 = 23, // MICROBIT_ID_IO_P16 + USB_TX = 1001, + USB_RX = 1002, } @@ -476,9 +530,25 @@ declare namespace motors { //% block=115200 BaudRate115200 = 115200, //% block=57600 - BaudRate56700 = 57600, + BaudRate57600 = 57600, + //% block=38400 + BaudRate38400 = 38400, + //% block=31250 + BaudRate31250 = 31250, + //% block=28800 + BaudRate28800 = 28800, + //% block=19200 + BaudRate19200 = 19200, + //% block=14400 + BaudRate14400 = 14400, //% block=9600 BaudRate9600 = 9600, + //% block=4800 + BaudRate4800 = 4800, + //% block=2400 + BaudRate2400 = 2400, + //% block=1200 + BaudRate1200 = 1200, } @@ -499,19 +569,4 @@ declare namespace motors { declare namespace serial { } - - declare const enum NumberFormat { - Int8LE = 1, - UInt8LE = 2, - Int16LE = 3, - UInt16LE = 4, - Int32LE = 5, - Int8BE = 6, - UInt8BE = 7, - Int16BE = 8, - UInt16BE = 9, - Int32BE = 10, - // UInt32, - } - // Auto-generated. Do not edit. Really. diff --git a/libs/core/game.ts b/libs/core/game.ts index 28153310..41038ce7 100644 --- a/libs/core/game.ts +++ b/libs/core/game.ts @@ -168,9 +168,10 @@ namespace game { /** * Sets the current life value - * @param value TODO + * @param value current life value */ - //% weight=10 + //% weight=10 help=game/set-life + //% blockId=game_set_life block="set life %value" blockGap=8 export function setLife(value: number): void { _life = Math.max(0, value); if (_life <= 0) { @@ -179,10 +180,11 @@ namespace game { } /** - * Adds life points to the current life - * @param lives TODO + * Add life points to the current life amount + * @param lives amount of lives to add */ - //% weight=10 + //% weight=10 help=game/add-life + //% blockId=game_add_life block="add life %lives" blockGap=8 export function addLife(lives: number): void { setLife(_life + lives); } @@ -200,14 +202,16 @@ namespace game { } /** - * Removes some life - * @param life TODO + * Remove some life + * @param life amount of life to remove */ - //% weight=10 + //% weight=10 help=game/remove-life //% parts="ledmatrix" + //% blockId=game_remove_life block="remove life %life" blockGap=8 export function removeLife(life: number): void { setLife(_life - life); - if (!_paused) + if (!_paused && !_backgroundAnimation) { + _backgroundAnimation = true; control.inBackground(() => { led.stopAnimation(); basic.showAnimation(`1 0 0 0 1 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 @@ -215,7 +219,9 @@ namespace game { 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0`, 40); + _backgroundAnimation = false; }); + } } /** @@ -247,12 +253,12 @@ namespace game { } /** - * Gets a value indicating if the game is still running. Returns `false` if game over. + * Indicates if the game is still running. Returns `false` if the game is over or paused. */ - //% weight=10 + //% weight=5 help=game/is-running + //% blockId=game_isrunning block="is running" blockGap=8 export function isRunning(): boolean { - let running: boolean; - return !_isGameOver; + return !_isGameOver && !_paused && !!_img; } /** @@ -267,8 +273,10 @@ namespace game { } /** - * Indicates if the game is display the game over sequence. + * Indicates if the game is over and displaying the game over sequence. */ + //% weight=7 help=game/is-game-over + //% blockId=game_isgameover block="is game over" blockGap=8 export function isGameOver(): boolean { return _isGameOver; } @@ -276,7 +284,8 @@ namespace game { /** * Indicates if the game rendering is paused to allow other animations */ - //% + //% weight=6 help=game/is-paused + //% blockId=game_ispaused block="is paused" blockGap=8 export function isPaused(): boolean { return _paused; } @@ -396,7 +405,7 @@ namespace game { /** * If touching the edge of the stage and facing towards it, then turn away. - * @param this TODO + * @param this the sprite to check for bounce */ //% weight=18 help=game/if-on-edge-bounce //% blockId=game_sprite_bounce block="%sprite|if on edge, bounce" @@ -448,7 +457,7 @@ namespace game { /** * Turn the sprite - * @param this TODO + * @param this the sprite to trun * @param direction left or right * @param degrees angle in degrees to turn, eg: 45, 90, 180, 135 */ @@ -463,7 +472,7 @@ namespace game { /** * Turn to the right (clockwise) - * @param this TODO + * @param this the sprite to turn * @param degrees TODO */ public turnRight(degrees: number): void { @@ -472,7 +481,7 @@ namespace game { /** * Turn to the left (counter-clockwise) - * @param this TODO + * @param this the sprite to turn * @param degrees TODO */ public turnLeft(degrees: number): void { @@ -532,12 +541,12 @@ namespace game { /** * Set the direction of the current sprite, rounded to the nearest multiple of 45 - * @param this TODO - * @param degrees TODO + * @param this the sprite to set direction for + * @param degrees new direction in degrees */ //% parts="ledmatrix" public setDirection(degrees: number): void { - this._dir = ((degrees / 45) % 8) * 45; + this._dir = (Math.floor(degrees / 45) % 8) * 45; if (this._dir <= -180) { this._dir = this._dir + 360; } else if (this._dir > 180) { @@ -608,23 +617,23 @@ namespace game { /** * Reports true if sprite has the same position as specified sprite - * @param this TODO - * @param other TODO + * @param this the sprite to check overlap or touch + * @param other the other sprite to check overlap or touch */ //% weight=20 help=game/is-touching - //% blockId=game_sprite_touching_sprite block="%sprite|touching %other|?" blockGap=8 + //% blockId=game_sprite_touching_sprite block="is %sprite|touching %other" blockGap=8 public isTouching(other: LedSprite): boolean { return this._enabled && other._enabled && this._x == other._x && this._y == other._y; } /** * Reports true if sprite is touching an edge - * @param this TODO + * @param this the sprite to check for an edge contact */ //% weight=19 help=game/is-touching-edge - //% blockId=game_sprite_touching_edge block="%sprite|touching edge?" blockGap=8 + //% blockId=game_sprite_touching_edge block="is %sprite|touching edge" blockGap=8 public isTouchingEdge(): boolean { - return this._x == 0 || this._x == 4 || this._y == 0 || this._y == 4; + return this._enabled && (this._x == 0 || this._x == 4 || this._y == 0 || this._y == 4); } /** @@ -686,14 +695,23 @@ namespace game { * Deletes the sprite from the game engine. The sprite will no longer appear on the screen or interact with other sprites. * @param this sprite to delete */ - //% weight=59 help=game/delete - //% blockId="game_delete_sprite" block="delete %this" + //% weight=59 blockGap=8 help=game/delete + //% blockId="game_delete_sprite" block="delete %this(sprite)" public delete(): void { this._enabled = false; if (_sprites.removeElement(this)) plot(); } + /** + * Reports whether the sprite has been deleted from the game engine. + */ + //% weight=58 help=game/is-deleted + //% blockId="game_sprite_is_deleted" block="is %sprite|deleted" + public isDeleted(): boolean { + return !this._enabled; + } + /** * Sets the blink duration interval in millisecond. * @param sprite TODO @@ -717,7 +735,6 @@ namespace game { * @param this TODO */ public blink(): number { - let r: number; return this._blink; } @@ -728,7 +745,7 @@ namespace game { if (ps._brightness > 0) { let r = 0; if (ps._blink > 0) { - r = (now / ps._blink) % 2; + r = Math.floor(now / ps._blink) % 2; } if (r == 0) { _img.setPixelBrightness(ps._x, ps._y, _img.pixelBrightness(ps._x, ps._y) + ps._brightness); @@ -766,7 +783,7 @@ namespace game { } // ensure greyscale mode const dm = led.displayMode(); - if (dm != DisplayMode.Greyscale) + if (dm != DisplayMode.Greyscale) led.setDisplayMode(DisplayMode.Greyscale); // render sprites const now = input.runningTime(); @@ -775,9 +792,6 @@ namespace game { _sprites[i]._plot(now); } _img.plotImage(0); - // restore previous display mode - if (dm != DisplayMode.Greyscale) - led.setDisplayMode(dm); } /** @@ -789,3 +803,4 @@ namespace game { } } + diff --git a/libs/core/gestures.jres b/libs/core/gestures.jres new file mode 100644 index 00000000..2df143ab --- /dev/null +++ b/libs/core/gestures.jres @@ -0,0 +1,39 @@ +{ + "*": { + "namespace": "gestures", + "dataEncoding": "base64" + }, + "shake": { + "icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAACXBIWXMAAAsTAAALEwEAmpwYAAAFIGlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS42LWMxNDUgNzkuMTYzNDk5LCAyMDE4LzA4LzEzLTE2OjQwOjIyICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ0MgMjAxOSAoTWFjaW50b3NoKSIgeG1wOkNyZWF0ZURhdGU9IjIwMTktMTEtMTVUMTU6NTc6NDIrMDE6MDAiIHhtcDpNb2RpZnlEYXRlPSIyMDE5LTExLTE1VDE1OjU5OjMxKzAxOjAwIiB4bXA6TWV0YWRhdGFEYXRlPSIyMDE5LTExLTE1VDE1OjU5OjMxKzAxOjAwIiBkYzpmb3JtYXQ9ImltYWdlL3BuZyIgcGhvdG9zaG9wOkNvbG9yTW9kZT0iMyIgcGhvdG9zaG9wOklDQ1Byb2ZpbGU9InNSR0IgSUVDNjE5NjYtMi4xIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjU4YTE4ZDdhLTVlOWEtNDAwMC04MDZhLWE5NmY4ZjgwYjY5ZSIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDo1OGExOGQ3YS01ZTlhLTQwMDAtODA2YS1hOTZmOGY4MGI2OWUiIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDo1OGExOGQ3YS01ZTlhLTQwMDAtODA2YS1hOTZmOGY4MGI2OWUiPiA8eG1wTU06SGlzdG9yeT4gPHJkZjpTZXE+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJjcmVhdGVkIiBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOjU4YTE4ZDdhLTVlOWEtNDAwMC04MDZhLWE5NmY4ZjgwYjY5ZSIgc3RFdnQ6d2hlbj0iMjAxOS0xMS0xNVQxNTo1Nzo0MiswMTowMCIgc3RFdnQ6c29mdHdhcmVBZ2VudD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTkgKE1hY2ludG9zaCkiLz4gPC9yZGY6U2VxPiA8L3htcE1NOkhpc3Rvcnk+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+HuWiaAAACblJREFUeJztmntwVNUdxz/3bm4ICS+hCUkIhPDwUUXRlojYGaF0qIUZFFGHsVCgTGvVllIsVrSUQbCltmO1VirVEStlsNAitFMYKxSxrZ2ioMVGwrM8QkIIrwRIstnde/vH926zLLs3uxfIdoZ8Z3aSvedxz/mec36/7+931nAchysZZqYHkGl0EJDpAWQaHQRkegCZRgcBmR5AptFBQKYHkGlc8QRkteO7CoHxwE3AGWAV8BFgezVavH8/K6qrKcjOjn2cBThAJNWXbyovT/i8PXdAAXAtcANwHTCQFBagxbYJ2TbG+Y+7AZ0uxaDaawcUAr8CbgVCgIV2w9eAV7waDsjNpadlcS4SIS8QwIFxwDTgMPBXoBLY6Xdg7bUDRqLJ7wQeBF53n88HvujVcHJxMbPLynCAulCIsOOMN+Be4DvAGuA9YBbwKT8Da68dcK379x1gGbAW7YoxwC+B6cCWZI3vLSzEANbX1XGkuXlhTTC42zLN6/MCgcGWYYxw4GfA7YiII24zA9kJTxjtkA/ohyY8FPgW8KL7/AbgTWAQ2s4PAhva6uyNmho2nzhBd8viw4YGzoXDs3MDgTmOCF0DfAUZx68DB4E/AnYyI9geBHwTeAHYg859ZUzZCGApIsMB5iESKoHGuH66AX2BzkALULG8ujry4sGDmDA+NxBY5kBP4D5gG7DP7fMaoG5TeXl9osFdbgL6An9Aq/8j4IkEdUqBZ4D73e/NwK/RBI6iSV0FDADuBPKBE4i4Z1ZUV9e/duQILba9OMswZgM7gLHAcnTEZgI1m8rLf5dogJeTgM7AEmSx/41W/z8e9ecAdwE3Al2T1KkHDgBDkAGfDfzi8V27QhuPHy/qblnvAf2BTyPSlwH/AKo2lZdPSdTh5TKCfdBqTwPOoa3tNXmAnwA/R27us2giUfVThyb+MbL6c4HvAl8CVjTb9jHTMGrQ0ekP3AFUACcRGfnJXnqpCSgGhqFz/wU0+VnICKaCIDJka9qoV4HOt8X5rnw7OibDgPVIcV6NRFhCXCwB/ZBxKnH/vx8Y7ZZVolV99SLfEY/OwFeBAPBPoCGm7M9IV+wCDpGCWvRLQH/ktu5ARqw4pmw/UmjPIa2fCEVIGH0C7E7z3bejeOIsiicaT4dCtEgub3Ekkqrduh8hXVCbrDM/BFyFjMtI9/tRZOR2osmsBT7waG8iy/w4sAmJoMNpvH8s0ANNfjfAnfn5HG9poSESwTKMAzF1ZyGiQsk680PAbWjy1cBTaLKn0Mqniuvcv58BenE+AaXIz9ckaXuz+3cDmhyTiorYXl/P5lOnsAKB2LoH2hqIHwJ6x3S+1Ed7G8nfY2iLfhxTNg65wyDwfeD9uLa5QBf3/12xBdXBoKJGBUwpw08w9C+0QregHeCnj7eQVF3C+TH93ciujEFnPR55iAQbeZj/YULv3uSaJmcjkfjQ2RN+Bl+JVF0O8u+J1J1frAL+grZ3ouCoCe0OiNu9EwsLeXLgQADOpUGCnyPQCCxy2z4JLEDbeJ2PvuLxNvLlQdzzHYezyO2ZSDFujy0cV1AAhsFTe/dyoKmJPjk5WIbheST85gPC6IyudvuYi7ZmIhQA9yDXlwpOkHjyUUSDqXuA7vGF4/LzmT9oEI+WldHTsgg7jj8CXj9yhGVVVWyoq/Ma7ELgNNLmExKU90DH5A1EWHaCOuliNdoFn0d65AKMzc/noX79sB2HA01NVDU1Je0s6RF4et8+Io5DT8vCcTtNgEoUuX0bhaErEtS5HknWa0ghQZEC3kXh7ihgEtIgCZOjM0pKOBEKETCSW4Sk0eDorVsxgEbbJmLbzB88OBkJw1Gmpxatyr648nL3sxlp+EuBacBLKHQejQjxBU8b4AC5polpGCzYu5c/JT4Oh1Gyo4RWdRiLrchYTUXhrhfKUCDVv416KxHp3VEE2a+N+knRphF0gLxAABNYtG8fa44eja9yCvib21fv+EJ3cMuRwHnIfXYLIiwe81D2aBFSiMkQBB5DBnMEsjG+SEjJC0RJaIpEWFd7QVzRSKsMDsQXIou+Bknml5Gx/A3wPDKSxcCXkYHMc9v0Qp7GCzuAGSgGuQ3lB7p4tkiAlHWAA3TLyuJkOMzqo0e5r7AwWtSVVm2fyMqfRIrxZRS8LHHr5yJfPgMZ0N7AD5AAehdlf9rCOjTpVxGxz+HtQi9AWkIo2zCoam5mXW1tLAE9UHgaJnnW54z7ARFRg1JVNciad0b5w13EafwkKEQ7pw9KtWWj4Cy5v0sCLwKi10+luOGtA2SbJj0tK7ZeF+TiavEOg6P40P1EMRUlPN9qo10BMBnlEQagyRfQeux+jFJnacGLgDmI6VuBb6BcXBHnh6kmcn15KHJLZfXisdn9JEM28Cha6eExz6uRDvk7sBHdMaStM7wIGIksa4E7iDFI+b2AjBjIbX0PRWdv0xqoXCqUAc+iKBEkel5DmaRD7vsOoejUF7wIaHFfcAzdsEwAym0YnmOaUQL6up/t6HrKC0PRDnqH1M7qQHRxOhJldBYCvyX9FJonvAjIRhI2xx1ME0CuaXbZceYMy6qqmF5SEm0fQKmynmin3IiIAZFoIUPZFSUu55I84wMyrIvR5CvREVif3tRSgxcBn6BAZwwyOnsALMMYXBMM8n59PdNLSqIJx5vQOQyjwMgLU1HecK1HnQeAiWjl53GZJg/eQmgbsurZaCUqABwY1MOyhu5pbGRFdfVelKLeiXz7EJQbeAUlPu8GHkHp8Rlo9XG/z0zy3iHo6ttAYulNf1NLDV7BUF/kBbYiO9APncG7DFjZGIk8YAOPlJYypbj4auSXHRQbHON8QWKh1RyAyBmFbMyz6DjE4gngaaT0xiP7c9ngGQ2iIzIBWfnfA59DOf+gAUsaI5HZeVlZ3NytG/WhEKN69WJSUZt5jxJ0Tf4YIuynaNJhZEdWoVulmcjjXFa0RUA8TJTYWABgwPKQ4zx/LhLZFrJtijp1ok9ODmPz85nYqhQToRPwMNoBYRQBLkUp7y1ot4zhIsLcVJFuTtBGiisCLHJgSpZhjOqelXXIgA1Ntr3og4YGKs6exUG/7EiCIApj+6OV/iGKDUqQp9hIevcMvpHuDogiC6WvZyBrnY0M5jCD1qzsw6WlTC4uTt6L3N1qtOUd92OisPmlNObhG37vBsPoWms7EihdcaO3aOhc1dzM/sb4H3lcgNPoJy0TkesLo9zBSp/jShsXezt8BqWlAsTk5RzAMk2yzZTSDSeQ2Klw+6jER1TnF+3xG6H/a1zxvxXuICDTA8g0OgjI9AAyjQ4CMj2ATKODgEwPINO44gn4LwUCxBjnaKoAAAAAAElFTkSuQmCC" + }, + "freefall": { + "icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAACXBIWXMAAAsTAAALEwEAmpwYAAAFIGlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS42LWMxNDUgNzkuMTYzNDk5LCAyMDE4LzA4LzEzLTE2OjQwOjIyICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ0MgMjAxOSAoTWFjaW50b3NoKSIgeG1wOkNyZWF0ZURhdGU9IjIwMTktMTEtMTVUMTU6NTc6NDIrMDE6MDAiIHhtcDpNb2RpZnlEYXRlPSIyMDE5LTExLTE1VDE2OjAxOjAxKzAxOjAwIiB4bXA6TWV0YWRhdGFEYXRlPSIyMDE5LTExLTE1VDE2OjAxOjAxKzAxOjAwIiBkYzpmb3JtYXQ9ImltYWdlL3BuZyIgcGhvdG9zaG9wOkNvbG9yTW9kZT0iMyIgcGhvdG9zaG9wOklDQ1Byb2ZpbGU9InNSR0IgSUVDNjE5NjYtMi4xIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjNlY2JkNGM3LTFhOTctNDgzMy1iMzk4LTBjYmRhMjE0MGUwNiIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDozZWNiZDRjNy0xYTk3LTQ4MzMtYjM5OC0wY2JkYTIxNDBlMDYiIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDozZWNiZDRjNy0xYTk3LTQ4MzMtYjM5OC0wY2JkYTIxNDBlMDYiPiA8eG1wTU06SGlzdG9yeT4gPHJkZjpTZXE+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJjcmVhdGVkIiBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOjNlY2JkNGM3LTFhOTctNDgzMy1iMzk4LTBjYmRhMjE0MGUwNiIgc3RFdnQ6d2hlbj0iMjAxOS0xMS0xNVQxNTo1Nzo0MiswMTowMCIgc3RFdnQ6c29mdHdhcmVBZ2VudD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTkgKE1hY2ludG9zaCkiLz4gPC9yZGY6U2VxPiA8L3htcE1NOkhpc3Rvcnk+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+jUiQ8QAACX5JREFUeJztm3twXFUdxz/3Jtkku0k36aYhJW1pSZNCqVJAqkUehRahaIEiD0WkIDAqIozO6IDAjIPDoyCCCoKPP3AEeYnDgANWoCBTUSt0QApji6WIhdJOSNqEJrub7P36x+8uuw2bbHbvTXYc+M6c2Tv3vH7nd37n9zp3HUl8mOFWmoBK4yMGVJqASuNDz4DqUhovXb++rEkERFzjdTKTocpxinVZAlwH/Br4eSlzPbVoUUm0TYoEeBL1rku965KWKLp8qANagYaJpm1SGNCdTnNGWxur581jWGIgkynGhNlABzAPqAEagdhE0DZpOqB7aIiuWIwburrISOzxvLGY4Pm/fcDBwMPA+RNB16QrweMSCa7t6qIaSBd3wvqA4/zSxQTQWxErsKylha/PmsXOVKpYUwcY8p8nxGUNkwF1QHzkSwfb6WQmE+JU4SEsBjQBVwJXjKxIS7TX1tIZK6rDXGCG/zxp3AqLAV3AVcBJwLTsSwd4J5ViWUsLK/fZZ68OSc8j6Xm4OZ9gX+Au4HJMmsKmsSBKcoTGwBC5XRvOvkxLzKyr46CGD5rzjmiUzliMZCaTdZLagYXY4l/Iazqh0jBh3HWx3T966lROHbH7AMdMncrpbW28mUxmpWAIM39D5BRfI/AXYA2wkZx5DA1BJWA6pp2z5X0kPY/Z9fUcOmXKqJ3nNzQwv6GB/uFhal034tPjkNuYOCYNJ2b7uI5D//DweD3KogjCgBim+A4FbgEGsxWu47AznebMtjZWtLbm94kAtcAAkDmquZkV06ax+vXX6Wpo6PWkrcCLwI5CE7qOw85Uik/E48yoqyPtBReIIAxoBOZjLutCIJmtSGYyzIlG+WRTU377jwPnYWd9I/BbYMsh8ThzolG60+lNLZHIBZ70MnCB38f1i+c6DjtSKTqiUa6aO5c59fUBSM8hiA7wgLT/m8wfq294mKObm/lcbvcXAg8C3wLOBK4B7gU6Fzc1cf28eUytqWHrwMCLSc/LuI6zC0gBO6ocZ/i9TIatAwN0xmL86MADQ1s8hGMFsmd/rCO5BDOVf8X8+i8DhwM3A2cvbmp674qODp7p6WFjfz//GRx8siUSOcWBzW+nUiyKx2mNRDi3vT3UxUN4ZrAaO9uO6ziRQc9j9/D71jAOHOU//wG4EXgJuB9YgcX85y1LJPqXJRI819vL1Zs397wxMLDGAxY2NnJlRwcd0WhIpH6Q8CBwMbu9E7jHdZzanqGhXa2RCCe0tGTbHAKcBvQC2YzKGuBrwD1+nYPph74jmpv5bkcHa999l4zEqvb2CVs8BGOAi8Xq1cAm13Fu7xkaitW7buqazk6OSySy7bK7/xzwTF7/+zDX9zpgJaYcfwCsPaGlZSCPgVlUAftgyncbsCcA7e+jJAbsTKctveU4JCKR3Z70gAvPJz3v+W2pFLPq6vZ8f+5cjs0t/mhy8cHT5HmJPn4IvAX8GFgEPAI8CjwG9GP6pRpoBuYChwEtwL+AO4AnCOgpOqVcjNz6xhvUuC7bBge5f/t2olVVJD2PudEoy1tbmVNfz8k5zZ8AfoGJ+BrgFEyzF8KBmE+xEhhL3kVO2Q4CnwHWjXsBBVASA7LYnkpx11tvEauqYjCT4YCGBk7Z2+GZAtwOnIOJ63nAU0WGjWJO1VLgIEx5VmOmdodf/gm8iTHrBODbmBNWPiSFWeolrZT0rAw9ks4sc6waSTFJVQXq7vDHXy0pEoTmoFYggmVvZ2EJzJOAz2NiuhO4CDvX5SA/KMrHNExfAGzCJKRslMuA/YFVmHs7A+gklw0aBH4H3AS8PEr/aZjW3wrsLnHuc7GjshWLFIOhRJGplTRT0t+1N7olrZF0naQl/lEYbYy4pNsk9Um6ugyxfdSf85Iwjm2pEnAYprEXYeL3E2A78DbwKma6iiF7VBqBT2HptF159dWYti9k3qYDM/3nV0ukvSBKZcBBWAQI5tj8rIw5XwJ+CZwO3M3ei/8C5iE+izG3e0TfTix11ovpmOAoUWQWS/qKL4KbJC0tU/TqRjkmD+Ydq5ML1J8oaUDSnyVND+MIlBoObwDWYva4CwtklpbB9yR5CZQ8rMc0/x8prECzxyMBhBMWlsm5BZIe8Xdqg0yxBd4NSY2SjpC03yj1CyVt8ec9Kow5g3ReIGm3T8zNY7RrlTQ7JAYh6XF/zgvCGC9IRmgjcKn/vATT5iMxA7gVs9fnBJgrH1nt/0VMIQZC0LT43zDf/FDg4gL1MzEdsS+wOOBcWfwGeN0f94DAo4UgRpf5IvlEgbpaSatkDs++IR6D+/w5n5E0o1JHIItslmc25iTlIwU8gEWEqzBHZizsh7nXtUXa3QRsAY4BLmPvq7TSEMJuzJH0isy1PbFA/ZEyV1mSbvTfVUlyRrSbLul+SRlJF45j3kskDfrjXispKsmthATswXa4hsKZ4e3AZixq2wCcgWWBvuPXz8NSXVOABZheGo9yuw3LJHnA97DU24wxexRAGAyIYZFdBsvbjcQW4EuYC70OuBBb8P5YbPErjDH7A9/EssYPjXPuy4E7/eezgbNKJT6MtHgc89F3YDtbCFvznu/DvL07sFulI/33nZj/v3Ycc1ZhuYj9yOmdPr+UhDAYMN0nZhujx//5uBdTjHuAf2PBTxy7JxgLrcCxwGcxxtVjiZhsBvZh4JXSSCewEoxK+qmviO4ucwyngELMLxFf4W2QlFYOGUn9kh6TBU6RIuMULEElYD5wCfAuJtrlYKys7CHYXcFyTF9twy5T1mE5iBQWFncXGWeM2YNJwDf83Xh8HG3jkhIljP0xSev98YclXSWLKaoD0hyaBNQAbf7zLv93CvBpzJy1Y8puN3ZWj8d2cTXFEylNwPXYBeo/sMuVtUzEp3IBObjC36FemVv6kv/saXQ8L6mryLjX+217JC0Lc8dHlrIuRvIQw+72Ls17149Ffy9gqasFmLT0YQFMF/Ak8FUsqBmJ5VjAk8AsRElfi5eMELhYJ0tinCXpeJlrPE0WCLmysx+XaeiL86Tjv5KWFxjvTr/+IUlTJ3L3pWAJkXLLIuVujrq1d/xwsKTX/LrTJoOeSjAAf2cf9hf6mqTD/fcX+e/WKWCYO95Sqb/M9GA64Ens2vsW7LP4w/36dZjNn3CE9YlMOdiBxfUHY6bzaeyyBHI5hglHpf809SfgVOyjCGHptfOB308WAZWUgCx6MWl4B3OaeiZz8qB+wP89Kn0EKo6PGFBpAiqNDz0D/getYBE04rS4SwAAAABJRU5ErkJggg==" + }, + "frontsideup": { + "icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAACXBIWXMAAAsTAAALEwEAmpwYAAAFIGlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS42LWMxNDUgNzkuMTYzNDk5LCAyMDE4LzA4LzEzLTE2OjQwOjIyICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ0MgMjAxOSAoTWFjaW50b3NoKSIgeG1wOkNyZWF0ZURhdGU9IjIwMTktMTEtMTVUMTU6NTc6NDIrMDE6MDAiIHhtcDpNb2RpZnlEYXRlPSIyMDE5LTExLTE1VDE2OjAxOjMxKzAxOjAwIiB4bXA6TWV0YWRhdGFEYXRlPSIyMDE5LTExLTE1VDE2OjAxOjMxKzAxOjAwIiBkYzpmb3JtYXQ9ImltYWdlL3BuZyIgcGhvdG9zaG9wOkNvbG9yTW9kZT0iMyIgcGhvdG9zaG9wOklDQ1Byb2ZpbGU9InNSR0IgSUVDNjE5NjYtMi4xIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOmMyODhjMTIyLTcyMTctNDAwOC04N2Q4LTE2OTVjYjc1MmIwOCIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDpjMjg4YzEyMi03MjE3LTQwMDgtODdkOC0xNjk1Y2I3NTJiMDgiIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDpjMjg4YzEyMi03MjE3LTQwMDgtODdkOC0xNjk1Y2I3NTJiMDgiPiA8eG1wTU06SGlzdG9yeT4gPHJkZjpTZXE+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJjcmVhdGVkIiBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOmMyODhjMTIyLTcyMTctNDAwOC04N2Q4LTE2OTVjYjc1MmIwOCIgc3RFdnQ6d2hlbj0iMjAxOS0xMS0xNVQxNTo1Nzo0MiswMTowMCIgc3RFdnQ6c29mdHdhcmVBZ2VudD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTkgKE1hY2ludG9zaCkiLz4gPC9yZGY6U2VxPiA8L3htcE1NOkhpc3Rvcnk+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+4K6CtQAAByFJREFUeJztmmtsHFcVx3+z69pre23iOE5DU9EmTrs2aeoG0agKhBInoCQtldoqanmoLR+oBAghCFJ4KgI+FJkQKhAgiFARSKGAqNQWQaFPHi2NRSgKJGmakoSmpHFaBz/WcdZs9s+Hcze7dnc3M/HMTiX8l0a7c+feM/975txzzj0zniT+n5GIm0DcmFNA3ATixpwC4iYQN+YUEDeBuDGngLgJxI2GIJ3XDQ5GweHjwA6gERgAts5W4OOrVvnu+0awgLdgkwdYAqTrefO4FXA1cEPZ+WZgYz0JxK2ALDBedn4KGK4ngbgVcBj4adn5/cAf6kkgkBMczed99y0AKc+jtaGBQu0t92+B54Ee4FdA1ZskPI9sPs+UhOebSW0EUkB/Z6fvvk2JBIdPn2ZfNktXY2MtJaQoOcGqfBKex8mpKVa2t3NpKsVUoeCbSy0EUsBAJhNI+P5sli0HDnA8l2NhU9P5LKEqEp7HyVyOy5qb+VJ3N90tLRckp6Ls0CRVwFvTabb39vLmpiaGcjkSXnDDTXgeQ27yO3p7Q5081MEJLk+n+UZvL4tTKYZyOZIBlJD0PE7kclzuJr8s5MlDnaLA8nSa7T09LE6leMWnEpKex/FcjqUtLZFNHuoYBpen0wxkMvS0tpL1EU2y+Twr3JioJg91zgNWtLWxqauLI5OTNa0g6Xkcnpzk1kWLyLS2Rsqp7onQdfPmsbK9nZfPnKmkBC/peRw7c+Zcv6hRdwX0ptMM9PTQ19bGuC2FJkp5QHIsn+ft7e0MZDKhe/xKiCUVviqdpr+zk71jY0ycPXs86XmHkp53cDyfP7p3bIwbFi7kyohNvwgv4jdDFwF9wFJsk7MXeBXgL6OjPD0ywp7RUZ4cHl4haN7Q1bVneTp9dl1nJ1e3tRVlpIGVwELgRWA/8N+wCEapgEXAFuAOjDzA08BO4GFs58fgyAiPDdsGcFNXF9fYuveAS4F1wAeA67Fl8hLwA+A7wEgYJKNUwFbga8Ae4D5s378Bm9wB4JfAC9hGaBib4MXYpmg1cCMwH3jN9S0At7m2jcAjobCUFMWRknSfDFtcW5ukTZJ2SnpNJUy68wlJZ13buKSnJH1G0rKy8X92128Mi2ugzVAAtGMmDDDkfseBX2NP7h7sSfdhZTAwh3wS8xN/Bw4BU2Uy34GVz0JFVAq4ElgP/AN4asa1AlYIOYwpxC96gUvc/1Oz5HcOUYXBfvc7CLwcksxi1vRMiDIjUcBtwJeBo8D3Ao5tAJJVru3HPH8f4L8ycz6E7PzeLynrHNUnKlxvl/RZSc9J2irJK7v2TkkPStotaW0V+Y862T+XtCAMzmFN/GJJOxy5MUkfqdKvW9Izrt9PZlzbphLurDJ+laQXw1TCbAYnJK2UtF3SS47UoKQ1NcZcJKlf0oclXTbj2jJJH5K0QdK8GjLWSzrm7vd7STdJaqyXAhKyGP9BmTmOOSL7JN0tqXO2T8Tn0SPpF5IK7v6PyJbWfEkNQWQFzQTXAN1YZnca2IWVsgeBV0JzTP7QAazFnO77gGbgC8BBLHP0h4Caf1i2BgtO437HNUpqDtC/OYBZN0u631nCXyXtCjKnoGFwHBjFYvLtwL2UYn419GNJzy4s+zsftmE7xk+dp98ybLP1Q+Ba13YJpQzUF4Jmgr/BJvM2LB73AXdir7fuAY5VGNMBLMZS3BM+7tENtFIqksxEBvgkptil2Ja7iJ3YEvCPgEtgvqTLJX1d0hFNxxOSVlQYk5J0naR7Zd77c5LSspzhi5LeJOm9kv4p6buu7zWSOirI+pjrV44RSb+TdJekFpmj9j2nC/XCjTJPfIekv5WR+ZOkJVXGFPOEr8hCZTFh6nfkJekBWbI0c2yTpG9Kypfd63lJX5X0Llk+4FUYF5kCyo+MLCkp4kdV+i2RdL3MihZI2izpdkldsri/Vq/PDYrHNk3Ht2UPINDTjkoByDLBhxy5vSrt4cM4Nks65WRPyPKNC3raUSoASdeqVNxYH5LMlKTHVcLdIfJFCh4Ga+EY8CzQAjVf3yexsHUXFk1qYSMWaQC+hSVgoSLMgkgHFpsneX3VtgH7HugKrFByM/ZdwAngx8CTWG3w1RnjrsK2vgXggQpyZ48QzWmDM9NHy9qWykLbbtmG6T+SpjQdpyX9W5Zh/kzTt8Lfd312K1y/cu4I0wKKspYAn8as4Was0jtzSRzElsxqbMk0u/Zu4D3AH4F9wLtd+3OEWAUqR5hl8TWUPnCawqpNRaWMAA+560eBI9gXYh1Y/XA1cCu2RCrh81imGT5CNKdislKOQ5I+KukKWVm71tgFkm6R9OwMGQ+6pRS6+SvkKJAD/uX+TwETWGn7Bdc+QfXokMdegBzClkex6juELYXREHlOQ9TvBt/wiPtDydgxp4C4CcSNOQXETSBuzCkgbgJxY04BcROIG/8DWEVpKnxIqAwAAAAASUVORK5CYII=" + }, + "backsideup": { + "icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAACXBIWXMAAAsTAAALEwEAmpwYAAAFIGlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS42LWMxNDUgNzkuMTYzNDk5LCAyMDE4LzA4LzEzLTE2OjQwOjIyICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ0MgMjAxOSAoTWFjaW50b3NoKSIgeG1wOkNyZWF0ZURhdGU9IjIwMTktMTEtMTVUMTU6NTc6NDIrMDE6MDAiIHhtcDpNb2RpZnlEYXRlPSIyMDE5LTExLTE1VDE2OjAxOjIzKzAxOjAwIiB4bXA6TWV0YWRhdGFEYXRlPSIyMDE5LTExLTE1VDE2OjAxOjIzKzAxOjAwIiBkYzpmb3JtYXQ9ImltYWdlL3BuZyIgcGhvdG9zaG9wOkNvbG9yTW9kZT0iMyIgcGhvdG9zaG9wOklDQ1Byb2ZpbGU9InNSR0IgSUVDNjE5NjYtMi4xIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjhmODFmNzM3LTQ5YmEtNDE3Yy1iMTgxLTJjM2VlZDNhNmVkMyIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDo4ZjgxZjczNy00OWJhLTQxN2MtYjE4MS0yYzNlZWQzYTZlZDMiIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDo4ZjgxZjczNy00OWJhLTQxN2MtYjE4MS0yYzNlZWQzYTZlZDMiPiA8eG1wTU06SGlzdG9yeT4gPHJkZjpTZXE+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJjcmVhdGVkIiBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOjhmODFmNzM3LTQ5YmEtNDE3Yy1iMTgxLTJjM2VlZDNhNmVkMyIgc3RFdnQ6d2hlbj0iMjAxOS0xMS0xNVQxNTo1Nzo0MiswMTowMCIgc3RFdnQ6c29mdHdhcmVBZ2VudD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTkgKE1hY2ludG9zaCkiLz4gPC9yZGY6U2VxPiA8L3htcE1NOkhpc3Rvcnk+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+8JKB6AAABltJREFUeJztmltsVEUcxn+nXWy3u2xboLRYAdtC2YohKgZBfUBFIwIBQ6IPmgjxkhgTNcHEqFFjjA+Ct8RojJIYTJQHE0OMMV7wfqXihYhCUSRAUbw0bm273dLdfj7MtLuUEnvsnD1N6JdMdrJnzn+++WbOzH/+M54kTmWUhE0gbEwIEDaBsDEhQNgEwsaEAGETCBsRP4Uva20NikcdUA0cADJjNfbeokWjLjteRsA0oBGoKHbF40WAe4A3gEuLXfF4EKAMmGrzfcWufDwIMGBTKBgPAoSKCQHCJhA2fPkBYaPE8+jKZjkm4Tmy6UuAVH+/L+MDEuWlpcQjEQbGGHgp8Tz+6OtjYSLBzGiUYwNu5k1fAlxZU+PLeHlJCft6etjV1UVtWdn/FqHE8/i9r4+GaJT75syhqcKdv+RLgEeam31XsKe7mw1793I4k2FGWRm5E0XI2QQnWQ7TuRxnxeM83NzstPFQhEmwJR5nUzJJMhajO5sdqUikgMdpwx+Weh4H0mluqK9nruPGQ5FWgfnxOFfX1nKgt5dS74TpazmwxOZvBmYPPij1PNozGRZXVZGMxQLhVrRl8LzKShYmEhzJZApFmArcitkJghFj9eDDrmyW8xIJNiaTNATQ+1BEAZKxGI+3tNBQUUF7XoRJjDDswfT+L729rK2rY05AjYciO0LzYjEeTyZpzItwFHgG2A/8DWwr9by3unI59nR3s3TKFM5NJALl5IVxMNLW08PdbW18lUoxMxolEYk05KSGUs/bdai3t+Oi6mqS8TjLa2o4Ox4PlEsoAgDs7Ozks1SKrzs7+aCjg0QkQmc2y5LqajbOm0dDNFoUHsUQoA6YD3jA15ihPoTWVIrtHR1URiKk+vtZVVvLgsmTC4uUArMwEaO/gD3AMWfsJAWVyiXdKOlHGQxI+tj+VzOK96OSlkp6XtLv1sZBSU9IqnPFM8gRsAp4HTgMvIxZ31cACeAQ8BqwA2gDeuw7VZieno8Jj12AGQEfAF8C1wBNwC3ACy5IBrkbHNw4vIOJ+XkYh+c6YCVwp33eRz4SHCW/LLZhVoi3gQ+BNNCMEWCuLTfmTyFIARrt7+A3L+Bzmx4GFgMLMHPEAEagY5jR8T1mdHQV2JuOmQvAiOFva3oSBCVAHXChze8c4flRYJtNo8U88qNqP0bQMSMoR2gxcAnQCmx3ZDMODG4IDjmyGYgASeBRm38J6HBkdyfQbvPunATHS9+Zkr6wS9bmAJbWzdb2XklJFzZdEYtLul3SAUvweUmVAQhwhqRvbR3fSGoKW4DJkm6TtMuS+lXSekkVATR+MM0vqO8HSddKmlRsAc6W6eV9lkiHpIdc9MgoU4Ok5yRlbP1fSHpAUr3tlMAEmCFpkUxPS9Lnku6Qo+/RZ4pKWiFpi6Ruy2eLpHuDFGCD8hPRlhAafbJ0u6S05bXfz7t+HaE0eb99MfAUxk3d5mxZGj2mARcDSzFO12Bbpvuy4lPpZkmrdTzSkrZKWlik3q6UmXg/ldQ5jMtHkl7wY89v5RFJVZIelLR7WOX7JK0KuPHLJL0vqX9Y3bsl3S9ptqSpQQpQKESjzBL0SQGRdklXBNT41ZJ+K6hrQNIrktZImmM5+bbrgtgsSS8WEHtPUonjxq+V9FdBHdtkRkN0rLZdESyX9KQld1TSSoeNr5fUWtD4x+TQ0XLZS03Ke2gbHNp9oqDxT1uxnfF2uRvcD7xp85P+o2wzcBNm+RrxYMSiCjjf5r/HRIjGfI+wEC4DIjFMIARGDlXVAC3AMmAd5jhMmHjhZuAn4J9h71yIEQtbZq9DvoBbARqBNZgg6GAQZApwPSYG2ITZx1dy/IXIdZgAahr4GXgWc2cQoB6otfndDrkOwaUAFZiIbwRYC1yFadxsoHxY2RywC5iMCXDW2//nYry7LzER5TX2/69wGAUqhMuweCOwFVgE9GICnYVn2jswc8R3mIjvPxgBFgDnYk6Gz4Gh6z99mIjVJOBdYD1wxBXZIbicUSXdpePRJWmTpAWSpuvk+/YyGQ/uYkmvSsoV2Dgk6XLHPIeS64ORckwvnoOJBe7AHGelfdioBE7H9LyAFPAbMOL1krHCdVg8AxzEzPB/YoKYfm+0pTHfewlGgCz5O0TOEdrp8HjBKX9TdEKAsAmEjQkBwiYQNiYECJtA2PgXQXgFRDEfffMAAAAASUVORK5CYII=" + }, + "impact3g": { + "icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAACXBIWXMAAAsTAAALEwEAmpwYAAAFIGlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS42LWMxNDUgNzkuMTYzNDk5LCAyMDE4LzA4LzEzLTE2OjQwOjIyICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ0MgMjAxOSAoTWFjaW50b3NoKSIgeG1wOkNyZWF0ZURhdGU9IjIwMTktMTEtMTVUMTU6NTc6NDIrMDE6MDAiIHhtcDpNb2RpZnlEYXRlPSIyMDE5LTExLTE1VDE2OjAwOjU1KzAxOjAwIiB4bXA6TWV0YWRhdGFEYXRlPSIyMDE5LTExLTE1VDE2OjAwOjU1KzAxOjAwIiBkYzpmb3JtYXQ9ImltYWdlL3BuZyIgcGhvdG9zaG9wOkNvbG9yTW9kZT0iMyIgcGhvdG9zaG9wOklDQ1Byb2ZpbGU9InNSR0IgSUVDNjE5NjYtMi4xIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOmZhNTA0MzFiLTQ4NWMtNDZlNS1iMmM3LTFiYzQ2MTQ3NjRlNyIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDpmYTUwNDMxYi00ODVjLTQ2ZTUtYjJjNy0xYmM0NjE0NzY0ZTciIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDpmYTUwNDMxYi00ODVjLTQ2ZTUtYjJjNy0xYmM0NjE0NzY0ZTciPiA8eG1wTU06SGlzdG9yeT4gPHJkZjpTZXE+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJjcmVhdGVkIiBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOmZhNTA0MzFiLTQ4NWMtNDZlNS1iMmM3LTFiYzQ2MTQ3NjRlNyIgc3RFdnQ6d2hlbj0iMjAxOS0xMS0xNVQxNTo1Nzo0MiswMTowMCIgc3RFdnQ6c29mdHdhcmVBZ2VudD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTkgKE1hY2ludG9zaCkiLz4gPC9yZGY6U2VxPiA8L3htcE1NOkhpc3Rvcnk+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+3RFC0gAACfxJREFUeJztm3twXFUdxz97N9ns5tGGpIEWaPrSVl4yQ20KDlqsjAyvEanyEOXtdEQUEBUQCvIoD9GKoozWAh3RURRay0vAoTBAeVooUFtamzalCSkxTZtts8mmu/v1j99Zskl3s7lpkmWk35k7N3Puuef8zvf8zu91NwFJfJzhFVqAQmMfAYUWoNDYR0ChBSg09hFQaAEKjaKRmujxlhauWb+eMaEQgT0fe8C5QCfwEJAcxBQBIAzMBi4GKoDzgG3P1NV15XppxAiIBINUFheTkCgO7EFBCDgQSADFDJ6A/YFaYDywnxsrC989GDECZldX05FKcenq1XyyrIw+8ecRwHcwEiqA+UDOXeuDEmAKtvNXAhNdewzTrI8GAQBlwSBTysroTqUo9nqZnwr4kJPrMKFvoX8SRgGTgNOBH7PnWq4DmjCtyokRNYKzq6q4YuJEGjo78XofgwPd1YbZgWuxBYSzDFMDzAQWAKuA64FdwBPufYDngEVAnDzHaUQ1AKA8GGRaWRldySShHi0IYbv+d2AdMA8jIYAtMImd66OAbwEnu/eagPXAXUAHtugI8BNg50DkGW4CKoDdZKjyF6qr6UyluGzNGmojkXRzrbtHgZ9ii7kTU+0OoAG4AviM61cPrATuBl7ENHk1dv5/Cbw6UAGHi4AIcBZwDLaoZ4F/At0Ard3dxFMpvECAlKXjIfdeg7v/BjNuN2MGMY1/A8vd83UZ7TcD0zCNWMDADeiwEBABLgduzWi7ErgM+BVAbSTC4RUVRBMJSjzPw841gOcFAuxMJAgGAgtKPa8kBXOB7cCjwD3A1j7zHYEdCw/4AfCeH2GHg4DDMNXtAh7EDNmZwE3AFmDpcVVVtHV3c/Hq1RxSXu6VBoNTUhJeINDYEo8zs7KS9kSCd3buvC3iec8D7wLbyoJBSjyPVM9cEeDnGIHPAP/wK+xwEDAWKAdeB87HdqYCOAn4GbAJWFUdCnHG2LG0JRKJt6PRpaXBYFNHMvnq+HCY26dOZVNnJ4saG6kqLl6RHvjNaJRt3d2MKipKk/BN4HPAZiz6a/cr7FATEAJmub83uHsK+C5moA4F/gJcMquqavmsqipea2/n/sbGu2tCIVrica6YNImqUIiqUIjpo0f3GnxZSwv3bN5MZzJJsedNAK7CNGwNRrJvDDUBU7CYPg48mdG+EZiDLf5I4GnMLjxdN3r02ro+C3WoxIKdALbDfHn//Xltxw4e3rqV8ZFIbUqKub4nApOBPwIrgLXsaSuyYqgJuACLx1dgPj0T7wJfwdzUqZjv3gDchxGUDl3D2DH6LEZoAgtyfgHsPHLUKFZFo+xMJF4o9ry5wNcx9zgT8wYAjwN/c3J0AY25BA4MYVX4QuBebPcvAP7cT995GAkz8oy5C7MnADdiMUJsfn09DzU3UxVKe0/KgOMwLTuHHre6FtjyTF3dCbkmGCoNOBfzv2Bq2N/iwXZqERYrHI7teKV71ga0Yru2HNOEq4DvA8uAN1N7blo6WFoJfA0jYDfQDGzrT5C9JWAq8A1sR3ECz8/dvReaMbVOoxI779v79GsALsFlim9Eo2yIxQgHg7j+szFtuizjnSeBpZhGDmkuEMaMzQQsLj8D+LR79iAWt2/yOWYaO3K0n40t/l/ApnsbG3llx47y2khkdko6ASMHLIl6DIsHfg+Z4UJuDJSAszEjMxaYDnwi49nLwF8x45bLoEzGbEPTAOdLoxw4zf29CNgyPhwm4nlzUtJi196JRYkPAkt8jp+XgJOwRd/bp30t8Bq2K0uA9/OMcS1m5ecBr/iQbxYW428FXnqqtZXX29spLyrqwHKLjZiHeMTHmL2Qj4BbgYMwdVqGna0WjIB1/byXiS9ihgxMaL8EjHJzr2/bvZuOZBLP6oZPYKTuFfIRcJjr0wx8j378aT94GMvlu4CnMtonYRFiJbAYeD7Lu+PcfSUQP3vcON6KRlmydSsTSktjWbyBb+QjYD1mgPbDMrx52Jnzg5fc1RfHYTk+WOqbjYC4u29JNxw/Zgz1sRjvx+OEvb0vaOUb4QZ3hbHQ9db+u/vCm8AbmNd4MkefoLt/GPEcX11NbSRCazzet6w2KOTTgIecEAcDP8S0YCUW7OwtVmHZ3GjMk2RDurBxqJMjCXBKTQ2rolHWdXRQ6nnUhEKEg0EGcyQG4gaTwI8wYzQXq7c9Su7UczLwXwZWk1uT53m9u88BFuJs0BeqqykNBnln1y5KPY/FTU2s6+igNhwm3LtekBd+coEDsLNci1Vs78jS5zTgauAdLChq9iFLNkzEostJWCH0iWydXty+nfpYjD80NVEfi31oGw4oKSEYCLC8ri7nBH6TobnAb4G3gM9j9b5M3ImVpToxtW3wM3gOLAIuwrLLc+jH9b3Q1sZ7XV2UOALuamggmkjw9rHH5h5dkp9rkqQWSTFJc7I8P0rSjZK+5HPc/q5ZkrZJSuaYM+e1vLWVRz74oN8+foUplbRQhhty9DlC0gJJp+UZq0TSdEk1A5h3sZtznaSDhpBc3wQEJF3qhFma4/nt7vmqPGOdK+ldSQ9IOjhP3ymSNrpxV0g6ZKgI8BtJZDre2hx90gnPy1jJegnmTqe59qPdfaprOx0Yk2feeiwha8bC6pvoKaXvHQbB2rfdTjyW43m1pJMljZV0oXpwnqRzJG2QdLmkyZKuce1lA5z7aEmbJe2W2Zu91gC/9YASLDmC3HnBNqwmBxbeLsS8wrNYSWsKtpt3AbcNcN50MDYNS5GL6IkS9wp+CSjHMrQk9pkqHzZglZoirL63EHON2XKDvpiBVXoOwdS9xv0dAB5g4Nlo//CpMjMkdUl6z6nwkFnjjGu6pD+px+hloknSHe54Dcl8fjSgFDNYJVgCs3FIdqA3zseKJ+mK0wqs2vQfLOiKYprnJ9rtHz7YGi/zw9slnTmA/vlcW9/rfEntbqeXSzpBUu0wadmgNCCE5QNdWDkMzCjNwGL2Euwjhoe5uMOwdPdq8n+lOQsziqOA32E/jxlM8cU/fLB1gKQX3A6tlPS0pPWS4lnOaiYuyjPuTEmtru/9ksqHe9czLz/JUBA4Hitfjc1ofws7l2ux8tZ0en6tcQoWvNyEJVHZcDdwKeYZTqXndz4jA5+MBSQdKulESRfIApMJkirdsxJJB8oCm09JesXtbFTSryWF+ox3rOzcxyV9dSR3Pn0N9wS1kuarB/epd9R3i2tf5sj7vyMASWGZHYhJSkm6zrVXSHrOETC3EIuX/IfCg0EX9mFlHPZR9Cp6Sl3HYKFzvtLYsGEoP4/nQylGxFlYQJMAqrCvOmfi45ddQ4mR/KFkDPu40owtOIyVua6nQIuHkf+l6C7sZ2ybsMBpC3t+Dh9RjOQR+EjiY/8fI/sIKLQAhcY+AgotQKGxj4BCC1Bo/A8o4RWazeFlBAAAAABJRU5ErkJggg==" + }, + "impact6g": { + "icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAACXBIWXMAAAsTAAALEwEAmpwYAAAFIGlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS42LWMxNDUgNzkuMTYzNDk5LCAyMDE4LzA4LzEzLTE2OjQwOjIyICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ0MgMjAxOSAoTWFjaW50b3NoKSIgeG1wOkNyZWF0ZURhdGU9IjIwMTktMTEtMTVUMTU6NTc6NDIrMDE6MDAiIHhtcDpNb2RpZnlEYXRlPSIyMDE5LTExLTE1VDE2OjAwOjQ2KzAxOjAwIiB4bXA6TWV0YWRhdGFEYXRlPSIyMDE5LTExLTE1VDE2OjAwOjQ2KzAxOjAwIiBkYzpmb3JtYXQ9ImltYWdlL3BuZyIgcGhvdG9zaG9wOkNvbG9yTW9kZT0iMyIgcGhvdG9zaG9wOklDQ1Byb2ZpbGU9InNSR0IgSUVDNjE5NjYtMi4xIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOmE4NTc4M2Y5LWIwM2UtNGVjOC05M2UwLTQxN2RjNjQ1MzRhNyIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDphODU3ODNmOS1iMDNlLTRlYzgtOTNlMC00MTdkYzY0NTM0YTciIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDphODU3ODNmOS1iMDNlLTRlYzgtOTNlMC00MTdkYzY0NTM0YTciPiA8eG1wTU06SGlzdG9yeT4gPHJkZjpTZXE+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJjcmVhdGVkIiBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOmE4NTc4M2Y5LWIwM2UtNGVjOC05M2UwLTQxN2RjNjQ1MzRhNyIgc3RFdnQ6d2hlbj0iMjAxOS0xMS0xNVQxNTo1Nzo0MiswMTowMCIgc3RFdnQ6c29mdHdhcmVBZ2VudD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTkgKE1hY2ludG9zaCkiLz4gPC9yZGY6U2VxPiA8L3htcE1NOkhpc3Rvcnk+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+DddyDAAACyZJREFUeJztm3twVNUdxz+7SzYJefIICa8YsCIBERULtpVaW7XVOq21ascqKmqLnamIWuujMxZsfbZWUGurBaWKjuhYCz5Li46tLdWRasRQkBACAUVEiBA2r9399Y/vWXdZdjc3z2WmfGfu3Lv3nj33nO/5vc+uz8z4f4Y/2wPINg4RkO0BZBuHCMj2ALKNAX3Z+YqdO5m9di0j8/K620UAOBM4AngC+KCnY1o5dep+nw92CRgADAMqgNy+esHBjEuB+UAQqAE29fYLDmYJ+ALwUzR5gPK+eEk2CMgFDgOKM7QpA+4FqoA9QBgYQ5wMr8gBRgDjgXxSqFGfEhA2ozUaTX7JicAK4G5gXIqvlQAPA8cDrwN3AU3Al4FRHl89FDgKuBp4Gvgv8EVgQnLDPrUBQ3JyGFdQQEskQtD/GQ1HoomPA84FrgeeB7Yhq/8LZPl3Aj8GPgGuAD4HDAHq07wuFxgNTARmAt9OeNaKpCia/KU+JWBaaSk3HX44F9bUUF1YSFSJVx2wD4lnCfB7tNJXAie4cwtwLTJ8AaABrX5RiteMACqBM4DLgeHuvgE+d30r8E9Ewn7ocy+Q7/dzdFERe8JhciUFjcBWpOcvI/08EXg74WsPAI+76wiww10PdedCYCwwDZgBTHf3Q8DfgY+AryM78wJwJykmD/1gBKeVlvKTMWPYGArh9/lAor4ZGAwsQdb+MSTqAH8CbkcTj6HBnb+KbMGvgNXAQ2jy65EazQJOAnahydcjgjrSja8vJKAIBS7taKIMDASYVFTEjvZ2yoLBPVGzja7tVOAl4CLgW8hQzSdORgx17jzLHaBJvovU52HiMcL1rs2naPK7Mw22twmYAMwBTnYD+CPwyAmlpc33Vldzzbp1fBoOk+f3r3PtK5CeGrDc7/Mt3xcO0xaVrRoYCJAXCBA1W41WczRQC7wFLAeeS3r/V4Cb3fVcYFVnA+5NAsqQQZuecG8KCmDmji8sDM+uquKSmhomFRfvdgZxIpDv9/lC+8JhPuno4PiSEqry8wFYs3cvH7S1MSgn582o2e1IrB8h9aqOBZ4EBgJPAfcjYjOiNwk4Gk1+F3ATUIqs740oiXmgdMAAji0pYVtra21Fbu56oLE5HPbvdBM/OhBgdlUVEwoLASVT8+rq2N3RwaCcnIXR9OW7ImQPypHnmEUao5eM3iLAh6w5yAo/6K7LUTByJ/DJCaWlS+dXV3Nlbe079aHQeT4IHV9S0nxscTFXVFYyqWh/L3fa0KH4fT7mbtjAlpYWhgWDMZVIfv/PgK8BHwMXo8DJE3qLgEHA+e460Z3djFzXDCS6JUcWFCy5b+LE0G83b37XB8wcNYpjitNHxacMGQJmvLxzJ1tbW9nW2poYVOHeey0Kcm5AEuAZvl6qCp8OvAhsB05BhiqGPCSeM9znRSi3r0FxfqKLKkYRYgnyIquRbwfgrk2bWLJtG2XBz1KCCcArSNLuA66iE71Prgf0hgSUIJ0HubTapOetSCd3Ind3mTteQEFRA4pHyoGRwGmIiAjwKHCLa0NLJELAFwvuGI3cXznwZzeGLq9mTwnwo6DlRBStzU/TrgW4Bq3WTBSsfDNN2ybgX0C1a2vAbBQ+J2IWigRx/TZ3Y/w9ImA4Yv1HSFxvQIFJJjzvjlNRUlSJJAg08c0oqvs38F3gd8A3kItb0xQO0xKJ4A8GiZrVoKhyJHCbG8+THsawH7pDwAgUjs5E4hpFwc8jXejjr+7IhEZkHwwXFp86ZAgNoRAft7eT6/c/jVzuxci+3Aicg/z/E0jlOoUXAsYiK1/lrk9HkR5oBeYBf/Dysi7AjwguQflCA8AZZWVsDIV4qLGRYTKEK93xCiqfTQcWIAlbhKQtYzyQjoAByHrPQ6s9BuXiMWwGXgMWA6+m6aMCSUgtsuZdwXjkTaLAMpwnWNXUxBtNTRQFAsntFyPx/74b85nIxtztPqe1D+kImOsmcJn7vAWJ5Frkvl4D3sgwAR8SzTuADcAlyLB5xSlIp98C1sRuPrdjB6uamhg7cGCqYGgwUplYFulDbjIn04vSEXADKkQ0AdehyTbTtapslTsfgcLiRAxHErWe1KnqZHd+FsUW1OzZQ30oRLkMYGLb6SgJOgeF46BFWkb6vOEzpCMgJmNNwMJMHaSBue/tQ9LzUsKzqch1DkWS9myKMZW56waA13fv5ta6Ora1tVGRm0tEBJyKPMTFxNXzVZQh/gVJa6dIR8AatGpVSL+uBPZ66TABq0mt+yejwgbunExAHsroQJVcln30Ee+HQhw+cCARs7OBs4GzgALX7gmklstQNcgz0hFwDdKphxDDEeL2oKdYAXweWfqnUjxvJR7+tgAMysmhMBAgYjaPeL4PqiS94PrpVkyfjoC/ubMPFTUuRVIxvzsvScLbKCQOkFqqwsRrgJUAuzo6aI5EKPf5AhGz91CBcznKP3qEzmqCS4nH+XPY3xUmYjDy25PTPE9GiMwqFbP8M4BR51ZUUF1QwIdtbbcEfL6zUZm8x5MHb0XRhcA6VJa+KsXzfBSrLwR+iSq2PcVzwEbkxqZNKy3lzvHjGZWX1769rW2DP54Q9RheCGhGsXaA/TcbYoiiSNGPEhhPlZhOUI/EHKR+RRMLC/n1+PGMzMtj7d69bG1tpS0apadkeK0HjEAFxhLgOxwY/VWijLAeJTK9gemoRB4rqCwBqG1uZm1zM/l+Pw82NvL2nj0UusiwLBgkz+8/cPsnAd2tB+xFK3I+2oFJJmCLOy5Be3r3Z+irHLjQ9fGfDO3+gaz81agm8D7w5sTCQia6muHo/HzqQyHyXIXonoYG1u/bx2H5+QR9Pk9uwSsBrcA7iICCFM8HI/0/CdXwF6GKb4gDA5LrUAnrNbSVVUd63AUc5/p9DPieGwcAk4uKmJxQRxwWDPJhWxv3NDSwMRSiMj+fnE6I8EpAB/H0MlXoGiK+lbUYOBaFoVuRy+tAoerjxH38UFQSy4TtyAY8iPKD29zn7akaTylRaWF4bi4ft7dzR309m1payMlgJ7wSkEN8Xy7VHn0rmvAKlClehGp7o5Eun+QGPsFNohaJ9I4UfSWjHuX6U1AqPpY0BMQQI6IsGGR3OJxYRjsAXgkoQLptqAaQCmHcVhjK0X+IbMcq4AeIuCq0R7DUwztHJxxnIXe7Hm+kAXEiMsGrFyhHK9aB9HCl10E4TEASUYvS43QoQ7W+L6FSVwUKvmLuejbaOY6k/HY34IUAH3J9z6AVrsbF6L2MOcjdHZdwL1aHaEQx/3I6txtdghcVKEVhLkjHe3vyo4DfIJIHoAhwAfAeUpdmZDgz5vXdhpl1dowzszYz22ZmR3XSdoqZnWdmFR76xczGmtlKi+PnZnakx+/2yuFFAgLIgBkKeStRHj8VWeQgsg1RVOouRqWs2chuZMIc11cL+j3Qo/ROKO0dHlgaZmavuxXaYmbrnUR0hps76fd8M9tnZh1mdkV/rnri4cUI+lFUt4B4OfwtVOSsQTpbhqz8emTBr0bltEfRzm1yVXYEquJOR1b9Kvp75WPoAlvDzWySmR1jZiPNrCDp+QB3HmxmixIk4UUzG5PU9gK38u9ZP+t88tFXHZeY2eVm1uRIeMbdw8xyzWyxu39bNifflwRgZj4zO8vMdplZxMwWuPtHmNkHZtZuZmdmm4C+/J2goW3rYSiZmYU2USNoX6AG+frsoh9YzjGzey2OmAeZa2b+bEtAb/1CpDMUol9uXoAiy6Wolt/VvYZeR3/9YaIVpbAforB2O32TT3QZ/SUBBy0O5n+M9AsOEZDtAWQbhwjI9gCyjf8BG+uU6Oq1I6AAAAAASUVORK5CYII=" + }, + "impact8g": { + "icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAACXBIWXMAAAsTAAALEwEAmpwYAAAFIGlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS42LWMxNDUgNzkuMTYzNDk5LCAyMDE4LzA4LzEzLTE2OjQwOjIyICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ0MgMjAxOSAoTWFjaW50b3NoKSIgeG1wOkNyZWF0ZURhdGU9IjIwMTktMTEtMTVUMTU6NTc6NDIrMDE6MDAiIHhtcDpNb2RpZnlEYXRlPSIyMDE5LTExLTE1VDE2OjAwOjM3KzAxOjAwIiB4bXA6TWV0YWRhdGFEYXRlPSIyMDE5LTExLTE1VDE2OjAwOjM3KzAxOjAwIiBkYzpmb3JtYXQ9ImltYWdlL3BuZyIgcGhvdG9zaG9wOkNvbG9yTW9kZT0iMyIgcGhvdG9zaG9wOklDQ1Byb2ZpbGU9InNSR0IgSUVDNjE5NjYtMi4xIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjdkYmNhMTNiLTJjNWEtNGNkZi1iOTdlLTc4YTcyYWMwOGVkYiIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDo3ZGJjYTEzYi0yYzVhLTRjZGYtYjk3ZS03OGE3MmFjMDhlZGIiIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDo3ZGJjYTEzYi0yYzVhLTRjZGYtYjk3ZS03OGE3MmFjMDhlZGIiPiA8eG1wTU06SGlzdG9yeT4gPHJkZjpTZXE+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJjcmVhdGVkIiBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOjdkYmNhMTNiLTJjNWEtNGNkZi1iOTdlLTc4YTcyYWMwOGVkYiIgc3RFdnQ6d2hlbj0iMjAxOS0xMS0xNVQxNTo1Nzo0MiswMTowMCIgc3RFdnQ6c29mdHdhcmVBZ2VudD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTkgKE1hY2ludG9zaCkiLz4gPC9yZGY6U2VxPiA8L3htcE1NOkhpc3Rvcnk+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+l7JkRQAADDtJREFUeJztm3l0VNUdxz8zE5JZkiEQCCIhQRJiAuSUoAKK1SM9tWqta6Vqa6mtPRZF6la1QlVatYqitEpdilVa22rt4nKsrQp1qagFLBAiEZLIFkrEDAkzmSSTyUz/+L5xhuHNRiaGnvo95515ee++++793d/y/f3ejSUcDvP/DOtgD2Cw8ZkABnsAg42cbHf4hsfD5fX1HJmX159u7MD3gK3AX4EBcVQrp007bDUgFxgGuBlgLc26BmQJ3wFuAeqANUBjP/pyGMc+TDTpcNSAIuB84/xI4IhD7McBVAK3Ak8BpWaNDkcN+CYw0zgvAsYB/8zgeStQDswB5gMFxvUJwPb4xoebAEYAs4Fe43AC49N81oJW+UvAXciHRPBb4B2zhw43E7gEmAG8CvzKuDYZyE/x3FHAd4HVwCPAUKL2/j5wPeAzezDrAgiGw3SFQmYdFwHHIFW0mDxaDHzNOP81EoAfmIJ8gRlGI4f5Jpr4CLTSDUAITXo+sCfReLMugGFDhlDtctEdCsXf+jqwFngLmAdUo3AXwRXAdKAeeAOt3AdIYCVxfY0GzgKeBpYbf28ArjOOEGAD7gReSzberPuAWreb2yZM4Lx165hYUEAommxFTkYCP0erew+aRAFwkXH/UWC3cb4TqEXaAYoI04FrgZOMax8Av0GTDaMJTwb+BtwP9CUb74A4wVyLhVq3m45gkFzrJ0rWafxuB7YBU1GIusa4Vgm8B7wY09WHxu90oA34AfBF49pm5Ct+CvzHuHYvcDIS4NVAd6qxDogTrHW7WVhRQZPfj9XyibnvMH7rgHOBy4EXkLrWGPcWA00xXW0EgsDFwMto8luBB4zz+UQnfy4w12g/D2lGSgxYGMyzWjlu6FDaenvJkxb4kBYcj+L0743jbOBKoBlYGddNHdCOTKAFeBtYAGyJa1cK3IfC5qMof0gLAxYGa91ubhw/nsbOzogW7EYDz+fAGP0ccCpKfj6O62YtsAJN6ELgAg6efB7wICJMm5FZ9aQ7zmxqQA3gQiFnG4DDZmPmsGHsCQSwW6370CrWorh9AKwWC75gkB4jejhtNhw2WzgUDl+f4r1XAKcD+4FLSRLyzJANDbAD3wdeQir6NPBVkBZcPW4cjZ2d2CwWL4ZggFEANouFrr4+PL29bO/qotzp5MziYs4sLmZEbi6e3t5YH2KGKShpykHsb22mg8+GBhwPLDXOtwLTgN8hsvNMfk4O0wsLafb7OdJu39WnsDjaZrGwp6eHSfn5VOXn81FPD1eWlTExX6RvVVsbtzY20hYIUJSbGxtOIxgGLAMKgb+gaJAIVmAIIkpBoDVyo78CGILsF2MQNwELEaX9GdBU63a/98DEicytr2d7V9f6UodjXUdv79bWQICjHA5uHD+eKW73QR3PKirCZrGwcMsWPIEAww8Wws3ACYAHeAiZ1ShjssOROYI4gQNpaqVx/yogADRZ+lkVLgFWIQc0F3gMSfkl4FgU+s4H1m7v6mJufT1rOjrGzCoq6hpjt3suLSmhJj85zX/N42FxczP7g8FINAH4BvA4WsA9iC+MRIlTKrMOA7OA7pXTpr3TXwHMQqFrO3AisMu4Xmpcr0BCmA88t62ri9saG5lXWsqxQ4em/ZI7mpp4bOdOyl2uiBY8i8JnBJ1oRdsRYfKhaFEOfJ4o5X4XcY0/g0pi/TEBK4rfoCxsV8y9HWiVlqLs7llgyTiH46Unamo2AXuJ8vVCpEHjjPO9SIN6I51Ncbspczhi/cFiohy/C5GnbkMADcj/HAN8C/gCosNPISYZIU4A9EcDLkLOzoekvN6kzWjkCy6IubYKqWwIqfBoY7AjY9osAxYhYQAqtt67bRueQCDWFMyQh5jgXUb/GxE5WhbfsD8aMBOpEsCTmE8eJO3ZKFc/DWnDLJN2PUiLOlCSc6XR5/JIg5OGD2dNRwcrWloYmZtr0gWghbgG0WIQ01xEElp8KAK4GLgROcB/AHek8cwvjWMGSm+dKBxZkXq2IvvchxzpHJQsWYgpZPr6+rCZ8wI3EvICFB5bUGK0NNXA0hVADrKlU1EqClqxeRxo+6nwDglKUzGI2P5BmZzdajXjAzONMZ1n/P0smvjr6QwokQBKkAcdhULLZLTyEfE/jnL5zem8JAPMQN69F2lXGGCT18u77e1s9ftx2myx7c9DPqYE1Q4eRisfSPeFZgK4BLgMMTp7zHUv8rzPoAJEIhwPnGJM4O10B2LgDOQMX8BYwU1eL9c3NFDn9VLmcFCQk0NfVAvuRJNvRiawKsP3HSCAamSbK9BKtyBv/SFyIu8itfcn6a8KOZ4yYwKnkUZRwoALCQ8Up/e/3d7O7Y2N7OruZlJBAX3hcOzkQSu+GGnKhxwCYgVwLkpVLajSci1yTh9l0F8I0WM4+CvMCKTea1BoisdRyOyCaEV5w+Nho89HtcsVP/EIlqLCyBkoGkWywrQRG1DtRFXeg4oRmUwexL4uRN74h0RX34JUdDmy0fgiJ4ivF6DQ+fFb+/axweulJC8v0eQjuMkY7wkoNc4IsQL4Oyokgvj7TzLtzMCbyDbjvf0M4/dkYKzJc5Hi5X7A/0pbG6v37aMgJ+ckVCZfhtLusxBxGm60r0OlcQ9ielMzGWysCaw2/r4TZVoLkeNbbPJcpgijqs0upCUNJm2GoAUpBOzhcDhiQ5XIMceiBZlJHWKLDajiNBlFhbORQFIiVgBhFH4WIEZ2NxLCKg6h0GCCV4wjEfYik6sAys4ZNaqhzudjs8/3/Fi7PdAXDpcjHzEeZZpjEPOLx4moMvQgaZTGkuUCryLy8wrRnD8WucYASoHnURbWH9gQW7wUuB34UaPfz3WbN7PV76fEbqcvHB6CwmQF4ijFSCgzjL/HoFzgj8C3kQYnxMpp05IK4Bi08j7EtuI99wQknDJUjbk5o+ma4zIkhBbkK5q2GkJo8vsZIyGYPVeCokwxyir/jb4xJP0okmqHSD1SfyfK5+MRQGrbSwZV2BR4Hg18DPBlgAlOJ0uqqqhwOqnzeukOhczqhLtQ8vQyyvzWkGLyESQTQADV2q3Irgri7u9Cmd4pwBPpvCwNfISIGOgbXyXABJeLJVVVPDRpEmPy8mjt6UlVLE0byQQQQqvRiiYfX8LpQ3X82agmd2aSviyIFd6CTCcZnkQRqRT4g/FLhcvFOaNG8ePKSkodDjZ7vfSYa0NGSFU/60POzYV8QjxqkHmcDhyHyMxVwNFx7SYgr7wIOadk8KB6wF7gc6jY+onQqlwu7quqYnlNDdX5+fiCwRTdJUcqAdjQ6uUQJR6xaEDh8mH0UfMexPQWIq2ZjYqlBcinQHofLtYT/Qo0FfhK7M1Kl4vTRo4kx2KhIxjslxakU0HNR0XHepP7HuT9rwPWIYaXizRnItrk8CBayStQ2Fxh0o8ZXscoXhItZx+AeWVllDudtAUChyyEVAURF/omH/muZ4YQ0QzxGhTG1qOQlIOSmx0otLWkeF8x+tpThcJZ5FP4Dky2uE3Kz+f+6moWNTbS1NmJ48BaQVpIJgAb8v5DkCNsT6O/ZuMAOcgT0MptSPHc5UjNxyKnVxhzbz3wJxLsFq1wOjkiN5cGnw9HGgOMRzIBONGWtT6U4GSKbhRFkuFE4MeIyUXG34wmvQVtp1lNio2SveGw6aajdJBMALWoQusBfnGI/SfDHDT5yAbGu1ElqBX5HC8JdnZlE4kEYEUUNwfR3WaTNiOQmruQp/cj++81aRuPOaiYUYiix63AJrLHKNNGMg2IFN/HIm0Yj+jp0cY9J/ILBSg56QMmEf1alAjTiU7+ETT51iTtBxSJBBBCtteFQteLKBzG0+F4XIQcVqLi5BFowoWo+HIDGZawso1kGtCA6oQ3oULDbiSI94gWNApRuOokWo15EvmM2036PNU4WhFhGtTJQ3IBhFGZbAPy0EFEixNVhTcCSxDnX4C+1twQc38EYnc2lDyl9eFioJHOFpnI9/edJC+Jv4/C5kKi22bujrk/Fa3+HuTt+0fis4Rs7xLbi1R7PnKUV6MiByihyUW5+r+y/N5DxkDsE+xB6XE50oK7UGktsu29gfRC5aeCgdooGUTV5Gqk9hca1zeRfjL0qWAg/2FiNwqLZyMhbEEh0iyrHDQM9D9M+BGVjhxJq7SDgf5ukvqfx+H2LzOfOj4TwGAPYLDxXxh+bZWKTP4NAAAAAElFTkSuQmCC" + }, + "tiltleft": { + "icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAACXBIWXMAAAsTAAALEwEAmpwYAAAFIGlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS42LWMxNDUgNzkuMTYzNDk5LCAyMDE4LzA4LzEzLTE2OjQwOjIyICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ0MgMjAxOSAoTWFjaW50b3NoKSIgeG1wOkNyZWF0ZURhdGU9IjIwMTktMTEtMTVUMTU6NTc6NDIrMDE6MDAiIHhtcDpNb2RpZnlEYXRlPSIyMDE5LTExLTE1VDE2OjAxOjE4KzAxOjAwIiB4bXA6TWV0YWRhdGFEYXRlPSIyMDE5LTExLTE1VDE2OjAxOjE4KzAxOjAwIiBkYzpmb3JtYXQ9ImltYWdlL3BuZyIgcGhvdG9zaG9wOkNvbG9yTW9kZT0iMyIgcGhvdG9zaG9wOklDQ1Byb2ZpbGU9InNSR0IgSUVDNjE5NjYtMi4xIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOmY0MTk1ZTgwLWZlZTMtNDUyNy04YzUxLWJhYzViNThmZDBmZSIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDpmNDE5NWU4MC1mZWUzLTQ1MjctOGM1MS1iYWM1YjU4ZmQwZmUiIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDpmNDE5NWU4MC1mZWUzLTQ1MjctOGM1MS1iYWM1YjU4ZmQwZmUiPiA8eG1wTU06SGlzdG9yeT4gPHJkZjpTZXE+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJjcmVhdGVkIiBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOmY0MTk1ZTgwLWZlZTMtNDUyNy04YzUxLWJhYzViNThmZDBmZSIgc3RFdnQ6d2hlbj0iMjAxOS0xMS0xNVQxNTo1Nzo0MiswMTowMCIgc3RFdnQ6c29mdHdhcmVBZ2VudD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTkgKE1hY2ludG9zaCkiLz4gPC9yZGY6U2VxPiA8L3htcE1NOkhpc3Rvcnk+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+AfSaAgAABrpJREFUeJztm3lsVFUUxn9vpnSzrbVQIICUYotWNAgqIsEASoAoriFqBCUxGqORuG9x32LcgpqIC7hEMZqYaFwjBtwlEQED7oAiFFygUhXoNjw+/zhv5HU6M/TNvOSZMF9yM9O7nvPdc88990zqSGJ/RixqAaJGgYCoBYgaBQKiFiBqFAiIWoCoUSAgagGiRoGAqAWIGgUCohYgauz3BBQF6XzS8uX76uIApUATMA2oBFyvfjWwFNgBJFIHbuno4J4RI5g5cGAQkfJGIAJ6gRgwEjgWOA6oBvYAAkqAf4CvgV9DXjdnhEnAEOBi4DZfXRtmAeXAicC1wPvAPOBzzBqIOQ67XJfOPXtCFKd3CIuAI4DHgMlAB7AE+Bj4DmgHBgBTMKuYCkwARgM7Yo7D1s5OmioqGFZWFpI4vUcYBIwCngXGAGuB+72/U/EKUAfcB2yKO07zzt27aUkkOLi0lHlNTYysqAhBnGDIl4BGYCGm/JfAJTHH+ardddnpuj06l8ZiG6uKis4D+MPb9dFVVVw6dGgkykPuBDQAp2PmfAzwA3BRzHHWtCYSDCwuZnq/fj0GrWtr47PWVgCGlZVx/fDhjKmqyrRGCXZMRgBd2JH6LUd5MyIoAUVAFebEZnh17cCjSeVL43Hm1tUxrba2x+C1bW08sXEjjuMwZ/BgRlVWZlpnHHAlMB5zrg7wHnAhIZMQlIBiYBBwsq9uF9Dc4boMKC7mqvp6pvTtm3bwiPJy5jU1ZZv/eOBM7Lb4A3gK2AzcCUwHxgJvBJQ5K4ISkAC2Yl5+qlfXFnOczVu7ujihpiZV+WKgP9AJbMsw5yDMkU4H5nprvALcAvyMHYMur29JQHn3iVwJmAvcCtQAizpcd/VhBxzAuOrqZL9+wDnAaUA98BewEtiQsnYDFjTVAa3AM9iur/D1O9An558B5d0ncnWCa4HzgXjMcdxtXV2Mq67mtP79wc7s45jy72CR32DgDMAf57YAm4AfsWvzBdIruA4jZwgwCQunQ0Ne12DMcdztiQQDS0qYWFOTrB6PKf+W9wnmxIYAwzAr2oOFw5t7scwWzDIewY5FLXZEPspH9iRyJiDmOLQmEpTF49zR0MCkvWc/+dD5y9ddQLNXMqEOM/cNeCGyD/OxsPoy4BKvvAp8D/wEbAeWYQ65M4gegQj4tXPv3B2uy+DSUu5ubGTS3t33z+lkmcrBSEliFnA79maYTc/dTQALMOc7E7sNJmOO+G/M0S7EQu8ngugUiIBr6+v/+97uuoysrGRyd+XBHj0AX6RZ63Sv/ATcC+z22qqwl+InZH8pbgAe9L7XYoTdBVyAWccWAhKApDDLBEldkr6X1D+lra+k5TI8JqnI1xaXdFDAtRol3SppjbojkMxhKt8g6VuPgIlp2sslTZV0rqTKPNYpl3S1pHUpir/sERIJAcf6BDozj3kqJM2VNF9mTantR0l6PUXxbyRdIak4lzXzVbxU0s2SdklqlnRKnvPVSWqR1C6zFn/beJmFJfG3pDsljcpnzXyEPUvSCk+Y1yWNzNJ3oqRTJfXJ0D5I0oWSbpA0J41STZK+8yn/oaRpeZKdEwF9JA2Q9JKkHZI+ljRb5sSyESVJKyX189UfI+kmSQdLuszrszjDHC/6lF/qjclb+VwIuEbSc54gL/RyzNGSbpS0SNIySU9KGqe91jNF0miZYzs+zfgzZEcsSeLwsJSXFDgSnIClvF0stH0au8s3AR8A6fLmK70yC3gY+BCL+R/27vE12APrqwxrnuz1A3gIeyGGh4CMzZH0oNJjraRnJY3JMLZW0uGSnIBrvu3Nv1521Ya2+7lYwGvAp1gU1gDEsbd8GZYfbMQeQ1cAi1PGbqN7TqAImIhFbz9kWbPD+3wT+CWgvPtEUAJ2eOVyjIQYdhTGAOdiMfqhwHVY3n9nhnlOAa7y+rZiBHT52ncB64E+wFFe3SHYDy0tAWXOjhDNqcF3PLZIGpumz9mSnpf0W4ZjlA1PK78IMpQjkA3rMSc1A7MKf557NuYEx2JZpCSSO1+GJVkAhgJH+vrsxPIBD9DzmZw3wv5tMOmtXSwfMAz7oWQa9tZP4hPgXSxp4mKmnjTtaiyDVIndMC3AKrofkdAQNgFxLCFRjl2RxXTfzQVYNmc9dnWmw+9kd4qhImwCmrHMzCjgaF/9auBmbOdDN+N8EDYBnVhCogzzA9uxwGcJtuv/O4RNANhdvwo7u39i0WG2XGCkcKTCP0zs1ygQELUAUaNAQNQCRI0CAVELEDUKBEQtQNQoEBC1AFGjQEDUAkSN/Z6AfwEcGVDrgnw68AAAAABJRU5ErkJggg==" + }, + "tiltright": { + "icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAACXBIWXMAAAsTAAALEwEAmpwYAAAFIGlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS42LWMxNDUgNzkuMTYzNDk5LCAyMDE4LzA4LzEzLTE2OjQwOjIyICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ0MgMjAxOSAoTWFjaW50b3NoKSIgeG1wOkNyZWF0ZURhdGU9IjIwMTktMTEtMTVUMTU6NTc6NDIrMDE6MDAiIHhtcDpNb2RpZnlEYXRlPSIyMDE5LTExLTE1VDE2OjAxOjEzKzAxOjAwIiB4bXA6TWV0YWRhdGFEYXRlPSIyMDE5LTExLTE1VDE2OjAxOjEzKzAxOjAwIiBkYzpmb3JtYXQ9ImltYWdlL3BuZyIgcGhvdG9zaG9wOkNvbG9yTW9kZT0iMyIgcGhvdG9zaG9wOklDQ1Byb2ZpbGU9InNSR0IgSUVDNjE5NjYtMi4xIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOmQ0ZTA5MjEyLTQ4ZmYtNDk2My05YTk1LTg3YjQxZmUwNDNiOCIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDpkNGUwOTIxMi00OGZmLTQ5NjMtOWE5NS04N2I0MWZlMDQzYjgiIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDpkNGUwOTIxMi00OGZmLTQ5NjMtOWE5NS04N2I0MWZlMDQzYjgiPiA8eG1wTU06SGlzdG9yeT4gPHJkZjpTZXE+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJjcmVhdGVkIiBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOmQ0ZTA5MjEyLTQ4ZmYtNDk2My05YTk1LTg3YjQxZmUwNDNiOCIgc3RFdnQ6d2hlbj0iMjAxOS0xMS0xNVQxNTo1Nzo0MiswMTowMCIgc3RFdnQ6c29mdHdhcmVBZ2VudD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTkgKE1hY2ludG9zaCkiLz4gPC9yZGY6U2VxPiA8L3htcE1NOkhpc3Rvcnk+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+/zhJZgAABr5JREFUeJztmntwlNUZxn+7S9hshEggiVpAUASFCk69RMYbXkDFqgMz2vEPZxwdO0g72lYq46XMUPpXtVNrUVHH+31GxakiqDOxneLgDdOhXKJc2yBthJIJ2QSSTXaf/vGeZT+S3ZBNNjnMsM/Mmd39zvud83zP9573e9/zbUgSxzPCvgn4RlEA3wR8oyiAbwK+URTANwHfKArgm4BvFAXwTcA3igL4JuAbx70Aw4Z6wrcbG/nN1q2MLS3N1h0FKoEbgNOBdmA4sAf4K7DdHesVtTU1feYz5AIcBacB04AaYDLQAZQADcBBIAVsKeSEQy5ARypFWzJJOBQildmMORmYCyzBRABIYAJEgcuAW4HdwO+B14DmQvAZcgEmxmJMHTGC7zs6qI5G0yJcCTzvTD4HPnWfTUAFcB5wMTALeBzzkF+5/gEh5GNLbHNrK/ds2cLu9nYqS0oYMWzYmUlpMbAP+C1wKMtpYWApcBdQBbwJ/JwsIuQTA7wIALApHmdFQwP7Ozupb23lpGgUgJauLtpTqR72IyIRYpEIKWk+8DQZEe4G/he0PRYEmAr8yH2vB/6Ry7CupYX7vvmGfx2ym35JRQWTy8p62H3e3ExjIkFFSQkpaR4mQjXwDvAx8DbOG3wLMB14FZiBBbJG4C3gOUyMHtgQj/PSnj1IYuGECUzJIsBH+/bxu507aU8m0yIsx5ZAyJksAR4BOmtranq6UA4UOgiGgOuxi6/D1vPlwC+A24CHgXex5/lhnDNyJH8866xeB76mqopIOMyju3bR0tXF8HC4jczFA8wGnsW8INFXwoXOBENYIgPQArwH3ItF7zpMgFosmM3GInwujHXtMGaPGcM55eXsTSQIh0JfA52B7jqgFUjmQ7jQHpAiE5CGAzEsoq8DrsEyvNuBXwO/BDYD67Fl0oUJeAJ24TPdGF8Aq7BllJo5ahSb43GaOjvfGh4On4wJuR/4MyZAXii0AKOAS933A/R8nL3v2jRMjBpnPwkodzZJ4L/ATkyYGVgSNAN45Mbq6ua1TU28v3cv42Ox5S4W9BuFEqAMuBq4A8vomoAnerHfwpEp7RnAKZhLJ4HvMBHAPKIeeBD4C/DlrNGj2X7wIPsSCaLhga3i/gowEcvORmF370IsmwNb448BH2Q5rxyYgt3dYAKznW6BMYAk5gnjcUHv+upqavfvp76tjfGlpcGUOm/0R4Bq4BVMgAbgVOA/wEtYCruS3CnqtcDLwCZgIfBVoC+MxZDuEJnAdrj/6spK6uJxtrW1EYtE+nEZhnwFmA6cDVyCFSovYglJEov6R8O/gTWYu1cFjk/AnuMJ4A1gbaCvA4vwM7F64CuAuVVVlEUi/DMep2wAAiApnzZH0r0ydEmqlXSnpBPyHCcmKRz4PVHSJ27cJ7PYT5N0UNIeSafkOVevLd8TTpR0uqQPdSQ+kXTrAMmMlbRA0vk5+tPCr5FU5kuAdKuUtExSQ0CElKQ/SRqXxX6epMck3TRAwkvdXLWSJvgUIN0ulrRc5p5prJF0aje7O13f3wtAeoEba5ekW3wLkG43S9oREOEdSWMC/RFZ/Fgo6SFJcyVFc4z1A0k/kXRGL/NdIelvbq7Vki71LUCa1LaACMuy2IyT1Oz650i6QNJiWVxJ21wu6ZCkA5LO7WW+kbK4sE0WHB91okd8CYCk6xwZSdqunnexxNkskjRF0v3O9ilJF0paJWmjpGckLZE0qQ9zjpG03o2zyI3fZ86FrgVWA89g1d5ErAAKZnidzma1+70SiANbsU3ONiy7XEEvmyjAVVjmORrLZWLu+GSsqOo7CuwBSJopKe7uyIo8zy2VNFVSeY7+OZJel7Rb2XGTpDN9egBYWrwBy9pCR7G9yH2uc5/t5Ng1wgqtZRy5R9AI7MC8YC2WZbblQ3YwBCgjU9rOAh4AIlgRFCzdTsTKYrDKcCnwdY4xz8aqwfTFf4ilzN8Ce924O/rFdhCWQLWkT3O4aG/4VtLTzs27j3m3szkg6WcqYDo8GAIgabqkF7Jc5CZZpF8le0p8Jqm+m813klZKuiow3mLX93yhuQ7Wm6GNwD1YtVhBplr8nswrrSpsvZYCPwZuBi7A3Hw+cD62gbqIzOZIFBiJPTkKAm8vRrJgEvYu4S7sMZfGOixe/BDbF/wptt1WGAzSEhhIGyfpDkmNWZbQAkmhQs53LHlAd8zAlkYN5gHrgT9gUb9gONb+HxDEVmz7bRgWR9bTj23vo+FY9oAhwXH/H6GiAL4J+EZRAN8EfKMogG8CvlEUwDcB3ygK4JuAbxQF8E3AN457Af4PF8MUPh39YIwAAAAASUVORK5CYII=" + }, + "tiltbackwards": { + "icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAACXBIWXMAAAsTAAALEwEAmpwYAAAFIGlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS42LWMxNDUgNzkuMTYzNDk5LCAyMDE4LzA4LzEzLTE2OjQwOjIyICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ0MgMjAxOSAoTWFjaW50b3NoKSIgeG1wOkNyZWF0ZURhdGU9IjIwMTktMTEtMTVUMTU6NTc6NDIrMDE6MDAiIHhtcDpNb2RpZnlEYXRlPSIyMDE5LTExLTE1VDE2OjAwOjE1KzAxOjAwIiB4bXA6TWV0YWRhdGFEYXRlPSIyMDE5LTExLTE1VDE2OjAwOjE1KzAxOjAwIiBkYzpmb3JtYXQ9ImltYWdlL3BuZyIgcGhvdG9zaG9wOkNvbG9yTW9kZT0iMyIgcGhvdG9zaG9wOklDQ1Byb2ZpbGU9InNSR0IgSUVDNjE5NjYtMi4xIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjhjY2NlM2I1LTEwMmQtNGIyYi04Y2E0LTZiODk2OTdlYzE4YSIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDo4Y2NjZTNiNS0xMDJkLTRiMmItOGNhNC02Yjg5Njk3ZWMxOGEiIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDo4Y2NjZTNiNS0xMDJkLTRiMmItOGNhNC02Yjg5Njk3ZWMxOGEiPiA8eG1wTU06SGlzdG9yeT4gPHJkZjpTZXE+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJjcmVhdGVkIiBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOjhjY2NlM2I1LTEwMmQtNGIyYi04Y2E0LTZiODk2OTdlYzE4YSIgc3RFdnQ6d2hlbj0iMjAxOS0xMS0xNVQxNTo1Nzo0MiswMTowMCIgc3RFdnQ6c29mdHdhcmVBZ2VudD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTkgKE1hY2ludG9zaCkiLz4gPC9yZGY6U2VxPiA8L3htcE1NOkhpc3Rvcnk+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+TsY1swAACBNJREFUeJzt23mMnGUdB/DPXu12u2WxhS5d6YElTeSQcpVDgVRQuWqIDYpCvFAJoiRIgkS8Ea9oghq8wKAEFEVNQVuKUFGoAipQTltLy9ECPXbbpey9O7v+8XvHToe5dmZk/uh+kyczfd/neeZ5vs/vfrZ1Y2Nj9mbU13oBtcYEAbVeQK0xQUCtF1BrTBBQ6wXUGhME1HoBtcYEAbVeQK2x1xPQWKV5JmExzsILWIH1GB7HHC1YiqPQh7vwN6QKDbp87Vr37dhhn8bcW1m1aFHBH60WAfvhCCzEDGxGJ7aNY47ZOFwQ0IuXsQa7qrTGnKgGAdNxA87IePYBLMNX8RSGCoxvxyJ8BwvEiTck803GtQpIQVNdnUoS+moQ8Bax2B34bjLnxTgHS5Jnd6ML64R4v1Gc+H64CGcncz2M63AIPoN342ZszfXD6/v6bBsa0lRXV/biq0FAHcbwDL6ePPsnrsDRyecV6Bdk/AVX4rSMOTYLu3GVUJ3D8QnMRKs8BFz73HMe6u7WMXmy0TIXXw0CtgkRbxUn2ok7k3Ye3iNO/Dh8PmmEbq/BBvwCf82Ys0MQO0Tuva3t6dGfSpnW2Fj25qkOAQ1JG0taJm5NWj0uw+eEzfgPvpS8y4V5mIbBHHOCH77wgge6ux3Y3Gy0grJeNQhoTuYZlT+uGBXivwEn4zd4sMCczwoXOjnXywe6u3UNDXlDU1P25uuFN9op3HFR4agGATOTzz4MFOm7LGnFsDNpHdgn++Wju3Z5aXDQpNcavyPxWywXdqZfkTii0kiwCack3zfg1QrnS+MlbBI2ZUH2y0/OmePotjZbh4ayN7BQqE9Hsrai+6uUgHk4X5z8XRXOlYkX8a/k+2JhEPfAcW1t5re0GNhTBfqF3chrO7JRKQFnYJZwgX8oof9k4eOnltD3LkHsUpyY/fLcWbPMb2nR9VopGBcqGXussOyEXu/M0adD+PMzhb15P36FjwndPjt5f1COsXcKXW7HN4S07YGTp08PKRgt3xGWS8AR+F6yqAeT77lwJn4iNnIs3m535HgEbk/efzjH2AFcI+KMk0S43Z7ZYWl7u9lTptg5PKy+zGiwHALOEoHLCdgiorzOPH0fwb+xSmzol/g1fi6SnTtEeHxfnvGP4kJhXE9Nxu1hFN85Y4Y3tbQYSBU09nkxHjd4gojvPyVS13W4FPfn6HsijsfTQuy78XzybmVGv4uF+M8Wsf/twptk4o9CTa7D6YLEG7AaT57T3m7F9u2e7etzQBkhcSkENCeLu0ToNNyEH9htqTPRJnT2ZEHAoQXm3oIRoe9tmCLEPhu3Cim4ShzE0XgS38RtS2bOHNo2OKhrZCRXbFAQxVTgNLwvWVSHOL0P4kNyb55wP6uFH18lCCyEKSIRejpp+bBcSNMXkn6H4XocvmTmTAumTi3LGBaTgNMwJ/n+UyGyxX5llziZleKUikWHm4SEHYAnivR9Hl8TKfLvReR3Eh4ZGB0dK8egjccGNAjX1V1C31fltg35sCVppeIlEfRUjGKk3WN3hHehMEiXiDCzFqgXBnGlMLT9guix5vr6stLiYhJwj9DhWcJXvzWjXS1c3OuFhSKdPjf590ZRW3ji7s5Oa3t7NdfXpzkYUWIoXIoKDAidXiHC0suEMZorpGJtiRuoBKfi+yKMHsCPcAsevmPbNt/euNHQ6Ki2xsaBhIEWvFLKxOOxG4+LIsZ5wlidiJ8Ja5wP++HjeG+yqEwcIk7w+CK/+w7hdg8RpbZzhNF8GFZu327n8LC2pqZpo3EwTUJCLxDEFUQ5hnOF0MP1goRr5MjWEizGj3GjKH6m0SACqqtFVHlMnvFHiqCnQ5TMzpeRdS7butXmwUHTozBygSC6XoTMVwqiCqLcXOBBoQo9IjS+PE+/1uQ3WsSm0xgTbo+oF47kGNssAp85+IewQeszO9y7Y4dnQvdh/6zx05JWEJVUhJbjW+IULxJZ3otZfVaKzK8Xf8p4PiruDJaLVHpNjvnPEOQOJ7/xXObL323ZYmNfnxlNTWnrfyPeJuKCXfiKElxrpSWxm8TJzBWZ3/VZ718WdiIX1si98TROF1Jwkz3JA6u6umzs79cxaVKagE0iUJsr3OMDpWyg0oLIiyK7axL6Xi1Mt9u4LpPjZqmtsVEO378Bf1bi5qmcgBT+nnzvKNRxnJgtag1dXpsdgq7hYf2pVNl1gDSqcT3el3xOUYLRKREHiWrzJnkuRy+dO9eifffVM5LLfpaOapTF03M0CWufrzJ8vLDUQ4KsDfInP+3JvHmv1w+bNk1LQ4NXRka0NjaWfTlSretxYrE9Wc+Ow0dEEDNf6HYam4VbWy0iu8yaYvpY6+SPMXx6zhx9qZR1PT1aGhrydSuIal2Ownbh7og7/s8KAuYmz4ZEDWGn8P0LcbBwd0uFy/yyIPJRIfotChDw5tZWk+vr9aRSWhsa/i/JUClIn9YxIvKqE+5ofvL8Ztwmrqq2i1i+VRi6Q0VAdVTSFgtXerBwgb1yB0n/w+Xz5hlMpazr7S1LCqpBwOMiPH2XuP9L4358Ufj67qwxXaK4sVpUjU4RZbQTBJHpdPtuRYKZBVOn2n/SJE/1ZGtfaagGAZ34qEg+zhRZ2L3ijm5zCeOfSdpDItZfIgi7RVyiFvrrEjA8NpZfT4qgWkawE4+JusErQirG8/dBxI3w4zgwmeMxJaa0laBu4r/M7OWYIKDWC6g1Jgio9QJqjQkCar2AWmOCgFovoNaYIKDWC6g19noC/gtsQyGeNU6zrQAAAABJRU5ErkJggg==" + }, + "tiltforward": { + "icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAACXBIWXMAAAsTAAALEwEAmpwYAAAFIGlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS42LWMxNDUgNzkuMTYzNDk5LCAyMDE4LzA4LzEzLTE2OjQwOjIyICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ0MgMjAxOSAoTWFjaW50b3NoKSIgeG1wOkNyZWF0ZURhdGU9IjIwMTktMTEtMTVUMTU6NTc6NDIrMDE6MDAiIHhtcDpNb2RpZnlEYXRlPSIyMDE5LTExLTE1VDE2OjAwOjI4KzAxOjAwIiB4bXA6TWV0YWRhdGFEYXRlPSIyMDE5LTExLTE1VDE2OjAwOjI4KzAxOjAwIiBkYzpmb3JtYXQ9ImltYWdlL3BuZyIgcGhvdG9zaG9wOkNvbG9yTW9kZT0iMyIgcGhvdG9zaG9wOklDQ1Byb2ZpbGU9InNSR0IgSUVDNjE5NjYtMi4xIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOmYzYTgyM2I5LWUxODEtNDYzYS04NTU2LWMyMTI0ODhiNTg0MSIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDpmM2E4MjNiOS1lMTgxLTQ2M2EtODU1Ni1jMjEyNDg4YjU4NDEiIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDpmM2E4MjNiOS1lMTgxLTQ2M2EtODU1Ni1jMjEyNDg4YjU4NDEiPiA8eG1wTU06SGlzdG9yeT4gPHJkZjpTZXE+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJjcmVhdGVkIiBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOmYzYTgyM2I5LWUxODEtNDYzYS04NTU2LWMyMTI0ODhiNTg0MSIgc3RFdnQ6d2hlbj0iMjAxOS0xMS0xNVQxNTo1Nzo0MiswMTowMCIgc3RFdnQ6c29mdHdhcmVBZ2VudD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTkgKE1hY2ludG9zaCkiLz4gPC9yZGY6U2VxPiA8L3htcE1NOkhpc3Rvcnk+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+Gws1uwAAB9dJREFUeJzt2nmQXFUVBvBfz5bZBJMJSShEIgQCEdkskIgBS5SAEVFRUcQFtdxAEFS0rMKtBEVLUMG1UrKoQIggoqBIRSsqJYqEgKxmIQExC1mYYaYnYZb2j/PGmUxeL9PT8ZWV+aq6uvv1vffd+91zzv3OeZ0rFAp2Z9RlPYGsMUFA1hPIGhMEZD2BrDFBQNYTyBoTBGQ9gawxQUDWE8gauz0BDTUc50TMRy/ux+3J50rRhHl4HSZhKe7A85V0Pv+RR9zT2am9vn6n35Ycc0zJidcC7TgMh4sJD+BRPDyGMWYkYxwpCNiKe7C+ks71uZxq8tpaENCEj+PLyfd+nIxzcBHuxmMl+k8XxH0Rc0dcPwGH4IPoKTWBFfm8LX19GnK5MU++FgTMxPvRh6twHz6GV2IhnsJX8ADWIS9Im5r0/RAWJGOtwA9RL8h7O34q3KkoLlu92rKuLtOamsZsBbWygBeiC4vxF/wSF+P1OFQsiiBnA/YQpt6WXF+Dv+NLeCi5Ng9vQEepmz/W06NvcFB7fX1mLrAZ/8BRYmHQjc/guzgXR+BAzEleOXQKq3gA1+KvI8Zsw57J53+VuvkVa9a4r7PT3s3NBquobtWCgH5h1mlH6pPClAkS9sM2NOJZYS0DKf0KI8brL3bjh7u7bRsY8IKGhqoWT20IaBaBjFhYMSxPXpUgl7woMcfL16xxX1eXvSdNqpqAWgihqWJ3t+CZGoxH7PpzyecpxRp1NDZqrqurevHUhoC9k/ensawG48F2ERiJo3CXYbwENIkjkAhmfeMcbyQeEbHgDLxoDP1m4TU4tpLG4yVgPk4XQfC6lN9bcAo+gINH/bZPcv1MTE7p+2usxkvx7rSbP9vXZ/vg4MhFTMP3kr6/wPvEUVwU4yFgX6HeJDe7O6XN4ULPL8TX7Bgkz0qu/wzvTOm72jCpF+LU0Q3m77WXmS0ttg0ODl06W+QSLUJaX4zPllpEtQTMwZXi7F+JL5CqQ/oM+/Jzo+7XJYLdNulHIaEjfi4C7beEaf8Xp0+fbt+WFlv7+tSFDB6dfHUbDqapqOYYXIBLReKyHudhVZG2y4UZHo1bRXAbwk1i8b2KS93NYvcPFNb0Y1wgLA6c1NHhwa4unX199mxouGaQ4/FmbMRlQnkWRW4Mzwbn4k1C2bWKoHcRflfpAOPAcfiOsLgefFOQsBzu3LTJVWvX6uzv15jLvQXX4zaRS5RMhytxgZyIxDeJBbfiahG8/heLJ+LLmbhZyOTPYxE+h7b5U6c6pK1Nb8SC5qRPXkjzUuKsrAvsKyLrQpHz/0Es/idVLWN8eBzvFUnTArwKl4gYc8O2wcFCsptDm9pgWE0WRTkLOBQvN7z4BbJZ/BB6xGnyRmHm8FaRjVaFsZwCBVGpqQRNwm8rFTB7iBjTWmH7TsNJ0ri0TLnOD4kcvlscQb8VZveSMv3OEIWMK/DiMm3r8emk/bll5lQnCii34z3JtetEZlkVyhHwlND3Zwvfe4UIPNfjpBL9DhbVnlOUOYeFBjgO+4sqUjEcgRtFceVkYQUX4FcoNNfVGSzetygq0QEFIUaWC+n7CaGzrxO7kHYSXCPO8KdFMvNvw4JoJGYJ879EyNc/k7qOuSIQzxHa4fvCCpbArRs2eLynR0vd2L1hLD1WCmV2hmB9uqjkzE9puwKXC7V3rXCFA3Ca2MWTMVsIm6Fgdjn+ljLWPBF45+BeoUUulCwe7njmGavzeZOqKIpWE0CGXOI2obcXCtdIw4lil48XceMiQeBZIhmaJ4g4qkj/DqHmDsDv8S7cObLBLRs2WL99u8mNjbvMBdKwGR9JJniciAunpbT7Af4pzP9+4UqNYjHL8Q5R+/tNkfucI9xtLT4pLGsHLNm82ep8PqpCVSxkPCWxdUKR3SUC4kl2jgcrk9cQrhS+/qTICxaVGH9/EWNySb/loxssXr/e2t5eU6rcfcZfD1gqlGGzUGnl0C92cXu5hkJ07S+eLi1Oa3D31q2eyOdNqiL4DWG8BAyI85vw5ZK6e4w4Uuz+ImExO2DRunVW5PM6mppG736jEGzNaiCFK8HW5H2G4sGsGsxI3h9N+/GPW7ZY29ubFvk3Cvd8StQjSnpHLcriW4V/HoS9yrQ9WqSoy3BDiXZzRA2AqDbvhP5CIarBuRw7pvR/EgF5g6g17HIC8oLx2UoXRd+Gr4ojrUucIFcVaTvF8FOm1GrR+TNner5Q8Fh3t9YdH4l3Cb1QEWpBQKsw17SJzsOHxROhlxl+3LUHvm54p263o0WMXFGqH89pb9daX6+rv197xk+GJgvtnzeclEzHN/BqUVMYwi1C+R0rSmmvTa6fKoi6VBylS8XxOU2JQHbefvvJDwykWUHFqAUBz4kK7kGi/neISFIOS36/WRyVG4Wg2SjU3A2CqNPE4k8Qfn91MuZsZfx3dlubSXV1ugcGtNfXV6UFxlITLIYG8X+Abyff+5NrTwgldy82lejfLmr/nxLFjZG4UZDTVazzynzeJatWlbSCXf0XmX6xa02iUkNI3euFDC6HbvFo/KMiv1gg8oS78CMlFg+zWlt1NDbqzzAGEP7/gAh2g3hQingpg2eTMfYRD1kfVOQIHI2BQqG84imCWrjA/zV2+/8JThCQ9QSyxgQBWU8ga0wQkPUEssYEAVlPIGtMEJD1BLLGbk/AfwAKxxUH6JUEpQAAAABJRU5ErkJggg==" + } +} \ No newline at end of file diff --git a/libs/core/helpers.ts b/libs/core/helpers.ts index a5276a9a..b5a3cc7f 100644 --- a/libs/core/helpers.ts +++ b/libs/core/helpers.ts @@ -1,17 +1,10 @@ -namespace console { - export function log(msg: string) { - serial.writeString(msg); - serial.writeString("\r\n"); - } -} - namespace Math { /** * Generates a `true` or `false` value randomly, just like flipping a coin. */ //% blockId=logic_random block="pick random true or false" - //% help=math/random-boolean color=230 + //% help=math/random-boolean weight=0 color=712672 export function randomBoolean(): boolean { - return Math.random(2) == 0; + return Math.randomRange(0, 1) === 1; } -} \ No newline at end of file +} diff --git a/libs/core/icons.jres b/libs/core/icons.jres new file mode 100644 index 00000000..3e4e037d --- /dev/null +++ b/libs/core/icons.jres @@ -0,0 +1,126 @@ +{ + "*": { + "namespace": "icons", + "dataEncoding": "base64" + }, + "heart": { + "icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAACXBIWXMAAAsTAAALEwEAmpwYAAAF0ElEQVR4nO3dMW4USRQG4NcrkVjObTgAF+AAFneCBDmFBG6zmyPIuQAHsNe55cQStcGM2Z311KPL3T2uNt+XMp73q2b+MZbsehEAAABAF4Zf/PtxRJxExFFEPJt59m1E3ETEVURcP+QJSilnEfE2Il5FxOl80SIi4u+I+BYRH4dh+PLA53B+Kz+/rCCnEfFi5lA1F7E50NFKKe8i4v0ycXZHRcT5MAwfGr/O+W1HxYrPr1aQ44h4uVic/b7HyE/C7Sff5/j1d8C5lIh43fBJ6Pz+NzJWen5/VB58smyWyTPfxuFe3NjOetPweOe3a7XnVyvI0YJBalpmvlosxTwznd+0md2cX60gc/9ANEbLzLl/oBzjecNjnd99qzy/WkGAUBBIKQgkFAQSCgIJBYGEgkBCQSChIJBQEEgoCCQUBBIKAgkFgYSCQEJBIKEgkFAQSCgIJGoFuT1oivaZTXdAzeSy4bHO775Vnl+tIDcLBqlpmfltsRTzzHR+02Z2c361glwtGKSmZebH2FxGdihlO3Ms57drtedXK8h1bK5jPJSLaLhfdntD33kc5kW+uzrza8PXOL9/rfr8nsLl1W9icylZy71LY1zG5r8Fn9Z8+XLG+U07PwAAAAAAAABgRynlrJTyVynlsszvcvvcZ/LJt7p8pZR3C4Ta50fZ7OyWT7515Cub5v44UMC7kKObLJ98h8pX+3X33vdoy7dLvmmq+WoF6X2PtnzTZso3cubelpZSDvnXZj8NwzDqU0O+/eSbZl8+t5pAQkEgoSCQUBBIKAgkFAQSCgIJBYGEgkBCQSChIJBQEEgoCCQUBBIKAgkFgYSCQEJBIKEgkKgVpPc92vLdJ980e/PVCtL7Hm35ps2Ub+TMWkF636Mt3y75pmnN9/Pqx0Pcbjflakr55HuUfHchz0opf5ZSLhYIdrF97qmXG8sn36PkAwAAAAAAAAB2lJ73VMsn32PmKz3vqZZPvsfMVzraUy2ffI+Zz570ceSbZrX57ElfZqZ802Z2k8+e9AbyTbPGfG41gYSCQEJBIKEgkFAQSCgIJBQEEgoCCQWBhIJAQkEgoSCQUBBIKAgkFAQSCgIJBYGEgkBCQSBhT/p48k2zynz2pC8zU75pM7vJZ0/6OPJN89Ty9b+nWj75HjPfXciz0vGeavnke8x8AAAAAAAAAPD7+dVKrOOIOImIo4h4NvPs24i4iYiriLh+yBNsf03gbWz2y53OFy0iNr9y/S0iPg7D8OUhTyDftHzRwfsvK8hpRLyYOVTNRTT+DUDZ/ILZ+2Xi7I6KiPNhGD40fZF8P0fFA/JFJ++/WkGOI+LlYnH2+x4jv5NsP/k+x+FWBZeIeD32k1C++yOjIV909P6r/T3IybJZJs/sZo92hXy7WvN18/6rFeRowSA1LTO72aM9w2Pn8pTydfP+qxVk7h+IxmiZOfcPlGM8b3isfPe15Ovm/edWE0goCCQUBBIKAgkFgYSCQEJBIKEgkFAQSCgIJBQEEgoCCQWBhIJAQkEgoSCQUBBIKAgkFAQStYLcHjRF+8xu9mhXyHdfS75u3n+1gtwsGKSmZWY3e7RneOxcnlK+bt5/tYJcLRikpmVm73u05dvVmq+b91+tINexuY7xUC6i4X7e7Q1953GYF/nu6syvY79Avh3N+aKj999TuLz6TWwuJWu5d2mMy9j8t+DTxMuh5Vvx5dUAAAAAAAAAwH+t+ldNovN89pCv//Vd7Z706DyfPeQ7Vvv6rnJPenSezx7yvVb5+q51T3rv+ewhnzazm3xr3ZPeez57yKfN7CbfWvek957PHvJpM7vJ51YTSCgIJBQEEgoCCQWBhIJAQkEgoSCQUBBIKAgkFAQSCgIJBYGEgkBCQSChIJBQEEgoCCQUBBJr3ZPeez57yKfN7CbfWvek957PHvJpM7vJt9Y96b3ns4d82sxu8q1yT3p0ns8e8ntW+/q6vLruye9xj87PL/rPBwAAABzKP8/KS45dYO2PAAAAAElFTkSuQmCC" + }, + "smallheart": { + "icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAACXBIWXMAAAsTAAALEwEAmpwYAAAE5ElEQVR4nO3dMY5URxQF0NdGTtAQY3sB3gALsNgTJBapneA9WXbOBryAARIiRABBO5i2Ru2hLv9P9W9V9ZyT8nveVfXcgZGaelUAAADAEHbf+POrqnpaVY+r6vsTz/5SVZ+q6n1Vfbzn15BPvvtalC8V5Ieq+unEoVquq+rdytfId0u+Ps183zVecFXnC1eHWVcrnpfvmHx9mvlaBXm6XZamNTPl65sp38KZrYI83jBIy5qZ8vXNlG/hzFZBTv0L0RJrZsrXN1O+hTNbBQFKQSBSEAgUBAIFgUBBIFAQCBQEAgWBQEEgUBAIFAQCBYFAQSBQEAgUBAIFgUBBIFAQCFoF+XLWFOtnytc3U76FM1sF+bRhkJY1M+XrmynfwpmtgrzfMEjLmpny9c2Ub+HMR42HP1fVvqqebBbn2HVVfVjxvHzH5OvTzOfy6jb5+jyEfAAAAAAAAADwwEz9UZP9fv9LVb2sqmd1szb4lN5V1Zuqer3b7f6659dwfpOf37R70vf7/a9V9ds2cY5HVdWr3W73+8rXOb/DqJr4/FoFuaqqnzeL83X/1MKfhIeffH/Wt/8GPJV9VT1f8ZPQ+f1vZE16frPuSX9Z53tz6zDrxYrnnd+xac9v1j3pzzZLcZqZzq9v5jDnN+ue9FP/QrnEjyuedX53TXl+bjWBQEEgUBAIFAQCBYFAQSBQEAgUBAIFgUBBIFAQCBQEAgWBQEEgUBAIFAQCBYFAQSBQEAhm3ZO+6g6oE3m74lnnd9eU5zfrnvQ3m6U4zUzn1zdzmPObdU/667q5jOxc9oeZSzm/Y9OeX6sgH+vmOsZzua4V98sebuh7Ved5k/+7OvPvFa9xfremPr9LuLz6Rd1cSrbm3qUl3tbNPwv+mPny5cT52ZMOAAAAAAAAAOtcwkdNht3zLZ896adycXu+5bsdVfakn8TF7PmW7+7Isie92yXt+ZbvmD3pJ3BJe77l65s5zPefPenLrfn/EvLdZU86XBoFgUBBIFAQCBQEAgWBQEEgUBAIFAQCBYFAQSBQEAgUBAIFgUBBIFAQCBQEAgWBQEEgsCd9uTV7vuW7y570Tpe051u+vpnDfP/Zk77M2j3f8h2zJ73TRe35lu+IPen3dPF7vuWzJx0AAAAAAAAALsvUHzWpwfPZQz7/+zvtnvQaPJ895EemfX+n3JNeg+ezh/yrpnx/Z92TPno+e8j7Zg6Tb9Y96aPns4e8b+Yw+Wbdkz56PnvI+2YOk8+tJhAoCAQKAoGCQKAgECgIBAoCgYJAoCAQKAgECgKBgkCgIBAoCAQKAoGCQKAgECgIBAoCwax70kfPZw9538xh8s26J330fPaQ980cJt+se9JHz2cPed/MYfJNuSe9Bs9nD/kd076/Lq9uu/g97jX4+dX4+QAAAAAAAADggfFRkzb5+lxEPnvSl5Gvz7T5Wp/mvarzhavDrKsVz8t3TL4+zXz2pG8zU76+mcPksyd9m5ny9c0cJp896dvMlK9v5jD53GoCgYJAoCAQKAgECgKBgkCgIBAoCAQKAoGCQKAgECgIBAoCgYJAoCAQKAgECgKBgkCgIBDYk77NTPn6Zg6Tz570bWbK1zdzmHz2pG8zU76+mcPke9R4+HPd7N9+slmcY9dV9WHF8/Idk69PM5/Lq9vk6/MQ8gEAAADn8i9uSXT/dv6GSgAAAABJRU5ErkJggg==" + }, + "yes": { + "icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAACXBIWXMAAAsTAAALEwEAmpwYAAAFHUlEQVR4nO3dQY5UZRQF4FsaJ6Qdoy7ADbAA455gYpjqBPdkdM4GXADCxBFhIINy0G2k0u+efsVfr/ir+L4h3e09eckRiOU7VQAAAMAUdg98/aaqHlfVo6r66sS331fVu6p6U1VvP/KfIZ98H2tVvlSQb6rquxOH6ryqqtdH/ox8/5NvTJvvi+YHbup84eru1s0R3y/fIfnGtPm6gjzeLkvrmJvyjd2Ub+XNriCPNgzSOeamfGM35Vt5syvIqf9CtMYxN+UbuynfyptdQYBSEIgUBAIFgUBBIFAQCBQEAgWBQEEgUBAIFAQCBYFAQSBQEAgUBAIFgUBBIFAQCBQEgq4g78+a4vib8o3dlG/lza4g7zYM0jnmpnxjN+VbebMryJsNg3SOuSnf2E35Vt78svnmf6pqX1Vfbxbn0Kuq+vuI75fvkHxj2nxeXt2Tb8znkA8AAAAAAAAAPjM+atKTb8xwvv1+/0NVPauqJ3U7C31Kr6vqZVW92O12v3ffZCd9HfnGHJ1vv9//VFU/bxPn8FRVPd/tdr8sfbEryE1Vfb9ZpGV/1vp/08h339Xku/ud47d6+E84p7Kvqh+Xfiexk77NTfnGbj6r85Wj7m49XfqCnfRtbso3dvPJZimOvGknfZub8o3dPPVfyNf4dukXvdUEAgWBQEEgUBAIFAQCBYFAQSBQEAgUBAIFgUBBIFAQCBQEAgWBQEEgUBAIFAQCBYFAQSCwk77NTfnGbh77jq9T+GvpF+2kb3NTvrGbLzdLceRNO+nb3JRv7OaLun2Z27ns727e0xXkbd2+LvJcXtVx72+V79BV5bt7w+HzOk9J/nv16B+LWR744alfblzyXXW+u1eQPq3bl7otvrdqwF91+8eqX9PLqwEAAAAAAACAD/moSe/q882wQ/6AT/787KSvc3X5ZtkhD6Z4fnbS17uafDPtkDemeX520re5OXu+aXbIG9M8Pzvp29ycPd80O+SNaZ6fnfRtbs6eb5od8sY0z89bTSBQEAgUBAIFgUBBIFAQCBQEAgWBQEEgUBAIFAQCBYFAQSBQEAgUBAIFgUBBIFAQCBQEAjvp29ycPd80O+SNaZ6fnfRtbs6eb5od8sY0z89O+jY3Z883zQ55Y5rnZyd9navKN9MOeWOa5+fl1b2rz3cBO+RTPz8AAAAAAAAA+PzEj5rY0bZDPuAqPqrTFsSO9gE75GMudmd+sSB2tBfZIR9zkTvz3cfd7WiP3fT8xm5Ok68riB3tsZue39jNafJ1BbGjPXbT8xu7OU0+bzWBQEEgUBAIFAQCBYFAQSBQEAgUBAIFgUBBIFAQCBQEAgWBQEEgUBAIFAQCBYFAQSBQEAi6gtjRHrvp+Y3dnCZfVxA72mM3Pb+xm9Pk6wpiR3vspuc3dnOafIsFsaN9jx3yMRe7M7/m5dV2tO2Qf4yreHk1AAAAAAAAAPChh4Ymp/5P/XbIr/6jHJ88XyrIFDvVHTvkBy52hzyYIl9XkGl2qpfYIV90kTvkjWnydf8/yDQ71Q075GM35Vt5syvINDvVDTvkYzflW3mzK8g0O9UNO+RjN+VbedNbTSBQEAgUBAIFgUBBIFAQCBQEAgWBQEEgUBAIFAQCBYFAQSBQEAgUBAIFgUBBIFAQCBQEgq4g0+xUN+yQj92Ub+XNriDT7FQ37JCP3ZRv5c2uINPsVDfskI/dlG/lza4g0+xUL7FDfs/F7pA3psl3DS+vtkN+wS+HfsDs+QAAAIBz+RdDw2v5jDe3GQAAAABJRU5ErkJggg==" + }, + "no": { + "icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAACXBIWXMAAAsTAAALEwEAmpwYAAAFCElEQVR4nO3dMY5URxQF0NeWnCBysBfgDbAAy3uCxCK1E7wny87ZgBcAJkckBO1g2sJN/7r+f6p7VPXnnJQZ3lNNXRBSU7cKAAAAGMIh/eLxePyxql5V1Yuqen7l2X9X1duqenM4HP645+/xtKqeVdWTqvr2WoudfK6qT1X1oao+3vP3sF/HfiPcv2ZAjsfjz1X1y5WXWhxVVa8Ph8OvG7/veVV9f4N9lryruwPdwn5fbN5vlPu3GJBTcn9v/foNHKvqpw1/kzytqh9uuM+Sv2r9n4T2u7R6v5Hu3zeNb3hVD7dcnWa93PD1z261yJVm2q9v5jD3rxWQF7fbpWnLzCc32+I6M+3XN3OY+9cKyLX/QbTGdxu+9tr/oLz2TPv1zRzm/rUCApSAQCQgEAgIBAICgYBAICAQCAgEAgKBgEAgIBAICAQCAoGAQCAgEAgIBAICgYBAICAQtAKy9Y2la3i/4Ws/32yL68y0X9/MYe5fKyBvb7hIy5aZn262xXVm2q9v5jD3rxWQN3X3mNZDOZ5mrvXhVotcaab9+mYOc/8WA3J6Ye51PcyS/z79+OeG7/lYd89ZPpR3te19Wfud27TfSPdvzePVL+vuUa0t71at8b7u/lr7zePV97L7/Sa4fwAAAAAAAADwyPxfUeIMH0XQ4+787mPV+aWA6NE+jaod9rg7vzPN82sFRI/2VyNrRz3uzm/R4vm1/j+IHu1ze+txd34rZ7YCoke7b6bz65s5zPm1AqJH+9Keetyd38qZXjWBQEAgEBAIBAQCAYFAQCAQEAgEBAIBgUBAIBAQCAQEAgGBQEAgEBAIBAQCAYFAQCAQEAhaAdGjfWlPPe7Ob+XMVkD0aPfNdH59M4c5v1ZA9Gif21uPu/NbObMVED3aX+yux935XWie3x4erx65R9v57fj8AAAAAAAAAODxmfqjJjX4fnrI5//5TtuTXoPvp4f8zLQ/3yl70mvw/fSQL5ry5ztrT/ro++kh75s5zH6z9qSPvp8e8r6Zw+w3a0/66PvpIe+bOcx+XjWBQEAgEBAIBAQCAYFAQCAQEAgEBAIBgUBAIBAQCAQEAgGBQEAgEBAIBAQCAYFAQCAQEAhm7UkffT895H0zh9lv1p700ffTQ943c5j9Zu1JH30/PeR9M4fZb8qe9Bp8Pz3kF6b9+Xq8uk0PeZ/d/3wBAAAAAAAA4PGZ+qMmesidX4d996TrIT/j/PrsqyddD/ki59dnVz3pesj7Zjq/lTNn7UnXQ9430/mtnDlrT7oe8r6Zzm/lTK+aQCAgEAgIBAICgYBAICAQCAgEAgKBgEAgIBAICAQCAoGAQCAgEAgIBAICgYBAICAQCAgEs/ak6yHvm+n8Vs6ctSddD3nfTOe3cuasPel6yPtmOr+VM6fsSddDfsH59dlnT7oecufXQU86AAAAAAAAAGwWP2qiR7v7owj2m7zHvRkQPdpnNveQl/3+a9oe98WA6NFetLqHvOy3ZMoe99bH3fVo9820X9/MYe5fKyB6tPtm2q9v5jD3rxUQPdp9M+3XN3OY++dVEwgEBAIBgUBAIBAQCAQEAgGBQEAgEBAIBAQCAYFAQCAQEAgEBAIBgUBAIBAQCAQEAgGBoBUQPdp9M+3XN3OY+9cKiB7tvpn265s5zP1rBUSPdt9M+/XNHOb+LQZEj/aFTT3kZb+vTdvjvubxaj3aO30cugbfb4L7BwAAADyUfwDmcbblze7mOAAAAABJRU5ErkJggg==" + }, + "happy": { + "icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAACXBIWXMAAAsTAAALEwEAmpwYAAAF2klEQVR4nO3dPXIUVxQF4DOmnLhE7J8FsAEW4PKeIHGR2gnsiTI5G/ACBCSOKAII2sEMJY+ld+mn7pl6Pfq+lJbuqeYdCaqkdxMAAABgCLtv/PlVkh+T/JDk+5Vnf0nyKcmHJB/v+Tnkk+++ZuWrCvJTkl9WDtVyneR958fId0O+ZZr5vmt8wFXOFy6HWVcdz8t3TL5lmvlaBfnxdFmaembKt2ymfDNntgrywwmDtPTMlG/ZTPlmzmwVZO3/EM3RM1O+ZTPlmzmzVRAgCgIlBYGCgkBBQaCgIFBQECgoCBQUBAoKAgUFgYKCQEFBoKAgUFAQKCgIFBQECgoCBQWBQqsgX86aon+mfMtmyjdzZqsgn04YpKVnpnzLZso3c2arIB9OGKSlZ6Z8y2bKN3Pmo8bDn5NMSR6fLM6x6yT/dDwv3zH5lmnmc3l1m3zLPIR8AAAAAAAAAPDAbPpHTaZp+jXJ8yRPs18bvKb3Sd4mebnb7f665+fw/jb+/ja7J32apt+T/HGaOMejkrzY7XZ/dn6c93cYlQ2/v1ZBrpI8OVmcu/2dmV8JD1/5Xufb3wHXMiX5reMroff3v5HZ6Pvb6p705znfX24Os551PO/9Hdvs+9vqnvSnJ0uxzkzvb9nMYd7fVvekr/0fyjl+7njW+7ttk+/PrSZQUBAoKAgUFAQKCgIFBYGCgkBBQaCgIFBQECgoCBQUBAoKAgUFgYKCQEFBoKAgUFAQKCgIFLa6J73rDqiVvOt41vu7bZPvb6t70t+eLMU6M72/ZTOHeX9b3ZP+MvvLyM5lOsycy/s7ttn31yrIx+yvYzyX63TcL3u4oe9FzvOX/PXqzDcdH+P93dj0+7uEy6ufZX8pWc+9S3O8y/6fBa+2fPlyxfuzJx0AAAAAAAAA+mz6R00in3z3d9l70iPff8m3TDNf66d5r3K+cDnMuup4Xr5j8i3TzLfVPenyLZsp38yZW92TLt+ymfLNnLnVPenyLZsp38yZbjWBgoJAQUGgoCBQUBAoKAgUFAQKCgIFBYGCgkBBQaCgIFBQECgoCBQUBAoKAgUFgYKCQEFBoLDVPenyLZsp38yZW92TLt+ymfLNnLnVPenyLZsp38yZjxoPf85+v/Xjk8U5dp3kn47n5Tsm3zLNfC6vbpNvmYeQDwAAAAAAAAAemPJHTaZp+jXJ8yRPs1/Lu6b3Sd4mebnb7f665+cY/UcR5FuQb4Tz1yzINE2/J/lj5VB3jkryYrfb/dn5cUPs0S7Id6M73yjn786CHJr7uvXnJzAl+a3jO8lVkicnzHOXvzP/K6F8t83ON9L5a/0+yPOcL1wOs551PD/MHu0Vnl3LJeUb5vy1CvL0dFmaemYOs0d7hWfXckn5hjl/rYKs/R+iOX7ueHaYPdorPLuWS8o3zPlzqwkUFAQKCgIFBYGCgkBBQaCgIFBQECgoCBQUBAoKAgUFgYKCQEFBoKAgUFAQKCgIFBQECgoChVZBeu9YWsO7jmeH2aO9wrNruaR8w5y/VkHenjBIS8/MYfZor/DsWi4p3zDnr1WQl9lfpnUu02HmXMPs0V7h2bVcUr5hzt+dBTncMPci5wn59erHNx0f8zH76yzP5Tp998vKd6wr30jnb87l1c+yv1Sr596qOd5l/23tlcur7+Xi823g/AEAAAAAAADAA/OtRYlb+FGEYfe4y7csXwY4f1VB7NE+jMo99rjLdzMq98iXQc5fqyD2aP9vZDr2uMt3e2Q68mWg89f6fRB7tI/17nGX71hvvmHOX6sg9mgvmynfspnDnL9WQezRvq3n9xHku60n3zDnz60mUFAQKCgIFBQECgoCBQWBgoJAQUGgoCBQUBAoKAgUFAQKCgIFBYGCgkBBQaCgIFBQECgoCBRaBbFH+7aePe7y3daTb5jz1yqIPdrLZsq3bOYw569VEHu0j/XucZfvWG++Yc5fqyD2aN/o3uMu35HufBno/F3C5dXD7tGWb/Ee8qHPHwAAAHBG/wKcHIXJ5Tep/gAAAABJRU5ErkJggg==" + }, + "sad": { + "icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAACXBIWXMAAAsTAAALEwEAmpwYAAAFqElEQVR4nO3dPZJTRxQF4CNTTlxD7J8FeAMswOU9QeIitRPYkwtyNuAFDJA4ogggeA4kbMRMX15PS/Jr+L6Up7mnWn00TJWqOwEAAAA2YfeZf79K8n2S75J8e+LZ75O8TfI6yZs7/gz55LurVfmqgvyQ5KcTh2q5TvKq8zXy/Ue+Mc183zRecJXLhcth1lXH8/Idk29MM1+rIN+fL0tTz0z5xmbKt3JmqyDfnTFIS89M+cZmyrdyZqsgp/6DaI2emfKNzZRv5cxWQYAoCJQUBAoKAgUFgYKCQEFBoKAgUFAQKCgIFBQECgoCBQWBgoJAQUGgoCBQUBAoKAgUFAQKrYK8v2iK/pnyjc2Ub+XMVkHenjFIS89M+cZmyrdyZqsgr88YpKVnpnxjM+VbOfNe4+F3SZYk988W59h1kr87npfvmHxjmvkcXt0m35ivIR8AAAAAAAAAfGWm/qrJsiy/JHmU5EH21waf0qskL5I82e12z+74M6zf5Os37T3py7L8luT388Q5HpXk8W63+6PzddbvMCoTr1+rIFdJfj5bnNv9lZWfhIdPvj/z+d+Ap7Ik+bXjk9D6fTIyk67frPekP8rl3twcZj3seN76HZt2/Wa9J/3B2VKcZqb1G5u5mfWb9Z70U/9BucaPHc9av5umXD+nmkBBQaCgIFBQECgoCBQUBAoKAgUFgYKCQEFBoKAgUFAQKCgIFBQECgoCBQWBgoJAQUGgoCBQmPWe9K4zoE7kZcez1u+mKddv1nvSX5wtxWlmWr+xmZtZv1nvSX+S/WFkl7IcZq5l/Y5Nu36tgrzJ/jjGS7lOx/myhxP6Hucyb/KHozOfd7zG+v1n6vX7Eg6vfpj9oWQ95y6t8TL7/xY8nfnw5Yr1c086AAAAAAAAAPSZ+qsmkU++u/uy70mPfB+Tb0wzX+vbvFe5XLgcZl11PC/fMfnGNPPNek+6fGMz5Vs5c9Z70uUbmynfypmz3pMu39hM+VbOdKoJFBQECgoCBQWBgoJAQUGgoCBQUBAoKAgUFAQKCgIFBYGCgkBBQaCgIFBQECgoCBQUBAoKAoVZ70mXb2ymfCtnznpPunxjM+VbOXPWe9LlG5sp38qZ9xoPv8v+fuv7Z4tz7DrJ3x3Py3dMvjHNfA6vbpNvzNeQDwAAAAAAAAC+MlN/1WRZll+SPEryIPtrg0/pVZIXSZ7sdrtnd/kB8o3lywb237T3pC/L8luS388T53hUkse73e6PrhfJ9++o3CFfNrL/WgW5SvLz2eLc7q+s/E1y+OT7M5//DXgqS5Jf134SyndzZDryZUP7b9Z70h/lcm9uDrMedjwv37HefJvZf7Pek/7gbClOM1O+sZmb2X+z3pN+6j8o1/ix41n5burJt5n951QTKCgIFBQECgoCBQWBgoJAQUGgoCBQUBAoKAgUFAQKCgIFBYGCgkBBQaCgIFBQECgoCBQUBAqz3pPedYbWibzseFa+m3rybWb/zXpP+ouzpTjNTPnGZm5m/816T/qT7A8ju5TlMHMt+Y715tvM/msV5E32xzFeynU6zuc9nND3OJd5kz8cnfl87QvkO9KdLxvaf1/C4dUPsz+UrOfcpTVeZv/fgqeDh0PLN/Hh1QAAAAAAAADAx8qvmrhHe/irCPKNf5Xof91/zYK4R/tI9z3uke9j3fm2sv9uLYh7tG+1+h73yHeb1fm2tP9aX3d3j/bYTPnGZm5m/7UK4h7tsZnyjc3czP5rFcQ92mMz5RubuZn951QTKCgIFBQECgoCBQWBgoJAQUGgoCBQUBAoKAgUFAQKCgIFBYGCgkBBQaCgIFBQECgoCBQUBAqtgrhHe2ymfGMzN7P/WgVxj/bYTPnGZm5m/7UK4h7tsZnyjc3czP67tSDu0b6h6x73yPeprnxb2n9rDq92j/YXejh0Np5vgv0HAAAAXMo/WNaFyX18J6sAAAAASUVORK5CYII=" + }, + "confused": { + "icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAACXBIWXMAAAsTAAALEwEAmpwYAAAFd0lEQVR4nO3dMW5TWxAG4N8PvQaFmsdbABvIAhB7ShqUFpqwJwR9NsACAjRUiAKK+wob8UxyhntzbMuHfF/LdWY01u8QyZpJAAAAgKOw+s2/nyR5nORhkr93XPt7kq9JPiX5csefoT/93dWs/qqA/JPk3x031XKd5OPC1+jvJ/31afb3V+MFJzlcc9nUOlnwvP626a9Ps79WQB7vr5emJTX111dTfzNrtgLycI+NtCypqb++mvqbWbMVkF3/QTTHkpr666upv5k1WwEBIiBQEhAoCAgUBAQKAgIFAYGCgEBBQKAgIFAQECgICBQEBAoCAgUBgYKAQEFAoCAgUBAQKLQC8v2gXSyvqb++mvqbWbMVkK97bKRlSU399dXU38yarYB82mMjLUtq6q+vpv5m1nzQePhbkinJo721s+06yecFz+tvm/76NPuzvLpNf33uQ38AAAAAAAAAcM8M/VWTaZqeJTlPcpr12eBd+pjkKsnlarV6e8efYX6Dz2/YO+nTNL1I8nI/7WyXSnKxWq1eLXyd+W1KZeD5tQJykuTp3tq53fvM/CTcfPK9ye9/A+7KlOT5gk9C8/ulZAad36h30s9zuDc3m1pnC543v23Dzm/UO+mne+tiNzXNr6/m0cxv1Dvpu/6Dco4nC541v5uGnJ+tJlAQECgICBQEBAoCAgUBgYKAQEFAoCAgUBAQKAgIFAQECgICBQGBgoBAQUCgICBQEBAoCAgURr2TvmgH1I58WPCs+d005PxGvZN+tbcudlPT/PpqHs38Rr2Tfpn1MrJDmTY15zK/bcPOrxWQL1mvYzyU6yzYL7vZ0HeRw7zJP1ZnvlvwGvP7aej5/QnLq8+yXkq2ZO/SHB+y/m/B65GXL1fMz510AAAAAAAAAFhm6K+aRH/6u7s/+0569Pd/+uvT7K/1bd6THK65bGqdLHhef9v016fZ36h30vXXV1N/M2uOeiddf3019Tez5qh30vXXV1N/M2vaagIFAYGCgEBBQKAgIFAQECgICBQEBAoCAgUBgYKAQEFAoCAgUBAQKAgIFAQECgICBQGBgoBAYdQ76frrq6m/mTVHvZOuv76a+ptZc9Q76frrq6m/mTUfNB7+lvV960d7a2fbdZLPC57X3zb99Wn2Z3l1m/763If+AAAAAAAAAOCeGfqrJtM0PUtynuQ067PBu/QxyVWSy9Vq9faOP8P8Bp/fsHfSp2l6keTlftrZLpXkYrVavVr4OvPblMrA82sF5CTJ0721c7v3mflJuPnke5Pf/wbclSnJ8wWfhOb3S8kMOr9R76Sf53Bvbja1zhY8b37bhp3fqHfST/fWxW5qml9fzaOZ36h30nf9B+UcTxY8a343DTk/W02gICBQEBAoCAgUBAQKAgIFAYGCgEBBQKAgIFAQECgICBQEBAoCAgUBgYKAQEFAoCAgUBAQKIx6J33RDqgd+bDgWfO7acj5jXon/WpvXeympvn11Tya+Y16J/0y62VkhzJtas5lftuGnV8rIF+yXsd4KNdZsF92s6HvIod5k3+szny34DXm99PQ8/sTllefZb2UbMnepTk+ZP3fgtcjL1+umJ876QAAAAAAAACwTPlVE3e03SHv8EfMrxkQd7S3uEPeZ9j53RoQd7Rv5Q55nyHn1/q6uzvafTXNr6/m0cyvFRB3tPtqml9fzaOZXysg7mj31TS/vppHMz9bTaAgIFAQECgICBQEBAoCAgUBgYKAQEFAoCAgUBAQKAgIFAQECgICBQGBgoBAQUCgICBQEBAotALijnZfTfPrq3k082sFxB3tvprm11fzaObXCog72n01za+v5tHM79aAuKN9gzvkfYad35zl1e5ou0N+F/dhfgAAAMCh/AecHIXJK5h09QAAAABJRU5ErkJggg==" + }, + "angry": { + "icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAACXBIWXMAAAsTAAALEwEAmpwYAAAF8klEQVR4nO3dMW4USRQG4Ne7IkHe2IYDcAEOYHEnnCCnkJjb7OYIci6wB7Ah2chysJaoDWa87Ky7Ht2u7qF7/H2px/N+PfVvZDGuigAAAAAWocu+WEo5jYiziHgZEScTz/4SEZ8j4qLruo8PfI+jiDiOiKcR8WSqYFu3EXETEV8j4vqB7yFfQ74lPH/VgpRS3kTE24lD9Y6KiPOu696N/L6TiHg+Q54+l7FZ6BjyfTc631Kev96CbJv7ofb1GZSIeDXiX5KjiHgxY54+f8bwn4Ty3Tc435Kev18q33AW+wsX21mvR7z+eK4gE82Ur23mYp6/WkFezpelaszMp7OlmGamfG0zF/P81Qoy9S9EQzwb8dqpf6GceqZ8bTMX8/zVCgKEgkBKQSChIJBQEEgoCCQUBBIKAgkFgYSCQEJBIKEgkFAQSCgIJBQEEgoCCQWBhIJAQkEgUSvI2DOWpnA14rW3s6WYZqZ8bTMX8/zVCvJ5xiA1Y2bezJZimpnytc1czPNXK8hFbA7T2peynTnU17mCTDRTvraZi3n+eguyPWHuPPYT8u7ox08jvuc6NsdZ7stljDtfVr5do/It6fkbcnj169gcqjXm3KohrmLzz9p7h1c/yMHnW8HzBwAAAAAAAACPzI8uSlzDRxHc425/DzFof1lB3KO9HRUHeI+7/e2o7q9WEPdo/29kHNA97vbXq3d/tb8HcY/2rkO7x93+Bs6sFcQ92m0z7a9t5mL2VyuIe7TvO6R73O1v4EynmkBCQSChIJBQEEgoCCQUBBIKAgkFgYSCQEJBIKEgkFAQSCgIJBQEEgoCCQWBhIJAQkEgoSCQqBXEPdr3HdI97vY3cGatIO7Rbptpf20zF7O/WkHco73r0O5xt7+BM2sFcY/2dwd3j7v93VPd3yEcXr3ke7Tt74D3BwAAAAAAAACPz6o/ahLyyfdwh31Pesj3X/K1qearfZr3KPYXLrazjka8Xr5d8rWp5lvrPenytc2Ub+DMtd6TLl/bTPkGzlzrPenytc2Ub+BMp5pAQkEgoSCQUBBIKAgkFAQSCgIJBYGEgkBCQSChIJBQEEgoCCQUBBIKAgkFgYSCQEJBIKEgkFjrPenytc2Ub+DMtd6TLl/bTPkGzlzrPenytc2Ub+DMXysv/js291v/NlucXZcR8deI18u3S7421XwOr66Tr81jyAcAAAAAAAAAfFdKOS2l/FFKuSrTu9q+96l88q0uXynlzQyh+nwrpbyRT77V5Cub5n7bU8C7kIObLJ98+8pX+3uQs/jxJ32n1EXE6xGvl2+XfG2q+WoFeTlflqoxM+VrmynfwJm9LS2llHmz9Ou6btBPDfn6ydemL59TTSChIJBQEEgoCCQUBBIKAgkFgYSCQEJBIKEgkFAQSCgIJBQEEgoCCQWBhIJAQkEgoSCQUBBI1AryZa8pNq5GvFa+++Rr05uvVpDPMwapGTNTvraZ8g2cWSvIRWyu4d2Xsp05lHy75GszNt+/Rz/u43S7lqMp5ZPvp+S7C3laSvm9lHI5Q7DL7Xu3Hm4sn3w/JR8AAAAAAAAAPD7plVjb/4Y/i839bScTz/4Sm09QXnRd9/GB73EUEccR8TQinkwVbOs2Im4i4mtEXD/kDexv/furFqRsPsD1duJQvaMi4rzruncjv+8kIp7PkKfPZYz8GwX727Ha/dUu8TyNiA+1r8+gRMSrET8JjyLixYx5+vwZA38S2l+vVe5vrfekH88VZKKZ9tc2czH7W+s96U9nSzHNTPtrm7mY/dUKMvUvREM8G/HaqX+hnHqm/bXNXMz+nGoCCQWBhIJAQkEgoSCQUBBIKAgkFAQSCgIJBYGEgkBCQSChIJBQEEgoCCQUBBIKAgkFgYSCQGKt96TfzpZimpn21zZzMftb6z3pN7OlmGam/bXNXMz+1npP+te5gkw00/7aZi5mf70F2Z4wdx77CXl39OOnEd9zHZvjLPflMkacL2t/96x2f0MOr34dm0O1xpy7NMRVbP5Ze3/ghy/b3+HuDwAAANiXfwDTXfEJIYpjngAAAABJRU5ErkJggg==" + }, + "asleep": { + "icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAACXBIWXMAAAsTAAALEwEAmpwYAAAF3klEQVR4nO3dPY4cVRQF4NNYJGgc87MAFoAXgNiTnSCnkJg9IcjNAljA2CSOEIEJiqAbcMvzrl/N62q98nxfOtVzj2rqTHuk9rsJAAAAMIXDB75+k+TzJJ8l+fTCs/9O8leSP5L8ec/vIZ9899WVryrIF0m+unColtskr1e+Rr7/yTemme+Txgtucr1wOc26WXG9fOfkG9PM1yrI59tlaVozU76xmfJ1zmwV5LMNg7SsmSnf2Ez5Ome2CnLpP4h6rJkp39hM+TpntgoCREGgpCBQUBAoKAgUFAQKCgIFBYGCgkBBQaCgIFBQECgoCBQUBAoKAgUFgYKCQEFBoKAgUGgV5O+rplg/U76xmfJ1zmwV5K8Ng7SsmSnf2Ez5Ome2CvLHhkFa1syUb2ymfJ0zHzUufptkSfJ4szjnbpO8WXG9fOfkG9PM5/DqNvnGPIR8AAAAAAAAAPDAlB81WZbl2yTPkjzJcS3vJb1O8jLJi8Ph8Mt9vsHs+TL5RyVmv38z5GsWZFmW75P8cOFQd45K8vxwOPy46kWT58ske75bZr9/s+S7syCn5v7c+voGliTf9f6mmT1fju8cX2+Y5y6/p/OdZPb7N1O+1v8HeZbrhctp1tMV18+eb5o93w2z379p8rUK8mS7LE1rZs6eb5o93w2z379p8rX+ibVsm+Vuh8Oh67fG7PmSfLNpkLbfei6a/f7NlM+pJlBQECgoCBQUBAoKAgUFgYKCQEFBoKAgUFAQKCgIFBQECgoCBQWBgoJAQUGgoCBQUBAoKAgUWgVZdcbShbxace3s+abZ890w+/2bJl+rIC83DNKyZubs+abZ890w+/2bJl+rIC9yPEzrWpbTzF6z55tmz3fD7Pdvmnx3FuR0wtzzXCfkv0c//tr7gtnz5XjC4e1Gee5ymxXn885+/2bK13N49dMcD9X68sLBXuX4tvbT4OHG0+bLPg6vnvb+zZ4PAAAAAAAAAB6eD63EmvqjEpFPvvvrylcVZOo935HvXfKNaeZrfdz9JtcLl9OsmxXXy3dOvjHNfK2CzL7nW76xmfJ1zmwVZPY93/KNzZSvc2arIJf+g6jHmpnyjc2Ur3OmU02goCBQUBAoKAgUFAQKCgIFBYGCgkBBQaCgIFBQECgoCBQUBAoKAgUFgYKCQEFBoKAgUFAQKLQKMvueb/nGZsrXObNVkNn3fMs3NlO+zpmtgsy+51u+sZnydc581Lj4bY77ox9vFufcbZI3K66X75x8Y5r5HF7dJt+Yh5APAAAAAAAAAB6YXX/UZFmWb5M8S/Ikx7XBl/Q6ycskLw6Hwy/3+QbyjeXLBM/fbvekL8vyfZIftolzPirJ88Ph8OOqF8n336jcI18mef5aBblJ8vVmce72ezrfSU6/+X7Oh98BL2VJ8l3vb0L53h+ZFfky0fO31z3pz3K9H25Os56uuF6+c2vzTfP87XVP+pPNUlxmpnxjM6d5/va6J/3Sf1D2+HLFtfK9b02+aZ4/p5pAQUGgoCBQUBAoKAgUFAQKCgIFBYGCgkBBQaCgIFBQECgoCBQUBAoKAgUFgYKCQEFBoKAgUNjrnvRVZ2hdyKsV18r3vjX5pnn+9ron/eVmKS4zU76xmdM8f3vdk/4ix8PIrmU5zewl37m1+aZ5/loF+TPH4xiv5TYrzuc9ndD3PNf5If97dOavvS+Q78zqfJno+fsYDq9+muOhZGvOXerxKsd/Fvw0eDi0fDs+vBoAAAAAAAAAeNeuP2oS+eS7v497T3rke5d8Y5r5Wp/mvcn1wuU062bF9fKdk29MM99e96TLNzZTvs6Ze92TLt/YTPk6Z+51T7p8YzPl65zpVBMoKAgUFAQKCgIFBYGCgkBBQaCgIFBQECgoCBQUBAoKAgUFgYKCQEFBoKAgUFAQKCgIFBQECnvdky7f2Ez5OmfudU+6fGMz5eucudc96fKNzZSvc+ajxsVvc9xv/XizOOduk7xZcb185+Qb08zn8Oo2+cY8hHwAAADAtfwDbK2ONrQZz3kAAAAASUVORK5CYII=" + }, + "surprised": { + "icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAACXBIWXMAAAsTAAALEwEAmpwYAAAFc0lEQVR4nO3dP25UVxQG8G8SpUFODWQBbMALiNiT3SC30Jg9Iei9ARbAnyYVogjFpJhBycR+h/d8543uNb9fmzHn07E+EyTrngQAAADowuYH//0syeMkj5L8duTZ35J8TfI5yZf7/AHb7fbPJJdJzpM8OV60JMmnJDdJrjebzdt7/hn2N/j+qoI8SfLHkUNN+ZDdQmfbbrcvkrxcJ87hqCRXm83m1cKvs7/9qAy8v6mCnCV5tlqcu73PzJ+E+598b/LjvwGPZZvk+YKfhPb3v5EZdH+/THz48bpZmmde5nTf3OxnXSz4vP0dGnZ/UwV5tGKQKUtmnq+W4jgz7a9tZjf7myrIsf9BNMeSmcf+B+UcTxd81v5uG3J/UwUBoiBQUhAoKAgUFAQKCgIFBYGCgkBBQaCgIFBQECgoCBQUBAoKAgUFgYKCQEFBoKAgUFAQKEwV5NtJUyyfuegNqCP5uOCz9nfbkPubKsjXFYNMWTLzZrUUx5lpf20zu9nfVEE+rxhkypKZ19k9RnYq2/3Muezv0LD7myrIl+yeYzyVD1nwvuz+hb6rnOab/P3pzHcLvsb+/jX0/h7C49UX2T1KtuTdpTk+Zve/Ba9Hfny5Yn9t+wMAAAAAAACAn8/Qv2oS+eS7v4d9Jz3y/Zd8bSbzTf0271lOFy77WWcLPi/fIfnaTOYb9U66fG0z5Zs5c9Q76fK1zZRv5sxR76TL1zZTvpkzvWoCBQWBgoJAQUGgoCBQUBAoKAgUFAQKCgIFBYGCgkBBQaCgIFBQECgoCBQUBAoKAgUFgYKCQGHUO+nytc2Ub+bMUe+ky9c2U76ZM0e9ky5f20z5Zs78deLDf2d33/r31eIc+pDkrwWfl++QfG0m83m8epp8bX6GfAAAAAAAAADwk/GrJtOa82232z+TXCY5z+6s8TF9SnKT5Hqz2by955/R9f7SQT530udZnG+73b5I8nKdOIejklxtNptXC7+u6/2lk3xTBTlL8my1OHd7n/k/abrOt/+b401+/Df0sWyTPF/wN0nX+0tH+dxJX2fmZU5XjuxnXSz4fO/76yafO+nrzDxfLcVxZva+v27yuZO+zsxj/4N8jqcLPtv7/rrJ51UTKCgIFBQECgoCBQWBgoJAQUGgoCBQUBAoKAgUFAQKCgIFBYGCgkBBQaCgIFBQECgoCBQUBArupK8zc+kbUMfwccFne99fN/ncSV9n5s1qKY4zs/f9dZPPnfR1Zl5n95jbqWz3M+fqfX/d5JsqyJfsnmM8lQ9Z9n5r1/n2Lxxe5TQl+f706LsFX9P1/tJRPo9XTzvW49UX2T3qtuTdqjk+Zve/Va89Xn0v7qQDAAAAAAAAwGJD/6qJO+T21+Bh30l3h/yA/bV5WHfS3SG/k/21eVB30t0hb5tpfzNnjnon3R3ytpn2N3PmqHfS3SFvm2l/M2d61QQKCgIFBYGCgkBBQaCgIFBQECgoCBQUBAoKAgUFgYKCQEFBoKAgUFAQKCgIFBQECgoCBQWBwqh30t0hb5tpfzNnjnon3R3ytpn2N3PmqHfS3SFvm2l/M2cOeSfdHfJb7K/Nw7yT7g65/TVwJx0AAAAAAAAAFhv6V03SeT53yMf//g57Jz2d53OH/MCw398h76Sn83zukN9pyO/vqHfSe8/nDnnbzG7yjXonvfd87pC3zewm36h30nvP5w5528xu8nnVBAoKAgUFgYKCQEFBoKAgUFAQKCgIFBQECgoCBQWBgoJAQUGgoCBQUBAoKAgUFAQKCgIFBYHCqHfSe8/nDnnbzG7yjXonvfd87pC3zewm36h30nvP5w5528xu8g15Jz2d53OH/JZhv78er57mDnmbB//9BQAAAE7oHzt4fMP9uDtRAAAAAElFTkSuQmCC" + }, + "silly": { + "icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAACXBIWXMAAAsTAAALEwEAmpwYAAAGGElEQVR4nO3dMW4USRQG4Ne7IkHe2MABuAAHsLgTThApJHCb3RxB7gtwABuSjSwHi0RtMMOyI6YeXa7uoRh/X+qeeb9Q/2NGateLAAAAAIYwZT8spZxFxHlEPImIBwvP/hgRFxHxepqmd7d8j5OIOI2I+xFxb6lgW58j4iYiPkXE9S3fQ76OfCPcf9WClFKeR8TLhUPtHRURL6ZpetX4ugcR8WiFPPtcxuYftIV83zTnG+X+21uQbXPf1n6+ghIRTxt+k5xExOMV8+zzIeZ/Esr3vdn5Rrr/fqu84DwOFy62s541XH+6VpCFZsrXN3OY+69WkCfrZalqmXl/tRTLzJSvb+Yw91+tIEt/IZrjYcO1S3+hXHqmfH0zh7n/agUBQkEgpSCQUBBIKAgkFAQSCgIJBYGEgkBCQSChIJBQEEgoCCQUBBIKAgkFgYSCQEJBIKEgkKgVpPWMpSVcNVz7ebUUy8yUr2/mMPdfrSAXKwapaZl5s1qKZWbK1zdzmPuvVpDXsTlM61DKduZcn9YKstBM+fpmDnP/7S3I9oS5F3GYkF+Pfnzf8Jrr2BxneSiX0Xa+rHy7mvKNdP/NObz6WWwO1Wo5t2qOq9j8Wnvj8OpbOfp8v8D9BwAAAAAAAAB3zI8WJQ79KELIJ9/tzcqXFWToPdoh3//J16ear/a4+0kcLlxsZ500XC/fLvn6VPPVCjL6Hm35+mbKN3NmrSCj79GWr2+mfDNn1goy+h5t+fpmyjdzplNNIKEgkFAQSCgIJBQEEgoCCQWBhIJAQkEgoSCQUBBIKAgkFAQSCgIJBYGEgkBCQSChIJBQEEjUCjL6Hm35+mbKN3NmrSCj79GWr2+mfDNn1goy+h5t+fpmyjdz5u+Vi/+Jzf7oP1aLs+syIv5uuF6+XfL1qeZzeHWdfH3uQj4AAAAAAAAA4JtSylkp5a9SylVZ3tX2vc/kk++Xy1dKeb5CqH2+lFKeyyffL5OvbJr75UABv4ac3WT55DtUvtrfg5zHj5/0XdIUEc8arpdvl3x9qvlqBXmyXpaqlpny9c2Ub+bMvS0tpZR1s+w3TdOsTw359pOvz758TjWBhIJAQkEgoSCQUBBIKAgkFAQSCgIJBYGEgkBCQSChIJBQEEgoCCQUBBIKAgkFgYSCQEJBIFEryMeDpti4arhWvu/J12dvvlpBLlYMUtMyU76+mfLNnFkryOvYrOE9lLKdOZd8u+Tr05rvv6MfD3G6Xc/RlPLJ91PyfQ15Vkr5s5RyuUKwy+179x5uLJ98PyUfAAAAAAAAANw9P1qJdRIRpxFxPyLuLTz7c0TcRMSniLi+5XvI15Fv+5jFeWz28z1YLlpEbB5Zv4iI19M0vbvNG4yQLyvIg4h4tHComsto/xsA+b5pzlc2D+i9XCfO7qiIeDFN06umFw2Sr1aQk4h4vFqk/T7E/E9C+b43O9/2k/ltHG7VcomIp3N/k4yUr/b3IKfr5umeKV/fzGH2kFcMk69WkPvrZalqmSlf38xh9pAvcO1S9s6sFWTpL5RztMyUr2/m0l9453jYcO0w+ZxqAgkFgYSCQEJBIKEgkFAQSCgIJBQEEgoCCQWBhIJAQkEgoSCQUBBIKAgkFAQSCgIJBYGEgkCiVpDPB03RPlO+vpnD7CGvGCZfrSA3KwapaZkpX9/MYfaQL3DtUpr2pH9aMUhNy0z5+maOvod8mHy1glzH5jjLQ7mMtvNl5dvVlG97guCLOMxN+PVoz/dzXzBSPodX1x19vu0Rn89ic2hay7lVc1zF5r8tbzoPrx42HwAAAAAAAADcPR41qTv6fCPsIc+MkM+e9HmOLt8oe8irLxoknz3p8x1NvpH2kO+9eKB89qSvM3P0fMPsIa8YJp896evMHD3fMHvIF7h2KfakdzqmfMPsIa8YJp9TTSChIJBQEEgoCCQUBBIKAgkFgYSCQEJBIKEgkFAQSCgIJBQEEgoCCQWBhIJAQkEgoSCQUBBI2JO+zszR8w2zh7ximHz2pK8zc/R8w+whX+DapdiT3umY8g2zh7ximHz2pM9zVPlG2kO+z0j5HF5dd/T5Rt9DPno+AAAA4ID+BZBL4D8AYb8+AAAAAElFTkSuQmCC" + }, + "fabulous": { + "icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAACXBIWXMAAAsTAAALEwEAmpwYAAAFs0lEQVR4nO3dMXIURxQG4Dd2OaHkGOMDcADrACruJCWUUkjEbeycglw+AAdYQeKIIjBVtINZGa+18+jRzCw9q+9LWe37afHvomLpFwEAAAC0r5RyVkr5o5RyU+Z3s33uM/nkW12+UsrzBULt86WU8lw++VaTr/TN/XKggLchq5ssn3yHyvfDQMaLiOhqf0Mz6CLifMTj5dsl3zSD+YYKcrpclkFjZso3baZ8lTP3trSUUpbNsl/XdVWvGvLtJ980+/INvYMAoSCQUhBIKAgkFAQSCgIJBYGEgkBCQSChIJBQEEgoCCQUBBIKAgkFgYSCQEJBIKEgkFAQSAwV5P1BU/RuRjxWvrvkm2ZvvqGCXC8YZMiYmfJNmylf5cyhglxFxCFvlijbmbXk2yXfNGPz/Xv14yFut5tyNaV88n2XfLchz0opv5dSNgsE22yfe+rlxvLJ913yAQAAAAAAAMDDk67E2v4z/EX0+9t+mXn2++g/QXnVdd2b+zxB6/ki4iQiHkfEo4j4aa5gW58j4lNEfIiIj/d5gtbPr4V8gwUp/Qe4Xswcau+oiLjsuu7lqC9qPF/039BfF8izzyZG/h+K1s+vlXxDSzzPIuL10K8voETEs9pXmtbzRf/O8XTBPPu8i8p3ktbPr6V89qTXGZvv8VJBZprZ+vk1k8+e9GVmPlosxTwzWz+/ZvLZkz5Cbb6I+G3RIMP+rHlQ6+fXUj63mkBCQSChIJBQEEgoCCQUBBIKAgkFgYSCQEJBIKEgkFAQSCgIJBQEEgoCCQWBhIJAQkEgoSCQsCe93ph8nxdLMc/M1s+vmXz2pC8z89NiKeaZ2fr5NZPPnvQ6Y/N9WCrITDNbP79m8u0tyPaGucs4TMjbqx/f1n5B6/miv+Fws1CefTYx4n7e1s+vpXw1l1efR3+p1pOZg91E/7b2auLlxs3mi3VcXt3s+bWeDwAAAAAAAAAenm+txGr6oxIhn3z3V5UvK0jTe75Dvv+Sb5rBfEMfdz+Jw4WL7ayTEY+Xb5d80wzmGypI63u+5Zs2U77KmUMFaX3Pt3zTZspXOXOoIHP/QFRjzEz5ps2Ur3KmW00goSCQUBBIKAgkFAQSCgIJBYGEgkBCQSChIJBQEEgoCCQUBBIKAgkFgYSCQEJBIKEgkFAQSAwVpPU93/JNmylf5cyhgrS+51u+aTPlq5w5VJDW93zLN22mfJUzfxx48N/R74/+ebE4uzYR8deIx8u3S75pBvO5vHqYfNM8hHwAAAAAAAAA8MCs+qMmpZSziLiIiNPo1wbP6X1EXEfEVdd1b+75HM5v5ee32j3ppZTnEfFimTi7oyLisuu6lyO/zvltR8WKz2+oICcR8XSxOPu9i8pXwu0r3+v49jvgXEpEPBvxSuj8/jcyVnp+a92TfhGH++bGdtb5iMc7v12rPb+17kk/XSzFPDOd37SZzZzfWvekz/0DZY0nIx7r/O5a5fm51QQSCgIJBYGEgkBCQSChIJBQEEgoCCQUBBIKAgkFgYSCQEJBIKEgkFAQSCgIJBQEEgoCCQWBxFr3pI+6A2omNyMe6/zuWuX5rXVP+vViKeaZ6fymzWzm/Na6J/0q+svIDqVsZ9ZyfrtWe35DBfkY/XWMh7KJEffLbm/ou4zDfJNvr858O+JrnN9Xqz6/Y7i8+jz6S8nG3LtU4yb6vxa8WvPlyxnnZ086AAAAAAAAAIxzDB81aXbPt3z2pM/l6PZ8y/d1VNiTPouj2fMt392RYU/6ZMe051u+Xfakz+CY9nzLN21mM3/+7EmvN+b/S8h3lz3pcGwUBBIKAgkFgYSCQEJBIKEgkFAQSCgIJBQEEgoCCQWBhIJAQkEgoSCQUBBIKAgkFAQSCgIJe9LrjdnzLd9d9qRPdEx7vuWbNrOZP3/2pNcZu+dbvl32pE90VHu+5dthT/o9Hf2eb/nsSQcAAABm8g/9piLdiLW0aAAAAABJRU5ErkJggg==" + }, + "meh": { + "icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAACXBIWXMAAAsTAAALEwEAmpwYAAAFn0lEQVR4nO3dMW4UWRAG4OpdbYJMzLIH4ADrAyDuZCfIKSTmTghy7wE4gA3JRohgCXqDGSQs5hWv3d1Dtf19KT2uX2/0e4w0ehUBAAAAlDBk/ziO4/OIOI+I04j4c+HZHyPiKiIuh2F4d5cfUD1fRJxExJOIeBQRfywVbO9rRHyJiE8R8fkuP6D6+VXI1yzIOI4vI+LVwqEOjoqIi2EYXk96UfF8sXtD/1ohzyHXsXvDu1U/vyr5DhZk39y3rX9fwRgRL3p/01TPF7tPjmcr5jnkQ3R+klQ/v0r5fmu84DyOFy72s84mPF8935O1giw0s/r5lcnXKsjpelmapsysnu/RaimWmVn9/Mrka/2JNa6b5bBhGLp+a1TPFxF/rxqk7Z+eh6qfX6V8rU8QIBQEUgoCCQWBhIJAQkEgoSCQUBBIKAgkFAQSCgIJBYGEgkBCQSChIJBQEEgoCCQUBBIKAolWQSbdsbSQmwnPVs/3dbUUy8ysfn5l8rUKcrVikJYpM6vn+7JaimVmVj+/MvlaBbmM3WVaxzLuZ/aqnu/TWkEWmln9/MrkO1iQ/Q1zF3GckN+ufnzf+4Lq+WJ3w+H1SnkOuY4J9/NWP79K+Xourz6L3aVaTxcOdhO7j7U3My83LpsvtnF5ddnzq54PAAAAAAAAAB6en63EKv1ViZBPvrvrypcVpPSe75Dve/LN08zX+rr7SRwvXOxnnUx4Xr7b5Junma9VkOp7vuWbN1O+zpmtglTf8y3fvJnydc5sFWTp/xD1mDJTvnkz5euc6VYTSCgIJBQEEgoCCQWBhIJAQkEgoSCQUBBIKAgkFAQSCgIJBYGEgkBCQSChIJBQEEgoCCQUBBKtglTf8y3fvJnydc5sFaT6nm/55s2Ur3NmqyDV93zLN2+mfJ0zf288/F/s9kc/Xi3ObdcR8e+E5+W7Tb55mvlcXt0m3zwPIR8AAAAAAAAAPDC+atJ27/ON4/g8Is4j4jR2a5eX9DEiriLichiGd3f8Gb/8/OxJ73Pv8o3j+DIiXq0T5/aoiLgYhuH1xNeVOL9WQU4i4tlqcQ77EP2/CeX7UXe+/SfH2/j5XxBLGSPixYRPkjLnZ0/6OjOr5zuP45Uj9rPOJjxf5vzsSV9nZvV8p6ulWGZmmfOzJ32dmdXzLf0f8h5PJzxb5vzcagIJBYGEgkBCQSChIJBQEEgoCCQUBBIKAgkFgYSCQEJBIKEgkFAQSCgIJBQEEgoCCQWBhIJAwp70dWZWzzf1jq8l3Ex4tsz52ZO+zszq+a5WS7HMzDLnZ0/6OjOr57uM3WVuxzLuZ/Yqc36tgnyO3XWMx3Id0+6Xle+2Sfn2NxxexHFK8u3q0fcTXlPm/Fxe3Xbv8+2vID2L3aVuU+6t6nETuz+r3mz58moAAAAAAAAA4Hu+atJmD/k89+L9tSe9jz3k82z2/bUnvZ895PNs8v21J32dmfaQz5tZJp896evMtId83swy+exJX2emPeTzZpbJ51YTSCgIJBQEEgoCCQWBhIJAQkEgoSCQUBBIKAgkFAQSCgIJBYGEgkBCQSChIJBQEEgoCCQUBBL2pK8z0x7yeTPL5LMnfZ2Z9pDPm1kmnz3p68y0h3zezDL57EnvYw/5PJt9f11e3WYP+Tz3/v0FAAAAAAAAgIdn0181sYf83n+V45fn2+yedHvIb9nsHvJEiXyb3JNuD/lBm9xD3lAm31b3pNtDPm+mfJ0zt7on3R7yeTPl65y51T3p9pDPmylf50y3mkBCQSChIJBQEEgoCCQUBBIKAgkFgYSCQEJBIKEgkFAQSCgIJBQEEgoCCQWBhIJAQkEgoSCQ2OqedHvI582Ur3PmVvek20M+b6Z8nTO3uifdHvJ5M+XrnLnJPen2kP9gs3vIG8rkuw+XV9tDvuHLoX+iej4AAADgWP4HgkqdvpUqExIAAAAASUVORK5CYII=" + }, + "tshirt": { + "icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAACXBIWXMAAAsTAAALEwEAmpwYAAAF1ElEQVR4nO3dMW4UWRAG4OqVSCxyAwfgAMsBLO4ECXIKCdxmN0eQswfYA9jrHDmxxNugx2gtpovu6e6hpvf7UsZTv9rvt0EaXkUAAAAAJXTZH7bWLiLidUS8iIgnC8/+JyK+RMT7rus+HfIG1fNFxOOIOI+Is4h4tFSwnbuIuI2Im4j4esgbVH9+FfINFqS19iYi3i4cau+oiLjsuu7dpC8qni/6b+izFfLscxX9N3y06s+vSr69Bdk19+PQn6+gRcTLsT9pqueL/jfH8xXz7PN3jPxNUv35Vcr328AXvI7jhYvdrFcTXl893/laQRaaWf35lck3VJAX62UZNGVm9Xxnq6VYZmb151cm39Bfsdq6Wfbrum7UT43q+SLi91WDDPtrzIuqP79K+YZ+gwChIJBSEEgoCCQUBBIKAgkFgYSCQEJBIKEgkFAQSCgIJBQEEgoCCQWBhIJAQkEgoSCQUBBIDBVk0h1LC7me8Nrq+e5WS7HMzOrPr0y+oYJ8WTHIkCkzq+e7XS3FMjOrP78y+YYK8j76y7SOpe1mjlU9381aQRaaWf35lcm3tyC7G+Yu4zgh769+/Dz2C6rni/6Gw6uV8uxzFRPu563+/CrlG3N59avoL9V6unCw6+h/rX2Yeblx2XxxGpdXl31+1fMBAAAAAAAAAA+01i5aa3+21q7b8q53730hn3wnl6+19maFUPt8a/1ObPnkO418rW/utyMFvA85usnyyXesfPakjyPfPCebz570dWbKN29mmXz2pE8g3zynmM+tJpBQEEgoCCQUBBIKAgkFgYSCQEJBIKEgkFAQSCgIJBQEEgoCCQWBhIJAQkEgoSCQUBBIKAgk7EkfT755TjKfPenrzJRv3swy+exJH0e+ebaW7/vVj8e43W7O1ZTyyfdL8t2HvGit/dFau1oh2NXuvedebiyffL8kHwAAAAAAAAD8//xsJdbjiDiPiLOIeLTw7LuIuI2Im4j4esgb7D4m8Dr6/XJPlosWEf1Hrr9ExPuu6z4d8gbyzcsXBc5fVpAnEfFs4VBDrmLi/wFo/QfM3q4T5+GoiLjsuu7dpC+S7/uoOCBfFDl/QwV5HBHPV4uz398x8jfJ7iffxzjequAWES/H/iSU78eRMSFfFDp/Q/8f5HzdLLNnltmjPUC+h6bmK3P+hgpytmKQIVNmltmjvcBrl7KlfGXO31BBlv4H0RhTZi79D8oxnk54rXw/mpKvzPlzqwkkFAQSCgIJBYGEgkBCQSChIJBQEEgoCCQUBBIKAgkFgYSCQEJBIKEgkFAQSCgIJBQEEgoCiaGC3B01xfSZZfZoD5DvR1PylTl/QwW5XTHIkCkzy+zRXuC1S9lSvjLnb6ggNysGGTJlZvU92vI9NDVfmfM3VJCv0V/HeCxXMeF+3t0NfZdxnG/y/dWZn8d+gXwPTM4Xhc7fFi6vfhX9pWRT7l0a4zr6vxZ8mHk5tHwnfHk1AAAAAAAAAPBfW/ioSdk93/LZk74Ue9IPt8l8UeT82ZM+zqb2kFfPF4XOnz3p42xtD3n1fGXOnz3p68yUb97MMufPnvTxtrSHvHq+MufPrSaQUBBIKAgkFAQSCgIJBYGEgkBCQSChIJBQEEgoCCQUBBIKAgkFgYSCQEJBIKEgkFAQSCgIJOxJH29Le8ir5ytz/uxJX2emfPNmljl/9qSPs7U95NXzlTl/9qT/3Ob2kFfPF4XO3xYury6751s+e9IBAAAAAAAAYFu28FGTsnu+5bMnfSn2pB9uk/miyPmzJ32cTe0hr54vCp0/e9LH2doe8ur5ypw/e9LXmSnfvJllzp896eNtaQ959Xxlzp9bTSChIJBQEEgoCCQUBBIKAgkFgYSCQEJBIKEgkFAQSCgIJBQEEgoCCQWBhIJAQkEgoSCQUBBI2JM+3pb2kFfPV+b82ZO+zkz55s0sc/7sSR9na3vIq+crc/7sSf+5ze0hr54vCp2/LVxeXXbPt3z2pAMAAAAL+RdTjm3JtMq/IQAAAABJRU5ErkJggg==" + }, + "rollerskate": { + "icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAACXBIWXMAAAsTAAALEwEAmpwYAAAFyUlEQVR4nO3dMW4USRQG4NcrkVjObTgAF+AAFneCBDmFBG6zmyPIuQAHsNe55cQStcGMQbN2Pbrc3ePq4ftSZub9KvgHjzSuFwEAAAB0YfjNnx9HxElEHEXEs5ln30bETURcRcT1I19Dvgn5SilnEfE2Il5FxOl80SIi4t+I+BYRH4dh+PKYF+ghX1aQ04h4MXOomovYBG4h3y/N+Uop7yLi/TJxdkdFxPkwDB+antRJvlpBjiPi5WKRHvY9xr8Tynff6Hzbd+bP8fufIOZSIuL12P9Jesr3V+UJJ8vmmTxTvmkz38b+/vHFdtabhsd3k69WkKPlslS1zJRv2sxXi6WYZ2Y3+WoFmfsD5RgtM+WbNnPuD7xjPG94bDf5agUBQkEgpSCQUBBIKAgkFAQSCgIJBYGEgkBCQSChIJBQEEgoCCQUBBIKAgkFgYSCQEJBIKEgkKgV5HavKdpnyjdtZusdX3O4bHhsN/lqBblZMEhNy0z5ps38tliKeWZ2k69WkKsFg9S0zJRv2syPsbksbV/KduZY3eSrFeQ6NtdZ7stFtN0vK9+upnzbGwTPYz//CO+u9vw69gk95XN5dd3B59te8fkmNpemtdxbNcZlbH5s+TTx8upu8wEAAAAAAADAn8dXTeoOPl8Pe8gzPeSzJ32cg8vXyx7y6pM6yWdP+ngHk6+nPeQPPrijfPakLzOz93zd7CGv6CafPenLzOw9Xzd7yGd47FzsSZ/okPJ1s4e8opt8bjWBhIJAQkEgoSCQUBBIKAgkFAQSCgIJBYGEgkBCQSChIJBQEEgoCCQUBBIKAgkFgYSCQEJBIGFP+jIze8/XzR7yim7y2ZO+zMze83Wzh3yGx87FnvSJDilfN3vIK7rJZ0/6OAeVr6c95A/pKZ/Lq+sOPl/ve8h7zwcAAAAAAAAA7CilnJVS/imlXJb5XW5f+0w++VaXr5TyboFQD/lRNjux5ZNvHfnKprk/9hTwLuToJssn377y1b7u3s2e6gr5dsk3TfOe9G72VM/w2LnIN80q8z3Y0lLKPn+b66dhGEa9a8j3MPmmeSifW00goSCQUBBIKAgkFAQSCgIJBYGEgkBCQSChIJBQEEgoCCQUBBIKAgkFgYSCQEJBIKEgkFAQSNQK0s2e6gr57pNvmqY96d3sqZ7hsXORb5pV5qsVpJs91RXy7ZJvmtZ8P69+3MftdlOuppRPvifJdxfyrJTydynlYoFgF9vXnnq5sXzyPUk+AAAAAAAAAGBH6XlPtXzyPWW+0vOeavnke8p8paM91fLJ95T57EkfR75pVpvPnvRlZso3bWY3+exJbyDfNGvM51YTSCgIJBQEEgoCCQWBhIJAQkEgoSCQUBBIKAgkFAQSCgIJBYGEgkBCQSChIJBQEEgoCCQUBBL2pI8n3zSrzGdP+jIz5Zs2s5t89qSPI980h5av/z3V8sn3lPnuQp6VjvdUyyffU+YDAAAAAAAAgD/P71ZiHUfESUQcRcSzmWffRsRNRFxFxPVjXmD7NYG3sdkvdzpftIjYfOX6W0R8HIbhyyNfw/mt/PyygpxGxIuZQ9VcROPvAJTNF8zeLxNnd1REnA/D8KHxec5vOypWfH61ghxHxMvF4jzse4x8J9y+832O/a0KLhHxuuGd0Pn9b2Ss9Pxqvw9ysmyWyTO72aNd4fx2rfb8agU5WjBITcvMbvZoVzi/aTO7Ob9aQeb+QDRGy8y5P1CO8bzhsc7vvlWen1tNIKEgkFAQSCgIJBQEEgoCCQWBhIJAQkEgoSCQUBBIKAgkFAQSCgIJBYGEgkBCQSChIJBQEEjUCnK71xTtM7vZo13h/O5b5fnVCnKzYJCalpnd7NGucH7TZnZzfrWCXC0YpKZlZu97tJ3frtWeX60g17G5jnFfLqLhftntDX3nsZ+/5LurM782PMf5/bLq8zuEy6vfxOZSspZ7l8a4jM2PBZ/WfPlyxvlNOz8AAABgj/4DKpNLjifM3PsAAAAASUVORK5CYII=" + }, + "duck": { + "icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAACXBIWXMAAAsTAAALEwEAmpwYAAAFW0lEQVR4nO3dMXIcVRQF0DdQJC4R27AAFoAXQLEnO6GcQmL2REFuFsACZJwQuRzgYAhGYKZm/tP/+t1Tr0fnpG7p36ruK1tlqW8EAAAAUMLunj+/iYinEfEkIr5Y+OyPEfEhIt5FxPuHfIL9fv9dRLyMiOcR8Wy5aBER8WdEvImI17vd7teHfILq+aL4/Y0C+bKCPIuIrxcO1XIbhxvebb/f/xARP64T5/ioiHi12+1+Gvqg4vmi+P2NIvlaBbmJiG9Wi3PeH9H5lebuK/Mvcf/fgEvZR8T3vV+pq+eL4vc3CuX7rHHx03WzTJ/5Mi738MXdWS8Grq+er/r9LZOvVZAnKwZpGTnz+Wopljmzer7q97dMvlZBlv6GqMfImUt/w9vjq4Frq+erfn/L5GsVBAgFgZSCQEJBIKEgkFAQSCgIJBQEEgoCCQWBhIJAQkEgoSCQUBBIKAgkFAQSCgIJBYGEgkCiVZCPF00xfuboO5aW8Hbg2ur5qt/fMvlaBfmwYpCWkTPfrJZimTOr56t+f8vkaxXk3YpBWkbOfB2Hl6Vdyv7uzF7V81W/v2XytQryPg6vY7yU2xh4f+vdGwRfxWUewn9f7flb7wdUzxfF728UyncNL69+EYeXpo28F6rH2zj8s+XnyZdXl80Xxe9v1M8HAAAAAAAAAI9M+qMm1Xe+5bOTPmFuJ736zrd8n44KO+mzxnbSq+98y3d6ZNhJnzW0k15951u+Y3bS5w3tpFff+ZZv7swyO+QLXLuUoZ306jvf8p2ykz7HTjqMUhBIKAgkFAQSCgIJBYGEgkBCQSChIJBQEEgoCCQUBBIKAgkFgYSCQEJBIKEgkFAQSCgIJFoFqb7zLd8pO+lzhnbSq+98yzd3Zpkd8gWuXcrQTnr1nW/5jtlJn9e/k15951u+I3bS5z1sJ736zrd8dtIn2EkHAAAAAAAAgGH3DU2W/q/+6jvk8m0/X1aQEjvVLdV3yOX7dFRsOF+rIGV2qs+pvkMu3+mRsdF8rd8HKbNT3VB9h1y+Y5vN1ypImZ3qhuo75PLNnVkmX6ul364YJPN7z0X7/f6Sv633n91u1/VVTb7ztpjPW00goSCQUBBIKAgkFAQSCgIJBYGEgkBCQSChIJBQEEgoCCQUBBIKAgkFgYSCQEJBIKEgkFAQSLQKUmanuqH6Drl8pzaZr1WQMjvVDdV3yOWbO7NMvlZByuxUN1TfIZfv2GbztQpSZqf6nOo75PId2XS+a3h5ddkdcvmuOx8AAAAAAAAAPD7X8KMmdr6vNF8UeP7spHccFRve+W5+UPF8UeT5s5PeZ7M732cvLp4vCj1/dtL7bHbnu6F6vjLPn530dc6Ub+7MMs9fqyBLf0PUY+TMpb+h7DHy+wjynRrJV+b581YTSCgIJBQEEgoCCQWBhIJAQkEgoSCQUBBIKAgkFAQSCgIJBYGEgkBCQSChIJBQEEgoCCQUBBJ20vttcue7oXq+Ms+fnfR1zpRv7swyz5+d9D6b3fluqJ6vzPNnJ/1+m975Pqd6vij0/F3Dy6vL7mjLN71DXvr5AwAAAAAAAIDHZ9M/ahLyyfdw172THvL9n3xzmvlaP817E5cLF3dn3QxcL98x+eY08211J12+uTPl6zxzqzvp8s2dKV/nmVvdSZdv7kz5Os/0VhNIKAgkFAQSCgIJBYGEgkBCQSChIJBQEEgoCCQUBBIKAgkFgYSCQEJBIKEgkFAQSCgIJBQEElvdSZdv7kz5Os/c6k66fHNnytd55lZ30uWbO1O+zjM/b1z8dxz2rb9cLc6x24j4a+B6+Y7JN6eZz8ur2+Sb8xjyAQAAAJfyD92s8bBtlgWFAAAAAElFTkSuQmCC" + }, + "house": { + "icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAACXBIWXMAAAsTAAALEwEAmpwYAAAF90lEQVR4nO3dMW4UWRAG4JqVSJBzGw7ABTiAxZ0gQaSQwG12cwQ5F+AA9jq3nCDxNpgBduR55W5391Btvi9lPPXr0b+NpeFVBAAAAFDC5o4/P4mI04h4HBGPZp79LSJuIuIqIq7v+R6l87XWziPiVUQ8j4iz+aJFRMS/EfElIt5vNptP93yP0ucXBfJlBTmLiKczh+q5iO1f+Bil87XWXkfE22Xi7I+KiDebzebdyK8rfX5RJF+vICcR8WyxOId9jeHfaUrn2/3k+Bh3/4SeS4uIFyN+kpQ+vyiU76/Oi0+XzTJ5ZvV8r+J45YjdrJcjXl/9/Mrk6xXk8YJBesbMrJ7v+WIp5plZ/fzK5OsVZO5fiIYYM7N6vrl/IR/iyYjXVj+/Mvl6BQFCQSClIJBQEEgoCCQUBBIKAgkFgYSCQEJBIKEgkFAQSCgIJBQEEgoCCQWBhIJAQkEgoSCQ6BXk21FTjJ9ZPd/YO6DmcDnitdXPr0y+XkFuFgzSM2Zm9XxfFksxz8zq51cmX68gVwsG6Rkzs3q+97G9zO1Y2m7mUNXPr0y+XkGuY3sd47FcxLj7W0vn291w+CaOU5IfV49+HvE1pc8vCuVzeXXfXJdXv4ztpW5j7q0a4jK2/6z64PLqe5kjHwAAAAAAAAD8YVb9UZPqe8jlW/8e99XuSa++h1y+X6NixXvcV7knvfoecvluj4yV7nFf65706nvI5du32j3ua92TXn0PuXzTZpZ5/ta6J736HnL5blvlHne3mkBCQSChIJBQEEgoCCQUBBIKAgkFgYSCQEJBIKEgkFAQSCgIJBQEEgoCCQWBhIJAQkEgoSCQWOue9Op7yOW7bZV73Ne6J736HnL5ps0s8/ytdU969T3k8u1b7R73Ve5Jr76HXL49q97j/hAury67h1y+B7/HHQAAAAAAAAD4pbV23lr7p7V22eZ3uXvvc/nkW12+1trrBUId8r1td3bLJ9868rVtc78fKeCPkIObLJ98x8rX+7h79T3a8u2Tb5puvl5Bqu/Rlm/aTPkGzjzY0tbaMf+32U+bzWbQdw35DpNvmkP53GoCCQWBhIJAQkEgoSCQUBBIKAgkFAQSCgIJBYGEgkBCQSChIJBQEEgoCCQUBBIKAgkFgYSCQKJXkOp7tOW7Tb5pDubrFaT6Hm35ps2Ub+DMXkGq79GWb59804zN9/Pqx2Pcbjflakr55Pst+X6EPG+t/d1au1gg2MXuvadebiyffL8lHwAAAAAAAAD8ee5aiXUSEacR8TgiHs08+1tE3ETEVURc3+cNdh8TeBXb/XJn80WLiO1Hrr9ExPvNZvPpPm8g37R8UeD5ywpyFhFPZw7VcxEj/w9A237A7O0ycfZHRcSbzWbzbtQXyfdzVNwjXxR5/noFOYmIZ4vFOexrDPxJsvvO9zGOtyq4RcSLod8J5bs9Mkbki0LPX+//g5wum2XyzDJ7tDvk2zc2X5nnr1eQxwsG6Rkzs8we7RleO5eHlK/M89cryNy/EA0xZubcv1AO8WTEa+W7bUy+Ms+fW00goSCQUBBIKAgkFAQSCgIJBYGEgkBCQSChIJBQEEgoCCQUBBIKAgkFgYSCQEJBIKEgkFAQSPQK8u2oKcbPLLNHu0O+28bkK/P89Qpys2CQnjEzy+zRnuG1c3lI+co8f72CXC0YpGfMzOp7tOXbNzZfmeevV5Dr2F7HeCwXMeJ+3t0NfW/iOH/JP67O/Dz0C+TbMzpfFHr+HsLl1S9jeynZmHuXhriM7T8LPky8HFq+FV9eDQAAAAAAAAD830P4qIk9387vPuxJn8mq93z3OL899qRPtNo934c4v4PsSZ9gtXu+O5zfwJn2pC8z0/lNm1nm/OxJH26Ve747nN/AmW41gYSCQEJBIKEgkFAQSCgIJBQEEgoCCQWBhIJAQkEgoSCQUBBIKAgkFAQSCgIJBYGEgkBCQSBhT/pwq9zz3eH8Bs60J32Zmc5v2swy52dP+jCr3fPd4fwGzrQn/W6r3vN9iPO7xZ70e3jwe76dnz3pAAAAsBr/ATSEGnDLtmOQAAAAAElFTkSuQmCC" + }, + "tortoise": { + "icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAACXBIWXMAAAsTAAALEwEAmpwYAAAF7ElEQVR4nO3dMY5cxRoF4NMgEmuIbVgAG2ABFnuyE+QUErObR44g9wZYwAxOiCwHWKJe0G3z+s3U71tT3c29nu9Lfbv/o5p7etzSnaoEAAAAWIXdR/79KsnjJI+SfHHi2e+SvE3yOsmbe76HfPLd16J8VUGeJPn6xKF6rpP8Mfga+f4h35xuvs86L7jK5cLlMOtq4Hr5jsk3p5uvV5DH58vSNTJTvrmZ8i2c2SvIozMG6RmZKd/cTPkWzuwV5NRfiJYYmSnf3Ez5Fs7sFQSIgkBJQaCgIFBQECgoCBQUBAoKAgUFgYKCQEFBoKAgUFAQKCgIFBQECgoCBQWBgoJAQUGg0CvIu4umGJ8p39xM+RbO7BXk7RmD9IzMlG9upnwLZ/YK8vqMQXpGZso3N1O+hTM/71z8V5KW5MuzxTl2neTPgevlOybfnG4+m1f3yTfnIeQDAAAAAAAAgAdm04+atNaeJnme5Nvsjw0+pT+SvErycrfb/XqfN5BvLl9WcP9t9pz01tr3SX44T5zjUUle7Ha7H4deJN+HUblHvqzk/usV5CrJN2eLc7ffs/A3yeGT75d8/DfgqbQk3y39JJTv9sgM5MuK7r+tnpP+PJf74eYw69nA9fIdG823mvtvq+ekf3u2FKeZKd/czNXcf1s9J/3UXyiX+GrgWvluG8m3mvvPriZQUBAoKAgUFAQKCgIFBYGCgkBBQaCgIFBQECgoCBQUBAoKAgUFgYKCQEFBoKAgUFAQKCgIFLZ6TvrQHloncjNwrXy3jeRbzf231XPSX50txWlmyjc3czX331bPSX+Z/WZkl9IOM5eS79hovtXcf72CvMl+O8ZLuc7A/ryHHfpe5DI/5PdbZ/629AXyHRnOlxXdf5/C5tXPst+UbGTfpSVusv9vwU+Tm0PLt+HNqwEAAAAAAACAxVprT1trP7fWbtrp3Rze+6l88m0uX2vt+zOEusvfbX9mt3zybSNf2zf37wsFfB9ycZPlk+9S+XqPu6/9HG35jsk3p5uvV5C1n6Mt39xM+RbOvLOlrbVL/rXZB7vdbtGnhnx3k2/OXfnsagIFBYGCgkBBQaCgIFBQECgoCBQUBAoKAgUFgYKCQEFBoKAgUFAQKCgIFBQECgoCBQWBgoJAoVeQtZ+jLd9t8s25M1+vIGs/R1u+uZnyLZzZK8jaz9GW75h8c0bzfdj68RK7281sTSmffP9Kvvchn7bW/tNauz5DsOvDe89ubiyffP9KPgAAAAAAAAB4eD52JNZVksdJHiX54sSz3yV5m+R1kjf3eYPDYwLPsz9f7snpoiXZP3L9KsnL3W736z3fw/ptfP2qgjxJ8vWJQ/VcZ/BvANr+AbMfzhPneFSSF7vd7sfB11m/w6hseP16BblK8s3Z4tzt9yz8JDx88v2Syx0V3JJ8N/BJaP3+b2Q2un69vwd5fN4s0zNXc452h/U7ttn16xXk0RmD9IzMXM052h3Wb27matavV5BTfyFaYmTmqb9QLvHVwLXW77ZNrp9dTaCgIFBQECgoCBQUBAoKAgUFgYKCQEFBoKAgUFAQKCgIFBQECgoCBQWBgoJAQUGgoCBQUBAo9Ary7qIpxmeu5hztDut32ybXr1eQt2cM0jMyczXnaHdYv7mZq1m/XkFenzFIz8jMtZ+jbf2ObXb9egV5k/12jJdynYH9ZQ879L3IZX7I77fO/G3gNdbvH5tev09h8+pn2W9KNrLv0hI32f+34Kctb75csX5z6wcAAAAAAAAAD8+mHzWJfPLd36d9Tnrk+1/yzenm6z3Ne5XLhcth1tXA9fIdk29ON99Wz0mXb26mfAtnbvWcdPnmZsq3cOZWz0mXb26mfAtn2tUECgoCBQWBgoJAQUGgoCBQUBAoKAgUFAQKCgIFBYGCgkBBQaCgIFBQECgoCBQUBAoKAgUFgcJWz0mXb26mfAtnbvWcdPnmZsq3cOZWz0mXb26mfAtnft65+K/sz7f+8mxxjl0n+XPgevmOyTenm8/m1X3yzXkI+QAAAIBL+S+Xv8exkeeOeAAAAABJRU5ErkJggg==" + }, + "butterfly": { + "icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAACXBIWXMAAAsTAAALEwEAmpwYAAAGqElEQVR4nO3dQW5TSRSF4VMtZRJlnsACWAAswGJPyQRlCpOwG5gjmMMCWIBN5lEmkXJ7UM+0on51u8qv6uW6+b9pYt+jio4dhHNLAgAAAAAAISTvi2a2kXQl6Y2ki86zf0n6LukmpfT1kCeInk/SmaRzSaeSTnoFmzxIupd0K+nukCeIfn4R8hULYmbvJL3vHGp2lKTrlNKHpgcFz6f8A305IM+crfIPvFr084uSb7YgU3O/lL4+gEl6W/tKEz2f8jvHq4F55vxU5TtJ9POLlO+vwgOutF44TbMuG74/er7zUUE6zYx+fmHylQryZlyWopaZ0fOdDkvRZ2b08wuTr/Qrlo3NMi+lVPWqET2fpNdDg5T9qPmm6OcXKV/pHQSAKAjgoiCAg4IADgoCOCgI4KAggIOCAA4KAjgoCOCgIICDggAOCgI4KAjgoCCAg4IADgoCOCgI4KAggKNUkKYdS53sGr43er6HYSn6zIx+fmHylQryfWCQkpaZ0fPdD0vRZ2b08wuTr1SQG+VlWmuxaWat6PluRwXpNDP6+YXJN1uQacPctdYJuV/9+K32AdHzKW843A7KM2erhv280c8vUr6a5dWXyku1XnQOtlN+W/u4cLlx2Hw6juXVYc8vej4AAAAAAAAAAAAAAPCEmW3M7LOZ7ay/3fTcG/KR7+jymdm7AaHmPFq+E5t85DuOfJab+7hSwH3I6iaTj3xr5eOe9DrkW+Zo83FP+piZ5Fs2M0w+7klvQL5ljjEfW00ABwUBHBQEcFAQwEFBAAcFARwUBHBQEMBBQQAHBQEcFARwUBDAQUEABwUBHBQEcFAQwEFBAAcFARwUBHBwT3o98i1zlPm4J33MTPItmxkmH/ek1yHfMv+3fL9XP66x3W7Jakryke9Z8u1Dbszsk5ltBwTbTs+9dLkx+cj3LPkAAAAAAAAAAAAAAPjz/NeVWGeSziWdSjrpPPtB0r2kW0l3Bz5H6HzTxxiulO+/u+gXTVL+SPh3STcppa8HPkfo81OAfF5BLiS97ByqZKv2vwEInc/yB+Dej4nzdJSk65TSh8bHhT4/BclXKsiZpFfD4sz7qfpXmtD5pneOL1rvKmOT9LbhnST0+SlQvtLfg5yPzbJ4ZvR8Ye75Loh+fmHylQpyOjBIScvM6PnC3PNdEP38wuQrFaT3P4hqtMyMnq/3P8hrvGj43ujnFyYfW00ABwUBHBQEcFAQwEFBAAcFARwUBHBQEMBBQQAHBQEcFARwUBDAQUEABwUBHBQEcFAQwEFBAAcFARwUBHCUCvKwaor2mdHzhbnnuyD6+YXJVyrI/cAgJS0zo+cLc893QfTzC5OvVJDbgUFKWmZGzxf9nu/o5xcmX6kgd8rrGNeyVdv+1tD5pg2H11qnJPvVo98aHhP6/BQoH8ury3otr75UXurWsreqxk7516qPLK8+SI98AAAAAAAAAAAAAADgH2a2MbPPZraz/nbTc2/IR76jy2dm7waEmvNo+U5x8pHvOPJZbu7jSgH3IaubTD7yrZWv9HH36Pd8k+8p8i1TzFcqSPR7vsm3bCb5KmfOttTM1vxruN9SSlWvGuSbR75l5vKx1QRwUBDAQUEABwUBHBQEcFAQwEFBAAcFARwUBHBQEMBBQQAHBQEcFARwUBDAQUEABwUBHBQEcFAQwEFBAEepINHv+Sbfv5Fvmdl8pYJEv+ebfMtmkq9yZqkg0e/5Jt9T5FumNd/v1Y9rbLdbspqSfOR7lnz7kBsz+2Rm2wHBttNzL11uTD7yPUs+AAAAAAAAAAAAAAD+PO6VWNN/w18p39920Xn2L+VPUN6klL4e8gTR80k6k3Qu6VTSSa9gkwdJ95JuJd0d8gTRzy9CvmJBLH+A633nULOjJF2nlD40PSh4PuUf6MsBeeZs1fg3FNHPL0q+0iWeG0lfSl8fwCS9rX2liZ5P+Z3j1cA8c36q8p0k+vlFysc96XVa852PCtJpZvTzC5OPe9LHzDwdlqLPzOjnFyYf96Q3qM0n6fXQIGU/ar4p+vlFysdWE8BBQQAHBQEcFARwUBDAQUEABwUBHBQEcFAQwEFBAAcFARwUBHBQEMBBQQAHBQEcFARwUBDAQUEABwUBHNyTXq8l38OwFH1mRj+/MPm4J33MzPthKfrMjH5+YfJxT3qd1ny3o4J0mhn9/MLkmy3ItGHuWuuE3K9+/Fb7gOj5lDccbgflmbNVw37e6OcXKV/N8upL5aVaLzoH2ym/rX1cuNw4bD4dx/LqsOcXPR8AAAAAAFjR37pFnk41Gl9cAAAAAElFTkSuQmCC" + }, + "stickfigure": { + "icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAACXBIWXMAAAsTAAALEwEAmpwYAAAF+UlEQVR4nO3dMW5TWRQG4OORaKL0CSyADbCAiD1Bg9JCA7uZ6RH0bIAFJJM+ShOJO4UdZjL4Ht7LfTbH4ftaHJ9fF/9xIjn3RAAAAAAlrH7y78cRcRIRRxHxZOHZtxFxExFXEXH9wOcona+1dhYRryPiRUScLhctIiL+jogvEfF+tVp9euBzlD6/KJAvK8hpRDxbOFTPRaz/w+cona+19iYi3u4mzv1REXG+Wq3ezfy60ucXRfL1CnIcEc93Fme7rzH9O03pfJt3jo/x83fopbSIeDnjnaT0+UWhfH90Hnyy2yzDM6vnex37K0dsZr2a8fjq51cmX68gRzsM0jNnZvV8L3aWYpmZ1c+vTL5eQZb+hWiKOTOr51v6F/Ipns54bPXzK5OvVxAgFARSCgIJBYGEgkBCQSChIJBQEEgoCCQUBBIKAgkFgYSCQEJBIKEgkFAQSCgIJBQEEgoCiV5BbveaYv7M6vnm3gG1hMsZj61+fmXy9Qpys8MgPXNmVs/3ZWcplplZ/fzK5OsV5GqHQXrmzKye732sL3Pbl7aZOVX18yuTr1eQ61hfx7gvFzHv/tbS+TY3HJ7Hfkpyd/Xo5xlfU/r8olA+l1f3LXV59atYX+o2596qKS5j/WPVB5dXP8gS+QAAAAAAAACAf7XWzlprf7XWLtvyLjfPfSaffAeXr7X2ZgehtvnW1jvF5ZPvMPK1dXO/7SngXcjJTZZPvn3l633cvfqeb/nuk29MN1+vINX3fMs3NlO+iTO3trS1ts+/hvtutVpN+q4h33byjdmWz60mkFAQSCgIJBQEEgoCCQWBhIJAQkEgoSCQUBBIKAgkFAQSCgIJBYGEgkBCQSChIJBQEEgoCCR6Bam+51u+H8k3Zmu+XkGq7/mWb2ymfBNn9gpSfc+3fPfJN2Zuvu9XP+7jdruRqynlk++X5LsLedZa+7O1drGDYBeb5x693Fg++X5JPgAAAAAAAAD4/fxsJdZxRJxExFFEPFl49m1E3ETEVURcP/A5SufbfIzhdaz3350uFy0i1h8J/xIR71er1acHPkfp84sC+bKCnEbEs4VD9VzE/L8BKJ2vrT8A93Y3ce6Piojz1Wr1bubXlT6/KJKvV5DjiHi+szjbfY3p32lK59u8c3yM/a0ybhHxcsY7Senzi0L5en8PcrLbLMMzq+crs+e7o/r5lcnXK8jRDoP0zJlZPV+ZPd8d1c+vTL5eQZb+hWiKOTOr51v6F/Ipns54bPXzK5PPrSaQUBBIKAgkFAQSCgIJBYGEgkBCQSChIJBQEEgoCCQUBBIKAgkFgYSCQEJBIKEgkFAQSCgIJHoFud1rivkzq+crs+e7o/r5lcnXK8jNDoP0zJlZPV+ZPd8d1c+vTL5eQa52GKRnzszq+arv+a5+fmXy9QpyHevrGPflIubd31o63+aGw/PYT0nurh79PONrSp9fFMrn8uq+pS6vfhXrS93m3Fs1xWWsf6z64PLqB1kiHwAAAAAAAAD8Zg76oyb2kDu/AY97T7o95Pc4vzGPa0+6PeRbOb8xj2pPuj3kYzOd38SZh7on3R7ysZnOb+LMQ92Tbg/52EznN3GmW00goSCQUBBIKAgkFAQSCgIJBYGEgkBCQSChIJBQEEgoCCQUBBIKAgkFgYSCQEJBIKEgkFAQSBzqnnR7yMdmOr+JMw91T7o95GMznd/EmYe6J90e8rGZzm/izIPck24P+Q+c35jHuSfdHnLnN8CedAAAAAAAAACYLf2oiT3awx9FkO/A97h3C2KP9j2z95CHfP91sHvctxbEHu2tJu8hD/m2Ocg97r2Pu9ujPTZTvrGZZV5/vYLYoz02U76xmWVef72C2KM9NlO+sZllXn9uNYGEgkBCQSChIJBQEEgoCCQUBBIKAgkFgYSCQEJBIKEgkFAQSCgIJBQEEgoCCQWBhIJAQkEg0SuIPdpjM+Ubm1nm9dcriD3aYzPlG5tZ5vXXK4g92mMz5RubWeb1t7Ug9mj/YNYe8pDv/w52j/uUy6vt0X6kl0NH8XwH8PoDAAAA9uUf0jPoA1IKTsUAAAAASUVORK5CYII=" + }, + "ghost": { + "icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAACXBIWXMAAAsTAAALEwEAmpwYAAAFt0lEQVR4nO3dMW4USRQG4NcrkVjObTgAF+AAFnfCCXIKCdxmN0eQcwEOYOPccmKJ2mDGXkYz/eh2dc9Uz35fynjer0f/47XWVEUAAAAATej+8OenEXEWEScR8WLi2Q8RcR8RtxFx95w3KKVcRMRlRLyJiPPpokVExM+I+B4Rn7qu+/qcN5CvLl808PxlBTmPiFcTh+pzHauFDlZKeR8RH+aJszkqIq66rvs46ovkexoVz8gXjTx/fQU5jYjXs8XZ7UcM/E6y/uT7En/+DjiVEhFvh34Syrc9Mkbki4aev796Xnw2b5bqmZexv7/cWM96N+L18m0am6+Z56+vICczBukzZuab2VJMM1O+upnNPH99BZn6B6Ihxsyc+gfKIV6OeK1828bka+b56ysIEAoCKQWBhIJAQkEgoSCQUBBIKAgkFAQSCgIJBYGEgkBCQSChIJBQEEgoCCQUBBIKAgkFgURfQR72mmL8zFFnaE3kZsRr5ds2Jl8zz19fQe5nDNJnzMzvs6WYZqZ8dTObef76CnI7Y5A+Y2Z+itVhZPtS1jOHkm/T2HzNPH99BbmL1XGM+3IdI87nXZ/QdxX7+Ut+PDrz29AvkG/D6HzR0PN3DIdXv4vVoWRjzl0a4iZW/1nwufJwaPkWfHg1AAAAAAAAAPC79FdN3KN93Pe4h/39cX+9BXGP9oaju8c97O9pVCT721kQ92jvdDT3uIf9bY2Mnv31/bq7e7TrZtpf3cxm9tdXEPdo1820v7qZzeyvryDu0a6baX91M5vZn1NNIKEgkFAQSCgIJBQEEgoCCQWBhIJAQkEgoSCQUBBIKAgkFAQSCgIJBYGEgkBCQSChIJBQEEj0FcQ92nUz7a9uZjP76yuIe7TrZtpf3cxm9tdXEPdo1820v7qZzexvZ0Hco73lqO5xD/v7Xbq/IYdXu0f7SO9xD/ur3R8AAAAAAAAA8J9SykUp5Z9Syk2Z3s36vS/kk29x+Uop72cItcuvsroTWz75lpGvrJr7a08BH0MObrJ88u0r31LvSZdvk3x1ju6edPnqZso3cObOlpZS9vmvuZ50XTfoU0O+3eSrsyufU00goSCQUBBIKAgkFAQSCgIJBYGEgkBCQSChIJBQEEgoCCQUBBIKAgkFgYSCQEJBIKEgkFAQSCz1nnT5tslX56juSZevbqZ8A2cu9Z50+TbJV2dsvqejH/dxul3N0ZTyyXeQfI8hL0opf5dSrmcIdr1+79rDjeWT7yD5AAAAAAAAAIANpeV7quWT75D5Ssv3VMsn3yHzlYbuqZZPvkPmc0/6MPLVWWw+96TPM1O+upnN5HNP+gjy1VliPqeaQEJBIKEgkFAQSCgIJBQEEgoCCQWBhIJAQkEgoSCQUBBIKAgkFAQSCgIJBYGEgkBCQSChIJBwT/pw8tVZZD73pM8zU766mc3kc0/6MPLVObZ87d9TLZ98h8z3GPKiNHxPtXzyHTIfAAAAAAAAAPz/pFdirf83/GWs7m87n3j2z1j9BuWnruu+PvM9TiPiLCJOIuLFVMHWHiLiPiJuI+LuOW9gf8vfX29ByuoXuD5MHGrnqIi46rru48ivO4+IVzPk2eU6Rv4bBfvbsNj99V3ieRERX/r+fAYlIt6O+CQ8jYjXM+bZ5UcM/CS0v50Wub+l3pN+NleQiWbaX93MZva31HvST2ZLMc1M+6ub2cz++goy9Q9EQ7wc8dqpf6Cceqb91c1sZn9ONYGEgkBCQSChIJBQEEgoCCQUBBIKAgkFgYSCQEJBIKEgkFAQSCgIJBQEEgoCCQWBhIJAQkEgsdR70h9mSzHNTPurm9nM/pZ6T/r9bCmmmWl/dTOb2d9S70m/nSvIRDPtr25mM/vbWZD1CXNXsZ+Qj0c/fhvxNXexOs5yX65jxPmy9rdlsfsbcnj1u1gdqjXm3KUhbmL1be3zkR++bH/Huz8AAABgX/4FumZ97KsUtWoAAAAASUVORK5CYII=" + }, + "sword": { + "icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAACXBIWXMAAAsTAAALEwEAmpwYAAAE40lEQVR4nO3dMY4UVxQF0NeWnCBysBfgDbAAy3uCBJHaCd6TZedswAsAkyMSgnYwY1mjoS5V86ta7/eckzLwrrq4HiON6lYBAAAALZy+8etPq+pZVT2pqu93vv2lqj5X1ceq+vTAP6N1vvP5/HNVvaqqF1X1fL9oVVX1T1W9q6q3p9Ppzwf+Ga0/v2qQLxXkeVX9uHOoJe/r5oFv0Trf+Xx+XVW/HhPn7qmqenM6nX7b+Ptaf37VJN9SQZ5W1U+Hxfm6v2v9f2la57v9zvFHffs79F7OVfXLhu8krT+/apTvu4UvfnZsluGb3fO9qsuVo25vvdzw9d0/vzb5lgry5MAgS7bc7J7vxWEp9rnZ/fNrk2+pIHv/g2iNLTe759v7H+Rr/LDha7t/fm3yLRUEKAWBSEEgUBAIFAQCBYFAQSBQEAgUBAIFgUBBIFAQCBQEAgWBQEEgUBAIFAQCBYFAQSBYKsiXi6bYfrN7vq3vgNrDhw1f2/3za5NvqSCfDwyyZMvN7vneHZZin5vdP782+ZYK8vHAIEu23Oye723dvMztUs63N9fq/vm1ybdUkE918zrGS3lf297f2jrf7RsO39RlSvLfq0f/2vB7Wn9+1Sifl1cv2+vl1S/r5qVuW95btcaHuvnfqt+9vPpB9sgHAAAAAAAAAI+MHzVZZid9zFU8Xzvp69hJHzPt87WTvp6d9DFTPl876cfctJM+drNNPjvpx9y0kz52s00+O+nH3LSTPnazTT5vNYFAQSBQEAgUBAIFgUBBIFAQCBQEAgWBQEEgUBAIFAQCBYFAQSBQEAgUBAIFgUBBIFAQCOykH3PTTvrYzTb57KQfc9NO+tjNNvnspB9z00762M02+eykr2Mnfcy0z9fLq5fZSR9z9c8XAAAAAAAAAB4fP2qyzE76mKt4vnbS17GTPmba52snfT076WOmfL520o+5aSd97GabfHbSj7lpJ33sZpt8dtKPuWknfexmm3zeagKBgkCgIBAoCAQKAoGCQKAgECgIBAoCgYJAoCAQKAgECgKBgkCgIBAoCAQKAoGCQKAgENhJP+amnfSxm23y2Uk/5qad9LGbbfLZST/mpp30sZtt8tlJX8dO+phpn6+XVy+zkz7m6p8vAAAAAAAAADw+U/+oSfcdcvnm33Gfdie9+w65fP+fqol33KfcSe++Qy7f/ZM16Y77rDvp3XfI5btr2h33WXfSu++Qyzd2s83fv1l30rvvkMt335Q77t5qAoGCQKAgECgIBAoCgYJAoCAQKAgECgKBgkCgIBAoCAQKAoGCQKAgECgIBAoCgYJAoCAQzLqT3n2HXL77ptxxn3UnvfsOuXxjN9v8/Zt1J737Drl8d0274z7lTnr3HXL57ph6x/0aXl7ddodcvqvfcQcAAAAAAACAR2bqHzWp5vnskM//fKfdSa/m+eyQ3zHt851yJ72a57ND/lVTPt9Zd9K757NDPnazTb5Zd9K757NDPnazTb5Zd9K757NDPnazTT5vNYFAQSBQEAgUBAIFgUBBIFAQCBQEAgWBQEEgUBAIFAQCBYFAQSBQEAgUBAIFgUBBIFAQCGbdSe+ezw752M02+WbdSe+ezw752M02+WbdSe+ezw752M02+abcSa/m+eyQ3zPt8/Xy6mVXv+NezT+/6p8PAAAAuJR/ATEXlVHvyECcAAAAAElFTkSuQmCC" + }, + "giraffe": { + "icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAACXBIWXMAAAsTAAALEwEAmpwYAAAE+UlEQVR4nO3dPY4cVRQF4NtIJBY5PwtgA14AYk92gpxCYvaEIPcGWICNc+TEQRP0IGs09U6/mqqy3+v5vtRj36PSnBEW7TpVAAAAwBBO6RfP5/NPVfWyqp5X1Xc73/6nqt5U1evT6fTnY/6A0fNV1TdV9W1VPauqr/cKdudjVX2oqvdV9e8j/wz5ruRrFuR8Pv9SVb/uHGrxVFW9Op1Ov636TYPnq0thfzggz5K3dSn0GvJ90sy3WJC7n8x/tH79AOeq+rn3J/Xo+eryk+/HA/Ms+bv6f1LL99Bivq8aX/yyPt83X93derHi60fP9+1RQXa6KV/nzVZBnh8YpGXNzdHzPTssxT435eu82SrI3n/h7fH9iq8dPd/ef6Hc+6Z8nTdbBQFKQSBSEAgUBAIFgUBBIFAQCBQEAgWBQEEgUBAIFAQCBYFAQSBQEAgUBAIFgUBBIFAQCFoFWfsOoz28W/G1o+f7eFiKfW7K13mzVZA3BwZpWXNz9HwfDkuxz035Om+2CvK6Li9L+1zOdzd7jZ7v/VFBdropX+fNxYLcvUHwVX2eb8L/X+35V+9vGD1fXd7Q9/agPEve1rr338p3XzNfz8urX9TlpWlr3gvV411d/rPl940vrx42Xw3w8uUr5NuWDwAAAAAAAACemGtDmEP/r3476Tf/UY4vni8VZIid6hY76fdMu0MeDJGvVZBhdqqX2ElfNOUOecMw+Vr/HmSYneoGO+nbbsrXebNVkGF2qhvspG+7KV/nzVZBhtmpbrCTvu2mfJ03vdUEAgWBQEEgUBAIFAQCBYFAQSBQEAgUBAIFgUBBIFAQCBQEAgWBQEEgUBAIFAQCBYFAQSBoFWSYneoGO+nbbsrXebNVkGF2qhvspG+7KV/nzVZBhtmpbrCTvu2mfJ03WwUZZqd6iZ30B6bdIW8YJt8tvLzaTvrEL4e+YvR8AAAAAAAAAPDE3MJHTeyk3+5HOb54PjvpHafKTvpW0+azk97HTvp2U+azk97HTvp2U+azk37MzdGfn3ydN+2k97OTvs2U+bzVBAIFgUBBIFAQCBQEAgWBQEEgUBAIFAQCBYFAQSBQEAgUBAIFgUBBIFAQCBQEAgWBQEEgsJPez076NlPms5N+zM3Rn598nTftpPexk77dlPnspF9nJ327afPdwsur7aRP/HLoK0bPBwAAAAAAAABPzC181GTYnXT55t+Zt5PecaoesZMu36dTNfHOvJ30Pqt20uV7eLIm3Zm3k95n7U66fPdNuzNvJ/2Ym/JtuznM95+d9H5r/r2JfA9NuTPvrSYQKAgECgKBgkCgIBAoCAQKAoGCQKAgECgIBAoCgYJAoCAQKAgECgKBgkCgIBAoCAQKAoGd9H5rdtLle2jKnXk76cfclG/bzWG+/+yk91m7ky7ffdPuzNtJv271Trp890y9M38LL68ediddvpvfmQcAAAAAAACAJ+YWPmpi59vzeww76TuZeue7xfO7x076RtPufC/x/BbZSd9g2p3vBs+v86ad9GNuen7bbg7z/Oyk95ty57vB8+u86a0mECgIBAoCgYJAoCAQKAgECgKBgkCgIBAoCAQKAoGCQKAgECgIBAoCgYJAoCAQKAgECgKBnfR+U+58N3h+nTftpB9z0/PbdnOY52cnvc+0O98Nnl/nTTvp1029873E83vATvoj3PzOt+dnJx0AAACm8R/nWLbllDXkpAAAAABJRU5ErkJggg==" + }, + "skull": { + "icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAACXBIWXMAAAsTAAALEwEAmpwYAAAF/klEQVR4nO3dMW4cVxYF0NsDOBGUS/YCvAEvQPCepMRQaifybmZyw861AS+AtHJBiQDXBE1x1Oj+j/VZVe3PmnNSNfkuiv+SItD8LwEAAACGcHjg358neZHkWZJvVp79OcmnJB+SfHzMJ5im6VWSN0l+SPJyvWhJkr+SvE/y7nA4/P6YTyDfsnwZ4PxVBXmZ5LuVQ7Xc5PhAZ5um6ackP28T53RUkreHw+GXrg+S735UHpEvg5y/VkGeJ/l+sziX/ZmZP0nuvvP9lod/Aq5lSvLj3O+E8p2PTEe+DHT+/tV48Yttsyye+SbX++LmbtbrjtfLd6o33zDnr1WQZxsGaemZ+cNmKdaZKd+ymcOcv1ZB1v6FaI6emWv/QjnHtx2vle9cT75hzl+rIEAUBEoKAgUFgYKCQEFBoKAgUFAQKCgIFBQECgoCBQWBgoJAQUGgoCBQUBAoKAgUFAQKCgKFVkE+XzVF/8yuO7RWctvxWvnO9eQb5vy1CvJpwyAtPTPfb5ZinZnyLZs5zPlrFeTDhkFaema+y/EysmuZ7mbOJd+p3nzDnL9WQT7meB3jtdyk437euxv63uY6X+QvV2f+MfcD5DvRnS8Dnb89XF79OsdLyXruXZrjNsf/Fvy68HJo+Z7w5dUAAAAAAAAAwNfKt5rYo73vPe7x/B58fs2C2KN9Ynd73OP53Y9K8fwuFsQe7Yt2s8c9nt/ZyDSeX+vt7vZoL5vp+S2bOczzaxXEHu1lMz2/ZTOHeX6tgtijvWym57ds5jDPz60mUFAQKCgIFBQECgoCBQWBgoJAQUGgoCBQUBAoKAgUFAQKCgIFBYGCgkBBQaCgIFBQECgoCBRaBbFHe9lMz2/ZzGGeX6sg9mgvm+n5LZs5zPNrFcQe7WUzPb9lM4d5fhcLYo/2mV3tcY/n97Xy+c25vNoe7Z3ucY/nt/T5AQAAAAAAAAD/M03Tq2ma/jNN0+20vtu7z/1KPvmeXL5pmn7aINQlf0/Hndjyyfc08k3H5v59pYBfQs5usnzyXSvfU92TLt8p+ZbZ3Z50+ZbNlG/mzIstnabpmn/Nde9wOMz6riHfZfItcymfW02goCBQUBAoKAgUFAQKCgIFBYGCgkBBQaCgIFBQECgoCBQUBAoKAgUFgYKCQEFBoKAgUFAQKDzVPenynZNvmV3tSZdv2Uz5Zs58qnvS5Tsl3zK9+e6vfrzG7XZLrqaUT75/JN+XkK+mafr3NE03GwS7ufvcSy83lk++fyQfAAAAAAAAAPz/eWgl1vMkL5I8S/LNyrM/J/mU5EOSj4/5BHdvE3iT4365l+tFS3J8y/X7JO8Oh8Pvj/kE8i3LlwHOX1WQl0m+WzlUy006/wZgOr7B7Odt4pyOSvL2cDj80vVB8t2PyiPyZZDz1yrI8yTfbxbnsj8z8yfJ3Xe+33K9VcFTkh/nfieU73xkOvJloPPX+nuQF9tmWTxzmD3aDfKd6s03zPlrFeTZhkFaemYOs0d7hdeuZU/5hjl/rYKs/QvRHD0z1/6Fco5vO14r37mefMOcP7eaQEFBoKAgUFAQKCgIFBQECgoCBQWBgoJAQUGgoCBQUBAoKAgUFAQKCgIFBYGCgkBBQaCgIFBoFeTzVVP0zxxmj3aDfOd68g1z/loF+bRhkJaemcPs0V7htWvZU75hzl+rIB82DNLSM3P0PdrynerNN8z5axXkY47XMV7LTTru5727oe9trvNF/nJ15h9zP0C+E935MtD528Pl1a9zvJSs596lOW5z/G/Brwsvh5bvCV9eDQAAAAAAAAB8bQ9vNRl2z7d89qSvxZ70x9tlvgxy/uxJn2dXe8hHz5eBzp896fPsbQ/56PmGOX/2pG8zU75lM4c5f/akz7enPeSj5xvm/LnVBAoKAgUFgYKCQEFBoKAgUFAQKCgIFBQECgoCBQWBgoJAQUGgoCBQUBAoKAgUFAQKCgIFBYGCPenz7WkP+ej5hjl/9qRvM1O+ZTOHOX/2pM+ztz3ko+cb5vzZk/6w3e0hHz1fBjp/e7i8etg93/LZkw4AAACs5L+H4EzOKL34ywAAAABJRU5ErkJggg==" + }, + "umbrella": { + "icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAACXBIWXMAAAsTAAALEwEAmpwYAAAF40lEQVR4nO3dQW4TSRQG4NcjsYmyT+AAXIADRNwJNihb2MBtZvYI9lyAAySTfZRNJGoWdpix7Hp0pdqm4vm+Lbbfr07/NpGcehEAAADAEKZf/PtpRJxFxElEPFt49n1E3EXETUTcPuYFSikXEfE2Il5FxPly0SIi4u+I+BYRH6dp+vKYF5CvL18McP9lBTmPiBcLh6q5itUFna2U8i4i3u8nzuaoiLicpulD05Pk+zkqHpEvBrn/agU5jYiXe4uz2/eY+Umyfuf7HL/+BFxKiYjXc98J5dseGQ35YqD774/Kg8/2m6V75ts43A831rPeNDxevk2t+Ya5/2oFOdljkJqWma/2lmKZmfL1zRzm/qsVZOlfiOZombn0L5RzPG94rHzbWvINc//VCgKEgkBKQSChIJBQEEgoCCQUBBIKAgkFgYSCQEJBIKEgkFAQSCgIJBQEEgoCCQWBhIJAQkEgUSvI/UFTtM9sOkNrIdcNj5VvW0u+Ye6/WkHu9hikpmXmt72lWGamfH0zh7n/agW52WOQmpaZH2N1GNmhlPXMueTb1JpvmPuvVpDbWB3HeChX0XA+7/qEvss4zA/54ejMr3OfIN+G5nwx0P13DIdXv4nVoWQt5y7NcR2r/xZ86jwcWr4nfHg1AAAAAAAAADBbKeWilPJXKeW6LO96/doX8sn35PKVUt7tIdQuP8pqZ7d88j2NfGXV3B8HCvgQcnaT5ZPvUPlqX3cffY+2fJvk61PNVyvI6Hu05eubKd/MmTtbWko55F+b/TRN06x3Dfl2k6/PrnxONYGEgkBCQSChIJBQEEgoCCQUBBIKAgkFgYSCQEJBIKEgkFAQSCgIJBQEEgoCCQWBhIJAQkEgUSvI6Hu05dsmX5+d+WoFGX2Ptnx9M+WbObNWkNH3aMu3Sb4+rfl+Hv14iNPteo6mlE++35LvIeRFKeXPUsrVHoJdrV+793Bj+eT7LfkAAAAAAAAA4P/nVyuxTiPiLCJOIuLZwrPvI+IuIm4i4vaRrzF0vvXXGN7Gav/d+XLRImL1lfBvEfFxmqYvj3yNoa9fDJAvK8h5RLxYOFTNVbT/DcDQ+crqC3Dv9xNnc1REXE7T9KHxeUNfvxgkX60gpxHxcm9xdvse899phs63/uT4HIdbZVwi4nXDJ8nQ1y8Gylf7e5Cz/Wbpnjl6vmH2fFeMfv2GyVcryMkeg9S0zBw93zB7vitGv37D5KsVZOlfiOZomTl6vqV/IZ/jecNjR79+w+RzqgkkFAQSCgIJBYGEgkBCQSChIJBQEEgoCCQUBBIKAgkFgYSCQEJBIKEgkFAQSCgIJBQEEgoCiVpB7g+aon3m6PmG2fNdMfr1GyZfrSB3ewxS0zJz9HzD7PmuGP36DZOvVpCbPQapaZk5er7R93yPfv2GyVcryG2sjmM8lKtoO7916HzrEw4v4zAleTh69GvDc4a+fjFQPodX1y11ePWbWB3q1nJu1RzXsfpv1SeHVz/KEvkAAAAAAAAA4H8m/aqJPd/2pHc4iq+aVAtiz/cGe9L7HNeedHu+d7Invc9R7Um357tvpuvXN3OYfLWC2PPdN9P165s5TL5aQez57pvp+vXNHCafU00goSCQUBBIKAgkFAQSCgIJBYGEgkBCQSChIJBQEEgoCCQUBBIKAgkFgYSCQEJBIKEgkFAQSNQKYs9330zXr2/mMPlqBbHnu2+m69c3c5h8tYLY89030/XrmzlMvp0Fsed7iz3pfY5zT7o93/akdziKw6sBAAAAAAAAgP960nvS5bMnvcNx70mX799RYU96r+Paky7f9siwJ73XUe1Jl2+TPen9jmpPunx9M4fZQ77AY5dyVHvS5dtmT3ofe9KhlYJAQkEgoSCQUBBIKAgkFAQSCgIJBYGEgkBCQSChIJBQEEgoCCQUBBIKAgkFgYSCQEJBIPFU96TLt82e9D5HtSddvr6Zw+whX+CxSzmqPenybbInvd/x7EmXb4M96f2Oc0+6fPakd7AnHQAAAJ6SfwCf6hpwMVaGmQAAAABJRU5ErkJggg==" + }, + "snake": { + "icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAACXBIWXMAAAsTAAALEwEAmpwYAAAFE0lEQVR4nO3dMY5bVRQG4GMQTTTUARbAAsgCIvaUNCgtNGFPCPqwABYwIQ1VlCIpTGHDYOx75r6571nnvfm+djxzfl35t8aSfU8EAAAAUMIu++F+v38eES8j4llEfDXz7D8j4k1EvN7tdr8+5A9UzxcRNxHxNCKeRMQXcwU7+hQRHyLiXUS8f+DfkO+efM2C7Pf7HyLix5lDXRwVEa92u91Pk36peL44FPabBfJcchuHQk8h351mvosFOb4y/9L6+QL2EfF97yt19XxxeOX7dsE8l/wR/a/U8p27mO+zxoNfxvWefHGc9WLC46vne7pUkJlmytc5s1WQZwsGaZkys3q+J4ulmGemfJ0zWwWZ+w1vj68nPLZ6vrnfUM49U77Oma2CAKEgkFIQSCgIJBQEEgoCCQWBhIJAQkEgoSCQUBBIKAgkFAQSCgIJBYGEgkBCQSChIJBQEEi0CjL1DqM5vJ3w2Or5Pi2WYp6Z8nXObBXkzYJBWqbMrJ7vw2Ip5pkpX+fMVkFex+GytGvZH2f2qp7v3VJBZpopX+fMiwU53iD4Kq7zJPznas/fen+her443NB3u1CeS25j2v238p1q5uu5vPpFHC5Nm3IvVI+3cfi35efBy6vL5osCly/fQ76xfAAAAAAAAADwyNiT3rb5PenVz69CPnvSO0bFBvekVz+/KvnsSe+zqT3p1c+vUj570vtsbU969fMrk8+e9GVmltnz3VD9/Mrka/2Ldc1v6/1rt9t1vWpUzxcR3y0apO33ngdVP79K+dxqAgkFgYSCQEJBIKEgkFAQSCgIJBQEEgoCCQWBhIJAQkEgoSCQUBBIKAgkFAQSCgIJBYGEgkDCnvR+W9qTXv38yuSzJ32ZmWX2fDdUP78y+exJ77O1PenVz69MPnvS77e5PenVz69SPnvS2za/J736+VXPBwAAAAAAAACPz30rsdbwUYmye77D+a3+/LKC2PN9HBX2pI9Y9fm1CmLP9/9Ghj3pI1Z7fq3vg9jzfcqe9DGrPb9WQez5Hpvp/MZmljm/VkHmfkPUY8rMud9Q9pjyfQTnd26V5+dWE0goCCQUBBIKAgkFgYSCQEJBIKEgkFAQSCgIJBQEEgoCCQWBhIJAQkEgoSCQUBBIKAgkFAQSrYLY833OnvQxqzy/VkHs+R6b6fzGZpY5v1ZB7Pk+ZU/6mNWeX6sg9nzfsSd9zKrPbwuXV1feo+38Nnx+AAAAAAAAAPD4bOGjJmX3fMtnT/pcNrfnW767UWFP+iw2s+dbvvORYU/6sC3t+ZbvlD3pM9jSnm/5xmaWef7Zk95vyvcl5DtnTzpsjYJAQkEgoSCQUBBIKAgkFAQSCgIJBYGEgkBCQSChIJBQEEgoCCQUBBIKAgkFgYSCQEJBIGFPer8pe77lO2dP+qAt7fmWb2xmmeefPel9pu75lu+UPemDNrXnW74T9qQ/0Ob3fMtnTzoAAAAAAAAAbMuqP2oS8sn3cNvekx7y/Zd8Y5r5Wp/mvYnrhYvjrJsJj5fvlHxjmvnWuiddvrGZ8nXOXOuedPnGZsrXOXOte9LlG5spX+dMt5pAQkEgoSCQUBBIKAgkFAQSCgIJBYGEgkBCQSChIJBQEEgoCCQUBBIKAgkFgYSCQEJBIKEgkFjrnnT5xmbK1zlzrXvS5RubKV/nzLXuSZdvbKZ8nTM/bzz4Yxz2W3+5WJxTtxHx14THy3dKvjHNfC6vbpNvzGPIBwAAAFzL3/Yj4OZvgj/VAAAAAElFTkSuQmCC" + }, + "rabbit": { + "icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAACXBIWXMAAAsTAAALEwEAmpwYAAAE50lEQVR4nO3dTW4UVxQF4FuRMkHMIVlAFgALiLInmERMkwnZU5TMYQFZAD9zxIRBZ2AH3O5+J1V+Va3Xpe8bGtv36prTsiW7ThUAAAAwhCn94+Fw+LmqXlbV86p6uvLsD1X1pqpeT9P01wM/x+OqelJVj6rq+7UWu/Wlqj5X1ceq+vSQT+B+fferAfZrBuRwOPxaVb+tvNTZUVX1apqm3xd+3NOq+nGDfc55Vzf/IWdzvyOL71eD7Hc2ILevfH+2/n0Dh6r6ZcEr4eOq+mnDfc75p2a+ErrfWbPvVwPt913jnV/W5b64dTvrxYL3f7LVIivNdL++mcPs1wrI8w0XaVky89FmW6wz0/36Zg6zXysga/9AOccPC9537R/Y1p7pfn0zh9mvFRCgBAQiAYFAQCAQEAgEBAIBgUBAIBAQCAQEAgGBQEAgEBAIBAQCAYFAQCAQEAgEBAIBgaAVkKXPMFrD+wXv+2WzLdaZ6X59M4fZrxWQNxsu0rJk5ufNtlhnpvv1zRxmv1ZAXtfNw8gu5XA7c66PWy2y0kz365s5zH5nA3L7hL5XdZkv8n+Pzvx7wcd8qpvHRV7Ku1rwfFn3O7HofjXQfnMeXv2ibh5KtuS5S3O8r5tvC/7Y68OX3e/6H14NAAAAAAAAANylJ71NT3qfXfyqiZ70efSk99GT3mlXPd/ud5ae9A576/l2v76Zw+ynJ32bme7XN3OY/fSkbzPT/fpmDrOfp5pAICAQCAgEAgKBgEAgIBAICAQCAoGAQCAgEAgIBAICgYBAICAQCAgEAgKBgEAgIBAICAR60reZ6X59M4fZT0/6NjPdr2/mMPvpSd9mpvv1zRxmPz3p8+hJ76Mn/QF23/Ptftf/8GoAAAAAAAAA4K6r7km33773qwF+1eRqe9Lt921U7XC/0pN+PLIW9Hzb73Rk7Wi/0pN+YmnPt/2O7W0/PemdM+3XN3P0/YbpSW99i3XJv4b7apqmWa9q9jtvL/tV1bNNF2l7e/8NnmoCgYBAICAQCAgEAgKBgEAgIBAICAQCAoGAQCAgEAgIBAICgYBAICAQCAgEAgKBgEAgIBBca0+6/U7taT896Z0z7dc3c/T99KTfs7Tn237H9rafnvQ7Fvd82+/I7vYrPelVtULPt/32vV8N8PBqAAAAAAAAAOAuPeltu+j5TtxPT/oarrrnu8X9juhJ73S1Pd/nuN9ZetI7XG3Pd4P7zZypJ32bmcP0fDe438yZrYCs/QPbHEv+HmH0/db+gXLtme43c6anmkAgIBAICAQCAoGAQCAgEAgIBAICgYBAICAQCAgEAgKBgEAgIBAICAQCAoGAQCAgEAgIBHrS57vKnu8G95s5U0/6NjOH6flucL+ZM/Wkz3O1Pd8N7jdzpp70/3fVPd/nuN8JPekPsPueb/fTkw4AAAAAAAAAy+hJb7NfHz3pK9llT7r9vo0qPenddtWTbr/TkaUnvcveetLtd0xP+gr21JNuv76Zw/Skt77FuuRfm301TdOsVzX7nbeX/arq2aaLtL29/wZPNYFAQCAQEAgEBAIBgUBAIBAQCAQEAgGBQEAgEBAIBAQCAYFAQCAQEAgEBAIBgUBAIBAQCPSkz2e/PnrSO+2pJ91+fTP1pN+zt550+x3Tk95hdz3p9juiJ/2Bdt+Tbj896QAAAMBK/gVsdTwSu+HRwQAAAABJRU5ErkJggg==" + }, + "cow": { + "icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAACXBIWXMAAAsTAAALEwEAmpwYAAAF2klEQVR4nO3dMW4USRQG4NcrkVjObTgAF+AAFneCBDmFBG6zmyPIuQAHsNe55cQStcGMYUeeftvl6h6qZ78vZWbeL0/9NpbG9SIAAACALgzZP5ZSLiLibUS8iojzmWf/HRHfIuLjMAxfnvgapxFxFhEnEfFsrmBb9xFxFxE3EXH7xNeQryFfD+dvtCCllHcR8X7mUHtHRcTlMAwfKp93HhEvFsizz1VsvqA15PulOl8v529vQbbN/Tz27wsoEfG64ifJaUS8XDDPPt9j+ndC+R6bnK+n8/fHyBPexuHCxXbWm4rHny0VZKaZ8rXN7Ob8jRXk1XJZRtXMPFksxTwz5Wub2c35GyvI3L8QTfG84rFz/0I590z52mZ2c/7GCgKEgkBKQSChIJBQEEgoCCQUBBIKAgkFgYSCQEJBIKEgkFAQSCgIJBQEEgoCCQWBhIJAQkEgMVaQ2juW5nBd8dj7xVLMM1O+tpndnL+xgnxbMMiYmpl3i6WYZ6Z8bTO7OX9jBfkYm8u0DqVsZ051s1SQmWbK1zazm/O3tyDbG+Yu4zAhH65+/FrxnNvYXGd5KFdRd7+sfLuq8vV0/qZcXv0mNpdq1dxbNcV1bH6sfXJ59ZMcfb4VnD8AAAAAAAAA+J+xJ33c0X+UIzrP18P5syd9mqPbQx6d5+vl/NmTPt3R7CGPzvP1dP7sSV9mpnxtM7s5f/akLzNTvraZ3Zw/e9KXmSlf28xuzp9bTSChIJBQEEgoCCQUBBIKAgkFgYSCQEJBIKEgkFAQSCgIJBQEEgoCCQWBhIJAQkEgoSCQUBBI2JO+zEz52mZ2c/7sSV9mpnxtM7s5f/akLzNTvraZ3Zw/e9KnOao95NF5vp7Onz3p447+cujoPN8Kzh8AAAAAAAAA8Esp5aKU8lcp5brM73r72hfyybe6fKWUdwuE2udH2ezElk++deQrm+b+OFDAh5CTmyyffIfKt9Y96fLtkq/N0e1Jl69tpnwTZ+5taSnlkH/N9dMwDJO+a8i3n3xt9uVzqwkkFAQSCgIJBYGEgkBCQSChIJBQEEgoCCQUBBIKAgkFgYSCQEJBIKEgkFAQSCgIJBQEEgoCibXuSZfvMfnaHNWedPnaZso3ceZa96TLt0u+NrX5fl79eIjb7VquppRPvt+S7yHkRSnlz1LK1QLBrrav3Xq5sXzy/ZZ8AAAAAAAAAPD/818rsU4j4iwiTiLi2cyz7yPiLiJuIuL2KS+w/ZjA29jslzufL1pEbD5y/S0iPg7D8OUpLyBfW77o4PxlBTmPiBczhxpzFZV/A1A2HzB7v0yc3VERcTkMw4eqJ8n3c1Q8IV90cv7GCnIaES8Xi7Pf95j4k2T7ne9zHG5VcImI11O/E8r3eGRU5IuOzt/Y34OcLZuleWY3e7RHyLerNl8352+sICcLBhlTM7ObPdozPHYux5Svm/M3VpC5fyGaombm3L9QTvG84rHyPVaTr5vz51YTSCgIJBQEEgoCCQWBhIJAQkEgoSCQUBBIKAgkFAQSCgIJBYGEgkBCQSChIJBQEEgoCCQUBBJjBbk/aIr6md3s0R4h32M1+bo5f2MFuVswyJiamd3s0Z7hsXM5pnzdnL+xgtwsGGRMzcze92jLt6s2Xzfnb6wgt7G5jvFQrqLift7tDX2XcZg3+eHqzK9TnyDfjup80dH5O4bLq9/E5lKymnuXpriOzX8LPjVeDi3fii+vBgAAAAAAAAD+bdUfNYnO89lDvv73d7V70qPzfPaQ71jt+7vKPenReT57yPda5fu71j3pveezh7xtZjf51ronvfd89pC3zewm31r3pPeezx7ytpnd5HOrCSQUBBIKAgkFgYSCQEJBIKEgkFAQSCgIJBQEEgoCCQWBhIJAQkEgoSCQUBBIKAgkFAQSCgKJte5J7z2fPeRtM7vJt9Y96b3ns4e8bWY3+da6J733fPaQt83sJt8q96RH5/nsIX9kte+vy6vHHf0e9+j86xf95wMAAAAO5R/MoQmmFihqmAAAAABJRU5ErkJggg==" + }, + "quarternote": { + "icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAACXBIWXMAAAsTAAALEwEAmpwYAAAE8ElEQVR4nO3dQY4VZRQF4PtMnBDmoAtwAyzAuCeYEKY6wT0ZnbMBFwAyJ0wYPAfdxnTaOl3V/1/P+4rvm1pwT97LAUk6daoAAACAFk4P/PenVfWsqp5U1beTb3+pqs9V9bGqPj3y92id73w+/1hVr6rqRVU9nxetqqr+qqp3VfX2dDr9/sjfo/XnVw3ypYI8r6rvJ4da8r5uvvAtWuc7n8+vq+rnfeLcPVVVb06n0y8bf13rz6+a5FsqyNOq+mG3OP/tz1r/J03rfLd/c/xWD/8NPcu5qn7a8DdJ68+vGuX7ZuHhZ/tmGb7ZPd+rulw56vbWyw3Pd//82uRbKsiTHYMs2XKze74Xu6WYc7P759cm31JBZv+DaI0tN7vnm/0P8jW+2/Bs98+vTb6lggClIBApCAQKAoGCQKAgECgIBAoCgYJAoCAQKAgECgKBgkCgIBAoCAQKAoGCQKAgECgIBEsF+XLRFNtvds+39R1QM3zY8Gz3z69NvqWCfN4xyJItN7vne7dbijk3u39+bfItFeTjjkGWbLnZPd/bunmZ26Wcb2+u1f3za5NvqSCf6uZ1jJfyvra9v7V1vts3HL6py5Tkn1eP/rHh17T+/KpRPi+vXjbr5dUv6+alblveW7XGh7r536pfvbz6UWbkAwAAAAAAAICvjB81WWYnfcwhvl876evYSR9ztd+vnfT17KSPucrv1076PjftpI/dbJPPTvo+N+2kj91sk89O+j437aSP3WyTz1tNIFAQCBQEAgWBQEEgUBAIFAQCBYFAQSBQEAgUBAIFgUBBIFAQCBQEAgWBQEEgUBAIFAQCO+n73LSTPnazTT476fvctJM+drNNPjvp+9y0kz52s00+O+nr2Ekfc7Xfr5dXL7OTPubw3y8AAAAAAAAAfH38qMkyO+ljDvH92klfx076mKv9fu2kr2cnfcxVfr920ve5aSd97GabfHbS97lpJ33sZpt8dtL3uWknfexmm3zeagKBgkCgIBAoCAQKAoGCQKAgECgIBAoCgYJAoCAQKAgECgKBgkCgIBAoCAQKAoGCQKAgENhJ3+emnfSxm23y2Unf56ad9LGbbfLZSd/npp30sZtt8tlJX8dO+pir/X69vHqZnfQxh/9+AQAAAAAAAODrE3/UpPvOt3x20geM7aR33/mW799TZSd91Lad9O473/LdP1l20kdt2knvvvMt31120sdt2knvvvMt39jNNjvkE56dZdNOevedb/nus5M+xk46bKUgECgIBAoCgYJAoCAQKAgECgKBgkCgIBAoCAQKAoGCQKAgECgIBAoCgYJAoCAQKAgESwXpvvMt33120sds2knvvvMt39jNNjvkE56dZdNOevedb/nuspM+bv1Oevedb/nusJM+7nE76d13vuWzkz7ATjoAAAAAAAAAbGYnfdnh81X/H+X43/PZSV9xqg6Yr5rskAct8tlJX+dQ+arRDvmCNvnspK9ztHxtdsgnPDuLnfRBR8rXZod8wrOz2EkfdKR8bXbIJzw7i5102EpBIFAQCBQEAgWBQEEgUBAIFAQCBYFAQSBQEAgUBAIFgUBBIFAQCBQEAgWBQEEgUBAI7KSvd6R8bXbIJzw7i530QUfK12aHfMKzs9hJH3C0fG12yCc8O4ud9Ec6XL5qtEO+oE0+O+nLDp+vGrwc+gHd8wEAAACX8jdzZLbl0C/0iwAAAABJRU5ErkJggg==" + }, + "eigthnote": { + "icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAACXBIWXMAAAsTAAALEwEAmpwYAAAFM0lEQVR4nO3dQY4VVRgF4P+ZOCHMQRfgBliAcU8wMUx1gnsyOmcDLgBkTpgweA66JXa6799V/W61J5fvm1pwT27lgCSdOlUAAABAhNM9//1pVT2rqidV9e3ksz9X1aeq+lBVHx/4e0TnO5/PP1bVq6p6UVXP50Wrqqq/q+ptVb05nU5/PPD3iL6/CsjXFeR5VX0/OdTIu7p64XtE5zufzz9X1S/HxLl5VFW9Pp1Ov+78ddH3VyH5RgV5WlU/HBbnbn/V9j9povNd/83xe93/N/Qs56r6acffJNH3V0H5vhk8/OzYLBefmZ7vVT1eOer6rJc7nk+/v5h8o4I8OTDIyJ4z0/O9OCzFnDPT7y8m36ggs/9BtMWeM9Pzzf4H+Rbf7Xg2/f5i8o0KApSCQEtBoKEg0FAQaCgINBQEGgoCDQWBhoJAQ0GgoSDQUBBoKAg0FAQaCgINBYGGgkBDQaAxKsjnR02x/8z0fHu/ATXD+x3Ppt9fTL5RQT4dGGRkz5np+d4elmLOmen3F5NvVJAPBwYZ2XNmer43dfUxt8dyvj5zq/T7i8k3KsjHuvoc42N5V/u+3xqd7/oLh6/rcUry76dH/9zxa6Lvr4Ly+Xj12KyPV7+sq4+67flu1Rbv6+p/q37z8eoHmZEPAAAAAAAAAL4yftRkbPmd9PR8FfB+7aRvs9xOenq+Cnm/dtK3W2YnPT1fBb1fO+nHnJm+k56eL+b92kk/5sz0nfT0fDHv1076MWem76Sn54t5v75qAg0FgYaCQENBoKEg0FAQaCgINBQEGgoCDQWBhoJAQ0GgoSDQUBBoKAg0FAQaCgINBYGGgkDDTvoxZ6bvpKfni3m/dtKPOTN9Jz09X8z7tZN+zJnpO+np+WLer530bZbaSU/PV0Hv18erx5bfSU/PV+HvFwAAAAAAAAC+Pn7UZGz5nfRyf/fen530bZbbSS/39+Woau7PTvp2y+ykl/u7dWQN7s9O+jFn2iG/7MyY+7OTfsyZdsgvOzPm/uykH3OmHfLLzoy5P181gYaCQENBoKEg0FAQaCgINBQEGgoCDQWBhoJAQ0GgoSDQUBBoKAg0FAQaCgINBYGGgkBDQaBhJ/2YM+2QX3ZmzP3ZST/mTDvkl50Zc3920o850w75ZWfG3J+d9G2W2kkv9/df7f35ePXY8jvp5f4uvT8AAAAAAAAA+Mq0P2qSsFPdkW/tnfQKyDcsSMpO9fAXyfflqFpwJ71C8t1ZkKSd6jsflu/WkbXQTnoF5Rv9uHvMTvWAfDettpMek29UkJid6gnPzrJSvvSd9Jh8o4LE7FQPyHfbSjvpMfl81QQaCgINBYGGgkBDQaChINBQEGgoCDQUBBoKAg0FgYaCQENBoKEg0FAQaCgINBQEGgoCDQWBxqggMTvVA/LdttJOeky+UUFidqonPDvLSvnSd9Jj8o0KErNTPSDfTavtpMfku7MgSTvVd5HvhuV20iso35aPV8fuVMu39k565ecDAAAAAAAAgK+MnfSx5fNV/o9y/O/57KRvOKoWzFchO+SNiHx20rdZKl8F7ZAPxOSzk77NavlidsgnPDuLnfQLrZQvZod8wrOz2Em/0Er5YnbIJzw7i5102EtBoKEg0FAQaCgINBQEGgoCDQWBhoJAQ0GgoSDQUBBoKAg0FAQaCgINBYGGgkBDQaChINCwk77dSvlidsgnPDuLnfQLrZQvZod8wrOz2Em/wGr5YnbIJzw7i530B1ouXwXtkA/E5LOTPrZ8vgr4OPQ90vMBAAAAj+Uf73PYeRwCFc4AAAAASUVORK5CYII=" + }, + "pitchfork": { + "icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAACXBIWXMAAAsTAAALEwEAmpwYAAAFsklEQVR4nO3dQU4VWRQG4FOdOCHMQRfgBlwAcU8yMUx1orvpnhuduwEXADInTEi8PXgPO7TvHqu4Vc9bj++bNnD+HPJjk+g9EQAAAEAXhuw/llLOIuI8Il5FxOnMs79HxNeI+DAMw+dHfo3jiDiJiKOIeDZXsK27iLiNiOuIuHnMF7C/9e+vWpBSytuIeDdzqJ2jIuJiGIb3Ez/vNCJeLJBnl8vYLHQ0+3tgtfvbWZBtcz/V/vsCSkS8nvCT8DgiXi6YZ5dvMfInof3ttMr9/VX5hPPYX7jYznoz4eNPlgoy00z7a5vZzf5qBXm1XJaqKTOPFksxz0z7a5vZzf5qBZn7F6Ixnk/42Ll/oZx7pv21zexmf7WCAKEgkFIQSCgIJBQEEgoCCQWBhIJAQkEgoSCQUBBIKAgkFAQSCgIJBYGEgkBCQSChIJBQEEjUCjLpDaOZXE342LvFUswz0/7aZnazv1pBvi4YpGbKzNvFUswz0/7aZnazv1pBPsTmMa19KduZY10vFWSmmfbXNrOb/e0syPaFuYvYT8j7px+/TPicm9g8Z7kvlzHhfVn7+8Vq9zfm8eo3sXlUa8q7S2NcxeaPtY8H/viy/R3u/gAAAAAAAADgiXEnve4g7nz/hv25kz6L1d75TtjfdlS4kz6LVd75rrC//40Md9KbrfLOd4X9PeRO+gxWeee7wv5GznQnfZmZ9tc2s5v9edUEEgoCCQWBhIJAQkEgoSCQUBBIKAgkFAQSCgIJBYGEgkBCQSChIJBQEEgoCCQUBBIKAgkFgYQ76cvMtL+2md3sz530ZWbaX9vMbvbnTvoyM+2vbWY3+3MnfZzV3vmusL//uJP+SE/hzrf9uZMOAAAAAAAAAHMppZyVUv4ppVyV+V1tv/aZfPKtLl8p5e0CoXb5UTY3seWTbx35yqa5P/YU8D7k6CbLJ9++8q31Trp8D8nX5uDupMvXNlO+kTN3trSUss9/zfXTMAyjfmrIt5t8bXbl86oJJBQEEgoCCQWBhIJAQkEgoSCQUBBIKAgkFAQSCgIJBYGEgkBCQSChIJBQEEgoCCQUBBIKAom13kmX71fytTmoO+nytc2Ub+TMtd5Jl+8h+dpMzffz6cd9vG7X8jSlfPL9kXz3Ic9KKX+XUi4XCHa5/dqtjxvLJ98fyQcAAAAAAAAAT8/vTmIdR8RJRBxFxLOZZ99FxG1EXEfEzSO/Rtf5tn+N4Tw29+9O54sWEZu/Ev41Ij4Mw/D5kV+j6/1FB/mygpxGxIuZQ9VcxvR/A9B1vrL5C3DvlonzcFREXAzD8H7i53W9v+gkX60gxxHxcrE4u32L8T9pus63/ZPjU+zvlHGJiNcT/iTpen/RUb7avwc5WTZL88ze83Vz57ui9/11k69WkKMFg9RMmdl7vm7ufFf0vr9u8tUKMvcvRGNMmdl7vrl/IR/j+YSP7X1/3eTzqgkkFAQSCgIJBYGEgkBCQSChIJBQEEgoCCQUBBIKAgkFgYSCQEJBIKEgkFAQSCgIJBQEEgoCiVpB7vaaYvrM3vN1c+e7ovf9dZOvVpDbBYPUTJnZe75u7nxX9L6/bvLVCnK9YJCaKTN7z9f7ne/e99dNvlpBbmLzHOO+XMa091u7zrd94fAi9lOS+6dHv0z4nK73Fx3l83h13VyPV7+JzaNuU96tGuMqNv9b9dHj1Y8yRz4AAAAAAAAAeGL8VZM6d9LbHMT31530cdxJb7Pa76876eO5k95mld9fd9KXmelOetvMbvK5k77MTHfS22Z2k8+d9GVmupPeNrObfF41gYSCQEJBIKEgkFAQSCgIJBQEEgoCCQWBhIJAQkEgoSCQUBBIKAgkFAQSCgIJBYGEgkBCQSDhTvoyM91Jb5vZTT530peZ6U5628xu8rmTvsxMd9LbZnaTz530cdxJb7Pa76/Hq+vcSW9z8N9fAAAAYI/+BXw0Caa5hJIxAAAAAElFTkSuQmCC" + }, + "target": { + "icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAACXBIWXMAAAsTAAALEwEAmpwYAAAFeElEQVR4nO3dMY5bVRgF4N9INFH6BBbAAsgCEHtKGpQWmrAnBH1YAAtISB+lSWGKGYiMff/xm/dsnTvzfW08uUfP72QykuedKgAAACDC7o4/f1pVz6rqSVV9vfHZn6vqU1V9qKqP9/w7ovPt9/sfqupVVb2oqufbRauqqr+r6m1Vvdntdr/f8++Ivn4VkK8ryPOq+nbjUCPv6uYNXyI6336//6mqfr5MnMOjqur1brf7ZeHXRV+/Csk3KsjTqvruYnFO+6vO/5cmOt/td47f6u7v0FvZV9WPC76TRF+/Csr31eDFzy6bZfWZ6fle1fXKUbdnvVzw+vTrF5NvVJAnFwwysuTM9HwvLpZimzPTr19MvlFBtv6B6BxLzkzPt/UP5Of4ZsFr069fTL5RQYBSEGgpCDQUBBoKAg0FgYaCQENBoKEg0FAQaCgINBQEGgoCDQWBhoJAQ0GgoSDQUBBoKAg0RgX5fNUUy89Mz7f0GVBbeL/gtenXLybfqCCfLhhkZMmZ6fneXizFNmemX7+YfKOCfLhgkJElZ6bne1M3D3O7lv3tmedKv34x+UYF+Vg3j2O8lne17Pmt0flun3D4uq5Tkn8fPfrHgq+Jvn4VlM/Dq8e2enj1y7p5qNuS51ad433d/LfqVw+vvpct8gEAAAAAAADAIzP1R03Sd8jlm3/Hfdqd9PQdcvm+HFUT77hPuZOevkMu3/GRNemO+6w76ek75PIdmnbHfdad9PQdcvnWnRlz/826k56+Qy7fsSl33D3VBBoKAg0FgYaCQENBoKEg0FAQaCgINBQEGgoCDQWBhoJAQ0GgoSDQUBBoKAg0FAQaCgINBYHGrDvp6Tvk8h2bcsd91p309B1y+dadGXP/zbqTnr5DLt+haXfcp9xJT98hl+/A1DvuD+Hh1bE75PI9+B13AAAAAAAAAHhk2o+apO9op+er8I9KpF+/hHzDgqTvaKfnq5Cd75H065eS72RB0ne00/NV0M73KenXLynf6OPu6Tva6flidr4H0q9fTL5RQdJ3tNPzxex8D6Rfv5h8o/9iXfO3zf6z2+3O+lcjPV9VfX/RIGN/nvOi9OuXlM9TTaChINBQEGgoCDQUBBoKAg0FgYaCQENBoKEg0FAQaCgINBQEGgoCDQWBhoJAQ0GgoSDQUBBojAqSvqOdni9m53sg/frF5BsVJH1HOz1fzM73QPr1i8k3Kkj6jnZ6vpid74H06xeT72RB0ne00/NV0M73KenXLynfOQ+vjt3RTs9Xczy8Ovb6pecDAAAAAAAAgMfnrkmsGT4qYef7geargPuvK4id79ujauKd7+EXheerkPtvVBA73/87sibd+T754vB8FXT/jX4fxM73oWl3vgfS88Xcf6OC2Pled6Z8686Muf9GBdn6B6JzLDlz6x8oz7Hk9xHkO7YkX8z956km0FAQaCgINBQEGgoCDQWBhoJAQ0GgoSDQUBBoKAg0FAQaCgINBYGGgkBDQaChINBQEGgoCDRGBbHzfWzKne+B9Hwx99+oIHa+150p37ozY+6/UUHsfB+adud7ID1fzP03Koid7y+m3vk+JT1fBd1/D+Hh1bE72vI97J15AAAAAAAAAHh8pv6oSYXns0M+//s77U56heezQ35g2vd3yp30Cs9nh/ykKd/fWXfS0/PZIV93Zky+WXfS0/PZIV93Zky+WXfS0/PZIV93Zkw+TzWBhoJAQ0GgoSDQUBBoKAg0FAQaCgINBYGGgkBDQaChINBQEGgoCDQUBBoKAg0FgYaCQENBoDHrTnp6Pjvk686MyTfrTnp6Pjvk686MyTfrTnp6Pjvk686MyTflTnqF57NDfmTa99fDq8ce/I57hV+/ys8HAAAAXMs/4tr5dC58svsAAAAASUVORK5CYII=" + }, + "triangle": { + "icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAACXBIWXMAAAsTAAALEwEAmpwYAAAFX0lEQVR4nO3dsW5URxQG4LNBNJapTXiAvAAPYOWdoEG0SUPeJumjpOcF8gA2bqiQCywxKXYBrfAcZjz3LrP297Xc3fNrpN+LpfWcCAAAAGAKm+/8+2lEnEXESUQ8Xnj2TURcR8RVRHy443vIJ99dNeXLCvI0Ip4tHKrmIiLedb5Gvq/kG1PN91PlBadxuHCxm3Xa8bx8++QbU81XK8jZelmqembKNzZTvsaZtYKcrBikpmemfGMz5WucWSvI0r8QteiZKd/YTPkaZ9YKAoSCQEpBIKEgkFAQSCgIJBQEEgoCCQWBhIJAQkEgoSCQUBBIKAgkFAQSCgIJBYGEgkBCQSBRK8jNQVP0z5RvbKZ8jTNrBbleMUhNz0z5xmbK1zizVpCrFYPU9MyUb2ymfI0zH1Ue/hgRJSKerBZn30VEvO94Xr598o2p5nN5dZ18Yx5CPgAAAAAAAAB4YHzVpG44XynlPCJeRsTz2K41XtK7iHgbEW82m80/d3yPqc8vJshnT3qb7nyllFcR8ds6cfZHRcTrzWbze+frpj6/mCRfrSCnEfHLanFu91+0/6SZOt/uk+Pv+P4n9FJKRPza8Uky9fnFRPnsSV9n5ss4XDliN+tFx/Ozn980+exJX2fm89VSLDNz9vObJp896evMXPoX8hY/dzw7+/lNk8+tJpBQEEgoCCQUBBIKAgkFgYSCQEJBIKEgkFAQSCgIJBQEEgoCCQWBhIJAQkEgoSCQUBBIKAgk7ElfZ2bvHVBLuOx4dvbzmyafPenrzHy7WoplZs5+ftPksyd9nZlvYnuZ26GU3cxWs5/fNPlqBfkQ2+sYD+Ui+u5vnTrf7obD13GYkny+evTfjtdMfX4xUT6XV9ctdXn1i9he6tZzb1WLy9j+t+oPl1ffiT3pAAAAAAAAANDtqL9qYg+58xtwv/ek20O+x/mNuV970u0hv5XzG3Ov9qTbQz420/k1zjzWPen2kI/NdH6NM491T7o95GMznV/jTLeaQEJBIKEgkFAQSCgIJBQEEgoCCQWBhIJAQkEgoSCQUBBIKAgkFAQSCgIJBYGEgkBCQSChIJA41j3p9pCPzXR+jTOPdU+6PeRjM51f48xj3ZNuD/nYTOfXOPMo96TbQ/4N5zfmfu5Jt4fc+Q2wJx0AAAAAAAAAllVKOS+l/FVKuSzLu9y997l88h1dvlLKqxVC3eZT2e7slk++48hXts39dKCAn0M2N1k++Q6Vr/Z199n3aMu3T74x1Xy1gsy+R1u+sZnyNc68taWllEP+tdkXm82m6aeGfLeTb8xt+dxqAgkFgYSCQEJBIKEgkFAQSCgIJBQEEgoCCQWBhIJAQkEgoSCQUBBIKAgkFAQSCgIJBYGEgkCiVpDZ92jL9y35xtyar1aQ2fdoyzc2U77GmbWCzL5HW7598o3pzffl6sdD3G43cjWlfPL9kHyfQ56XUv4spVysEOxi996jlxvLJ98PyQcAAAAAAAAAD8/3VmKdRsRZRJxExOOFZ99ExHVEXEXEhzu+h3zy3VVTvqwgTyPi2cKhai6i/28A5PtKvjHVfLWvu5/G4cLFbtZpx/Py7ZNvTDVfrSBn62Wp6pkp39hM+Rpn1gpysmKQmp6Z8o3NlK9xZq0gS/9C1KJnpnxjM+VrnOlWE0goCCQUBBIKAgkFgYSCQEJBIKEgkFAQSCgIJBQEEgoCCQWBhIJAQkEgoSCQUBBIKAgkFAQStYLcHDRF/0z5xmbK1zizVpDrFYPU9MyUb2ymfI0zawW5WjFITc9M+cZmytc481Hl4Y+xXa7+ZLU4+y4i4n3H8/Ltk29MNZ/Lq+vkG/MQ8gEAAACH8j9qsKYdhQgxPgAAAABJRU5ErkJggg==" + }, + "lefttriangle": { + "icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAACXBIWXMAAAsTAAALEwEAmpwYAAAFGklEQVR4nO3dPY4UVxQG0NuWnCBysBfgDbCAkfcECSK1E7wbO7fsnA14ATOQIxIknoPuAY+m6rpq6lVzX3NOOtV9P1Xpmx+p590IAAAAoIRD9sXW2lVEvIiIZxHxtPPstxHxJiJeHw6Hvx74Ho8j4klEPIqI73sFO/kYER8i4l1EvH/ge8g3eL7ZgrTWXkbEL51DTY6KiFeHw+HXla97GhE/7pBnynUcC72GfF8Mm2+yIKefHH/OfX0HLSJ+XvGT5HFE/LRjnin/xPLvhPLdN2S+72YufhHnK0ecZj1fcf2TvYJ0minftpll8s0V5NmOQeasmflotxR9Zsq3bWaZfHMF6f0H+RI/rLi29x9svWfKt21mmXxzBQFCQSClIJBQEEgoCCQUBBIKAgkFgYSCQEJBIKEgkFAQSCgIJBQEEgoCCQWBhIJAQkEgoSCQmCvI2jOMerhZce3H3VL0mSnftpll8s0V5M2OQeasmflhtxR9Zsq3bWaZfHMFeR3Hw9zOpZ1mLvVuryCdZsq3bWaZfJMFOZ1w+CrOU5Lbo0f/XvGa93E8LvJcrmPd+bLy3TVsviWHVz+P46Fua86tWuImjr9W/ebw6geRb5se+QAAAAAAAADgGzP0nvTq+aL+RyXku9Q96dXzRZE93wn5vrisPenV80WhPd8z5LvvovakV89XZs93h2t7GTLfqHvSq+crs+e7w7W9DJlv1D3p1fOV2fPd4dpehsznVBNIKAgkFAQSCgIJBYGEgkBCQSChIJBQEEgoCCQUBBIKAgkFgYSCQEJBIKEgkFAQSCgIJBQEEqPuSa+er8ye7w7X9jJkvlH3pFfPV2bPd4drexky36h70qvnK7Pnu8O1vQyZb8g96dXzRaE93zPku+sy96RXzxcFDl/+H/LZkw4AAAAAAAAAKwy9Jz2KfxTB/Rv/oybD7kmPInu057h/d9iTvtFF7SF3/ybZk77Bpe0hd/+2zSyTb9Q96WX2aM9w/7bNLJNv1D3pZfZoz3D/ts0sk8+pJpBQEEgoCCQUBBIKAgkFgYSCQEJBIKEgkFAQSCgIJBQEEgoCCQWBhIJAQkEgoSCQUBBIKAgkRt2TXmaP9gz3b9vMMvlG3ZNeZo/2DPdv28wy+Ubdk15mj/YM92/bzDL5htyTHoX2aE9x/+6xJ/0BLn4Pufs3/uHVAAAAAAAAAMB/2ZM+7+I/KuH52pPey7B7vud4vnfYk97BkHu+p3i+k+xJ32jIPd8zPN+FM+1J32dm9Xye78KZ9qTvM7N6Ps934UynmkBCQSChIJBQEEgoCCQUBBIKAgkFgYSCQEJBIKEgkFAQSCgIJBQEEgoCCQWBhIJAQkEgoSCQsCd9n5nV83m+C2fak77PzOr5PN+FM+1J32dm9Xye78KZ9qQvM+ye7yme7z32pD/At3J4tedrTzoAAAAAAAAA9NBau2qt/dFau2n93Zze+0o++YbL11p7uUOoKZ/acWe3fPKNka8dm/vpTAFvQy5usnzynSvfqHvS5btLvm1m8426J12+bTPlWzhzsqWttXP+t9lnh8Nh0XcN+abJt81UPqeaQEJBIKEgkFAQSCgIJBQEEgoCCQWBhIJAQkEgoSCQUBBIKAgkFAQSCgIJBYGEgkBCQSChIJAYdU+6fPfJt81kvlH3pMu3baZ8C2eOuiddvrvk22Ztvs9HP57jdLstR1PKJ99XyXcb8qq19ntr7XqHYNen9956uLF88n2VfAAAAMAZ/QsAIPjNRI6mtwAAAABJRU5ErkJggg==" + }, + "chessboard": { + "icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAACXBIWXMAAAsTAAALEwEAmpwYAAAE7klEQVR4nO3dMY5TZxQF4OtIaRA9JAvIBlhAlD1BE9EmDdlTlPRsIAuA0CMaCqcYRyNj/2f85trW+z3f1zJwnw46A0jmnSoAAABgFTYP/PjzqnpRVc+q6vsz3/5aVV+q6lNVfX7ML7Ddbn+uqjdV9aqqXp7v0aqq6t+qel9V7zabzV+P/DXkN3l+qSAvq+rHMz/UyIe6C/Rk2+3216r67TKPs3+qqt5uNpvfF/48+e1O1cT5jQryvKp+utjjHPdPnfidcPed7896+E/Ac9lW1S8LvhPK75uTNWl+3w2++MVln6V9801d7ze3drdeL/h6+e2bNr9RQZ5d8EFGltx8dbGnOM9N+fVuria/UUHO/Q+iUyy5ee5/UJ7ihwVfK79DU+Y3KghQCgKRgkCgIBAoCAQKAoGCQKAgECgIBAoCgYJAoCAQKAgECgKBgkCgIBAoCAQKAoGCQDAqyNerPsXym4veAXUmHxd8rfwOTZnfqCBfLvggI0tuvr/YU5znpvx6N1eT36ggny74ICNLbr6ru5eRXct2d/NU8ts3bX6jgnyuu9cxXsuHWvB+2d0b+t7WdX6T/3915t8Lfo787k2d3y28vPp13b2UbMl7l07xse7+WvDHzC9fTuTXyw8AAAAAAAAAnp74URM72nbIG24iv2FB7GjvsUPeM21+RwtiR/soO+Q9U+Y3+ri7He3eTfn1bq4mv1FB7Gj3bsqvd3M1+Y0KYke7d1N+vZuryc9bTSBQEAgUBAIFgUBBIFAQCBQEAgWBQEEgUBAIFAQCBYFAQSBQEAgUBAIFgUBBIFAQCBQEglFB7Gj3bsqvd3M1+Y0KYke7d1N+vZuryW9UEDvavZvy691cTX5HC2JH+4Ad8p5p8zvl5dV2tO2QP8ZTyA8AAAAAAAAAnpiHhhJn+CiCHXL5PcZJ+aWC2NHenSo75B1T5zcqiB3tb06WHfKOafMb/X8QO9r77JD3TJvfqCB2tHs35de7uZr8RgWxo33IDnnPlPl5qwkECgKBgkCgIBAoCAQKAoGCQKAgECgIBAoCgYJAoCAQKAgECgKBgkCgIBAoCAQKAoGCQDAqiB3tQ3bIe6bMb1QQO9q9m/Lr3VxNfqOC2NHeZ4e8Z9r8RgWxo33PDnnP1Pndwsur17yjLb8bzg8AAAAAAAAAnp74URM72nbIG24iv2FB7GjvsUPeM21+RwtiR/soO+Q9U+Y3+ri7He3eTfn1bq4mv1FB7Gj3bsqvd3M1+Y0KYke7d1N+vZuryc9bTSBQEAgUBAIFgUBBIFAQCBQEAgWBQEEgUBAIFAQCBYFAQSBQEAgUBAIFgUBBIFAQCBQEglFB7Gj3bsqvd3M1+Y0KYke7d1N+vZuryW9UEDvavZvy691cTX5HC2JH+4Ad8p5p8zvl5dV2tO2QP8ZTyA8AAAAAAAAAnpiHhhJn+CiCHXL5PcZJ+aWC2NHenSo75B1T5zcqiB3tb06WHfKOafMb/X8QO9r77JD3TJvfqCB2tHs35de7uZr8RgWxo33IDnnPlPl5qwkECgKBgkCgIBAoCAQKAoGCQKAgECgIBAoCgYJAoCAQKAgECgKBgkCgIBAoCAQKAoGCQDAqiB3tQ3bIe6bMb1QQO9q9m/Lr3VxNfqOC2NHeZ4e8Z9r8RgWxo33PDnnP1Pndwsur17yjLb8bzg8AAAC4ov8AwGjpQ+5xFXQAAAAASUVORK5CYII=" + }, + "diamond": { + "icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAACXBIWXMAAAsTAAALEwEAmpwYAAAFF0lEQVR4nO3dMY4UZxAF4BpLThA52AfwBTiA5TtBYpHaCb6TZedcwAcAkyMSgnGwa9nDzv+2e/+ZVXXzfSm7VKlmHgvS0K8KAAAAaOFwz68/rapnVfWkqr698OzPVfWpqj5U1ccH/h6t9zsejz9W1auqelFVzy+3WlVV/V1Vb6vqzeFw+OOBv0fr+1WD/VJAnlfV9xdeauRd3bzga7Te73g8/lxVv1xnndNRVfX6cDj8uvL7Wt+vmuw3CsjTqvrhauuc91ct/5Om9X63Pzl+r/t/Ql/Ksap+WvGTpPX9qtF+3wy++Nl1d5me2X2/V/V44ajbWS9XfH33+7XZbxSQJ1dcZGTNzO77vbjaFpeZ2f1+bfYbBeTS/yBaYs3M7vtd+h/kS3y34mu736/NfqOAACUgEAkIBAICgYBAICAQCAgEAgKBgEAgIBAICAQCAoGAQCAgEAgIBAICgYBAICAQCAgEo4B8ftQt1s/svt/aZ0BdwvsVX9v9fm32GwXk0xUXGVkzs/t+b6+2xWVmdr9fm/1GAflwxUVG1szsvt+bunmY22M53s5cqvv92uw3CsjHunkc42N5V+ue39p6v9snHL6uxwnJv48e/XPF97S+XzXaz8Orxy718OqXdfNQtzXPrVrifd38teo3D69+kEvsBwAAAAAAAABfmU1/1EQPuftN2HdPuh7yE+43Z1896XrIz3K/ObvqSddDPjfT/RbO3GpPuh7yuZnut3DmVnvS9ZDPzXS/hTM91QQCAYFAQCAQEAgEBAIBgUBAIBAQCAQEAgGBQEAgEBAIBAQCAYFAQCAQEAgEBAIBgUBAINhqT7oe8rmZ7rdw5lZ70vWQz810v4Uzt9qTrod8bqb7LZy5yZ50PeR3uN+cffak6yF3vwl60gEAAAAAAABgtfhREz3a0x9FsN/Ge9yHAdGjfWJ1D3nZ7/822+N+NiB6tM9a3ENe9jtnkz3uo4+769Gem2m/uZlt3n+jgOjRnptpv7mZbd5/o4Do0Z6bab+5mW3ef55qAoGAQCAgEAgIBAICgYBAICAQCAgEAgKBgEAgIBAICAQCAoGAQCAgEAgIBAICgYBAICAQjAKiR3tupv3mZrZ5/40Cokd7bqb95ma2ef+NAqJHe26m/eZmtnn/nQ2IHu07VvWQl/2+tNke9yUPr9ajvdOHQ1fz/Tbw/gMAAAAAAACAr8x9RYlb+CiCHnf3e4hF90sB0aN9O6p22OPufieG9xsFRI/2FyNrRz3u7nfW2fuN/j+IHu1Te+txd7+FM0cB0aM9N9P95ma2ud8oIHq079pTj7v7LZzpqSYQCAgEAgKBgEAgIBAICAQCAoGAQCAgEAgIBAICgYBAICAQCAgEAgKBgEAgIBAICAQCAsEoIHq079pTj7v7LZw5Coge7bmZ7jc3s839RgHRo31qbz3u7rdw5iggerT/s7sed/e7Y3i/PTy8unOPtvvt+H4AAAAAAAAA8PXZ9EdNqvl+esi3//putie9mu+nh/zEZl/fTfakV/P99JCftcnXd6s96d3300M+N7PNflvtSe++nx7yuZlt9ttqT3r3/fSQz81ss5+nmkAgIBAICAQCAoGAQCAgEAgIBAICgYBAICAQCAgEAgKBgEAgIBAICAQCAoGAQCAgEAgIBFvtSe++nx7yuZlt9ttqT3r3/fSQz81ss99We9K776eHfG5mm/022ZNezffTQ37HZl9fD68e00M+Z/evLwAAAPCI/gFIfqYbRE+aDAAAAABJRU5ErkJggg==" + }, + "smalldiamond": { + "icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAACXBIWXMAAAsTAAALEwEAmpwYAAAE7ElEQVR4nO3dMY5TVxQG4OOgNGioSbKAbIAFROwJmog2acieoqRnA1nAAA0VooDCKewospj78+5cP+s+z/e1PM/5da1/zEjWPVUAAADAFHbf+PebqnpaVY+r6vszz/5SVZ+q6n1Vfbznz5BPvvtalC8V5Ieq+unMoVpuq+pd52vk+598Y5r5vmu84KYuF66Os246npfvlHxjmvlaBXm6Xpamnpnyjc2Ub+HMVkEerxikpWemfGMz5Vs4s1WQc/9BtETPTPnGZsq3cGarIEApCEQKAoGCQKAgECgIBAoCgYJAoCAQKAgECgKBgkCgIBAoCAQKAoGCQKAgECgIBAoCQasgXy6aon+mfGMz5Vs4s1WQTysGaemZKd/YTPkWzmwV5P2KQVp6Zso3NlO+hTMfNR7+XFX7qnqyWpxTt1X1oeN5+U7JN6aZz+XVbfKNeQj5AAAAAAAAAOCB8VWTtuF8+/3+l6p6WVXP6rDW+JzeVdWbqnq92+3+uufPmPr8aoJ89qQv051vv9//WlW/rRPndFRVvdrtdr93vm7q86tJ8rUKclNVP68W527/1PLfNFPnO35y/Fnf/oQ+l31VPe/4JJn6/GqifPakrzPzZV2uHHWc9aLj+dnPb5p89qSvM/PZainOM3P285smnz3p68w89x/kS/zY8ezs5zdNPreaQKAgECgIBAoCgYJAoCAQKAgECgKBgkCgIBAoCAQKAoGCQKAgECgIBAoCgYJAoCAQKAgE9qSvM7P3DqhzeNvx7OznN00+e9LXmflmtRTnmTn7+U2Tz570dWa+rsNlbpeyP85cavbzmyZfqyAf63Ad46XcVt/9rVPnO95w+KouU5L/rh79u+M1U59fTZTP5dVt57q8+kUdLnXrubdqibd1+G/VHy6vvhd70gEAAAAAAACg26a/amIPufMbcN170u0hP+H8xlzXnnR7yO/k/MZc1Z50e8jHZjq/hTO3uifdHvKxmc5v4cyt7km3h3xspvNbONOtJhAoCAQKAoGCQKAgECgIBAoCgYJAoCAQKAgECgKBgkCgIBAoCAQKAoGCQKAgECgIBAoCwVb3pNtDPjbT+S2cudU96faQj810fgtnbnVPuj3kYzOd38KZm9yTbg/5V5zfmOvck24PufMbYE86AAAAAAAAAHTb9FdNavJ89pBv//3d7J70mjyfPeQnNvv+bnJPek2ezx7yO23y/d3qnvTZ89lDPjZzmnxb3ZM+ez57yMdmTpNvq3vSZ89nD/nYzGnyudUEAgWBQEEgUBAIFAQCBYFAQSBQEAgUBAIFgUBBIFAQCBQEAgWBQEEgUBAIFAQCBYFAQSDY6p702fPZQz42c5p8W92TPns+e8jHZk6Tb6t70mfPZw/52Mxp8m1yT3pNns8e8q9s9v11eXWbPeRjrv79BQAAAAAAAICHx1dN2uQbcxX57ElfRr4xm83X+jbvTV0uXB1n3XQ8L98p+cY089mTvs5M+cZmTpPPnvR1Zso3NnOafPakrzNTvrGZ0+RzqwkECgKBgkCgIBAoCAQKAoGCQKAgECgIBAoCgYJAoCAQKAgECgKBgkCgIBAoCAQKAoGCQGBP+joz5RubOU0+e9LXmSnf2Mxp8tmTvs5M+cZmTpPvUePhz3XYv/1ktTinbqvqQ8fz8p2Sb0wzn8ur2+Qb8xDyAQAAAJfyL3WaU2vK5kXFAAAAAElFTkSuQmCC" + }, + "square": { + "icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAACXBIWXMAAAsTAAALEwEAmpwYAAAFJElEQVR4nO3dQW4UVxAG4OpI2SD2kBwgF8gBRrkTbCy2yYbcBvZRss8FcgAb9ogNkiuLGRtZ7i5187rHr4fv2wamfqT6baGYVxEAAABA/zLzkJnvM/Mm13dz+uyDfPLtLl9mXm0QasxtZl7JJ99u8uWxubdnCngXcnaT5ZPvXPl+mMj4OiKGuX+gFQwR8WrBr5fvIfnaTOabKsiv22WZtGSmfG0z5Zs5c7SlmZnbZhk3DMOsrxryjZOvzVi+qe8gQCgIlBQECgoCBQWBgoJAQUGgoCBQUBAoKAgUFAQKCgIFBYGCgkBBQaCgIFBQECgoCBQUBApTBflw1hRHNwt+rXyPyddmNN9UQf7dMMiUJTPla5sp38yZUwV5GxHnfFkiTzPnku8h+doszXf/9OM5XrdreZpSPvmeJN9dyENmvsvM6w2CXZ8+u/VxY/nke5J8AAAAAAAAAPD9KU9inf43/Os43m97ufLsD3H8Ccq3wzD8/Y2f8TwiXkTEs4j4ca1gJ18i4nNEfIyIT9/4GfI15Oth/yYLkscf4Pp95VCjoyLizTAMfyz8fS8j4ucN8oy5juX/RkG+rxbn62X/po54HiLir6n/voGMiN8WfCd5HhG/bJhnzH8x/yuhfI/NztfT/u31TvqLrYKsNFO+tpnd7N9e76Q/2yzFOjPla5vZzf5NFWTtvxDN8dOCX7v2XyjXnilf28xu9s+rJlBQECgoCBQUBAoKAgUFgYKCQEFBoKAgUFAQKCgIFBQECgoCBQWBgoJAQUGgoCBQUBAoKAgU9non/ctmKdaZKV/bzG72b6930j9vlmKdmfK1zexm//Z6J/3jVkFWmilf28xu9m+0IKcX5t7EeULePf34z4Lf8ymOz1mey3Use19WvocW5etp/+Y8Xv0qjo9qLXm3ao6bOH5b+9Pj1d/k4vPtYP8AAAAAAAAA4DvjTvq0i/9Rjug8Xw/75076PBd3hzw6z9fL/rmTPt/F3CGPzvP1tH/upG8zU762md3snzvp28yUr21mN/vnTvo2M+Vrm9nN/nnVBAoKAgUFgYKCQEFBoKAgUFAQKCgIFBQECgoCBQWBgoJAQUGgoCBQUBAoKAgUFAQKCgIFBYGCO+nbzJSvbWY3++dO+jYz5Wub2c3+uZO+zUz52mZ2s3/upM9zUXfIo/N8Pe2fO+nTLv5x6Og83w72DwAAAAAAAAC+M+6kT7v4H+WIzvP1sH/upM9zcXfIo/N8veyfO+nzXcwd8ug8X0/75076NjPla5vZzf65k77NTPnaZnazf+6kbzNTvraZ3eyfV02goCBQUBAoKAgUFAQKCgIFBYGCgkBBQaCgIFBQECgoCBQUBAoKAgUFgYKCQEFBoKAgUFAQKLiTvs1M+dpmdrN/7qRvM1O+tpnd7J876dvMlK9tZjf75076PBd1hzw6z9fT/rmTPu3iH4eOzvPtYP8AAAAAAAAAgK8y85CZ7zPzJtd3c/rsg3zy7S5fZl5tEGrMbR5vYssn3z7y5bG5t2cKeBdydpPlk+9c+fZ6J12+h+Rrc3F30uVrmynfzJmjLc3Mc/5rrnvDMMz6qiHfOPnajOXzqgkUFAQKCgIFBYGCgkBBQaCgIFBQECgoCBQUBAoKAgUFgYKCQEFBoKAgUFAQKCgIFBQECgoChb3eSZfvMfnaXNSddPnaZso3c+Ze76TL95B8bZbmu3/68Ryv27U8TSmffE+S7y7kITPfZeb1BsGuT5/d+rixfPI9ST4AAADgjP4Hm2pLjkVf1VMAAAAASUVORK5CYII=" + }, + "smallsquare": { + "icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAACXBIWXMAAAsTAAALEwEAmpwYAAAE6ElEQVR4nO3dP44URxQH4DdGTtAQY3wAX4ADWNwJEkRqEnwny865gA+wQEKECCAYghkbWrP1tmqqe9TV+33p9uz7qbd/+0earRcBAAAArMLujo/vI+JxRDyMiJ9nnv01Ij5HxIeI+HTh55BPvktV5csK8ktE/DpzqJKbiHjf+Br5vpOvTzHfT4UX7ON64eI0a99wvXxT8vUp5isV5PFyWYpaZsrXN1O+ypmlgjxcMEhJy0z5+mbKVzmzVJC5/yCq0TJTvr6Z8lXOLBUECAWBlIJAQkEgoSCQUBBIKAgkFAQSCgIJBYGEgkBCQSChIJBQEEgoCCQUBBIKAgkFgYSCQKJUkK9XTdE+U76+mfJVziwV5POCQUpaZsrXN1O+ypmlgnxYMEhJy0z5+mbKVznzQeHiLxFxiIhHi8WZuomIjw3XyzclX59iPodXl8nX5z7kAwAAAAAAAIB7Zui3mhwOh98j4kVEPI3j2uA5vY+ItxHxZrfb/X3JJ5CvL1+s4Pkbdk/64XB4GRF/LBNnOioiXu12u9dNL5Lv/1FxQb5YyfNXKsg+In5bLM7t/o3KnySn73x/xd0/AedyiIhntd8J5TsfGQ35YkXP36h70l/E9b64cZr1vOF6+aZa863m+Rt1T/rTxVLMM1O+vpmref5G3ZM+9x+UNZ40XCvfuZZ8q3n+nGoCCQWBhIJAQkEgoSCQUBBIKAgkFAQSCgIJBYGEgkBCQSChIJBQEEgoCCQUBBIKAgkFgYSCQGLUPelNZ2jN5F3DtfKda8m3mudv1D3pbxdLMc9M+fpmrub5G3VP+ps4HkZ2LYfTzFryTbXmW83zVyrIpzgex3gtN9FwPu/phL5XcZ0v8n9HZ/5T+wL5JprzxYqevy0cXv08joeStZy7VONdHH8t+LPzcGj5Bj68GgAAAAAAAAD40RbeamLPt/t3CXvSZzL0nu8S92/CnvROw+75vo37dyt70jsMu+e7wP2rnGlP+jIz3b++mau5f/ak1xtyz3eB+1c506kmkFAQSCgIJBQEEgoCCQWBhIJAQkEgoSCQUBBIKAgkFAQSCgIJBYGEgkBCQSChIJBQEEgoCCTsSa835J7vAvevcqY96cvMdP/6Zq7m/tmTXmfYPd8F7l/lTHvS7zb0nu/buH9n7Em/wOb3fLt/9qQDAAAAAAAAQJstvNVktXu+5bMnfS6b2/Mt3/dRYU/6LDaz51u+85FhT3q3Le35lm/KnvQZbGnPt3x9M1fz/NmTXq/l/yXkO2dPOmyNgkBCQSChIJBQEEgoCCQUBBIKAgkFgYSCQEJBIKEgkFAQSCgIJBQEEgoCCQWBhIJAQkEgYU96vZY93/Kdsye905b2fMvXN3M1z5896XVa93zLN2VPeqdN7fmWb8Ke9Attfs+3fPakAwAAAAAAAMC2DP1Wk5BPvstte096yPcj+foU85XezbuP64WL06x9w/XyTcnXp5hv1D3p8vXNlK9y5qh70uXrmylf5cxR96TL1zdTvsqZTjWBhIJAQkEgoSCQUBBIKAgkFAQSCgIJBYGEgkBCQSChIJBQEEgoCCQUBBIKAgkFgYSCQEJBIDHqnnT5+mbKVzlz1D3p8vXNlK9y5qh70uXrmylf5cwHhYu/xHG/9aPF4kzdRMTHhuvlm5KvTzGfw6vL5OtzH/IBAAAA1/IN7YSWk669SX0AAAAASUVORK5CYII=" + }, + "scissors": { + "icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAACXBIWXMAAAsTAAALEwEAmpwYAAAFUUlEQVR4nO3dMW6cRRgG4G+RaCL6AAfgAjkA4k5Jg9JCE+6EoM8FOEBC+ihNiqVYU0TZeT3rnd/6/vXztB57Ps3odWTFnrcKAAAAaOGQPng8Hn+uqldV9aKqvl+8979V9baq3hwOh78e8gW6z1dV31XV86p6VlXfrhrszueq+lRVH6rq4wO/Ruv5OtzvMCDH4/HXqvpt8VBnt6qq14fD4feLPqn5fHW60B83mOecd3W68Eu0nq/L/Z4NyF1y/xx9fAPHqvpl9jt19/nq9J35pw3nOeefmv9O3Xq+Tvf7zeATXtXjDVd3e728YH33+Z5vNciiPbvP1+Z+RwF5sd0sQ5fs2X2+Z5tNsWbP7vO1ud9RQFb/QDTjhwvWdp9v9Q+8q/fsPl+b+x0FBCgBgUhAIBAQCAQEAgGBQEAgEBAIBAQCAYFAQCAQEAgEBAIBgUBAIBAQCAQEAgGBQEAgGAXk0jeWVnh/wdru833ebIo1e3afr839jgLydsNBRi7Zs/t8nzabYs2e3edrc7+jgLyp02Naj+V4t+es7vN92GqQRXt2n6/N/Z4NyN0Lc6/rcYb8/+nHv2c/oft8dXpB8N1G85zzri57/7b1fJ3ud+bx6pd1elTrknehZryv0z9rf1z5eHXb+ar549DVfL4d3C8AAAAAAAAAPDF60sduvifd+d1/fnrSJ7aqG+xJd35fGJ6fnvQ5N9WT7vzOOnt+etLn3FpPuvOb3FNP+jZ76iG/bs8256cnfd4t9aQ7v8k9vWoCgYBAICAQCAgEAgKBgEAgIBAICAQCAoGAQCAgEAgIBAICgYBAICAQCAgEAgKBgEAgIBDoSZ93Sz3pzm9yTz3p2+yph/y6Pducn570ObfWk+78JvfUk36/m+tJd35fGZ6fnvSxm+9Jd35X98wDAAAAAAAAwBNzX5Fj9//qbz2fHvL9328KSIue6qD1fHrIv7Db+x0FpE1P9UDr+fSQn7XL+x39PUibnuoFa1fRQ36dXd7vKCBteqoXrF1FD/l1dnm/o4C06alesHYVPeTX2eX9etUEAgGBQEAgEBAIBAQCAYFAQCAQEAgEBAIBgUBAIBAQCAQEAgGBQEAgEBAIBAQCAYFAQCAYBaRNT/WCtavoIb/OLu93FJA2PdUL1q6ih/w6u7zfUUDa9FQvWLuKHvLr7PJ+RwFp01M90Ho+PeRf2e39erx6TA/5dW7+fgEAAAAAAADg6Ym/atK957v7fNX8VyWc3xU96d17vrvPV016vkec3xcu60nv3vPdfb5q1PN9jvM766Ke9O49393na9PzPeD8JvccBaR7z3f3+dr0fA84v8k9RwHp3vPdfb42Pd8Dzm9yT6+aQCAgEAgIBAICgYBAICAQCAgEAgKBgEAgIBAICAQCAoGAQCAgEAgIBAICgYBAICAQCAgEo4B07/nuPl+bnu8B5ze55ygg3Xu+u8/Xpud7wPlN7jkKSPee7+7zten5HnB+k3ueDUj3nu/u81Wjnu9znN9XHtaT3r3nu/t81eDx5cT56UkHAAAAAAAAgMvoSR+7iZ7ve7Ser8P96kmf2Kp23PMdtJ6vy/3qSZ+z257vgdbzdbpfPelzdtvzvWDtKrvscdeTvs2ebXq+F6xdZZc97nrS5+2y53vB2lV22ePuVRMIBAQCAYFAQCAQEAgEBAIBgUBAIBAQCAQEAgGBQEAgEBAIBAQCAYFAQCAQEAgEBAIBgUBP+rxd9nwvWLvKLnvc9aRvs2ebnu8Fa1fZZY+7nvQ5u+35XrB2lV32uOtJv9+ue74HWs/X6X71pI89hZ7v1vPt4H4BAACAx/IfV5v6DSxvZ+4AAAAASUVORK5CYII=" + } +} \ No newline at end of file diff --git a/libs/core/icons.ts b/libs/core/icons.ts index bc37a407..c250a23d 100644 --- a/libs/core/icons.ts +++ b/libs/core/icons.ts @@ -27,124 +27,124 @@ THE SOFTWARE. enum IconNames { //% block="heart" - //% blockImage=1 + //% jres=icons.heart Heart = 0, //% block="small heart" - //% blockImage=1 + //% jres=icons.smallheart SmallHeart, //% block="yes" - //% blockImage=1 + //% jres=icons.yes Yes, //% block="no" - //% blockImage=1 + //% jres=icons.no No, //% block="happy" - //% blockImage=1 + //% jres=icons.happy Happy, //% block="sad" - //% blockImage=1 + //% jres=icons.sad Sad, //% block="confused" - //% blockImage=1 + //% jres=icons.confused Confused, //% block="angry" - //% blockImage=1 + //% jres=icons.angry Angry, //% block="asleep" - //% blockImage=1 + //% jres=icons.asleep Asleep, //% block="surprised" - //% blockImage=1 + //% jres=icons.surprised Surprised, //% block="silly" - //% blockImage=1 + //% jres=icons.silly Silly, //% block="fabulous" - //% blockImage=1 + //% jres=icons.fabulous Fabulous, //% block="meh" - //% blockImage=1 + //% jres=icons.meh Meh, //% block="t-shirt" - //% blockImage=1 + //% jres=icons.tshirt TShirt, //% block="roller skate" - //% blockImage=1 + //% jres=icons.rollerskate Rollerskate, //% block="duck" - //% blockImage=1 + //% jres=icons.duck Duck, //% block="house" - //% blockImage=1 + //% jres=icons.house House, //% block="tortoise" - //% blockImage=1 + //% jres=icons.tortoise Tortoise, //% block="butterfly" - //% blockImage=1 + //% jres=icons.butterfly Butterfly, //% block="stick figure" - //% blockImage=1 + //% jres=icons.stickfigure StickFigure, //% block="ghost" - //% blockImage=1 + //% jres=icons.ghost Ghost, //% block="sword" - //% blockImage=1 + //% jres=icons.sword Sword, //% block="giraffe" - //% blockImage=1 + //% jres=icons.giraffe Giraffe, //% block="skull" - //% blockImage=1 + //% jres=icons.skull Skull, //% block="umbrella" - //% blockImage=1 + //% jres=icons.umbrella Umbrella, //% block="snake" - //% blockImage=1 + //% jres=icons.snake Snake, //% block="rabbit" - //% blockImage=1 + //% jres=icons.rabbit Rabbit, //% block="cow" - //% blockImage=1 + //% jres=icons.cow Cow, //% block="quarter note" - //% blockImage=1 + //% jres=icons.quarternote QuarterNote, //% block="eigth note" - //% blockImage=1 + //% jres=icons.eigthnote EigthNote, //% block="pitchfork" - //% blockImage=1 + //% jres=icons.pitchfork Pitchfork, //% block="target" - //% blockImage=1 + //% jres=icons.target Target, //% block="triangle" - //% blockImage=1 + //% jres=icons.triangle Triangle, //% block="left triangle" - //% blockImage=1 + //% jres=icons.lefttriangle LeftTriangle, //% block="chess board" - //% blockImage=1 + //% jres=icons.chessboard Chessboard, //% block="diamond" - //% blockImage=1 + //% jres=icons.diamond Diamond, //% block="small diamond" - //% blockImage=1 + //% jres=icons.smalldiamond SmallDiamond, //% block="square" - //% blockImage=1 + //% jres=icons.square Square, //% block="small square" - //% blockImage=1 + //% jres=icons.smallsquare SmallSquare, //% block="scissors" - //% blockImage=1 + //% jres=icons.scissors Scissors } @@ -171,7 +171,7 @@ namespace basic { /** * Draws the selected icon on the LED screen - * @param icon the predifined icon id + * @param icon the predefined icon id * @param interval the amount of time (milliseconds) to show the icon. Default is 600. */ //% weight=90 blockGap=8 @@ -179,16 +179,17 @@ namespace basic { //% block="show icon %i" icon="\uf00a" //% parts="ledmatrix" //% help=basic/show-icon - //% i.fieldEditor="gridpicker" - //% i.fieldOptions.width="400" i.fieldOptions.columns="5" - //% i.fieldOptions.itemColour="black" i.fieldOptions.tooltips="true" + //% icon.fieldEditor="imagedropdown" + //% icon.fieldOptions.columns="5" + //% icon.fieldOptions.width="380" + //% icon.fieldOptions.maxRows=4 export function showIcon(icon: IconNames, interval = 600) { let res = images.iconImage(icon) res.showImage(0, interval) } /** - * Shows an arrow on screent + * Draws an arrow on the LED screen * @param direction the direction of the arrow * @param interval the amount of time (milliseconds) to show the icon. Default is 600. */ @@ -213,49 +214,49 @@ namespace images { export function arrowImage(i: ArrowNames): Image { switch (i) { // compass directions - case ArrowNames.North: return images.createImage(` + case ArrowNames.North: return images.createImage(` . . # . . . # # # . # . # . # . . # . . . . # . .`); - case ArrowNames.NorthEast: return images.createImage(` + case ArrowNames.NorthEast: return images.createImage(` . . # # # . . . # # . . # . # . # . . . # . . . .`); - case ArrowNames.East: return images.createImage(` + case ArrowNames.East: return images.createImage(` . . # . . . . . # . # # # # # . . . # . . . # . .`); - case ArrowNames.SouthEast: return images.createImage(` + case ArrowNames.SouthEast: return images.createImage(` # . . . . . # . . . . . # . # . . . # # . . # # #`); - case ArrowNames.South: return images.createImage(` + case ArrowNames.South: return images.createImage(` . . # . . . . # . . # . # . # . # # # . . . # . .`); - case ArrowNames.SouthWest: return images.createImage(` + case ArrowNames.SouthWest: return images.createImage(` . . . . # . . . # . # . # . . # # . . . # # # . .`); - case ArrowNames.West: return images.createImage(` + case ArrowNames.West: return images.createImage(` . . # . . . # . . . # # # # # . # . . . . . # . .`); - case ArrowNames.NorthWest: return images.createImage(` + case ArrowNames.NorthWest: return images.createImage(` # # # . . # # . . . # . # . . @@ -274,9 +275,10 @@ namespace images { //% weight=50 blockGap=8 //% help=images/icon-image //% blockId=builtin_image block="icon image %i" - //% i.fieldEditor="gridpicker" - //% i.fieldOptions.width="400" i.fieldOptions.columns="5" - //% i.fieldOptions.itemColour="black" i.fieldOptions.tooltips="true" + //% i.fieldEditor="imagedropdown" + //% i.fieldOptions.columns="5" + //% i.fieldOptions.width="380" + //% i.fieldOptions.maxRows=4 export function iconImage(i: IconNames): Image { switch (i) { case IconNames.Heart: return images.createImage(` diff --git a/libs/core/images.cpp b/libs/core/images.cpp index 32ab137a..941b9b05 100644 --- a/libs/core/images.cpp +++ b/libs/core/images.cpp @@ -1,156 +1,183 @@ #include "pxt.h" +PXT_VTABLE(RefMImage, ValType::Object) + +RefMImage::RefMImage(ImageData *d) : PXT_VTABLE_INIT(RefMImage), img(d) { + img->incr(); +} + +void RefMImage::destroy(RefMImage *t) { + t->img->decr(); +} + +void RefMImage::print(RefMImage *t) { + DMESG("RefMImage %p r=%d size=%d x %d", t, t->refcnt, img->width, img->height); +} + +void RefMImage::makeWritable() { + if (img->isReadOnly()) { + MicroBitImage i(img); + img = i.clone().leakData(); + } +} + +void RefMImage::scan(RefMImage *t) {} + +unsigned RefMImage::gcsize(RefMImage *t) { + return (sizeof(*t) + 3) >> 2; +} + /** -* Creation, manipulation and display of LED images. -*/ -//% color=#5C2D91 weight=31 icon="\uf03e" + * Creation, manipulation and display of LED images. + */ +//% color=#7600A8 weight=31 icon="\uf03e" //% advanced=true namespace images { - /** - * Creates an image that fits on the LED screen. - */ - //% weight=75 help=images/create-image - //% blockId=device_build_image block="create image" - //% parts="ledmatrix" - Image createImage(ImageLiteral leds) { - return MicroBitImage(imageBytes(leds)).clone().leakData(); - } - - /** - * Creates an image with 2 frames. - */ - //% weight=74 help=images/create-big-image - //% blockId=device_build_big_image block="create big image" imageLiteral=2 - //% parts="ledmatrix" - Image createBigImage(ImageLiteral leds) { - return createImage(leds); - } +/** + * Creates an image that fits on the LED screen. + */ +//% weight=75 help=images/create-image +//% blockId=device_build_image block="create image" +//% parts="ledmatrix" +Image createImage(ImageLiteral_ leds) { + return NEW_GC(RefMImage, imageBytes(leds)); } +/** + * Creates an image with 2 frames. + */ +//% weight=74 help=images/create-big-image +//% blockId=device_build_big_image block="create big image" imageLiteral=2 +//% parts="ledmatrix" +Image createBigImage(ImageLiteral_ leds) { + return createImage(leds); +} +} // namespace images + namespace ImageMethods { - /** - * Plots the image at a given column to the screen - */ - //% help=images/plot-image - //% parts="ledmatrix" - void plotImage(Image i, int xOffset = 0) { - uBit.display.print(MicroBitImage(i), -xOffset, 0, 0, 0); - } - - /** - * Shows an frame from the image at offset ``x offset``. - * @param xOffset column index to start displaying the image - */ - //% help=images/show-image weight=80 blockNamespace=images - //% blockId=device_show_image_offset block="show image %sprite|at offset %offset" blockGap=8 - //% parts="ledmatrix" async - void showImage(Image sprite, int xOffset, int interval = 400) { - uBit.display.print(MicroBitImage(sprite), -xOffset, 0, 0, interval); - } - - /** - * Draws the ``index``-th frame of the image on the screen. - * @param xOffset column index to start displaying the image - */ - //% help=images/plot-frame weight=80 - //% parts="ledmatrix" - void plotFrame(Image i, int xOffset) { - // TODO showImage() used in original implementation - plotImage(i, xOffset * 5); - } - - /** - * Scrolls an image . - * @param frameOffset x offset moved on each animation step, eg: 1, 2, 5 - * @param interval time between each animation step in milli seconds, eg: 200 - */ - //% help=images/scroll-image weight=79 async blockNamespace=images - //% blockId=device_scroll_image block="scroll image %sprite|with offset %frameoffset|and interval (ms) %delay" blockGap=8 - //% parts="ledmatrix" - void scrollImage(Image id, int frameOffset, int interval) { - MicroBitImage i(id); - uBit.display.animate(i, interval, frameOffset, MICROBIT_DISPLAY_ANIMATE_DEFAULT_POS, 0); - } - - - /** - * Sets all pixels off. - */ - //% help=images/clear - //% parts="ledmatrix" - void clear(Image i) { - MicroBitImage(i).clear(); - } - - /** - * Sets a specific pixel brightness at a given position - */ - //% - //% parts="ledmatrix" - void setPixelBrightness(Image i, int x, int y, int value) { - MicroBitImage(i).setPixelValue(x, y, value); - } - - - /** - * Gets the pixel brightness ([0..255]) at a given position - */ - //% - //% parts="ledmatrix" - int pixelBrightness(Image i, int x, int y) { - int pix = MicroBitImage(i).getPixelValue(x, y); - if (pix < 0) return 0; - return pix; - } - - - /** - * Gets the width in columns - */ - //% help=functions/width - int width(Image i) { - return i->width; - } - - /** - * Gets the height in rows (always 5) - */ - //% - int height(Image i) { - return i->height; - } - - /** - * Set a pixel state at position ``(x,y)`` - * @param x TODO - * @param y TODO - * @param value TODO - */ - //% help=images/set-pixel - //% parts="ledmatrix" - void setPixel(Image i, int x, int y, bool value) { - setPixelBrightness(i, x, y, value ? 255 : 0); - } - - /** - * Get the pixel state at position ``(x,y)`` - * @param x TODO - * @param y TODO - */ - //% help=images/pixel - //% parts="ledmatrix" - bool pixel(Image i, int x, int y) { - return pixelBrightness(i, x, y) > 0; - } - - - /** - * Shows a particular frame of the image strip. - * @param frame TODO - */ - //% weight=70 help=images/show-frame - //% parts="ledmatrix" - void showFrame(Image i, int frame, int interval = 400) { - showImage(i, frame * 5, interval); - } +/** + * Plots the image at a given column to the screen + */ +//% help=images/plot-image +//% parts="ledmatrix" +void plotImage(Image i, int xOffset = 0) { + uBit.display.print(MicroBitImage(i->img), -xOffset, 0, 0, 0); } + +/** + * Shows an frame from the image at offset ``x offset``. + * @param xOffset column index to start displaying the image + */ +//% help=images/show-image weight=80 blockNamespace=images +//% blockId=device_show_image_offset block="show image %sprite(myImage)|at offset %offset" +//% blockGap=8 parts="ledmatrix" async +void showImage(Image sprite, int xOffset, int interval = 400) { + uBit.display.print(MicroBitImage(sprite->img), -xOffset, 0, 0, interval); +} + +/** + * Draws the ``index``-th frame of the image on the screen. + * @param xOffset column index to start displaying the image + */ +//% help=images/plot-frame weight=80 +//% parts="ledmatrix" +void plotFrame(Image i, int xOffset) { + // TODO showImage() used in original implementation + plotImage(i, xOffset * 5); +} + +/** + * Scrolls an image . + * @param frameOffset x offset moved on each animation step, eg: 1, 2, 5 + * @param interval time between each animation step in milli seconds, eg: 200 + */ +//% help=images/scroll-image weight=79 async blockNamespace=images +//% blockId=device_scroll_image +//% block="scroll image %sprite(myImage)|with offset %frameoffset|and interval (ms) %delay" +//% blockGap=8 parts="ledmatrix" +void scrollImage(Image id, int frameOffset, int interval) { + MicroBitImage i(id->img); + uBit.display.animate(i, interval, frameOffset, MICROBIT_DISPLAY_ANIMATE_DEFAULT_POS, 0); +} + +/** + * Sets all pixels off. + */ +//% help=images/clear +//% parts="ledmatrix" +void clear(Image i) { + i->makeWritable(); + MicroBitImage(i->img).clear(); +} + +/** + * Sets a specific pixel brightness at a given position + */ +//% +//% parts="ledmatrix" +void setPixelBrightness(Image i, int x, int y, int value) { + i->makeWritable(); + MicroBitImage(i->img).setPixelValue(x, y, value); +} + +/** + * Gets the pixel brightness ([0..255]) at a given position + */ +//% +//% parts="ledmatrix" +int pixelBrightness(Image i, int x, int y) { + int pix = MicroBitImage(i->img).getPixelValue(x, y); + if (pix < 0) + return 0; + return pix; +} + +/** + * Gets the width in columns + */ +//% help=functions/width +int width(Image i) { + return i->img->width; +} + +/** + * Gets the height in rows (always 5) + */ +//% +int height(Image i) { + return i->img->height; +} + +/** + * Set a pixel state at position ``(x,y)`` + * @param x pixel column + * @param y pixel row + * @param value pixel state + */ +//% help=images/set-pixel +//% parts="ledmatrix" +void setPixel(Image i, int x, int y, bool value) { + setPixelBrightness(i, x, y, value ? 255 : 0); +} + +/** + * Get the pixel state at position ``(x,y)`` + * @param x pixel column + * @param y pixel row + */ +//% help=images/pixel +//% parts="ledmatrix" +bool pixel(Image i, int x, int y) { + return pixelBrightness(i, x, y) > 0; +} + +/** + * Show a particular frame of the image strip. + * @param frame image frame to show + */ +//% weight=70 help=images/show-frame +//% parts="ledmatrix" +void showFrame(Image i, int frame, int interval = 400) { + showImage(i, frame * 5, interval); +} +} // namespace ImageMethods \ No newline at end of file diff --git a/libs/core/input.cpp b/libs/core/input.cpp index da226fdb..03dc9592 100644 --- a/libs/core/input.cpp +++ b/libs/core/input.cpp @@ -60,56 +60,67 @@ enum class Gesture { * Raised when shaken */ //% block=shake + //% jres=gestures.shake Shake = MICROBIT_ACCELEROMETER_EVT_SHAKE, /** * Raised when the logo is upward and the screen is vertical */ //% block="logo up" + //% jres=gestures.tiltforward LogoUp = MICROBIT_ACCELEROMETER_EVT_TILT_UP, /** * Raised when the logo is downward and the screen is vertical */ //% block="logo down" + //% jres=gestures.tiltbackwards LogoDown = MICROBIT_ACCELEROMETER_EVT_TILT_DOWN, /** * Raised when the screen is pointing down and the board is horizontal */ //% block="screen up" + //% jres=gestures.frontsideup ScreenUp = MICROBIT_ACCELEROMETER_EVT_FACE_UP, /** * Raised when the screen is pointing up and the board is horizontal */ //% block="screen down" + //% jres=gestures.backsideup ScreenDown = MICROBIT_ACCELEROMETER_EVT_FACE_DOWN, /** * Raised when the screen is pointing left */ //% block="tilt left" + //% jres=gestures.tiltleft TiltLeft = MICROBIT_ACCELEROMETER_EVT_TILT_LEFT, /** * Raised when the screen is pointing right */ //% block="tilt right" + //% jres=gestures.tiltright TiltRight = MICROBIT_ACCELEROMETER_EVT_TILT_RIGHT, /** * Raised when the board is falling! */ //% block="free fall" + //% jres=gestures.freefall FreeFall = MICROBIT_ACCELEROMETER_EVT_FREEFALL, /** * Raised when a 3G shock is detected */ //% block="3g" + //% jres=gestures.impact3g ThreeG = MICROBIT_ACCELEROMETER_EVT_3G, /** * Raised when a 6G shock is detected */ //% block="6g" + //% jres=gestures.impact6g SixG = MICROBIT_ACCELEROMETER_EVT_6G, /** * Raised when a 8G shock is detected */ //% block="8g" + //% jres=gestures.impact8g EightG = MICROBIT_ACCELEROMETER_EVT_8G }; @@ -155,7 +166,7 @@ namespace input { * @param button the button that needs to be pressed * @param body code to run when event is raised */ - //% help=input/on-button-pressed weight=85 blockGap=8 + //% help=input/on-button-pressed weight=85 blockGap=16 //% blockId=device_button_event block="on button|%NAME|pressed" //% parts="buttonpair" void onButtonPressed(Button button, Action body) { @@ -167,10 +178,10 @@ namespace input { * @param gesture the type of gesture to track, eg: Gesture.Shake * @param body code to run when gesture is raised */ - //% help=input/on-gesture weight=84 blockGap=8 + //% help=input/on-gesture weight=84 blockGap=16 //% blockId=device_gesture_event block="on |%NAME" //% parts="accelerometer" - //% NAME.fieldEditor="gridpicker" NAME.fieldOptions.columns=4 + //% NAME.fieldEditor="gestures" NAME.fieldOptions.columns=4 void onGesture(Gesture gesture, Action body) { int gi = (int)gesture; if (gi == MICROBIT_ACCELEROMETER_EVT_3G && uBit.accelerometer.getRange() < 3) @@ -180,12 +191,27 @@ namespace input { registerWithDal(MICROBIT_ID_GESTURE, gi, body); } + /** + * Tests if a gesture is currently detected. + * @param gesture the type of gesture to detect, eg: Gesture.Shake + */ + //% help=input/is-gesture weight=10 blockGap=8 + //% blockId=deviceisgesture block="is %gesture gesture" + //% parts="accelerometer" + //% gesture.fieldEditor="gestures" gesture.fieldOptions.columns=4 + bool isGesture(Gesture gesture) { + // turn on acceleration + uBit.accelerometer.getX(); + int gi = (int)gesture; + return uBit.accelerometer.getGesture() == gi; + } + /** * Do something when a pin is touched and released again (while also touching the GND pin). * @param name the pin that needs to be pressed, eg: TouchPin.P0 * @param body the code to run when the pin is pressed */ - //% help=input/on-pin-pressed weight=83 + //% help=input/on-pin-pressed weight=83 blockGap=32 //% blockId=device_pin_event block="on pin %name|pressed" void onPinPressed(TouchPin name, Action body) { auto pin = getPin((int)name); @@ -201,7 +227,7 @@ namespace input { * @param name the pin that needs to be released, eg: TouchPin.P0 * @param body the code to run when the pin is released */ - //% help=input/on-pin-released weight=6 blockGap=8 + //% help=input/on-pin-released weight=6 blockGap=16 //% blockId=device_pin_released block="on pin %NAME|released" //% advanced=true void onPinReleased(TouchPin name, Action body) { @@ -220,7 +246,7 @@ namespace input { //% help=input/button-is-pressed weight=60 //% block="button|%NAME|is pressed" //% blockId=device_get_button2 - //% blockGap=8 + //% icon="\uf192" blockGap=8 //% parts="buttonpair" bool buttonIsPressed(Button button) { if (button == Button::A) @@ -253,7 +279,7 @@ namespace input { /** * Get the acceleration value in milli-gravitys (when the board is laying flat with the screen up, x=0, y=0 and z=-1024) - * @param dimension TODO + * @param dimension x, y, or z dimension, eg: Dimension.X */ //% help=input/acceleration weight=58 //% blockId=device_acceleration block="acceleration (mg)|%NAME" blockGap=8 @@ -303,7 +329,7 @@ namespace input { /** * The pitch or roll of the device, rotation along the ``x-axis`` or ``y-axis``, in degrees. - * @param kind TODO + * @param kind pitch or roll */ //% help=input/rotation weight=52 //% blockId=device_get_rotation block="rotation (°)|%NAME" blockGap=8 @@ -318,7 +344,7 @@ namespace input { /** * Get the magnetic force value in ``micro-Teslas`` (``µT``). This function is not supported in the simulator. - * @param dimension TODO + * @param dimension the x, y, or z dimension, eg: Dimension.X */ //% help=input/magnetic-force weight=51 //% blockId=device_get_magnetic_force block="magnetic force (µT)|%NAME" blockGap=8 @@ -362,8 +388,9 @@ namespace input { */ //% help=input/calibrate-compass advanced=true //% blockId="input_compass_calibrate" block="calibrate compass" - void calibrateCompass() { - uBit.compass.calibrate(); + //% weight=45 + void calibrateCompass() { + uBit.compass.calibrate(); } /** diff --git a/libs/core/input.ts b/libs/core/input.ts index 8cb992c4..59377fa3 100644 --- a/libs/core/input.ts +++ b/libs/core/input.ts @@ -8,7 +8,7 @@ namespace input { * @param body TODO */ //% help=input/on-screen-up - export function onScreenUp(body: Action): void { + export function onScreenUp(body: () => void): void { onGesture(Gesture.ScreenUp, body); } @@ -17,7 +17,7 @@ namespace input { * @param body TODO */ //% help=input/on-screen-down - export function onScreenDown(body: Action): void { + export function onScreenDown(body: () => void): void { onGesture(Gesture.ScreenDown, body); } @@ -26,7 +26,7 @@ namespace input { * @param body TODO */ //% help=input/on-shake - export function onShake(body: Action): void { + export function onShake(body: () => void): void { onGesture(Gesture.Shake, body); } @@ -35,7 +35,7 @@ namespace input { * @param body TODO */ //% help=input/on-logo-up - export function onLogoUp(body: Action): void { + export function onLogoUp(body: () => void): void { onGesture(Gesture.LogoUp, body); } @@ -44,7 +44,15 @@ namespace input { * @param body TODO */ //% help=input/on-logo-down - export function onLogoDown(body: Action): void { + export function onLogoDown(body: () => void): void { onGesture(Gesture.LogoDown, body); } + + /** + * Obsolete, use input.calibrateCompass instead. + */ + //% weight=0 help=input/calibrate-compass + export function calibrate() { + input.calibrateCompass(); + } } diff --git a/libs/core/jres/gestures/backsideup-icon.png b/libs/core/jres/gestures/backsideup-icon.png new file mode 100644 index 00000000..225d5cb3 Binary files /dev/null and b/libs/core/jres/gestures/backsideup-icon.png differ diff --git a/libs/core/jres/gestures/freefall-icon.png b/libs/core/jres/gestures/freefall-icon.png new file mode 100644 index 00000000..5b2bb2ed Binary files /dev/null and b/libs/core/jres/gestures/freefall-icon.png differ diff --git a/libs/core/jres/gestures/frontsideup-icon.png b/libs/core/jres/gestures/frontsideup-icon.png new file mode 100644 index 00000000..074e7d3d Binary files /dev/null and b/libs/core/jres/gestures/frontsideup-icon.png differ diff --git a/libs/core/jres/gestures/impact3g-icon.png b/libs/core/jres/gestures/impact3g-icon.png new file mode 100644 index 00000000..759d23ed Binary files /dev/null and b/libs/core/jres/gestures/impact3g-icon.png differ diff --git a/libs/core/jres/gestures/impact6g-icon.png b/libs/core/jres/gestures/impact6g-icon.png new file mode 100644 index 00000000..ca128d96 Binary files /dev/null and b/libs/core/jres/gestures/impact6g-icon.png differ diff --git a/libs/core/jres/gestures/impact8g-icon.png b/libs/core/jres/gestures/impact8g-icon.png new file mode 100644 index 00000000..7c70a7cd Binary files /dev/null and b/libs/core/jres/gestures/impact8g-icon.png differ diff --git a/libs/core/jres/gestures/shake-icon.png b/libs/core/jres/gestures/shake-icon.png new file mode 100644 index 00000000..59e1dc43 Binary files /dev/null and b/libs/core/jres/gestures/shake-icon.png differ diff --git a/libs/core/jres/gestures/tiltforward-icon.png b/libs/core/jres/gestures/tiltforward-icon.png new file mode 100644 index 00000000..41d49270 Binary files /dev/null and b/libs/core/jres/gestures/tiltforward-icon.png differ diff --git a/libs/core/jres/gestures/tiltleft-icon.png b/libs/core/jres/gestures/tiltleft-icon.png new file mode 100644 index 00000000..d119a15f Binary files /dev/null and b/libs/core/jres/gestures/tiltleft-icon.png differ diff --git a/libs/core/jres/gestures/tiltright-icon.png b/libs/core/jres/gestures/tiltright-icon.png new file mode 100644 index 00000000..9f8308f8 Binary files /dev/null and b/libs/core/jres/gestures/tiltright-icon.png differ diff --git a/libs/core/jres/icons/angry-icon.png b/libs/core/jres/icons/angry-icon.png new file mode 100644 index 00000000..4c55747e Binary files /dev/null and b/libs/core/jres/icons/angry-icon.png differ diff --git a/libs/core/jres/icons/asleep-icon.png b/libs/core/jres/icons/asleep-icon.png new file mode 100644 index 00000000..7b4d65c8 Binary files /dev/null and b/libs/core/jres/icons/asleep-icon.png differ diff --git a/libs/core/jres/icons/butterfly-icon.png b/libs/core/jres/icons/butterfly-icon.png new file mode 100644 index 00000000..fcd60187 Binary files /dev/null and b/libs/core/jres/icons/butterfly-icon.png differ diff --git a/libs/core/jres/icons/chessboard-icon.png b/libs/core/jres/icons/chessboard-icon.png new file mode 100644 index 00000000..dd7a597e Binary files /dev/null and b/libs/core/jres/icons/chessboard-icon.png differ diff --git a/libs/core/jres/icons/confused-icon.png b/libs/core/jres/icons/confused-icon.png new file mode 100644 index 00000000..873453f9 Binary files /dev/null and b/libs/core/jres/icons/confused-icon.png differ diff --git a/libs/core/jres/icons/cow-icon.png b/libs/core/jres/icons/cow-icon.png new file mode 100644 index 00000000..bd558775 Binary files /dev/null and b/libs/core/jres/icons/cow-icon.png differ diff --git a/libs/core/jres/icons/diamond-icon.png b/libs/core/jres/icons/diamond-icon.png new file mode 100644 index 00000000..e75b01a1 Binary files /dev/null and b/libs/core/jres/icons/diamond-icon.png differ diff --git a/libs/core/jres/icons/duck-icon.png b/libs/core/jres/icons/duck-icon.png new file mode 100644 index 00000000..5504f1ab Binary files /dev/null and b/libs/core/jres/icons/duck-icon.png differ diff --git a/libs/core/jres/icons/eigthnote-icon.png b/libs/core/jres/icons/eigthnote-icon.png new file mode 100644 index 00000000..559c73aa Binary files /dev/null and b/libs/core/jres/icons/eigthnote-icon.png differ diff --git a/libs/core/jres/icons/fabulous-icon.png b/libs/core/jres/icons/fabulous-icon.png new file mode 100644 index 00000000..280beaf7 Binary files /dev/null and b/libs/core/jres/icons/fabulous-icon.png differ diff --git a/libs/core/jres/icons/ghost-icon.png b/libs/core/jres/icons/ghost-icon.png new file mode 100644 index 00000000..565e9bfb Binary files /dev/null and b/libs/core/jres/icons/ghost-icon.png differ diff --git a/libs/core/jres/icons/giraffe-icon.png b/libs/core/jres/icons/giraffe-icon.png new file mode 100644 index 00000000..7d3e041d Binary files /dev/null and b/libs/core/jres/icons/giraffe-icon.png differ diff --git a/libs/core/jres/icons/happy-icon.png b/libs/core/jres/icons/happy-icon.png new file mode 100644 index 00000000..90c3dfba Binary files /dev/null and b/libs/core/jres/icons/happy-icon.png differ diff --git a/libs/core/jres/icons/heart-icon.png b/libs/core/jres/icons/heart-icon.png new file mode 100644 index 00000000..dd2c61e8 Binary files /dev/null and b/libs/core/jres/icons/heart-icon.png differ diff --git a/libs/core/jres/icons/house-icon.png b/libs/core/jres/icons/house-icon.png new file mode 100644 index 00000000..22fb9f1a Binary files /dev/null and b/libs/core/jres/icons/house-icon.png differ diff --git a/libs/core/jres/icons/lefttriangle-icon.png b/libs/core/jres/icons/lefttriangle-icon.png new file mode 100644 index 00000000..b349b683 Binary files /dev/null and b/libs/core/jres/icons/lefttriangle-icon.png differ diff --git a/libs/core/jres/icons/meh-icon.png b/libs/core/jres/icons/meh-icon.png new file mode 100644 index 00000000..72a66b70 Binary files /dev/null and b/libs/core/jres/icons/meh-icon.png differ diff --git a/libs/core/jres/icons/no-icon.png b/libs/core/jres/icons/no-icon.png new file mode 100644 index 00000000..01a1d549 Binary files /dev/null and b/libs/core/jres/icons/no-icon.png differ diff --git a/libs/core/jres/icons/pitchfork-icon.png b/libs/core/jres/icons/pitchfork-icon.png new file mode 100644 index 00000000..2a22985d Binary files /dev/null and b/libs/core/jres/icons/pitchfork-icon.png differ diff --git a/libs/core/jres/icons/quarternote-icon.png b/libs/core/jres/icons/quarternote-icon.png new file mode 100644 index 00000000..dbe27f24 Binary files /dev/null and b/libs/core/jres/icons/quarternote-icon.png differ diff --git a/libs/core/jres/icons/rabbit-icon.png b/libs/core/jres/icons/rabbit-icon.png new file mode 100644 index 00000000..a4da265d Binary files /dev/null and b/libs/core/jres/icons/rabbit-icon.png differ diff --git a/libs/core/jres/icons/rollerskate-icon.png b/libs/core/jres/icons/rollerskate-icon.png new file mode 100644 index 00000000..9d1b72f7 Binary files /dev/null and b/libs/core/jres/icons/rollerskate-icon.png differ diff --git a/libs/core/jres/icons/sad-icon.png b/libs/core/jres/icons/sad-icon.png new file mode 100644 index 00000000..07e4f9f5 Binary files /dev/null and b/libs/core/jres/icons/sad-icon.png differ diff --git a/libs/core/jres/icons/scissors-icon.png b/libs/core/jres/icons/scissors-icon.png new file mode 100644 index 00000000..1472667b Binary files /dev/null and b/libs/core/jres/icons/scissors-icon.png differ diff --git a/libs/core/jres/icons/silly-icon.png b/libs/core/jres/icons/silly-icon.png new file mode 100644 index 00000000..42b5d987 Binary files /dev/null and b/libs/core/jres/icons/silly-icon.png differ diff --git a/libs/core/jres/icons/skull-icon.png b/libs/core/jres/icons/skull-icon.png new file mode 100644 index 00000000..990911d2 Binary files /dev/null and b/libs/core/jres/icons/skull-icon.png differ diff --git a/libs/core/jres/icons/smalldiamond-icon.png b/libs/core/jres/icons/smalldiamond-icon.png new file mode 100644 index 00000000..0313b3a3 Binary files /dev/null and b/libs/core/jres/icons/smalldiamond-icon.png differ diff --git a/libs/core/jres/icons/smallheart-icon.png b/libs/core/jres/icons/smallheart-icon.png new file mode 100644 index 00000000..73566f22 Binary files /dev/null and b/libs/core/jres/icons/smallheart-icon.png differ diff --git a/libs/core/jres/icons/smallsquare-icon.png b/libs/core/jres/icons/smallsquare-icon.png new file mode 100644 index 00000000..592bd304 Binary files /dev/null and b/libs/core/jres/icons/smallsquare-icon.png differ diff --git a/libs/core/jres/icons/snake-icon.png b/libs/core/jres/icons/snake-icon.png new file mode 100644 index 00000000..4fe28a02 Binary files /dev/null and b/libs/core/jres/icons/snake-icon.png differ diff --git a/libs/core/jres/icons/square-icon.png b/libs/core/jres/icons/square-icon.png new file mode 100644 index 00000000..c14b8557 Binary files /dev/null and b/libs/core/jres/icons/square-icon.png differ diff --git a/libs/core/jres/icons/stickfigure-icon.png b/libs/core/jres/icons/stickfigure-icon.png new file mode 100644 index 00000000..bec156af Binary files /dev/null and b/libs/core/jres/icons/stickfigure-icon.png differ diff --git a/libs/core/jres/icons/surprised-icon.png b/libs/core/jres/icons/surprised-icon.png new file mode 100644 index 00000000..c21d3626 Binary files /dev/null and b/libs/core/jres/icons/surprised-icon.png differ diff --git a/libs/core/jres/icons/sword-icon.png b/libs/core/jres/icons/sword-icon.png new file mode 100644 index 00000000..140341c4 Binary files /dev/null and b/libs/core/jres/icons/sword-icon.png differ diff --git a/libs/core/jres/icons/target-icon.png b/libs/core/jres/icons/target-icon.png new file mode 100644 index 00000000..a36a0307 Binary files /dev/null and b/libs/core/jres/icons/target-icon.png differ diff --git a/libs/core/jres/icons/tortoise-icon.png b/libs/core/jres/icons/tortoise-icon.png new file mode 100644 index 00000000..026b8315 Binary files /dev/null and b/libs/core/jres/icons/tortoise-icon.png differ diff --git a/libs/core/jres/icons/triangle-icon.png b/libs/core/jres/icons/triangle-icon.png new file mode 100644 index 00000000..e32cc6af Binary files /dev/null and b/libs/core/jres/icons/triangle-icon.png differ diff --git a/libs/core/jres/icons/tshirt-icon.png b/libs/core/jres/icons/tshirt-icon.png new file mode 100644 index 00000000..55d1bee7 Binary files /dev/null and b/libs/core/jres/icons/tshirt-icon.png differ diff --git a/libs/core/jres/icons/umbrella-icon.png b/libs/core/jres/icons/umbrella-icon.png new file mode 100644 index 00000000..e911179f Binary files /dev/null and b/libs/core/jres/icons/umbrella-icon.png differ diff --git a/libs/core/jres/icons/yes-icon.png b/libs/core/jres/icons/yes-icon.png new file mode 100644 index 00000000..e0fd2749 Binary files /dev/null and b/libs/core/jres/icons/yes-icon.png differ diff --git a/libs/core/led.cpp b/libs/core/led.cpp index 24d03878..ccb0d2ac 100644 --- a/libs/core/led.cpp +++ b/libs/core/led.cpp @@ -2,6 +2,8 @@ enum class DisplayMode_ { //% block="black and white" + BlackAndWhite = DISPLAY_MODE_BLACK_AND_WHITE, + //% blockHidden=true BackAndWhite = DISPLAY_MODE_BLACK_AND_WHITE, //% block="greyscale" Greyscale = DISPLAY_MODE_GREYSCALE, @@ -20,6 +22,7 @@ namespace led { //% blockId=device_plot block="plot|x %x|y %y" blockGap=8 //% parts="ledmatrix" //% x.min=0 x.max=4 y.min=0 y.max=4 + //% x.fieldOptions.precision=1 y.fieldOptions.precision=1 void plot(int x, int y) { uBit.display.image.setPixelValue(x, y, 0xff); } @@ -34,6 +37,7 @@ namespace led { //% blockId=device_plot_brightness block="plot|x %x|y %y|brightness %brightness" blockGap=8 //% parts="ledmatrix" //% x.min=0 x.max=4 y.min=0 y.max=4 brightness.min=0 brightness.max=255 + //% x.fieldOptions.precision=1 y.fieldOptions.precision=1 //% advanced=true void plotBrightness(int x, int y, int brightness) { brightness = max(0, min(0xff, brightness)); @@ -45,26 +49,28 @@ namespace led { /** * Turn off the specified LED using x, y coordinates (x is horizontal, y is vertical). (0,0) is upper left. - * @param x TODO - * @param y TODO + * @param x the horizontal coordinate of the LED + * @param y the vertical coordinate of the LED */ //% help=led/unplot weight=77 //% blockId=device_unplot block="unplot|x %x|y %y" blockGap=8 //% parts="ledmatrix" //% x.min=0 x.max=4 y.min=0 y.max=4 + //% x.fieldOptions.precision=1 y.fieldOptions.precision=1 void unplot(int x, int y) { uBit.display.image.setPixelValue(x, y, 0); } /** * Get the on/off state of the specified LED using x, y coordinates. (0,0) is upper left. - * @param x TODO - * @param y TODO + * @param x the horizontal coordinate of the LED + * @param y the vertical coordinate of the LED */ //% help=led/point weight=76 //% blockId=device_point block="point|x %x|y %y" //% parts="ledmatrix" //% x.min=0 x.max=4 y.min=0 y.max=4 + //% x.fieldOptions.precision=1 y.fieldOptions.precision=1 bool point(int x, int y) { int pix = uBit.display.image.getPixelValue(x, y); return pix > 0; @@ -110,7 +116,8 @@ namespace led { * @param mode mode the display mode in which the screen operates */ //% weight=1 help=led/set-display-mode - //% parts="ledmatrix" advanced=true + //% parts="ledmatrix" advanced=true weight=1 + //% blockId="led_set_display_mode" block="set display mode $mode" void setDisplayMode(DisplayMode_ mode) { uBit.display.setDisplayMode((DisplayMode)mode); } @@ -124,7 +131,7 @@ namespace led { } /** - * Turns on or off the display + * Turns on or off the display */ //% help=led/enable blockId=device_led_enable block="led enable %on" //% advanced=true parts="ledmatrix" @@ -139,7 +146,10 @@ namespace led { //% help=led/screenshot //% parts="ledmatrix" Image screenshot() { - return uBit.display.screenShot().leakData(); + auto d = uBit.display.screenShot().leakData(); + auto r = NEW_GC(RefMImage, d); + d->decr(); + return r; /* let Image img; img = image.createImage(""); diff --git a/libs/core/led.ts b/libs/core/led.ts index ecf77ca6..18bf83c4 100644 --- a/libs/core/led.ts +++ b/libs/core/led.ts @@ -16,22 +16,28 @@ * @param high maximum value. If 0, maximum value adjusted automatically, eg: 0 */ //% help=led/plot-bar-graph weight=20 - //% blockId=device_plot_bar_graph block="plot bar graph of %value |up to %high" icon="\uf080" blockExternalInputs=true + //% blockId=device_plot_bar_graph block="plot bar graph of %value up to %high" icon="\uf080" blockExternalInputs=true //% parts="ledmatrix" export function plotBarGraph(value: number, high: number): void { - let now = input.runningTime(); - serial.writeString(value.toString() + "\r\n"); + const now = input.runningTime(); + console.logValue("", value); value = Math.abs(value); - if (high != 0) barGraphHigh = high; - else if (value > barGraphHigh || now - barGraphHighLast > 10000) { + // auto-scale "high" is not provided + if (high > 0) { + barGraphHigh = high; + } else if (value > barGraphHigh || now - barGraphHighLast > 10000) { barGraphHigh = value; barGraphHighLast = now; } - barGraphHigh = Math.max(barGraphHigh, 16); + // normalize lack of data to 0..1 + if (barGraphHigh < 16 * Number.EPSILON) + barGraphHigh = 1; - let v = (value * 15) / barGraphHigh; + // normalize value to 0..1 + const v = value / barGraphHigh; + const dv = 1 / 16; let k = 0; for (let y = 4; y >= 0; --y) { for (let x = 0; x < 3; ++x) { @@ -42,19 +48,21 @@ plot(2 - x, y); plot(2 + x, y); } - ++k; + k += dv; } } } /** * Toggles a particular pixel - * @param x TODO - * @param y TODO + * @param x pixel column + * @param y pixel row */ //% help=led/toggle weight=77 //% blockId=device_led_toggle block="toggle|x %x|y %y" icon="\uf204" blockGap=8 //% parts="ledmatrix" + //% x.min=0 x.max=4 y.min=0 y.max=4 + //% x.fieldOptions.precision=1 y.fieldOptions.precision=1 export function toggle(x: number, y: number): void { if (led.point(x, y)) { led.unplot(x, y); @@ -91,7 +99,7 @@ /** * Fades in the screen display. - * @param ms TODO + * @param ms fade time in milleseconds */ //% help=led/fade-in //% parts="ledmatrix" @@ -114,7 +122,7 @@ /** * Fades out the screen brightness. - * @param ms TODO + * @param ms fade time in milliseconds */ //% help=led/fade-out //% parts="ledmatrix" diff --git a/libs/core/music.cpp b/libs/core/music.cpp index 48fddccf..b63e8cd8 100644 --- a/libs/core/music.cpp +++ b/libs/core/music.cpp @@ -17,4 +17,5 @@ namespace music { } } -} + +} \ No newline at end of file diff --git a/libs/core/music.ts b/libs/core/music.ts index d0d13070..3c619a8a 100644 --- a/libs/core/music.ts +++ b/libs/core/music.ts @@ -127,7 +127,7 @@ enum BeatFraction { } enum MelodyOptions { - //% block="once"" + //% block="once" Once = 1, //% block="forever" Forever = 2, @@ -137,6 +137,15 @@ enum MelodyOptions { ForeverInBackground = 8 } +enum MelodyStopOptions { + //% block="all" + All = MelodyOptions.Once | MelodyOptions.OnceInBackground, + //% block="foreground" + Foreground = MelodyOptions.Once, + //% block="background" + Background = MelodyOptions.OnceInBackground +} + enum MusicEvent { //% block="melody note played" MelodyNotePlayed = 1, @@ -166,13 +175,19 @@ enum MusicEvent { //% color=#DF4600 weight=98 icon="\uf025" namespace music { let beatsPerMinute: number = 120; - let freqTable: number[] = []; + //% whenUsed + const freqs = hex` + 1f00210023002500270029002c002e003100340037003a003e004100450049004e00520057005c00620068006e00 + 75007b0083008b0093009c00a500af00b900c400d000dc00e900f70006011501260137014a015d01720188019f01 + b801d201ee010b022a024b026e029302ba02e40210033f037003a403dc03170455049704dd0427057505c8052006 + 7d06e0064907b8072d08a9082d09b9094d0aea0a900b400cfa0cc00d910e6f0f5a1053115b1272139a14d4152017 + 8018f519801b231dde1e`; let _playTone: (frequency: number, duration: number) => void; const MICROBIT_MELODY_ID = 2000; /** * Plays a tone through pin ``P0`` for the given duration. - * @param frequency pitch of the tone to play in Hertz (Hz) + * @param frequency pitch of the tone to play in Hertz (Hz), eg: Note.C * @param ms tone duration in milliseconds (ms) */ //% help=music/play-tone weight=90 @@ -186,7 +201,7 @@ namespace music { /** * Plays a tone through pin ``P0``. - * @param frequency pitch of the tone to play in Hertz (Hz) + * @param frequency pitch of the tone to play in Hertz (Hz), eg: Note.C */ //% help=music/ring-tone weight=80 //% blockId=device_ring block="ring tone (Hz)|%note=device_note" blockGap=8 @@ -209,21 +224,24 @@ namespace music { /** - * Gets the frequency of a note. + * Get the frequency of a note. * @param name the note name, eg: Note.C */ - //% weight=50 help=music/note-frequency - //% blockId=device_note block="%note" + //% weight=1 help=music/note-frequency + //% blockId=device_note block="%name" //% shim=TD_ID - //% note.fieldEditor="note" note.defl="262" + //% color="#FFFFFF" colorSecondary="#FFFFFF" + //% name.fieldEditor="note" name.defl="262" + //% name.fieldOptions.decompileLiterals=true //% useEnumVal=1 + //% weight=10 blockGap=8 export function noteFrequency(name: Note): number { return name; } + function init() { if (beatsPerMinute <= 0) beatsPerMinute = 120; - if (freqTable.length == 0) freqTable = [31, 33, 35, 37, 39, 41, 44, 46, 49, 52, 55, 58, 62, 65, 69, 73, 78, 82, 87, 92, 98, 104, 110, 117, 123, 131, 139, 147, 156, 165, 175, 185, 196, 208, 220, 233, 247, 262, 277, 294, 311, 330, 349, 370, 392, 415, 440, 466, 494, 523, 554, 587, 622, 659, 698, 740, 784, 831, 880, 932, 988, 1047, 1109, 1175, 1245, 1319, 1397, 1480, 1568, 1661, 1760, 1865, 1976, 2093, 2217, 2349, 2489, 2637, 2794, 2960, 3136, 3322, 3520, 3729, 3951, 4186] } /** @@ -234,14 +252,14 @@ namespace music { export function beat(fraction?: BeatFraction): number { init(); if (fraction == null) fraction = BeatFraction.Whole; - let beat = 60000 / beatsPerMinute; + let beat = Math.idiv(60000, beatsPerMinute); switch (fraction) { - case BeatFraction.Half: return beat / 2; - case BeatFraction.Quarter: return beat / 4; - case BeatFraction.Eighth: return beat / 8; - case BeatFraction.Sixteenth: return beat / 16; - case BeatFraction.Double: return beat * 2; - case BeatFraction.Breve: return beat * 4; + case BeatFraction.Half: return beat >> 1; + case BeatFraction.Quarter: return beat >> 2; + case BeatFraction.Eighth: return beat >> 3; + case BeatFraction.Sixteenth: return beat >> 4; + case BeatFraction.Double: return beat << 1; + case BeatFraction.Breve: return beat << 2; default: return beat; } } @@ -299,18 +317,18 @@ namespace music { * Registers code to run on various melody events */ //% blockId=melody_on_event block="music on %value" - //% help=music/on-event weight=59 - export function onEvent(value: MusicEvent, handler: Action) { + //% help=music/on-event weight=59 blockGap=32 + export function onEvent(value: MusicEvent, handler: () => void) { control.onEvent(MICROBIT_MELODY_ID, value, handler); } /** * Starts playing a melody. * Notes are expressed as a string of characters with this format: NOTE[octave][:duration] - * @param melodyArray the melody array to play, eg: ['g5:1'] + * @param melodyArray the melody array to play * @param options melody options, once / forever, in the foreground / background */ - //% help=music/begin-melody weight=60 blockGap=8 + //% help=music/begin-melody weight=60 blockGap=16 //% blockId=device_start_melody block="start melody %melody=device_builtin_melody| repeating %options" //% parts="headphone" export function beginMelody(melodyArray: string[], options: MelodyOptions = 1) { @@ -348,6 +366,20 @@ namespace music { } } + /** + * Stops the melodies + * @param options which melody to stop + */ + //% help=music/stop-melody weight=59 blockGap=16 + //% blockId=device_stop_melody block="stop melody $options" + //% parts="headphone" + export function stopMelody(options: MelodyStopOptions) { + if (options & MelodyStopOptions.Background) + beginMelody([], MelodyOptions.OnceInBackground); + if (options & MelodyStopOptions.Foreground) + beginMelody([], MelodyOptions.Once); + } + /** * Sets a custom playTone function for playing melodies */ @@ -368,33 +400,34 @@ namespace music { let isrest: boolean = false; let beatPos: number; let parsingOctave: boolean = true; + let prevNote: boolean = false; for (let pos = 0; pos < currNote.length; pos++) { let noteChar = currNote.charAt(pos); switch (noteChar) { - case 'c': case 'C': note = 1; break; - case 'd': case 'D': note = 3; break; - case 'e': case 'E': note = 5; break; - case 'f': case 'F': note = 6; break; - case 'g': case 'G': note = 8; break; - case 'a': case 'A': note = 10; break; - case 'b': case 'B': note = 12; break; - case 'r': case 'R': isrest = true; break; - case '#': note++; break; - case 'b': note--; break; - case ':': parsingOctave = false; beatPos = pos; break; - default: if (parsingOctave) currentOctave = parseInt(noteChar); + case 'c': case 'C': note = 1; prevNote = true; break; + case 'd': case 'D': note = 3; prevNote = true; break; + case 'e': case 'E': note = 5; prevNote = true; break; + case 'f': case 'F': note = 6; prevNote = true; break; + case 'g': case 'G': note = 8; prevNote = true; break; + case 'a': case 'A': note = 10; prevNote = true; break; + case 'B': note = 12; prevNote = true; break; + case 'r': case 'R': isrest = true; prevNote = false; break; + case '#': note++; prevNote = false; break; + case 'b': if (prevNote) note--; else { note = 12; prevNote = true; } break; + case ':': parsingOctave = false; beatPos = pos; prevNote = false; break; + default: prevNote = false; if (parsingOctave) currentOctave = parseInt(noteChar); } } if (!parsingOctave) { currentDuration = parseInt(currNote.substr(beatPos + 1, currNote.length - beatPos)); } - let beat = (60000 / beatsPerMinute) / 4; + let beat = Math.idiv(60000, beatsPerMinute) >> 2; if (isrest) { music.rest(currentDuration * beat) } else { let keyNumber = note + (12 * (currentOctave - 1)); - let frequency = keyNumber >= 0 && keyNumber < freqTable.length ? freqTable[keyNumber] : 0; + let frequency = freqs.getNumber(NumberFormat.UInt16LE, keyNumber * 2) || 0; music.playTone(frequency, currentDuration * beat); } melody.currentDuration = currentDuration; diff --git a/libs/core/pins.cpp b/libs/core/pins.cpp index 6b6d2748..3ac64d4b 100644 --- a/libs/core/pins.cpp +++ b/libs/core/pins.cpp @@ -32,7 +32,9 @@ enum class AnalogPin { }; enum class PulseValue { + //% block=high High = MICROBIT_PIN_EVT_PULSE_HI, + //% block=low Low = MICROBIT_PIN_EVT_PULSE_LO }; @@ -56,6 +58,9 @@ enum class PinEventType { None = MICROBIT_PIN_EVENT_NONE }; + +namespace pxt +{ MicroBitPin *getPin(int id) { switch (id) { case MICROBIT_ID_IO_P0: return &uBit.io.P0; @@ -82,6 +87,7 @@ MicroBitPin *getPin(int id) { } } +} // pxt namespace pins { #define PINOP(op) \ @@ -133,7 +139,7 @@ namespace pins { //% help=pins/analog-read-pin weight=25 //% blockId=device_get_analog_pin block="analog read|pin %name" blockGap="8" //% name.fieldEditor="gridpicker" name.fieldOptions.columns=4 - //% name.fieldOptions.tooltips="false" + //% name.fieldOptions.tooltips="false" name.fieldOptions.width="250" int analogReadPin(AnalogPin name) { PINREAD(getAnalogValue()); } @@ -147,13 +153,13 @@ namespace pins { //% blockId=device_set_analog_pin block="analog write|pin %name|to %value" blockGap=8 //% value.min=0 value.max=1023 //% name.fieldEditor="gridpicker" name.fieldOptions.columns=4 - //% name.fieldOptions.tooltips="false" + //% name.fieldOptions.tooltips="false" name.fieldOptions.width="250" void analogWritePin(AnalogPin name, int value) { PINOP(setAnalogValue(value)); } /** - * Configures the Pulse-width modulation (PWM) of the analog output to the given value in **microseconds** or `1/1000` milliseconds. + * Configure the pulse-width modulation (PWM) period of the analog output in microseconds. * If this pin is not configured as an analog output (using `analog write pin`), the operation has no effect. * @param name analog pin to set period to, eg: AnalogPin.P0 * @param micros period in micro seconds. eg:20000 @@ -167,11 +173,11 @@ namespace pins { } /** - * Configures this pin to a digital input, and generates events where the timestamp is the duration that this pin was either ``high`` or ``low``. + * Configure the pin as a digital input and generate an event when the pin is pulsed either high or low. * @param name digital pin to register to, eg: DigitalPin.P0 * @param pulse the value of the pulse, eg: PulseValue.High */ - //% help=pins/on-pulsed weight=22 blockGap=8 advanced=true + //% help=pins/on-pulsed weight=22 blockGap=16 advanced=true //% blockId=pins_on_pulsed block="on|pin %pin|pulsed %pulse" //% pin.fieldEditor="gridpicker" pin.fieldOptions.columns=4 //% pin.fieldOptions.tooltips="false" pin.fieldOptions.width="300" @@ -184,7 +190,7 @@ namespace pins { } /** - * Gets the duration of the last pulse in micro-seconds. This function should be called from a ``onPulsed`` handler. + * Get the duration of the last pulse in microseconds. This function should be called from a ``onPulsed`` handler. */ //% help=pins/pulse-duration advanced=true //% blockId=pins_pulse_duration block="pulse duration (µs)" @@ -194,10 +200,10 @@ namespace pins { } /** - * Returns the duration of a pulse in microseconds + * Return the duration of a pulse at a pin in microseconds. * @param name the pin which measures the pulse, eg: DigitalPin.P0 * @param value the value of the pulse, eg: PulseValue.High - * @param maximum duration in micro-seconds + * @param maximum duration in microseconds */ //% blockId="pins_pulse_in" block="pulse in (µs)|pin %name|pulsed %value" //% weight=20 advanced=true @@ -237,7 +243,7 @@ namespace pins { } /** - * Writes a value to the servo, controlling the shaft accordingly. On a standard servo, this will set the angle of the shaft (in degrees), moving the shaft to that orientation. On a continuous rotation servo, this will set the speed of the servo (with ``0`` being full-speed in one direction, ``180`` being full speed in the other, and a value near ``90`` being no movement). + * Write a value to the servo, controlling the shaft accordingly. On a standard servo, this will set the angle of the shaft (in degrees), moving the shaft to that orientation. On a continuous rotation servo, this will set the speed of the servo (with ``0`` being full-speed in one direction, ``180`` being full speed in the other, and a value near ``90`` being no movement). * @param name pin to write to, eg: AnalogPin.P0 * @param value angle or rotation speed, eg:180,90,0 */ @@ -246,21 +252,21 @@ namespace pins { //% parts=microservo trackArgs=0 //% value.min=0 value.max=180 //% name.fieldEditor="gridpicker" name.fieldOptions.columns=4 - //% name.fieldOptions.tooltips="false" + //% name.fieldOptions.tooltips="false" name.fieldOptions.width="250" void servoWritePin(AnalogPin name, int value) { fixMotorIssue(name); PINOP(setServoValue(value)); } /** - * Configures this IO pin as an analog/pwm output, configures the period to be 20 ms, and sets the pulse width, based on the value it is given **microseconds** or `1/1000` milliseconds. + * Configure the IO pin as an analog/pwm output and set a pulse width. The period is 20 ms period and the pulse width is set based on the value given in **microseconds** or `1/1000` milliseconds. * @param name pin name * @param micros pulse duration in micro seconds, eg:1500 */ //% help=pins/servo-set-pulse weight=19 //% blockId=device_set_servo_pulse block="servo set pulse|pin %value|to (µs) %micros" //% value.fieldEditor="gridpicker" value.fieldOptions.columns=4 - //% value.fieldOptions.tooltips="false" + //% value.fieldOptions.tooltips="false" value.fieldOptions.width="250" void servoSetPulse(AnalogPin name, int micros) { fixMotorIssue(name); PINOP(setServoPulseUs(micros)); @@ -270,45 +276,45 @@ namespace pins { MicroBitPin* pitchPin = NULL; /** - * Sets the pin used when using `analog pitch` or music. + * Set the pin used when using analog pitch or music. * @param name pin to modulate pitch from */ //% blockId=device_analog_set_pitch_pin block="analog set pitch pin %name" //% help=pins/analog-set-pitch-pin weight=3 advanced=true //% name.fieldEditor="gridpicker" name.fieldOptions.columns=4 - //% name.fieldOptions.tooltips="false" + //% name.fieldOptions.tooltips="false" name.fieldOptions.width="250" void analogSetPitchPin(AnalogPin name) { - pitchPin = getPin((int)name); - } - + pitchPin = getPin((int)name); + } + /** - * Emits a Pulse-width modulation (PWM) signal to the current pitch pin. Use `analog set pitch pin` to define the pitch pin. - * @param frequency frequency to modulate in Hz. - * @param ms duration of the pitch in milli seconds. - */ + * Emit a plse-width modulation (PWM) signal to the current pitch pin. Use `analog set pitch pin` to define the pitch pin. + * @param frequency frequency to modulate in Hz. + * @param ms duration of the pitch in milli seconds. + */ //% blockId=device_analog_pitch block="analog pitch %frequency|for (ms) %ms" //% help=pins/analog-pitch weight=4 async advanced=true blockGap=8 void analogPitch(int frequency, int ms) { if (pitchPin == NULL) analogSetPitchPin(AnalogPin::P1); if (frequency <= 0) { - pitchPin->setAnalogValue(0); - } else { - pitchPin->setAnalogValue(512); - pitchPin->setAnalogPeriodUs(1000000/frequency); - } - - if (ms > 0) { - fiber_sleep(ms); + pitchPin->setAnalogValue(0); + } else { + pitchPin->setAnalogValue(512); + pitchPin->setAnalogPeriodUs(1000000/frequency); + } + + if (ms > 0) { + fiber_sleep(ms); pitchPin->setAnalogValue(0); // TODO why do we use wait_ms() here? it's a busy wait I think wait_ms(5); } } - + /** - * Configures the pull of this pin. + * Configure the pull directiion of of a pin. * @param name pin to set the pull mode on, eg: DigitalPin.P0 * @param pull one of the mbed pull configurations, eg: PinPullMode.PullUp */ @@ -325,7 +331,7 @@ namespace pins { } /** - * Configures the events emitted by this pin. Events can be subscribed to + * Configure the events emitted by this pin. Events can be subscribed to * using ``control.onEvent()``. * @param name pin to set the event mode on, eg: DigitalPin.P0 * @param type the type of events for this pin to emit, eg: PinEventType.Edge @@ -345,7 +351,7 @@ namespace pins { //% Buffer createBuffer(int size) { - return ManagedBuffer(size).leakData(); + return mkBuffer(NULL, size); } /** @@ -355,7 +361,7 @@ namespace pins { Buffer i2cReadBuffer(int address, int size, bool repeat = false) { Buffer buf = createBuffer(size); - uBit.i2c.read(address << 1, (char*)buf->payload, size, repeat); + uBit.i2c.read(address << 1, (char*)buf->data, size, repeat); return buf; } @@ -363,11 +369,11 @@ namespace pins { * Write bytes to a 7-bit I2C `address`. */ //% - void i2cWriteBuffer(int address, Buffer buf, bool repeat = false) + int i2cWriteBuffer(int address, Buffer buf, bool repeat = false) { - uBit.i2c.write(address << 1, (char*)buf->payload, buf->length, repeat); + return uBit.i2c.write(address << 1, (char*)buf->data, buf->length, repeat); } - + SPI* spi = NULL; SPI* allocSPI() { if (NULL == spi) @@ -387,7 +393,7 @@ namespace pins { } /** - * Sets the SPI frequency + * Set the SPI frequency * @param frequency the clock frequency, eg: 1000000 */ //% help=pins/spi-frequency weight=4 advanced=true @@ -398,7 +404,7 @@ namespace pins { } /** - * Sets the SPI bits and mode + * Set the SPI bits and mode * @param bits the number of bits, eg: 8 * @param mode the mode, eg: 3 */ @@ -410,17 +416,17 @@ namespace pins { } /** - * Sets the MOSI, MISO, SCK pins used by the SPI instance + * Set the MOSI, MISO, SCK pins used by the SPI connection * */ //% help=pins/spi-pins weight=2 advanced=true //% blockId=spi_pins block="spi set pins|MOSI %mosi|MISO %miso|SCK %sck" //% mosi.fieldEditor="gridpicker" mosi.fieldOptions.columns=4 - //% mosi.fieldOptions.tooltips="false" mosi.fieldOptions.width="300" + //% mosi.fieldOptions.tooltips="false" mosi.fieldOptions.width="250" //% miso.fieldEditor="gridpicker" miso.fieldOptions.columns=4 - //% miso.fieldOptions.tooltips="false" miso.fieldOptions.width="300" + //% miso.fieldOptions.tooltips="false" miso.fieldOptions.width="250" //% sck.fieldEditor="gridpicker" sck.fieldOptions.columns=4 - //% sck.fieldOptions.tooltips="false" sck.fieldOptions.width="300" + //% sck.fieldOptions.tooltips="false" sck.fieldOptions.width="250" void spiPins(DigitalPin mosi, DigitalPin miso, DigitalPin sck) { if (NULL != spi) { delete spi; diff --git a/libs/core/pins.ts b/libs/core/pins.ts index aec32295..ab4d7c72 100644 --- a/libs/core/pins.ts +++ b/libs/core/pins.ts @@ -5,7 +5,7 @@ //% advanced=true namespace pins { /** - * Re-maps a number from one range to another. That is, a value of ``from low`` would get mapped to ``to low``, a value of ``from high`` to ``to high``, values in-between to values in-between, etc. + * Map a number from one range to another. That is, a value of ``from low`` would get mapped to ``to low``, a value of ``from high`` to ``to high``, values in-between to values in-between, etc. * @param value value to map in ranges * @param fromLow the lower bound of the value's current range * @param fromHigh the upper bound of the value's current range, eg: 1023 @@ -13,7 +13,7 @@ namespace pins { * @param toHigh the upper bound of the value's target range, eg: 4 */ //% help=pins/map weight=23 - //% blockId=math_map block="map %value|from low %fromLow|from high %fromHigh|to low %toLow|to high %toHigh" + //% blockId=pin_map block="map %value|from low %fromLow|from high %fromHigh|to low %toLow|to high %toHigh" export function map(value: number, fromLow: number, fromHigh: number, toLow: number, toHigh: number): number { return ((value - fromLow) * (toHigh - toLow)) / (fromHigh - fromLow) + toLow; } @@ -21,50 +21,21 @@ namespace pins { /** * Read one number from 7-bit I2C address. */ - //% help=pins/i2c-read-number blockGap=8 - //% blockId=pins_i2c_readnumber block="i2c read number|at address %address|of format %format=i2c_sizeof|repeat %repeat" weight=7 - export function i2cReadNumber(address: number, format: NumberFormat, repeat?: boolean): number { - let buf = pins.i2cReadBuffer(address, pins.sizeOf(format), repeat) + //% help=pins/i2c-read-number blockGap=8 advanced=true + //% blockId=pins_i2c_readnumber block="i2c read number|at address %address|of format %format|repeated %repeat" weight=7 + export function i2cReadNumber(address: number, format: NumberFormat, repeated?: boolean): number { + let buf = pins.i2cReadBuffer(address, pins.sizeOf(format), repeated) return buf.getNumber(format, 0) } /** * Write one number to a 7-bit I2C address. */ - //% help=pins/i2c-write-number blockGap=8 - //% blockId=i2c_writenumber block="i2c write number|at address %address|with value %value|of format %format=i2c_sizeof|repeat %repeat" weight=6 - export function i2cWriteNumber(address: number, value: number, format: NumberFormat, repeat?: boolean): void { + //% help=pins/i2c-write-number blockGap=8 advanced=true + //% blockId=i2c_writenumber block="i2c write number|at address %address|with value %value|of format %format|repeated %repeat" weight=6 + export function i2cWriteNumber(address: number, value: number, format: NumberFormat, repeated?: boolean): void { let buf = createBuffer(pins.sizeOf(format)) buf.setNumber(format, 0, value) - pins.i2cWriteBuffer(address, buf, repeat) - } - - /** - * Get the size in bytes of specified number format. - */ - //% - export function sizeOf(format: NumberFormat) { - switch (format) { - case NumberFormat.Int8LE: - case NumberFormat.UInt8LE: - case NumberFormat.Int8BE: - case NumberFormat.UInt8BE: - return 1; - case NumberFormat.Int16LE: - case NumberFormat.UInt16LE: - case NumberFormat.Int16BE: - case NumberFormat.UInt16BE: - return 2; - case NumberFormat.Int32LE: - case NumberFormat.Int32BE: - return 4; - } - return 0; + pins.i2cWriteBuffer(address, buf, repeated) } } - - -interface Buffer { - [index: number]: number; - // rest defined in buffer.cpp -} diff --git a/libs/core/platform.h b/libs/core/platform.h new file mode 100644 index 00000000..785d7341 --- /dev/null +++ b/libs/core/platform.h @@ -0,0 +1,3 @@ +// helpful define to handle C++ differences in package +#define PXT_MICROBIT_TAGGED_INT 1 +#define PXT_POWI 1 diff --git a/libs/core/pxt.cpp b/libs/core/pxt.cpp deleted file mode 100644 index bdea3518..00000000 --- a/libs/core/pxt.cpp +++ /dev/null @@ -1,746 +0,0 @@ -#include "pxt.h" -#include - -MicroBit uBit; - -namespace pxt { - int incr(uint32_t e) - { - if (e) { - if (hasVTable(e)) - ((RefObject*)e)->ref(); - else - ((RefCounted*)e)->incr(); - } - return e; - } - - void decr(uint32_t e) - { - if (e) { - if (hasVTable(e)) - ((RefObject*)e)->unref(); - else - ((RefCounted*)e)->decr(); - } - } - - Action mkAction(int reflen, int totallen, int startptr) - { - check(0 <= reflen && reflen <= totallen, ERR_SIZE, 1); - check(reflen <= totallen && totallen <= 255, ERR_SIZE, 2); - check(bytecode[startptr] == 0xffff, ERR_INVALID_BINARY_HEADER, 3); - check(bytecode[startptr + 1] == 0, ERR_INVALID_BINARY_HEADER, 4); - - uint32_t tmp = (uint32_t)&bytecode[startptr]; - - if (totallen == 0) { - return tmp; // no closure needed - } - - void *ptr = ::operator new(sizeof(RefAction) + totallen * sizeof(uint32_t)); - RefAction *r = new (ptr) RefAction(); - r->len = totallen; - r->reflen = reflen; - r->func = (ActionCB)((tmp + 4) | 1); - memset(r->fields, 0, r->len * sizeof(uint32_t)); - - return (Action)r; - } - - uint32_t runAction3(Action a, int arg0, int arg1, int arg2) - { - if (hasVTable(a)) - return ((RefAction*)a)->runCore(arg0, arg1, arg2); - else { - check(*(uint16_t*)a == 0xffff, ERR_INVALID_BINARY_HEADER, 4); - return ((ActionCB)((a + 4) | 1))(NULL, arg0, arg1, arg2); - } - } - - uint32_t runAction2(Action a, int arg0, int arg1) - { - return runAction3(a, arg0, arg1, 0); - } - - uint32_t runAction1(Action a, int arg0) - { - return runAction3(a, arg0, 0, 0); - } - - uint32_t runAction0(Action a) - { - return runAction3(a, 0, 0, 0); - } - - RefRecord* mkClassInstance(int vtableOffset) - { - VTable *vtable = (VTable*)&bytecode[vtableOffset]; - - intcheck(vtable->methods[0] == &RefRecord_destroy, ERR_SIZE, 3); - intcheck(vtable->methods[1] == &RefRecord_print, ERR_SIZE, 4); - - void *ptr = ::operator new(vtable->numbytes); - RefRecord *r = new (ptr) RefRecord(PXT_VTABLE_TO_INT(vtable)); - memset(r->fields, 0, vtable->numbytes - sizeof(RefRecord)); - return r; - } - - uint32_t RefRecord::ld(int idx) - { - //intcheck((reflen == 255 ? 0 : reflen) <= idx && idx < len, ERR_OUT_OF_BOUNDS, 1); - return fields[idx]; - } - - uint32_t RefRecord::ldref(int idx) - { - //printf("LD %p len=%d reflen=%d idx=%d\n", this, len, reflen, idx); - //intcheck(0 <= idx && idx < reflen, ERR_OUT_OF_BOUNDS, 2); - uint32_t tmp = fields[idx]; - incr(tmp); - return tmp; - } - - void RefRecord::st(int idx, uint32_t v) - { - //intcheck((reflen == 255 ? 0 : reflen) <= idx && idx < len, ERR_OUT_OF_BOUNDS, 3); - fields[idx] = v; - } - - void RefRecord::stref(int idx, uint32_t v) - { - //printf("ST %p len=%d reflen=%d idx=%d\n", this, len, reflen, idx); - //intcheck(0 <= idx && idx < reflen, ERR_OUT_OF_BOUNDS, 4); - decr(fields[idx]); - fields[idx] = v; - } - - void RefObject::destroy() { - ((RefObjectMethod)getVTable()->methods[0])(this); - } - - void RefObject::print() { - ((RefObjectMethod)getVTable()->methods[1])(this); - } - - void RefRecord_destroy(RefRecord *r) { - auto tbl = r->getVTable(); - uint8_t *refmask = (uint8_t*)&tbl->methods[tbl->userdata & 0xff]; - int len = (tbl->numbytes >> 2) - 1; - for (int i = 0; i < len; ++i) { - if (refmask[i]) decr(r->fields[i]); - r->fields[i] = 0; - } - //RefRecord is allocated using placement new - r->~RefRecord(); - ::operator delete(r); - } - - void RefRecord_print(RefRecord *r) - { - printf("RefRecord %p r=%d size=%d bytes\n", r, r->refcnt, r->getVTable()->numbytes); - } - - uint32_t Segment::get(uint32_t i) - { -#ifdef DEBUG_BUILD - printf("In Segment::get index:%u\n", i); - this->print(); -#endif - - if (i < length) - { - return data[i]; - } - return Segment::DefaultValue; - } - - void Segment::set(uint32_t i, uint32_t value) - { - if (i < size) - { - data[i] = value; - } - else if (i < Segment::MaxSize) - { - growByMin(i + 1); - data[i] = value; - } - if (length <= i) - { - length = i + 1; - } - -#ifdef DEBUG_BUILD - printf("In Segment::set\n"); - this->print(); -#endif - - return; - } - - uint16_t Segment::growthFactor(uint16_t size) - { - if (size == 0) - { - return 4; - } - if (size < 64) - { - return size * 2; // Double - } - if (size < 512) - { - return size * 5/3; //Grow by 1.66 rate - } - return size + 256; //Grow by constant rate - } - - void Segment::growByMin(uint16_t minSize) - { - growBy(max(minSize, growthFactor(size))); - } - - void Segment::growBy(uint16_t newSize) - { -#ifdef DEBUG_BUILD - printf("growBy: %d\n", newSize); - this->print(); -#endif - if (size < newSize) - { - //this will throw if unable to allocate - uint32_t *tmp = (uint32_t*)(::operator new(newSize * sizeof(uint32_t))); - - //Copy existing data - if (size) - { - memcpy(tmp, data, size * sizeof(uint32_t)); - } - //fill the rest with default value - memset(tmp + size, Segment::DefaultValue, (newSize - size) * sizeof(uint32_t)); - - //free older segment; - ::operator delete(data); - - data = tmp; - size = newSize; - -#ifdef DEBUG_BUILD - printf("growBy - after reallocation\n"); - this->print(); -#endif - - } - //else { no shrinking yet; } - return; - } - - void Segment::ensure(uint16_t newSize) - { - if (newSize < size) - { - return; - } - growByMin(newSize); - } - - void Segment::setLength(uint32_t newLength) - { - if (newLength > size) - { - ensure(length); - } - length = newLength; - return; - } - - void Segment::push(uint32_t value) - { - this->set(length, value); - } - - uint32_t Segment::pop() - { -#ifdef DEBUG_BUILD - printf("In Segment::pop\n"); - this->print(); -#endif - - if (length > 0) - { - --length; - uint32_t value = data[length]; - data[length] = Segment::DefaultValue; - return value; - } - return Segment::DefaultValue; - } - - //this function removes an element at index i and shifts the rest of the elements to - //left to fill the gap - uint32_t Segment::remove(uint32_t i) - { -#ifdef DEBUG_BUILD - printf("In Segment::remove index:%u\n", i); - this->print(); -#endif - if (i < length) - { - //value to return - uint32_t ret = data[i]; - if (i + 1 < length) - { - //Move the rest of the elements to fill in the gap. - memmove(data + i, data + i + 1, (length - i - 1) * sizeof(uint32_t)); - } - length--; - data[length] = Segment::DefaultValue; -#ifdef DEBUG_BUILD - printf("After Segment::remove index:%u\n", i); - this->print(); -#endif - return ret; - } - return Segment::DefaultValue; - } - - //this function inserts element value at index i by shifting the rest of the elements right. - void Segment::insert(uint32_t i, uint32_t value) - { -#ifdef DEBUG_BUILD - printf("In Segment::insert index:%u value:%u\n", i, value); - this->print(); -#endif - - if (i < length) - { - ensure(length + 1); - if (i + 1 < length) - { - //Move the rest of the elements to fill in the gap. - memmove(data + i + 1, data + i, (length - i) * sizeof(uint32_t)); - } - - data[i] = value; - length++; - } - else - { - //This is insert beyond the length, just call set which will adjust the length - set(i, value); - } -#ifdef DEBUG_BUILD - printf("After Segment::insert index:%u\n", i); - this->print(); -#endif - } - - void Segment::print() - { - printf("Segment: %x, length: %u, size: %u\n", data, (uint32_t)length, (uint32_t)size); - for(uint32_t i = 0; i < size; i++) - { - printf("%d ",(uint32_t)data[i]); - } - printf("\n"); - } - - bool Segment::isValidIndex(uint32_t i) - { - if (i > length) - { - return false; - } - return true; - } - - void Segment::destroy() - { -#ifdef DEBUG_BUILD - printf("In Segment::destroy\n"); - this->print(); -#endif - length = size = 0; - ::operator delete(data); - data = nullptr; - } - - void RefCollection::push(uint32_t x) - { - if (isRef()) incr(x); - head.push(x); - } - - uint32_t RefCollection::pop() - { - uint32_t ret = head.pop(); - if (isRef()) - { - incr(ret); - } - return ret; - } - - uint32_t RefCollection::getAt(int i) - { - uint32_t tmp = head.get(i); - if (isRef()) - { - incr(tmp); - } - return tmp; - } - - uint32_t RefCollection::removeAt(int i) - { - // no decr() - we return the result - return head.remove(i); - } - - void RefCollection::insertAt(int i, uint32_t value) - { - head.insert(i, value); - if (isRef()) - { - incr(value); - } - } - - void RefCollection::setAt(int i, uint32_t value) - { - if (isRef()) - { - if (head.isValidIndex((uint32_t)i)) - { - decr(head.get(i)); - } - incr(value); - } - head.set(i, value); - } - - int RefCollection::indexOf(uint32_t x, int start) - { - if (isString()) - { - StringData *xx = (StringData*)x; - uint32_t i = start; - while(head.isValidIndex(i)) - { - StringData *ee = (StringData*)head.get(i); - if (ee == xx) - { - //handles ee being null - return (int) i; - } - if (ee && xx->len == ee->len && memcmp(xx->data, ee->data, xx->len) == 0) - { - return (int)i; - } - i++; - } - } - else - { - uint32_t i = start; - while(head.isValidIndex(i)) - { - if (head.get(i) == x) - { - return (int)i; - } - i++; - } - } - - return -1; - } - - int RefCollection::removeElement(uint32_t x) - { - int idx = indexOf(x, 0); - if (idx >= 0) { - uint32_t elt = removeAt(idx); - if (isRef()) decr(elt); - return 1; - } - return 0; - } - - namespace Coll0 { - PXT_VTABLE_BEGIN(RefCollection, 0, 0) - PXT_VTABLE_END - } - namespace Coll1 { - PXT_VTABLE_BEGIN(RefCollection, 1, 0) - PXT_VTABLE_END - } - namespace Coll3 { - PXT_VTABLE_BEGIN(RefCollection, 3, 0) - PXT_VTABLE_END - } - - RefCollection::RefCollection(uint16_t flags) : RefObject(0) { - switch (flags) { - case 0: - vtable = PXT_VTABLE_TO_INT(&Coll0::RefCollection_vtable); - break; - case 1: - vtable = PXT_VTABLE_TO_INT(&Coll1::RefCollection_vtable); - break; - case 3: - vtable = PXT_VTABLE_TO_INT(&Coll3::RefCollection_vtable); - break; - default: - error(ERR_SIZE); - break; - } - } - - void RefCollection::destroy() - { - if (this->isRef()) - { - for(uint32_t i = 0; i < this->head.getLength(); i++) - { - decr(this->head.get(i)); - } - } - this->head.destroy(); - delete this; - } - - void RefCollection::print() - { - printf("RefCollection %p r=%d flags=%d size=%d\n", this, refcnt, getFlags(), head.getLength()); - head.print(); - } - - PXT_VTABLE_CTOR(RefAction) {} - - // fields[] contain captured locals - void RefAction::destroy() - { - for (int i = 0; i < this->reflen; ++i) { - decr(fields[i]); - fields[i] = 0; - } - //RefAction is allocated using placement new - this->~RefAction(); - ::operator delete(this); - } - - void RefAction::print() - { - printf("RefAction %p r=%d pc=0x%lx size=%d (%d refs)\n", this, refcnt, (const uint8_t*)func - (const uint8_t*)bytecode, len, reflen); - } - - void RefLocal::print() - { - printf("RefLocal %p r=%d v=%d\n", this, refcnt, v); - } - - void RefLocal::destroy() - { - delete this; - } - - PXT_VTABLE_CTOR(RefLocal) { - v = 0; - } - - PXT_VTABLE_CTOR(RefRefLocal) { - v = 0; - } - - void RefRefLocal::print() - { - printf("RefRefLocal %p r=%d v=%p\n", this, refcnt, (void*)v); - } - - void RefRefLocal::destroy() - { - decr(v); - delete this; - } - - PXT_VTABLE_BEGIN(RefMap, 0, RefMapMarker) - PXT_VTABLE_END - RefMap::RefMap() : PXT_VTABLE_INIT(RefMap) {} - - void RefMap::destroy() { - for (unsigned i = 0; i < data.size(); ++i) { - if (data[i].key & 1) { - decr(data[i].val); - } - data[i].val = 0; - } - data.resize(0); - delete this; - } - - int RefMap::findIdx(uint32_t key) { - for (unsigned i = 0; i < data.size(); ++i) { - if (data[i].key >> 1 == key) - return i; - } - return -1; - } - - void RefMap::print() - { - printf("RefMap %p r=%d size=%d\n", this, refcnt, data.size()); - } - - -#ifdef DEBUG_MEMLEAKS - std::set allptrs; - void debugMemLeaks() - { - printf("LIVE POINTERS:\n"); - for(std::set::iterator itr = allptrs.begin();itr!=allptrs.end();itr++) - { - (*itr)->print(); - } - printf("\n"); - } -#else - void debugMemLeaks() {} -#endif - - - // --------------------------------------------------------------------------- - // An adapter for the API expected by the run-time. - // --------------------------------------------------------------------------- - - map, Action> handlersMap; - - MicroBitEvent lastEvent; - - // We have the invariant that if [dispatchEvent] is registered against the DAL - // for a given event, then [handlersMap] contains a valid entry for that - // event. - void dispatchEvent(MicroBitEvent e) { - - lastEvent = e; - - Action curr = handlersMap[{ e.source, e.value }]; - if (curr) - runAction1(curr, e.value); - - curr = handlersMap[{ e.source, MICROBIT_EVT_ANY }]; - if (curr) - runAction1(curr, e.value); - } - - void registerWithDal(int id, int event, Action a) { - Action prev = handlersMap[{ id, event }]; - if (prev) - decr(prev); - else - uBit.messageBus.listen(id, event, dispatchEvent); - incr(a); - handlersMap[{ id, event }] = a; - } - - void fiberDone(void *a) - { - decr((Action)a); - release_fiber(); - } - - - void runInBackground(Action a) { - if (a != 0) { - incr(a); - create_fiber((void(*)(void*))runAction0, (void*)a, fiberDone); - } - } - - - void error(ERROR code, int subcode) - { - printf("Error: %d [%d]\n", code, subcode); - uBit.panic(42); - } - - uint16_t *bytecode; - uint32_t *globals; - int numGlobals; - - uint32_t *allocate(uint16_t sz) - { - uint32_t *arr = new uint32_t[sz]; - memset(arr, 0, sz * 4); - return arr; - } - - void checkStr(bool cond, const char *msg) - { - if (!cond) { - while (true) { - uBit.display.scroll(msg, 100); - uBit.sleep(100); - } - } - } - - int templateHash() - { - return ((int*)bytecode)[4]; - } - - int programHash() - { - return ((int*)bytecode)[6]; - } - - int getNumGlobals() - { - return bytecode[16]; - } - - void exec_binary(int32_t *pc) - { - // XXX re-enable once the calibration code is fixed and [editor/embedded.ts] - // properly prepends a call to [internal_main]. - // ::touch_develop::internal_main(); - - // unique group for radio based on source hash - // ::touch_develop::micro_bit::radioDefaultGroup = programHash(); - - // repeat error 4 times and restart as needed - microbit_panic_timeout(4); - - int32_t ver = *pc++; - checkStr(ver == 0x4209, ":( Bad runtime version"); - - bytecode = *((uint16_t**)pc++); // the actual bytecode is here - globals = allocate(getNumGlobals()); - - // just compare the first word - checkStr(((uint32_t*)bytecode)[0] == 0x923B8E70 && - templateHash() == *pc, - ":( Failed partial flash"); - - uint32_t startptr = (uint32_t)bytecode; - startptr += 48; // header - startptr |= 1; // Thumb state - - ((uint32_t (*)())startptr)(); - -#ifdef DEBUG_MEMLEAKS - pxt::debugMemLeaks(); -#endif - - return; - } - - void start() - { - exec_binary((int32_t*)functionsAndBytecode); - } -} - -// vim: ts=2 sw=2 expandtab diff --git a/libs/core/pxt.h b/libs/core/pxt.h index 39482b28..76677b84 100644 --- a/libs/core/pxt.h +++ b/libs/core/pxt.h @@ -5,375 +5,70 @@ #pragma GCC diagnostic ignored "-Wunused-parameter" -#include "MicroBit.h" -#include "MicroBitImage.h" -#include "ManagedString.h" -#include "ManagedType.h" -#include "ManagedBuffer.h" - -#define printf(...) uBit.serial.printf(__VA_ARGS__) -// #define printf(...) - -#define intcheck(...) check(__VA_ARGS__) -//#define intcheck(...) do {} while (0) - -#include -#include -#include -#include - -#ifdef DEBUG_MEMLEAKS -#include -#endif - -extern MicroBit uBit; +#include "pxtbase.h" namespace pxt { - typedef uint32_t Action; - typedef uint32_t ImageLiteral; - - typedef enum { - ERR_INVALID_BINARY_HEADER = 5, - ERR_OUT_OF_BOUNDS = 8, - ERR_REF_DELETED = 7, - ERR_SIZE = 9, - } ERROR; - - extern const uint32_t functionsAndBytecode[]; - extern uint32_t *globals; - extern uint16_t *bytecode; - class RefRecord; - - // Utility functions - extern MicroBitEvent lastEvent; - void registerWithDal(int id, int event, Action a); - void runInBackground(Action a); - uint32_t runAction3(Action a, int arg0, int arg1, int arg2); - uint32_t runAction2(Action a, int arg0, int arg1); - uint32_t runAction1(Action a, int arg0); - uint32_t runAction0(Action a); - Action mkAction(int reflen, int totallen, int startptr); - void error(ERROR code, int subcode = 0); - void exec_binary(uint16_t *pc); - void start(); - void debugMemLeaks(); - // allocate [sz] words and clear them - uint32_t *allocate(uint16_t sz); - int templateHash(); - int programHash(); - uint32_t programSize(); - uint32_t afterProgramPage(); - int getNumGlobals(); - RefRecord* mkClassInstance(int vtableOffset); - - // The standard calling convention is: - // - when a pointer is loaded from a local/global/field etc, and incr()ed - // (in other words, its presence on stack counts as a reference) - // - after a function call, all pointers are popped off the stack and decr()ed - // This does not apply to the RefRecord and st/ld(ref) methods - they unref() - // the RefRecord* this. - int incr(uint32_t e); - void decr(uint32_t e); - - inline void *ptrOfLiteral(int offset) - { - return &bytecode[offset]; - } - - inline ImageData* imageBytes(int offset) - { - return (ImageData*)(void*)&bytecode[offset]; - } - - // Checks if object has a VTable, or if its RefCounted* from the runtime. - inline bool hasVTable(uint32_t e) - { - return (*((uint32_t*)e) & 1) == 0; - } - - inline void check(int cond, ERROR code, int subcode = 0) - { - if (!cond) error(code, subcode); - } - - - class RefObject; -#ifdef DEBUG_MEMLEAKS - extern std::set allptrs; -#endif - - typedef void (*RefObjectMethod)(RefObject *self); - typedef void *PVoid; - typedef void **PPVoid; - - const PPVoid RefMapMarker = (PPVoid)(void*)43; - - struct VTable { - uint16_t numbytes; // in the entire object, including the vtable pointer - uint16_t userdata; - PVoid *ifaceTable; - PVoid methods[2]; // we only use up to two methods here; pxt will generate more - // refmask sits at &methods[nummethods] - }; - - const int vtableShift = 2; - - // A base abstract class for ref-counted objects. - class RefObject - { +class RefMImage : public RefObject { public: - uint16_t refcnt; - uint16_t vtable; + ImageData *img; - RefObject(uint16_t vt) - { - refcnt = 2; - vtable = vt; -#ifdef DEBUG_MEMLEAKS - allptrs.insert(this); -#endif - } + RefMImage(ImageData *d); + void makeWritable(); + static void destroy(RefMImage *map); + static void print(RefMImage *map); + static void scan(RefMImage *t); + static unsigned gcsize(RefMImage *t); +}; - inline VTable *getVTable() { - return (VTable*)(vtable << vtableShift); - } +#define MSTR(s) ManagedString((s)->getUTF8Data(), (s)->getUTF8Size()) - void destroy(); - void print(); - - // Call to disable pointer tracking on the current instance (in destructor or some other hack) - inline void untrack() { -#ifdef DEBUG_MEMLEAKS - allptrs.erase(this); -#endif - } - - // Increment/decrement the ref-count. Decrementing to zero deletes the current object. - inline void ref() - { - check(refcnt > 0, ERR_REF_DELETED); - //printf("INCR "); this->print(); - refcnt += 2; - } - - inline void unref() - { - //printf("DECR "); this->print(); - check(refcnt > 0, ERR_REF_DELETED); - refcnt -= 2; - if (refcnt == 0) { - destroy(); - } - } - }; - - class Segment { - private: - uint32_t* data; - uint16_t length; - uint16_t size; - - static const uint16_t MaxSize = 0xFFFF; - static const uint32_t DefaultValue = 0x0; - - static uint16_t growthFactor(uint16_t size); - void growByMin(uint16_t minSize); - void growBy(uint16_t newSize); - void ensure(uint16_t newSize); - - public: - Segment() : data (nullptr), length(0), size(0) {}; - - uint32_t get(uint32_t i); - void set(uint32_t i, uint32_t value); - - uint32_t getLength() { return length;}; - void setLength(uint32_t newLength); - - void push(uint32_t value); - uint32_t pop(); - - uint32_t remove(uint32_t i); - void insert(uint32_t i, uint32_t value); - - bool isValidIndex(uint32_t i); - - void destroy(); - - void print(); - }; - - // A ref-counted collection of either primitive or ref-counted objects (String, Image, - // user-defined record, another collection) - class RefCollection - : public RefObject - { - private: - Segment head; - public: - // 1 - collection of refs (need decr) - // 2 - collection of strings (in fact we always have 3, never 2 alone) - inline uint32_t getFlags() { return getVTable()->userdata; } - inline bool isRef() { return getFlags() & 1; } - inline bool isString() { return getFlags() & 2; } - - RefCollection(uint16_t f); - - void destroy(); - void print(); - - uint32_t length() { return head.getLength();} - void setLength(uint32_t newLength) { head.setLength(newLength); } - - void push(uint32_t x); - uint32_t pop(); - uint32_t getAt(int i); - void setAt(int i, uint32_t x); - //removes the element at index i and shifts the other elements left - uint32_t removeAt(int i); - //inserts the element at index i and moves the other elements right. - void insertAt(int i, uint32_t x); - - int indexOf(uint32_t x, int start); - int removeElement(uint32_t x); - }; - - struct MapEntry { - uint32_t key; - uint32_t val; - }; - - class RefMap - : public RefObject - { - public: - std::vector data; - - RefMap(); - void destroy(); - void print(); - int findIdx(uint32_t key); - }; - - // A ref-counted, user-defined JS object. - class RefRecord - : public RefObject - { - public: - // The object is allocated, so that there is space at the end for the fields. - uint32_t fields[]; - - RefRecord(uint16_t v) : RefObject(v) {} - - uint32_t ld(int idx); - uint32_t ldref(int idx); - void st(int idx, uint32_t v); - void stref(int idx, uint32_t v); - }; - - // these are needed when constructing vtables for user-defined classes - void RefRecord_destroy(RefRecord *r); - void RefRecord_print(RefRecord *r); - - class RefAction; - typedef uint32_t (*ActionCB)(uint32_t *captured, uint32_t arg0, uint32_t arg1, uint32_t arg2); - - // Ref-counted function pointer. It's currently always a ()=>void procedure pointer. - class RefAction - : public RefObject - { - public: - // This is the same as for RefRecord. - uint8_t len; - uint8_t reflen; - ActionCB func; // The function pointer - // fields[] contain captured locals - uint32_t fields[]; - - void destroy(); - void print(); - - RefAction(); - - inline void stCore(int idx, uint32_t v) - { - //printf("ST [%d] = %d ", idx, v); this->print(); - intcheck(0 <= idx && idx < len, ERR_OUT_OF_BOUNDS, 10); - intcheck(fields[idx] == 0, ERR_OUT_OF_BOUNDS, 11); // only one assignment permitted - fields[idx] = v; - } - - inline uint32_t runCore(int arg0, int arg1, int arg2) // internal; use runAction*() functions - { - this->ref(); - uint32_t r = this->func(&this->fields[0], arg0, arg1, arg2); - this->unref(); - return r; - } - }; - - // These two are used to represent locals written from inside inline functions - class RefLocal - : public RefObject - { - public: - uint32_t v; - void destroy(); - void print(); - RefLocal(); - }; - - class RefRefLocal - : public RefObject - { - public: - uint32_t v; - void destroy(); - void print(); - RefRefLocal(); - }; +static inline String PSTR(ManagedString s) { + return mkString(s.toCharArray(), s.length()); } -using namespace pxt; +typedef uint32_t ImageLiteral_; + +static inline ImageData *imageBytes(ImageLiteral_ lit) { + return (ImageData *)lit; +} + +typedef RefMImage *Image; + +extern MicroBit uBit; +extern MicroBitEvent lastEvent; + MicroBitPin *getPin(int id); -typedef ImageData* Image; -typedef BufferData* Buffer; -// The ARM Thumb generator in the JavaScript code is parsing -// the hex file and looks for the magic numbers as present here. -// -// Then it fetches function pointer addresses from there. - -#define PXT_SHIMS_BEGIN \ -namespace pxt { \ - const uint32_t functionsAndBytecode[] __attribute__((aligned(0x20))) = { \ - 0x08010801, 0x42424242, 0x08010801, 0x8de9d83e, +static inline int min_(int a, int b) { + if (a < b) + return a; + else + return b; +} -#define PXT_SHIMS_END }; } +static inline int max_(int a, int b) { + if (a > b) + return a; + else + return b; +} -#pragma GCC diagnostic ignored "-Wpmf-conversions" +void initMicrobitGC(); -#define PXT_VTABLE_TO_INT(vt) ((uint32_t)(vt) >> vtableShift) -#define PXT_VTABLE_BEGIN(classname, flags, iface) \ -const VTable classname ## _vtable \ - __attribute__((aligned(1 << vtableShift))) \ - = { \ - sizeof(classname), \ - flags, \ - iface, \ - { \ - (void*)&classname::destroy, \ - (void*)&classname::print, +} // namespace pxt -#define PXT_VTABLE_END } }; +using namespace pxt; -#define PXT_VTABLE_INIT(classname) \ - RefObject(PXT_VTABLE_TO_INT(&classname ## _vtable)) +#define DEVICE_EVT_ANY 0 -#define PXT_VTABLE_CTOR(classname) \ - PXT_VTABLE_BEGIN(classname, 0, 0) PXT_VTABLE_END \ - classname::classname() : PXT_VTABLE_INIT(classname) +#undef PXT_MAIN +#define PXT_MAIN \ + int main() { \ + pxt::initMicrobitGC(); \ + pxt::start(); \ + return 0; \ + } #endif diff --git a/libs/core/pxt.json b/libs/core/pxt.json index 45efd4f1..3f580965 100644 --- a/libs/core/pxt.json +++ b/libs/core/pxt.json @@ -1,41 +1,54 @@ { "name": "core", "description": "The microbit core library", - "installedVersion": "tsmdvf", + "additionalFilePath": "../../node_modules/pxt-common-packages/libs/base", "files": [ "README.md", - "ManagedBuffer.cpp", - "ManagedBuffer.h", + "platform.h", "pxt.cpp", "pxt.h", + "pxtbase.h", + "pxtcore.h", + "math.ts", "dal.d.ts", "enums.d.ts", "shims.d.ts", - "pxt-core.d.ts", + "pxt-core.d.ts", "core.cpp", "pxt-helpers.ts", "helpers.ts", + "configkeys.h", + "gc.cpp", + "codal.cpp", "images.cpp", "basic.cpp", "basic.ts", + "icons.ts", + "icons.jres", "input.cpp", "input.ts", + "gestures.jres", "control.ts", "control.cpp", + "console.ts", "game.ts", "led.cpp", "led.ts", "motors.cpp", "music.cpp", - "melodies.ts", "music.ts", + "melodies.ts", "pins.cpp", "pins.ts", "serial.cpp", "serial.ts", - "icons.ts", "buffer.cpp", + "buffer.ts", "pxtparts.json", + "advmath.cpp", + "trig.cpp", + "fixed.ts", + "templates.ts", "parts/speaker.svg", "parts/headphone.svg", "parts/dcmotor.svg", @@ -47,6 +60,7 @@ "yotta": { "optionalConfig": { "microbit-dal": { + "fiber_user_data": 1, "bluetooth": { "private_addressing": 0, "advertising_timeout": 0, @@ -59,9 +73,48 @@ "open": 0, "pairing_mode": 1, "whitelist": 1, - "security_level": "SECURITY_MODE_ENCRYPTION_NO_MITM" + "security_level": "SECURITY_MODE_ENCRYPTION_NO_MITM", + "partial_flashing": 1 } } - } + }, + "userConfigs": [ + { + "description": "No Pairing Required: Anyone can connect via Bluetooth.", + "config": { + "microbit-dal": { + "bluetooth": { + "open": 1, + "whitelist": 0, + "security_level": null + } + } + } + }, + { + "description": "JustWorks pairing (default): Pairing is automatic once the pairing is initiated.", + "config": { + "microbit-dal": { + "bluetooth": { + "open": 0, + "whitelist": 1, + "security_level": "SECURITY_MODE_ENCRYPTION_NO_MITM" + } + } + } + }, + { + "description": "Passkey pairing: Pairing requires 6 digit key to pair.", + "config": { + "microbit-dal": { + "bluetooth": { + "open": 0, + "whitelist": 1, + "security_level": "SECURITY_MODE_ENCRYPTION_WITH_MITM" + } + } + } + } + ] } -} \ No newline at end of file +} diff --git a/libs/core/pxtcore.h b/libs/core/pxtcore.h new file mode 100644 index 00000000..154171da --- /dev/null +++ b/libs/core/pxtcore.h @@ -0,0 +1,24 @@ +#ifndef __PXTCORE_H +#define __PXTCORE_H + +#include "MicroBit.h" +#include "MicroBitImage.h" +#include "ManagedString.h" +#include "ManagedType.h" + +namespace pxt { +void debuglog(const char *format, ...); +} + +// #define GC_GET_HEAP_SIZE() device_heap_size(0) +#define xmalloc malloc +#define xfree free + +#define GC_MAX_ALLOC_SIZE 9000 + +#define GC_BLOCK_SIZE 256 +#define NON_GC_HEAP_RESERVATION 1024 + +#define DMESG NOLOG + +#endif diff --git a/libs/core/pxtparts.json b/libs/core/pxtparts.json index 1a9d5cb4..470c7e2a 100644 --- a/libs/core/pxtparts.json +++ b/libs/core/pxtparts.json @@ -1,5 +1,5 @@ -{ - "buttonpair": { +{ + "buttonpair": { "simulationBehavior": "buttonpair", "visual": { "builtIn": "buttonpair", @@ -7,26 +7,66 @@ "height": 45, "pinDistance": 15, "pinLocations": [ - {"x": 0, "y": 0}, - {"x": 30, "y": 45}, - {"x": 45, "y": 0}, - {"x": 75, "y": 45} + { + "x": 0, + "y": 0 + }, + { + "x": 30, + "y": 45 + }, + { + "x": 45, + "y": 0 + }, + { + "x": 75, + "y": 45 + } ] }, "numberOfPins": 4, "pinDefinitions": [ - {"target": "P14", "style": "male", "orientation": "-Z"}, - {"target": "ground", "style": "male", "orientation": "-Z"}, - {"target": "P15", "style": "male", "orientation": "-Z"}, - {"target": "ground", "style": "male", "orientation": "-Z"} + { + "target": "P14", + "style": "male", + "orientation": "-Z" + }, + { + "target": "ground", + "style": "male", + "orientation": "-Z" + }, + { + "target": "P15", + "style": "male", + "orientation": "-Z" + }, + { + "target": "ground", + "style": "male", + "orientation": "-Z" + } ], "instantiation": { "kind": "singleton" }, "assembly": [ - {"part": true}, - {"pinIndices": [0, 1]}, - {"pinIndices": [2, 3]} + { + "part": true + }, + { + "pinIndices": [ + 0, + 1 + ] + }, + { + "pinIndices": [ + 2, + 3 + ] + } ] }, "microservo": { @@ -37,27 +77,65 @@ "height": 200, "pinDistance": 10, "pinLocations": [ - {"x": 30, "y": 5}, - {"x": 37, "y": 5}, - {"x": 45, "y": 5} + { + "x": 30, + "y": 5 + }, + { + "x": 37, + "y": 5 + }, + { + "x": 45, + "y": 5 + } ] }, "numberOfPins": 3, "pinDefinitions": [ - {"target": {"pinInstantiationIdx": 0}, "style": "croc", "orientation": "+Z"}, - {"target": "threeVolt", "style": "croc", "orientation": "+Z"}, - {"target": "ground", "style": "croc", "orientation": "+Z"} + { + "target": { + "pinInstantiationIdx": 0 + }, + "style": "croc", + "orientation": "+Z" + }, + { + "target": "threeVolt", + "style": "croc", + "orientation": "+Z" + }, + { + "target": "ground", + "style": "croc", + "orientation": "+Z" + } + ], + "instantiations": [ + { + "kind": "function", + "fullyQualifiedName": "pins.servoWritePin,pins.servoSetPulse,PwmOnlyPin.servoWrite,PwmOnlyPin.servoSetPulse,servos.Servo.setAngle,servos.Servo.run,servos.Servo.setPulse", + "argumentRoles": [ + { + "pinInstantiationIdx": 0, + "partParameter": "name" + } + ] + } ], - "instantiation": { - "kind": "function", - "fullyQualifiedName": "pins.servoWritePin", - "argumentRoles": [ - {"pinInstantiationIdx": 0, "partParameter": "name"} - ] - }, "assembly": [ - {"part": true, "pinIndices": [2]}, - {"pinIndices": [0, 1]} + { + "part": true, + "pinIndices": [ + 2 + ] + }, + { + "pinIndices": [ + 0, + 1 + ] + } ] }, "neopixel": { @@ -68,28 +146,66 @@ "height": 113, "pinDistance": 9, "pinLocations": [ - {"x": 10, "y": 0}, - {"x": 19, "y": 0}, - {"x": 28, "y": 0} + { + "x": 10, + "y": 0 + }, + { + "x": 19, + "y": 0 + }, + { + "x": 28, + "y": 0 + } ] }, "numberOfPins": 3, "pinDefinitions": [ - {"target": {"pinInstantiationIdx": 0}, "style": "solder", "orientation": "+Z"}, - {"target": "threeVolt", "style": "solder", "orientation": "+Z"}, - {"target": "ground", "style": "solder", "orientation": "+Z"} + { + "target": { + "pinInstantiationIdx": 0 + }, + "style": "solder", + "orientation": "+Z" + }, + { + "target": "threeVolt", + "style": "solder", + "orientation": "+Z" + }, + { + "target": "ground", + "style": "solder", + "orientation": "+Z" + } ], "instantiation": { "kind": "function", "fullyQualifiedName": "neopixel.create", "argumentRoles": [ - {"pinInstantiationIdx": 0, "partParameter": "pin"}, - {"partParameter": "mode"} + { + "pinInstantiationIdx": 0, + "partParameter": "pin" + }, + { + "partParameter": "mode" + } ] }, "assembly": [ - {"part": true, "pinIndices": [2]}, - {"pinIndices": [0, 1]} + { + "part": true, + "pinIndices": [ + 2 + ] + }, + { + "pinIndices": [ + 0, + 1 + ] + } ] }, "ledmatrix": { @@ -99,37 +215,137 @@ "height": 105, "pinDistance": 15, "pinLocations": [ - {"x": 0, "y": 0}, - {"x": 15, "y": 0}, - {"x": 30, "y": 0}, - {"x": 45, "y": 0}, - {"x": 105, "y": 105}, - {"x": 0, "y": 105}, - {"x": 15, "y": 105}, - {"x": 30, "y": 105}, - {"x": 45, "y": 105}, - {"x": 60, "y": 0} + { + "x": 0, + "y": 0 + }, + { + "x": 15, + "y": 0 + }, + { + "x": 30, + "y": 0 + }, + { + "x": 45, + "y": 0 + }, + { + "x": 105, + "y": 105 + }, + { + "x": 0, + "y": 105 + }, + { + "x": 15, + "y": 105 + }, + { + "x": 30, + "y": 105 + }, + { + "x": 45, + "y": 105 + }, + { + "x": 60, + "y": 0 + } ] }, "simulationBehavior": "ledmatrix", "numberOfPins": 10, - "instantiation": {"kind": "singleton"}, + "instantiation": { + "kind": "singleton" + }, "pinDefinitions": [ - {"target": "P6", "style": "male", "orientation": "-Z", "colorGroup": 0}, - {"target": "P7", "style": "male", "orientation": "-Z", "colorGroup": 0}, - {"target": "P8", "style": "male", "orientation": "-Z", "colorGroup": 0}, - {"target": "P9", "style": "male", "orientation": "-Z", "colorGroup": 0}, - {"target": "P10", "style": "male", "orientation": "-Z", "colorGroup": 0}, - {"target": "P12", "style": "male", "orientation": "-Z", "colorGroup": 1}, - {"target": "P13", "style": "male", "orientation": "-Z", "colorGroup": 1}, - {"target": "P16", "style": "male", "orientation": "-Z", "colorGroup": 1}, - {"target": "P19", "style": "male", "orientation": "-Z", "colorGroup": 1}, - {"target": "P20", "style": "male", "orientation": "-Z", "colorGroup": 1} + { + "target": "P6", + "style": "male", + "orientation": "-Z", + "colorGroup": 0 + }, + { + "target": "P7", + "style": "male", + "orientation": "-Z", + "colorGroup": 0 + }, + { + "target": "P8", + "style": "male", + "orientation": "-Z", + "colorGroup": 0 + }, + { + "target": "P9", + "style": "male", + "orientation": "-Z", + "colorGroup": 0 + }, + { + "target": "P10", + "style": "male", + "orientation": "-Z", + "colorGroup": 0 + }, + { + "target": "P12", + "style": "male", + "orientation": "-Z", + "colorGroup": 1 + }, + { + "target": "P13", + "style": "male", + "orientation": "-Z", + "colorGroup": 1 + }, + { + "target": "P16", + "style": "male", + "orientation": "-Z", + "colorGroup": 1 + }, + { + "target": "P19", + "style": "male", + "orientation": "-Z", + "colorGroup": 1 + }, + { + "target": "P20", + "style": "male", + "orientation": "-Z", + "colorGroup": 1 + } ], "assembly": [ - {"part": true}, - {"pinIndices": [0, 1, 2, 3, 4]}, - {"pinIndices": [5, 6, 7, 8, 9]} + { + "part": true + }, + { + "pinIndices": [ + 0, + 1, + 2, + 3, + 4 + ] + }, + { + "pinIndices": [ + 5, + 6, + 7, + 8, + 9 + ] + } ] }, "headphone": { @@ -140,18 +356,43 @@ "height": 180, "pinDistance": 20, "pinLocations": [ - {"x": 17, "y": 11}, - {"x": 55, "y": 50} + { + "x": 17, + "y": 11 + }, + { + "x": 55, + "y": 50 + } ] }, "pinDefinitions": [ - {"target": "P0", "style": "croc", "orientation": "Y"}, - {"target": "ground", "style": "croc", "orientation": "Y"} + { + "target": "P0", + "style": "croc", + "orientation": "Y" + }, + { + "target": "ground", + "style": "croc", + "orientation": "Y" + } ], - "instantiation": {"kind": "singleton"}, + "instantiation": { + "kind": "singleton" + }, "assembly": [ - {"part": true, "pinIndices": [0]}, - {"pinIndices": [1]} + { + "part": true, + "pinIndices": [ + 0 + ] + }, + { + "pinIndices": [ + 1 + ] + } ] }, "speaker": { @@ -162,39 +403,43 @@ "height": 500, "pinDistance": 70, "pinLocations": [ - {"x": 180, "y": 135}, - {"x": 320, "y": 135} + { + "x": 180, + "y": 135 + }, + { + "x": 320, + "y": 135 + } ] }, "pinDefinitions": [ - {"target": "P0", "style": "male", "orientation": "-Z"}, - {"target": "ground", "style": "male", "orientation": "-Z"} + { + "target": "P0", + "style": "male", + "orientation": "-Z" + }, + { + "target": "ground", + "style": "male", + "orientation": "-Z" + } ], - "instantiation": {"kind": "singleton"}, - "assembly": [ - {"part": true, "pinIndices": [0]}, - {"pinIndices": [1]} - ] - }, - "dcmotor": { - "numberOfPins": 2, - "visual": { - "image": "parts/dcmotor.svg", - "width": 488, - "height": 836, - "pinDistance": 65, - "pinLocations": [ - {"x": 89, "y": 48}, - {"x": 393, "y": 48} ] + "instantiation": { + "kind": "singleton" }, - "pinDefinitions": [ - { "target": "M_OUT1", "style": "croc", "orientation": "-Z"}, - { "target": "M_OUT2", "style": "croc", "orientation": "-Z"} - ], - "instantiation": {"kind": "singleton"}, "assembly": [ - {"part": true, "pinIndices": [0]}, - {"pinIndices": [1]} + { + "part": true, + "pinIndices": [ + 0 + ] + }, + { + "pinIndices": [ + 1 + ] + } ] - } + } } \ No newline at end of file diff --git a/libs/core/serial.cpp b/libs/core/serial.cpp index 512f3912..656213b7 100644 --- a/libs/core/serial.cpp +++ b/libs/core/serial.cpp @@ -1,21 +1,45 @@ #include "pxt.h" +#define MICROBIT_SERIAL_READ_BUFFER_LENGTH 64 + +// make sure USB_TX and USB_RX don't overlap with other pin ids enum SerialPin { - C16 = MICROBIT_ID_IO_P2, - C17 = MICROBIT_ID_IO_P8, - P0 = MICROBIT_ID_IO_P12, - P1 = MICROBIT_ID_IO_P0, - P2 = MICROBIT_ID_IO_P1, - P3 = MICROBIT_ID_IO_P16, + P0 = MICROBIT_ID_IO_P0, + P1 = MICROBIT_ID_IO_P1, + P2 = MICROBIT_ID_IO_P2, + P8 = MICROBIT_ID_IO_P8, + P12 = MICROBIT_ID_IO_P12, + P13 = MICROBIT_ID_IO_P13, + P14 = MICROBIT_ID_IO_P14, + P15 = MICROBIT_ID_IO_P15, + P16 = MICROBIT_ID_IO_P16, + USB_TX = 1001, + USB_RX = 1002 }; enum BaudRate { //% block=115200 BaudRate115200 = 115200, //% block=57600 - BaudRate56700 = 57600, + BaudRate57600 = 57600, + //% block=38400 + BaudRate38400 = 38400, + //% block=31250 + BaudRate31250 = 31250, + //% block=28800 + BaudRate28800 = 28800, + //% block=19200 + BaudRate19200 = 19200, + //% block=14400 + BaudRate14400 = 14400, //% block=9600 - BaudRate9600 = 9600 + BaudRate9600 = 9600, + //% block=4800 + BaudRate4800 = 4800, + //% block=2400 + BaudRate2400 = 2400, + //% block=1200 + BaudRate1200 = 1200 }; enum Delimiters { @@ -33,71 +57,158 @@ enum Delimiters { Hash = 6, }; -//% weight=2 color=30 +//% weight=2 color=#002050 icon="\uf287" //% advanced=true namespace serial { // note that at least one // followed by % is needed per declaration! /** - * Reads a line of text from the serial port and returns the buffer when the delimiter is met. + * Read a line of text from the serial port and return the buffer when the delimiter is met. * @param delimiter text delimiter that separates each text chunk */ //% help=serial/read-until //% blockId=serial_read_until block="serial|read until %delimiter=serial_delimiter_conv" //% weight=19 - StringData* readUntil(StringData* delimiter) { - return uBit.serial.readUntil(ManagedString(delimiter)).leakData(); + String readUntil(String delimiter) { + return PSTR(uBit.serial.readUntil(MSTR(delimiter))); } /** - * Reads the buffered received data as a string + * Read the buffered received data as a string */ + //% help=serial/read-string //% blockId=serial_read_buffer block="serial|read string" //% weight=18 - StringData* readString() { + String readString() { int n = uBit.serial.getRxBufferSize(); - if (n == 0) return ManagedString("").leakData(); - return ManagedString(uBit.serial.read(n, MicroBitSerialMode::ASYNC)).leakData(); + if (n == 0) return mkString("", 0); + return PSTR(uBit.serial.read(n, MicroBitSerialMode::ASYNC)); } /** - * Registers an event to be fired when one of the delimiter is matched. + * Register an event to be fired when one of the delimiter is matched. * @param delimiters the characters to match received characters against. */ //% help=serial/on-data-received //% weight=18 blockId=serial_on_data_received block="serial|on data received %delimiters=serial_delimiter_conv" - void onDataReceived(StringData* delimiters, Action body) { - uBit.serial.eventOn(ManagedString(delimiters)); + void onDataReceived(String delimiters, Action body) { + uBit.serial.eventOn(MSTR(delimiters)); registerWithDal(MICROBIT_ID_SERIAL, MICROBIT_SERIAL_EVT_DELIM_MATCH, body); // lazy initialization of serial buffers uBit.serial.read(MicroBitSerialMode::ASYNC); } /** - * Sends a piece of text through Serial connection. + * Send a piece of text through the serial connection. */ //% help=serial/write-string - //% weight=87 + //% weight=87 blockGap=8 //% blockId=serial_writestring block="serial|write string %text" - void writeString(StringData *text) { - uBit.serial.send(ManagedString(text)); + //% text.shadowOptions.toString=true + void writeString(String text) { + if (!text) return; + + uBit.serial.send(MSTR(text)); } /** - * Dynamically configuring the serial instance to use pins other than USBTX and USBRX. - * @param tx the new transmission pins, eg: SerialPin.P0 + * Send a buffer through serial connection + */ + //% blockId=serial_writebuffer block="serial|write buffer %buffer=serial_readbuffer" + //% help=serial/write-buffer advanced=true weight=6 + void writeBuffer(Buffer buffer) { + if (!buffer) return; + + uBit.serial.send(buffer->data, buffer->length); + } + + /** + * Read multiple characters from the receive buffer. Pause until enough characters are present. + * @param length default buffer length, eg: 64 + */ + //% blockId=serial_readbuffer block="serial|read buffer %length" + //% help=serial/read-buffer advanced=true weight=5 + Buffer readBuffer(int length) { + if (length <= 0) + length = MICROBIT_SERIAL_READ_BUFFER_LENGTH; + + auto buf = mkBuffer(NULL, length); + int read = uBit.serial.read(buf->data, buf->length); + if (read != length) { + auto prev = buf; + buf = mkBuffer(buf->data, read); + decrRC(prev); + } + + return buf; + } + + bool tryResolvePin(SerialPin p, PinName& name) { + switch(p) { + case SerialPin::USB_TX: name = USBTX; return true; + case SerialPin::USB_RX: name = USBRX; return true; + default: + auto pin = getPin(p); + if (NULL != pin) { + name = pin->name; + return true; + } + } + return false; + } + + /** + * Set the serial input and output to use pins instead of the USB connection. + * @param tx the new transmission pin, eg: SerialPin.P0 * @param rx the new reception pin, eg: SerialPin.P1 * @param rate the new baud rate. eg: 115200 */ //% weight=10 - //% help=serial/redirect-to + //% help=serial/redirect //% blockId=serial_redirect block="serial|redirect to|TX %tx|RX %rx|at baud rate %rate" //% blockExternalInputs=1 + //% tx.fieldEditor="gridpicker" tx.fieldOptions.columns=3 + //% tx.fieldOptions.tooltips="false" + //% rx.fieldEditor="gridpicker" rx.fieldOptions.columns=3 + //% rx.fieldOptions.tooltips="false" + //% blockGap=8 void redirect(SerialPin tx, SerialPin rx, BaudRate rate) { - MicroBitPin* txp = getPin(tx); if (!tx) return; - MicroBitPin* rxp = getPin(rx); if (!rx) return; - - uBit.serial.redirect(txp->name, rxp->name); + PinName txn; + PinName rxn; + if (tryResolvePin(tx, txn) && tryResolvePin(rx, rxn)) + uBit.serial.redirect(txn, rxn); uBit.serial.baud((int)rate); } + + /** + * Direct the serial input and output to use the USB connection. + */ + //% weight=9 help=serial/redirect-to-usb + //% blockId=serial_redirect_to_usb block="serial|redirect to USB" + void redirectToUSB() { + uBit.serial.redirect(USBTX, USBRX); + uBit.serial.baud(115200); + } + + /** + * Sets the size of the RX buffer in bytes + * @param size length of the rx buffer in bytes, eg: 32 + */ + //% help=serial/set-rx-buffer-size + //% blockId=serialSetRxBufferSize block="serial set rx buffer size to $size" + //% advanced=true + void setRxBufferSize(uint8_t size) { + uBit.serial.setRxBufferSize(size); + } + + /** + * Sets the size of the TX buffer in bytes + * @param size length of the tx buffer in bytes, eg: 32 + */ + //% help=serial/set-tx-buffer-size + //% blockId=serialSetTxBufferSize block="serial set tx buffer size to $size" + //% advanced=true + void setTxBufferSize(uint8_t size) { + uBit.serial.setTxBufferSize(size); + } } diff --git a/libs/core/serial.ts b/libs/core/serial.ts index fbcdc1fc..c98944d1 100644 --- a/libs/core/serial.ts +++ b/libs/core/serial.ts @@ -5,18 +5,48 @@ //% advanced=true namespace serial { /** - * Prints a line of text to the serial + * The string used to mark a new line, default is \r\n + */ + export let NEW_LINE = "\r\n"; + let writeLinePadding = 32; + + /** + * Print a line of text to the serial port * @param value to send over serial */ //% weight=90 //% help=serial/write-line blockGap=8 //% blockId=serial_writeline block="serial|write line %text" + //% text.shadowOptions.toString=true export function writeLine(text: string): void { - writeString(text + "\r\n"); + if (!text) text = ""; + serial.writeString(text); + // pad data to the 32 byte boundary + // to ensure apps receive the packet + if (writeLinePadding > 0) { + let r = (writeLinePadding - (text.length + NEW_LINE.length) % writeLinePadding) % writeLinePadding; + for (let i = 0; i < r; ++i) + serial.writeString(" "); + } + serial.writeString(NEW_LINE); } /** - * Prints a numeric value to the serial + * Sets the padding length for lines sent with "write line". + * @param length the number of bytes alignment, eg: 0 + * + */ + //% weight=1 + //% help=serial/set-write-line-padding + //% blockId=serialWriteNewLinePadding block="serial set write line padding to $length" + //% advanced=true + //% length.min=0 length.max=128 + export function setWriteLinePadding(length: number) { + writeLinePadding = length | 0; + } + + /** + * Print a numeric value to the serial port */ //% help=serial/write-number //% weight=89 blockGap=8 @@ -26,7 +56,22 @@ namespace serial { } /** - * Writes a ``name: value`` pair line to the serial. + * Print an array of numeric values as CSV to the serial port + */ + //% help=serial/write-numbers + //% weight=86 + //% blockId=serial_writenumbers block="serial|write numbers %values" + export function writeNumbers(values: number[]): void { + if (!values) return; + for (let i = 0; i < values.length; ++i) { + if (i > 0) writeString(","); + writeNumber(values[i]); + } + writeLine("") + } + + /** + * Write a name:value pair as a line to the serial port. * @param name name of the value stream, eg: x * @param value to write */ @@ -34,11 +79,11 @@ namespace serial { //% help=serial/write-value //% blockId=serial_writevalue block="serial|write value %name|= %value" export function writeValue(name: string, value: number): void { - writeString(name + ":" + value + "\r\n"); + writeLine((name ? name + ":" : "") + value); } /** - * Reads a line of text from the serial port. + * Read a line of text from the serial port. */ //% help=serial/read-line //% blockId=serial_read_line block="serial|read line" @@ -48,14 +93,14 @@ namespace serial { } /** - * Returns the delimiter corresponding string + * Return the corresponding delimiter string */ //% blockId="serial_delimiter_conv" block="%del" //% weight=1 blockHidden=true export function delimiters(del: Delimiters): string { // even though it might not look like, this is more // (memory) efficient than the C++ implementation, because the - // strings are statically allocated and take no RAM + // strings are statically allocated and take no RAM switch (del) { case Delimiters.NewLine: return "\n" case Delimiters.Comma: return "," diff --git a/libs/core/shims.d.ts b/libs/core/shims.d.ts index 6bc77d2f..70d6f4c2 100644 --- a/libs/core/shims.d.ts +++ b/libs/core/shims.d.ts @@ -4,7 +4,7 @@ /** * Creation, manipulation and display of LED images. */ - //% color=#5C2D91 weight=31 icon="\uf03e" + //% color=#7600A8 weight=31 icon="\uf03e" //% advanced=true declare namespace images { @@ -32,16 +32,16 @@ declare interface Image { */ //% help=images/plot-image //% parts="ledmatrix" xOffset.defl=0 shim=ImageMethods::plotImage - plotImage(xOffset?: number): void; + plotImage(xOffset?: int32): void; /** * Shows an frame from the image at offset ``x offset``. * @param xOffset column index to start displaying the image */ //% help=images/show-image weight=80 blockNamespace=images - //% blockId=device_show_image_offset block="show image %sprite|at offset %offset" blockGap=8 - //% parts="ledmatrix" async interval.defl=400 shim=ImageMethods::showImage - showImage(xOffset: number, interval?: number): void; + //% blockId=device_show_image_offset block="show image %sprite(myImage)|at offset %offset" + //% blockGap=8 parts="ledmatrix" async interval.defl=400 shim=ImageMethods::showImage + showImage(xOffset: int32, interval?: int32): void; /** * Draws the ``index``-th frame of the image on the screen. @@ -49,7 +49,7 @@ declare interface Image { */ //% help=images/plot-frame weight=80 //% parts="ledmatrix" shim=ImageMethods::plotFrame - plotFrame(xOffset: number): void; + plotFrame(xOffset: int32): void; /** * Scrolls an image . @@ -57,9 +57,10 @@ declare interface Image { * @param interval time between each animation step in milli seconds, eg: 200 */ //% help=images/scroll-image weight=79 async blockNamespace=images - //% blockId=device_scroll_image block="scroll image %sprite|with offset %frameoffset|and interval (ms) %delay" blockGap=8 - //% parts="ledmatrix" shim=ImageMethods::scrollImage - scrollImage(frameOffset: number, interval: number): void; + //% blockId=device_scroll_image + //% block="scroll image %sprite(myImage)|with offset %frameoffset|and interval (ms) %delay" + //% blockGap=8 parts="ledmatrix" shim=ImageMethods::scrollImage + scrollImage(frameOffset: int32, interval: int32): void; /** * Sets all pixels off. @@ -73,79 +74,76 @@ declare interface Image { */ //% //% parts="ledmatrix" shim=ImageMethods::setPixelBrightness - setPixelBrightness(x: number, y: number, value: number): void; + setPixelBrightness(x: int32, y: int32, value: int32): void; /** * Gets the pixel brightness ([0..255]) at a given position */ //% //% parts="ledmatrix" shim=ImageMethods::pixelBrightness - pixelBrightness(x: number, y: number): number; + pixelBrightness(x: int32, y: int32): int32; /** * Gets the width in columns */ //% help=functions/width shim=ImageMethods::width - width(): number; + width(): int32; /** * Gets the height in rows (always 5) */ //% shim=ImageMethods::height - height(): number; + height(): int32; /** * Set a pixel state at position ``(x,y)`` - * @param x TODO - * @param y TODO - * @param value TODO + * @param x pixel column + * @param y pixel row + * @param value pixel state */ //% help=images/set-pixel //% parts="ledmatrix" shim=ImageMethods::setPixel - setPixel(x: number, y: number, value: boolean): void; + setPixel(x: int32, y: int32, value: boolean): void; /** * Get the pixel state at position ``(x,y)`` - * @param x TODO - * @param y TODO + * @param x pixel column + * @param y pixel row */ //% help=images/pixel //% parts="ledmatrix" shim=ImageMethods::pixel - pixel(x: number, y: number): boolean; + pixel(x: int32, y: int32): boolean; /** - * Shows a particular frame of the image strip. - * @param frame TODO + * Show a particular frame of the image strip. + * @param frame image frame to show */ //% weight=70 help=images/show-frame //% parts="ledmatrix" interval.defl=400 shim=ImageMethods::showFrame - showFrame(frame: number, interval?: number): void; + showFrame(frame: int32, interval?: int32): void; } /** * Provides access to basic micro:bit functionality. */ - //% color=#54C9C9 weight=100 icon="\uf00a" + //% color=#1E90FF weight=116 icon="\uf00a" declare namespace basic { /** * Sets the color on the build-in LED. Set to 0 to turn off. */ - //% blockId=device_set_led_color block="set led to %color=color_id" + //% blockId=device_set_led_color + //% block="set led to %color=colorNumberPicker" //% weight=50 shim=basic::setLedColor - function setLedColor(color: number): void; + function setLedColor(color: int32): void; /** - * Scroll a number on the screen. If the number fits on the screen (i.e. is a single digit), do not scroll. - * @param interval speed of scroll; eg: 150, 100, 200, -100 + * Sets the color on the build-in LED. Set to 0 to turn off. */ - //% help=basic/show-number - //% weight=96 - //% blockId=device_show_number block="show|number %number" blockGap=8 - //% async - //% parts="ledmatrix" interval.defl=150 shim=basic::showNumber - function showNumber(value: number, interval?: number): void; + //% blockId=device_turn_rgb_led_off block="turn build-in LED off" + //% weight=50 shim=basic::turnRgbLedOff + function turnRgbLedOff(): void; /** * Draws an image on the LED screen. @@ -158,20 +156,21 @@ declare namespace basic { //% blockId=device_show_leds //% block="show leds" icon="\uf00a" //% parts="ledmatrix" interval.defl=400 shim=basic::showLeds - function showLeds(leds: string, interval?: number): void; + function showLeds(leds: string, interval?: int32): void; /** * Display text on the display, one character at a time. If the string fits on the screen (i.e. is one letter), does not scroll. - * @param text the text to scroll on the screen, eg: "Hello!" + * @param text the text to scroll on the screen, eg: "hi!" * @param interval how fast to shift characters; eg: 150, 100, 200, -100 */ //% help=basic/show-string - //% weight=87 blockGap=8 + //% weight=87 blockGap=16 //% block="show|string %text" //% async //% blockId=device_print_message - //% parts="ledmatrix" interval.defl=150 shim=basic::showString - function showString(text: string, interval?: number): void; + //% parts="ledmatrix" + //% text.shadowOptions.toString=true interval.defl=150 shim=basic::showString + function showString(text: string, interval?: int32): void; /** * Turn off all LEDs @@ -189,7 +188,7 @@ declare namespace basic { */ //% help=basic/show-animation imageLiteral=1 async //% parts="ledmatrix" interval.defl=400 shim=basic::showAnimation - function showAnimation(leds: string, interval?: number): void; + function showAnimation(leds: string, interval?: int32): void; /** * Draws an image on the LED screen. @@ -203,7 +202,7 @@ declare namespace basic { * Repeats the code forever in the background. On each iteration, allows other codes to run. * @param body code to execute */ - //% help=basic/forever weight=55 blockGap=8 blockAllowMultiple=1 afterOnStart=true + //% help=basic/forever weight=55 blockGap=16 blockAllowMultiple=1 afterOnStart=true //% blockId=device_forever block="forever" icon="\uf01e" shim=basic::forever function forever(a: () => void): void; @@ -212,9 +211,10 @@ declare namespace basic { * @param ms how long to pause for, eg: 100, 200, 500, 1000, 2000 */ //% help=basic/pause weight=54 - //% async block="pause (ms) %pause" - //% blockId=device_pause icon="\uf110" shim=basic::pause - function pause(ms: number): void; + //% async block="pause (ms) %pause" blockGap=16 + //% blockId=device_pause icon="\uf110" + //% pause.shadow=timePicker shim=basic::pause + function pause(ms: int32): void; } @@ -227,7 +227,7 @@ declare namespace input { * @param button the button that needs to be pressed * @param body code to run when event is raised */ - //% help=input/on-button-pressed weight=85 blockGap=8 + //% help=input/on-button-pressed weight=85 blockGap=16 //% blockId=device_button_event block="on button|%NAME|pressed" //% parts="buttonpair" shim=input::onButtonPressed function onButtonPressed(button: Button, body: () => void): void; @@ -237,18 +237,28 @@ declare namespace input { * @param gesture the type of gesture to track, eg: Gesture.Shake * @param body code to run when gesture is raised */ - //% help=input/on-gesture weight=84 blockGap=8 + //% help=input/on-gesture weight=84 blockGap=16 //% blockId=device_gesture_event block="on |%NAME" //% parts="accelerometer" - //% NAME.fieldEditor="gridpicker" NAME.fieldOptions.columns=4 shim=input::onGesture + //% NAME.fieldEditor="gestures" NAME.fieldOptions.columns=4 shim=input::onGesture function onGesture(gesture: Gesture, body: () => void): void; + /** + * Tests if a gesture is currently detected. + * @param gesture the type of gesture to detect, eg: Gesture.Shake + */ + //% help=input/is-gesture weight=10 blockGap=8 + //% blockId=deviceisgesture block="is %gesture gesture" + //% parts="accelerometer" + //% gesture.fieldEditor="gestures" gesture.fieldOptions.columns=4 shim=input::isGesture + function isGesture(gesture: Gesture): boolean; + /** * Do something when a pin is touched and released again (while also touching the GND pin). * @param name the pin that needs to be pressed, eg: TouchPin.P0 * @param body the code to run when the pin is pressed */ - //% help=input/on-pin-pressed weight=83 + //% help=input/on-pin-pressed weight=83 blockGap=32 //% blockId=device_pin_event block="on pin %name|pressed" shim=input::onPinPressed function onPinPressed(name: TouchPin, body: () => void): void; @@ -257,7 +267,7 @@ declare namespace input { * @param name the pin that needs to be released, eg: TouchPin.P0 * @param body the code to run when the pin is released */ - //% help=input/on-pin-released weight=6 blockGap=8 + //% help=input/on-pin-released weight=6 blockGap=16 //% blockId=device_pin_released block="on pin %NAME|released" //% advanced=true shim=input::onPinReleased function onPinReleased(name: TouchPin, body: () => void): void; @@ -269,7 +279,7 @@ declare namespace input { //% help=input/button-is-pressed weight=60 //% block="button|%NAME|is pressed" //% blockId=device_get_button2 - //% blockGap=8 + //% icon="\uf192" blockGap=8 //% parts="buttonpair" shim=input::buttonIsPressed function buttonIsPressed(button: Button): boolean; @@ -284,12 +294,12 @@ declare namespace input { /** * Get the acceleration value in milli-gravitys (when the board is laying flat with the screen up, x=0, y=0 and z=-1024) - * @param dimension TODO + * @param dimension x, y, or z dimension, eg: Dimension.X */ //% help=input/acceleration weight=58 //% blockId=device_acceleration block="acceleration (mg)|%NAME" blockGap=8 //% parts="accelerometer" shim=input::acceleration - function acceleration(dimension: Dimension): number; + function acceleration(dimension: Dimension): int32; /** * Reads the light level applied to the LED screen in a range from ``0`` (dark) to ``255`` bright. @@ -297,7 +307,7 @@ declare namespace input { //% help=input/light-level weight=57 //% blockId=device_get_light_level block="light level" blockGap=8 //% parts="ledmatrix" shim=input::lightLevel - function lightLevel(): number; + function lightLevel(): int32; /** * Get the current compass heading in degrees. @@ -306,7 +316,7 @@ declare namespace input { //% weight=56 //% blockId=device_heading block="compass heading (°)" blockGap=8 //% parts="compass" shim=input::compassHeading - function compassHeading(): number; + function compassHeading(): int32; /** * Gets the temperature in Celsius degrees (°C). @@ -315,26 +325,26 @@ declare namespace input { //% help=input/temperature //% blockId=device_temperature block="temperature (°C)" blockGap=8 //% parts="thermometer" shim=input::temperature - function temperature(): number; + function temperature(): int32; /** * The pitch or roll of the device, rotation along the ``x-axis`` or ``y-axis``, in degrees. - * @param kind TODO + * @param kind pitch or roll */ //% help=input/rotation weight=52 //% blockId=device_get_rotation block="rotation (°)|%NAME" blockGap=8 //% parts="accelerometer" advanced=true shim=input::rotation - function rotation(kind: Rotation): number; + function rotation(kind: Rotation): int32; /** * Get the magnetic force value in ``micro-Teslas`` (``µT``). This function is not supported in the simulator. - * @param dimension TODO + * @param dimension the x, y, or z dimension, eg: Dimension.X */ //% help=input/magnetic-force weight=51 //% blockId=device_get_magnetic_force block="magnetic force (µT)|%NAME" blockGap=8 //% parts="compass" //% advanced=true shim=input::magneticForce - function magneticForce(dimension: Dimension): number; + function magneticForce(dimension: Dimension): int32; /** * Gets the number of milliseconds elapsed since power on. @@ -342,7 +352,7 @@ declare namespace input { //% help=input/running-time weight=50 blockGap=8 //% blockId=device_get_running_time block="running time (ms)" //% advanced=true shim=input::runningTime - function runningTime(): number; + function runningTime(): int32; /** * Gets the number of microseconds elapsed since power on. @@ -350,13 +360,14 @@ declare namespace input { //% help=input/running-time-micros weight=49 //% blockId=device_get_running_time_micros block="running time (micros)" //% advanced=true shim=input::runningTimeMicros - function runningTimeMicros(): number; + function runningTimeMicros(): int32; /** * Obsolete, compass calibration is automatic. */ //% help=input/calibrate-compass advanced=true - //% blockId="input_compass_calibrate" block="calibrate compass" shim=input::calibrateCompass + //% blockId="input_compass_calibrate" block="calibrate compass" + //% weight=45 shim=input::calibrateCompass function calibrateCompass(): void; /** @@ -397,7 +408,7 @@ declare namespace control { */ //% help=control/wait-micros weight=29 //% blockId="control_wait_us" block="wait (µs)%micros" shim=control::waitMicros - function waitMicros(micros: number): void; + function waitMicros(micros: int32): void; /** * Raises an event in the event bus. @@ -408,15 +419,15 @@ declare namespace control { //% weight=21 blockGap=12 blockId="control_raise_event" block="raise event|from source %src=control_event_source_id|with value %value=control_event_value_id" blockExternalInputs=1 //% help=control/raise-event //% mode.defl=1 shim=control::raiseEvent - function raiseEvent(src: number, value: number, mode?: EventCreationMode): void; + function raiseEvent(src: int32, value: int32, mode?: EventCreationMode): void; /** - * Raises an event in the event bus. + * Registers an event handler. */ //% weight=20 blockGap=8 blockId="control_on_event" block="on event|from %src=control_event_source_id|with value %value=control_event_value_id" //% help=control/on-event - //% blockExternalInputs=1 shim=control::onEvent - function onEvent(src: number, value: number, handler: () => void): void; + //% blockExternalInputs=1 flags.defl=0 shim=control::onEvent + function onEvent(src: int32, value: int32, handler: () => void, flags?: int32): void; /** * Gets the value of the last event executed on the bus @@ -424,7 +435,7 @@ declare namespace control { //% blockId=control_event_value" block="event value" //% help=control/event-value //% weight=18 shim=control::eventValue - function eventValue(): number; + function eventValue(): int32; /** * Gets the timestamp of the last event executed on the bus @@ -432,10 +443,10 @@ declare namespace control { //% blockId=control_event_timestamp" block="event timestamp" //% help=control/event-timestamp //% weight=19 blockGap=8 shim=control::eventTimestamp - function eventTimestamp(): number; + function eventTimestamp(): int32; /** - * Gets a friendly name for the device derived from the its serial number + * Make a friendly name for the device based on its serial number */ //% blockId="control_device_name" block="device name" weight=10 blockGap=8 //% advanced=true shim=control::deviceName @@ -446,7 +457,20 @@ declare namespace control { */ //% blockId="control_device_serial_number" block="device serial number" weight=9 //% advanced=true shim=control::deviceSerialNumber - function deviceSerialNumber(): number; + function deviceSerialNumber(): int32; + + /** + * Informs simulator/runtime of a MIDI message + * Internal function to support the simulator. + */ + //% part=midioutput blockHidden=1 shim=control::__midiSend + function __midiSend(buffer: Buffer): void; + + /** + * + */ + //% shim=control::__log + function __log(text: string): void; } @@ -462,8 +486,9 @@ declare namespace led { //% help=led/plot weight=78 //% blockId=device_plot block="plot|x %x|y %y" blockGap=8 //% parts="ledmatrix" - //% x.min=0 x.max=4 y.min=0 y.max=4 shim=led::plot - function plot(x: number, y: number): void; + //% x.min=0 x.max=4 y.min=0 y.max=4 + //% x.fieldOptions.precision=1 y.fieldOptions.precision=1 shim=led::plot + function plot(x: int32, y: int32): void; /** * Turn on the specified LED with specific brightness using x, y coordinates (x is horizontal, y is vertical). (0,0) is upper left. @@ -475,30 +500,33 @@ declare namespace led { //% blockId=device_plot_brightness block="plot|x %x|y %y|brightness %brightness" blockGap=8 //% parts="ledmatrix" //% x.min=0 x.max=4 y.min=0 y.max=4 brightness.min=0 brightness.max=255 + //% x.fieldOptions.precision=1 y.fieldOptions.precision=1 //% advanced=true shim=led::plotBrightness - function plotBrightness(x: number, y: number, brightness: number): void; + function plotBrightness(x: int32, y: int32, brightness: int32): void; /** * Turn off the specified LED using x, y coordinates (x is horizontal, y is vertical). (0,0) is upper left. - * @param x TODO - * @param y TODO + * @param x the horizontal coordinate of the LED + * @param y the vertical coordinate of the LED */ //% help=led/unplot weight=77 //% blockId=device_unplot block="unplot|x %x|y %y" blockGap=8 //% parts="ledmatrix" - //% x.min=0 x.max=4 y.min=0 y.max=4 shim=led::unplot - function unplot(x: number, y: number): void; + //% x.min=0 x.max=4 y.min=0 y.max=4 + //% x.fieldOptions.precision=1 y.fieldOptions.precision=1 shim=led::unplot + function unplot(x: int32, y: int32): void; /** * Get the on/off state of the specified LED using x, y coordinates. (0,0) is upper left. - * @param x TODO - * @param y TODO + * @param x the horizontal coordinate of the LED + * @param y the vertical coordinate of the LED */ //% help=led/point weight=76 //% blockId=device_point block="point|x %x|y %y" //% parts="ledmatrix" - //% x.min=0 x.max=4 y.min=0 y.max=4 shim=led::point - function point(x: number, y: number): boolean; + //% x.min=0 x.max=4 y.min=0 y.max=4 + //% x.fieldOptions.precision=1 y.fieldOptions.precision=1 shim=led::point + function point(x: int32, y: int32): boolean; /** * Get the screen brightness from 0 (off) to 255 (full bright). @@ -507,7 +535,7 @@ declare namespace led { //% blockId=device_get_brightness block="brightness" blockGap=8 //% parts="ledmatrix" //% advanced=true shim=led::brightness - function brightness(): number; + function brightness(): int32; /** * Set the screen brightness from 0 (off) to 255 (full bright). @@ -518,7 +546,7 @@ declare namespace led { //% parts="ledmatrix" //% advanced=true //% value.min=0 value.max=255 shim=led::setBrightness - function setBrightness(value: number): void; + function setBrightness(value: int32): void; /** * Cancels the current animation and clears other pending animations. @@ -534,7 +562,8 @@ declare namespace led { * @param mode mode the display mode in which the screen operates */ //% weight=1 help=led/set-display-mode - //% parts="ledmatrix" advanced=true shim=led::setDisplayMode + //% parts="ledmatrix" advanced=true weight=1 + //% blockId="led_set_display_mode" block="set display mode $mode" shim=led::setDisplayMode function setDisplayMode(mode: DisplayMode): void; /** @@ -544,7 +573,7 @@ declare namespace led { function displayMode(): DisplayMode; /** - * Turns on or off the display + * Turns on or off the display */ //% help=led/enable blockId=device_led_enable block="led enable %on" //% advanced=true parts="ledmatrix" shim=led::enable @@ -571,7 +600,7 @@ declare namespace motors { */ //% blockId=motor_on block="motor on at %percent" //% parts=dcmotor weight=90 blockGap=8 shim=motors::motorPower - function motorPower(power: number): void; + function motorPower(power: int32): void; /** * Send break, coast or sleep commands to the motor. Has no effect in dual-motor mode. @@ -585,7 +614,7 @@ declare namespace motors { */ //% blockId=block_dual_motor block="motor %motor|at %percent" //% weight=80 shim=motors::dualMotorPower - function dualMotorPower(motor: Motor, duty_percent: number): void; + function dualMotorPower(motor: Motor, duty_percent: int32): void; } declare namespace music { @@ -596,7 +625,7 @@ declare namespace music { */ //% //% parts="speaker" async useEnumVal=1 shim=music::speakerPlayTone - function speakerPlayTone(frequency: number, ms: number): void; + function speakerPlayTone(frequency: int32, ms: int32): void; } declare namespace pins { @@ -608,7 +637,7 @@ declare namespace pins { //% blockId=device_get_digital_pin block="digital read|pin %name" blockGap=8 //% name.fieldEditor="gridpicker" name.fieldOptions.columns=4 //% name.fieldOptions.tooltips="false" name.fieldOptions.width="300" shim=pins::digitalReadPin - function digitalReadPin(name: DigitalPin): number; + function digitalReadPin(name: DigitalPin): int32; /** * Set a pin or connector value to either 0 or 1. @@ -620,7 +649,7 @@ declare namespace pins { //% value.min=0 value.max=1 //% name.fieldEditor="gridpicker" name.fieldOptions.columns=4 //% name.fieldOptions.tooltips="false" name.fieldOptions.width="300" shim=pins::digitalWritePin - function digitalWritePin(name: DigitalPin, value: number): void; + function digitalWritePin(name: DigitalPin, value: int32): void; /** * Read the connector value as analog, that is, as a value comprised between 0 and 1023. @@ -629,8 +658,8 @@ declare namespace pins { //% help=pins/analog-read-pin weight=25 //% blockId=device_get_analog_pin block="analog read|pin %name" blockGap="8" //% name.fieldEditor="gridpicker" name.fieldOptions.columns=4 - //% name.fieldOptions.tooltips="false" shim=pins::analogReadPin - function analogReadPin(name: AnalogPin): number; + //% name.fieldOptions.tooltips="false" name.fieldOptions.width="250" shim=pins::analogReadPin + function analogReadPin(name: AnalogPin): int32; /** * Set the connector value as analog. Value must be comprised between 0 and 1023. @@ -641,11 +670,11 @@ declare namespace pins { //% blockId=device_set_analog_pin block="analog write|pin %name|to %value" blockGap=8 //% value.min=0 value.max=1023 //% name.fieldEditor="gridpicker" name.fieldOptions.columns=4 - //% name.fieldOptions.tooltips="false" shim=pins::analogWritePin - function analogWritePin(name: AnalogPin, value: number): void; + //% name.fieldOptions.tooltips="false" name.fieldOptions.width="250" shim=pins::analogWritePin + function analogWritePin(name: AnalogPin, value: int32): void; /** - * Configures the Pulse-width modulation (PWM) of the analog output to the given value in **microseconds** or `1/1000` milliseconds. + * Configure the pulse-width modulation (PWM) period of the analog output in microseconds. * If this pin is not configured as an analog output (using `analog write pin`), the operation has no effect. * @param name analog pin to set period to, eg: AnalogPin.P0 * @param micros period in micro seconds. eg:20000 @@ -654,42 +683,42 @@ declare namespace pins { //% blockId=device_set_analog_period block="analog set period|pin %pin|to (µs)%micros" //% pin.fieldEditor="gridpicker" pin.fieldOptions.columns=4 //% pin.fieldOptions.tooltips="false" shim=pins::analogSetPeriod - function analogSetPeriod(name: AnalogPin, micros: number): void; + function analogSetPeriod(name: AnalogPin, micros: int32): void; /** - * Configures this pin to a digital input, and generates events where the timestamp is the duration that this pin was either ``high`` or ``low``. + * Configure the pin as a digital input and generate an event when the pin is pulsed either high or low. * @param name digital pin to register to, eg: DigitalPin.P0 * @param pulse the value of the pulse, eg: PulseValue.High */ - //% help=pins/on-pulsed weight=22 blockGap=8 advanced=true + //% help=pins/on-pulsed weight=22 blockGap=16 advanced=true //% blockId=pins_on_pulsed block="on|pin %pin|pulsed %pulse" //% pin.fieldEditor="gridpicker" pin.fieldOptions.columns=4 //% pin.fieldOptions.tooltips="false" pin.fieldOptions.width="300" shim=pins::onPulsed function onPulsed(name: DigitalPin, pulse: PulseValue, body: () => void): void; /** - * Gets the duration of the last pulse in micro-seconds. This function should be called from a ``onPulsed`` handler. + * Get the duration of the last pulse in microseconds. This function should be called from a ``onPulsed`` handler. */ //% help=pins/pulse-duration advanced=true //% blockId=pins_pulse_duration block="pulse duration (µs)" //% weight=21 blockGap=8 shim=pins::pulseDuration - function pulseDuration(): number; + function pulseDuration(): int32; /** - * Returns the duration of a pulse in microseconds + * Return the duration of a pulse at a pin in microseconds. * @param name the pin which measures the pulse, eg: DigitalPin.P0 * @param value the value of the pulse, eg: PulseValue.High - * @param maximum duration in micro-seconds + * @param maximum duration in microseconds */ //% blockId="pins_pulse_in" block="pulse in (µs)|pin %name|pulsed %value" //% weight=20 advanced=true //% help=pins/pulse-in //% name.fieldEditor="gridpicker" name.fieldOptions.columns=4 //% name.fieldOptions.tooltips="false" name.fieldOptions.width="300" maxDuration.defl=2000000 shim=pins::pulseIn - function pulseIn(name: DigitalPin, value: PulseValue, maxDuration?: number): number; + function pulseIn(name: DigitalPin, value: PulseValue, maxDuration?: int32): int32; /** - * Writes a value to the servo, controlling the shaft accordingly. On a standard servo, this will set the angle of the shaft (in degrees), moving the shaft to that orientation. On a continuous rotation servo, this will set the speed of the servo (with ``0`` being full-speed in one direction, ``180`` being full speed in the other, and a value near ``90`` being no movement). + * Write a value to the servo, controlling the shaft accordingly. On a standard servo, this will set the angle of the shaft (in degrees), moving the shaft to that orientation. On a continuous rotation servo, this will set the speed of the servo (with ``0`` being full-speed in one direction, ``180`` being full speed in the other, and a value near ``90`` being no movement). * @param name pin to write to, eg: AnalogPin.P0 * @param value angle or rotation speed, eg:180,90,0 */ @@ -698,41 +727,41 @@ declare namespace pins { //% parts=microservo trackArgs=0 //% value.min=0 value.max=180 //% name.fieldEditor="gridpicker" name.fieldOptions.columns=4 - //% name.fieldOptions.tooltips="false" shim=pins::servoWritePin - function servoWritePin(name: AnalogPin, value: number): void; + //% name.fieldOptions.tooltips="false" name.fieldOptions.width="250" shim=pins::servoWritePin + function servoWritePin(name: AnalogPin, value: int32): void; /** - * Configures this IO pin as an analog/pwm output, configures the period to be 20 ms, and sets the pulse width, based on the value it is given **microseconds** or `1/1000` milliseconds. + * Configure the IO pin as an analog/pwm output and set a pulse width. The period is 20 ms period and the pulse width is set based on the value given in **microseconds** or `1/1000` milliseconds. * @param name pin name * @param micros pulse duration in micro seconds, eg:1500 */ //% help=pins/servo-set-pulse weight=19 //% blockId=device_set_servo_pulse block="servo set pulse|pin %value|to (µs) %micros" //% value.fieldEditor="gridpicker" value.fieldOptions.columns=4 - //% value.fieldOptions.tooltips="false" shim=pins::servoSetPulse - function servoSetPulse(name: AnalogPin, micros: number): void; + //% value.fieldOptions.tooltips="false" value.fieldOptions.width="250" shim=pins::servoSetPulse + function servoSetPulse(name: AnalogPin, micros: int32): void; /** - * Sets the pin used when using `analog pitch` or music. + * Set the pin used when using analog pitch or music. * @param name pin to modulate pitch from */ //% blockId=device_analog_set_pitch_pin block="analog set pitch pin %name" //% help=pins/analog-set-pitch-pin weight=3 advanced=true //% name.fieldEditor="gridpicker" name.fieldOptions.columns=4 - //% name.fieldOptions.tooltips="false" shim=pins::analogSetPitchPin + //% name.fieldOptions.tooltips="false" name.fieldOptions.width="250" shim=pins::analogSetPitchPin function analogSetPitchPin(name: AnalogPin): void; /** - * Emits a Pulse-width modulation (PWM) signal to the current pitch pin. Use `analog set pitch pin` to define the pitch pin. + * Emit a plse-width modulation (PWM) signal to the current pitch pin. Use `analog set pitch pin` to define the pitch pin. * @param frequency frequency to modulate in Hz. * @param ms duration of the pitch in milli seconds. */ //% blockId=device_analog_pitch block="analog pitch %frequency|for (ms) %ms" //% help=pins/analog-pitch weight=4 async advanced=true blockGap=8 shim=pins::analogPitch - function analogPitch(frequency: number, ms: number): void; + function analogPitch(frequency: int32, ms: int32): void; /** - * Configures the pull of this pin. + * Configure the pull directiion of of a pin. * @param name pin to set the pull mode on, eg: DigitalPin.P0 * @param pull one of the mbed pull configurations, eg: PinPullMode.PullUp */ @@ -743,7 +772,7 @@ declare namespace pins { function setPull(name: DigitalPin, pull: PinPullMode): void; /** - * Configures the events emitted by this pin. Events can be subscribed to + * Configure the events emitted by this pin. Events can be subscribed to * using ``control.onEvent()``. * @param name pin to set the event mode on, eg: DigitalPin.P0 * @param type the type of events for this pin to emit, eg: PinEventType.Edge @@ -759,19 +788,19 @@ declare namespace pins { * @param size number of bytes in the buffer */ //% shim=pins::createBuffer - function createBuffer(size: number): Buffer; + function createBuffer(size: int32): Buffer; /** * Read `size` bytes from a 7-bit I2C `address`. */ //% repeat.defl=0 shim=pins::i2cReadBuffer - function i2cReadBuffer(address: number, size: number, repeat?: boolean): Buffer; + function i2cReadBuffer(address: int32, size: int32, repeat?: boolean): Buffer; /** * Write bytes to a 7-bit I2C `address`. */ //% repeat.defl=0 shim=pins::i2cWriteBuffer - function i2cWriteBuffer(address: number, buf: Buffer, repeat?: boolean): void; + function i2cWriteBuffer(address: int32, buf: Buffer, repeat?: boolean): int32; /** * Write to the SPI slave and return the response @@ -779,48 +808,48 @@ declare namespace pins { */ //% help=pins/spi-write weight=5 advanced=true //% blockId=spi_write block="spi write %value" shim=pins::spiWrite - function spiWrite(value: number): number; + function spiWrite(value: int32): int32; /** - * Sets the SPI frequency + * Set the SPI frequency * @param frequency the clock frequency, eg: 1000000 */ //% help=pins/spi-frequency weight=4 advanced=true //% blockId=spi_frequency block="spi frequency %frequency" shim=pins::spiFrequency - function spiFrequency(frequency: number): void; + function spiFrequency(frequency: int32): void; /** - * Sets the SPI bits and mode + * Set the SPI bits and mode * @param bits the number of bits, eg: 8 * @param mode the mode, eg: 3 */ //% help=pins/spi-format weight=3 advanced=true //% blockId=spi_format block="spi format|bits %bits|mode %mode" shim=pins::spiFormat - function spiFormat(bits: number, mode: number): void; + function spiFormat(bits: int32, mode: int32): void; /** - * Sets the MOSI, MISO, SCK pins used by the SPI instance + * Set the MOSI, MISO, SCK pins used by the SPI connection * */ //% help=pins/spi-pins weight=2 advanced=true //% blockId=spi_pins block="spi set pins|MOSI %mosi|MISO %miso|SCK %sck" //% mosi.fieldEditor="gridpicker" mosi.fieldOptions.columns=4 - //% mosi.fieldOptions.tooltips="false" mosi.fieldOptions.width="300" + //% mosi.fieldOptions.tooltips="false" mosi.fieldOptions.width="250" //% miso.fieldEditor="gridpicker" miso.fieldOptions.columns=4 - //% miso.fieldOptions.tooltips="false" miso.fieldOptions.width="300" + //% miso.fieldOptions.tooltips="false" miso.fieldOptions.width="250" //% sck.fieldEditor="gridpicker" sck.fieldOptions.columns=4 - //% sck.fieldOptions.tooltips="false" sck.fieldOptions.width="300" shim=pins::spiPins + //% sck.fieldOptions.tooltips="false" sck.fieldOptions.width="250" shim=pins::spiPins function spiPins(mosi: DigitalPin, miso: DigitalPin, sck: DigitalPin): void; } - //% weight=2 color=30 + //% weight=2 color=#002050 icon="\uf287" //% advanced=true declare namespace serial { /** - * Reads a line of text from the serial port and returns the buffer when the delimiter is met. + * Read a line of text from the serial port and return the buffer when the delimiter is met. * @param delimiter text delimiter that separates each text chunk */ //% help=serial/read-until @@ -829,14 +858,15 @@ declare namespace serial { function readUntil(delimiter: string): string; /** - * Reads the buffered received data as a string + * Read the buffered received data as a string */ + //% help=serial/read-string //% blockId=serial_read_buffer block="serial|read string" //% weight=18 shim=serial::readString function readString(): string; /** - * Registers an event to be fired when one of the delimiter is matched. + * Register an event to be fired when one of the delimiter is matched. * @param delimiters the characters to match received characters against. */ //% help=serial/on-data-received @@ -844,81 +874,169 @@ declare namespace serial { function onDataReceived(delimiters: string, body: () => void): void; /** - * Sends a piece of text through Serial connection. + * Send a piece of text through the serial connection. */ //% help=serial/write-string - //% weight=87 - //% blockId=serial_writestring block="serial|write string %text" shim=serial::writeString + //% weight=87 blockGap=8 + //% blockId=serial_writestring block="serial|write string %text" + //% text.shadowOptions.toString=true shim=serial::writeString function writeString(text: string): void; /** - * Dynamically configuring the serial instance to use pins other than USBTX and USBRX. - * @param tx the new transmission pins, eg: SerialPin.P0 + * Send a buffer through serial connection + */ + //% blockId=serial_writebuffer block="serial|write buffer %buffer=serial_readbuffer" + //% help=serial/write-buffer advanced=true weight=6 shim=serial::writeBuffer + function writeBuffer(buffer: Buffer): void; + + /** + * Read multiple characters from the receive buffer. Pause until enough characters are present. + * @param length default buffer length, eg: 64 + */ + //% blockId=serial_readbuffer block="serial|read buffer %length" + //% help=serial/read-buffer advanced=true weight=5 shim=serial::readBuffer + function readBuffer(length: int32): Buffer; + + /** + * Set the serial input and output to use pins instead of the USB connection. + * @param tx the new transmission pin, eg: SerialPin.P0 * @param rx the new reception pin, eg: SerialPin.P1 * @param rate the new baud rate. eg: 115200 */ //% weight=10 - //% help=serial/redirect-to + //% help=serial/redirect //% blockId=serial_redirect block="serial|redirect to|TX %tx|RX %rx|at baud rate %rate" - //% blockExternalInputs=1 shim=serial::redirect + //% blockExternalInputs=1 + //% tx.fieldEditor="gridpicker" tx.fieldOptions.columns=3 + //% tx.fieldOptions.tooltips="false" + //% rx.fieldEditor="gridpicker" rx.fieldOptions.columns=3 + //% rx.fieldOptions.tooltips="false" + //% blockGap=8 shim=serial::redirect function redirect(tx: SerialPin, rx: SerialPin, rate: BaudRate): void; + + /** + * Direct the serial input and output to use the USB connection. + */ + //% weight=9 help=serial/redirect-to-usb + //% blockId=serial_redirect_to_usb block="serial|redirect to USB" shim=serial::redirectToUSB + function redirectToUSB(): void; + + /** + * Sets the size of the RX buffer in bytes + * @param size length of the rx buffer in bytes, eg: 32 + */ + //% help=serial/set-rx-buffer-size + //% blockId=serialSetRxBufferSize block="serial set rx buffer size to $size" + //% advanced=true shim=serial::setRxBufferSize + function setRxBufferSize(size: uint8): void; + + /** + * Sets the size of the TX buffer in bytes + * @param size length of the tx buffer in bytes, eg: 32 + */ + //% help=serial/set-tx-buffer-size + //% blockId=serialSetTxBufferSize block="serial set tx buffer size to $size" + //% advanced=true shim=serial::setTxBufferSize + function setTxBufferSize(size: uint8): void; } //% indexerGet=BufferMethods::getByte indexerSet=BufferMethods::setByte declare interface Buffer { + /** + * Reads an unsigned byte at a particular location + */ + //% shim=BufferMethods::getUint8 + getUint8(off: int32): int32; + + /** + * Writes an unsigned byte at a particular location + */ + //% shim=BufferMethods::setUint8 + setUint8(off: int32, v: int32): void; + /** * Write a number in specified format in the buffer. */ //% shim=BufferMethods::setNumber - setNumber(format: NumberFormat, offset: number, value: number): void; + setNumber(format: NumberFormat, offset: int32, value: number): void; /** * Read a number in specified format from the buffer. */ //% shim=BufferMethods::getNumber - getNumber(format: NumberFormat, offset: number): number; + getNumber(format: NumberFormat, offset: int32): number; /** Returns the length of a Buffer object. */ //% property shim=BufferMethods::length - length: number; + length: int32; /** * Fill (a fragment) of the buffer with given value. */ //% offset.defl=0 length.defl=-1 shim=BufferMethods::fill - fill(value: number, offset?: number, length?: number): void; + fill(value: int32, offset?: int32, length?: int32): void; /** * Return a copy of a fragment of a buffer. */ //% offset.defl=0 length.defl=-1 shim=BufferMethods::slice - slice(offset?: number, length?: number): Buffer; + slice(offset?: int32, length?: int32): Buffer; /** * Shift buffer left in place, with zero padding. * @param offset number of bytes to shift; use negative value to shift right * @param start start offset in buffer. Default is 0. - * @param length number of elements in buffer. If negative, length is set as the buffer length minus start. eg: -1 + * @param length number of elements in buffer. If negative, length is set as the buffer length minus + * start. eg: -1 */ //% start.defl=0 length.defl=-1 shim=BufferMethods::shift - shift(offset: number, start?: number, length?: number): void; + shift(offset: int32, start?: int32, length?: int32): void; + + /** + * Convert a buffer to string assuming UTF8 encoding + */ + //% shim=BufferMethods::toString + toString(): string; + + /** + * Convert a buffer to its hexadecimal representation. + */ + //% shim=BufferMethods::toHex + toHex(): string; /** * Rotate buffer left in place. * @param offset number of bytes to shift; use negative value to shift right * @param start start offset in buffer. Default is 0. - * @param length number of elements in buffer. If negative, length is set as the buffer length minus start. eg: -1 + * @param length number of elements in buffer. If negative, length is set as the buffer length minus + * start. eg: -1 */ //% start.defl=0 length.defl=-1 shim=BufferMethods::rotate - rotate(offset: number, start?: number, length?: number): void; + rotate(offset: int32, start?: int32, length?: int32): void; /** * Write contents of `src` at `dstOffset` in current buffer. */ //% shim=BufferMethods::write - write(dstOffset: number, src: Buffer): void; + write(dstOffset: int32, src: Buffer): void; +} +declare namespace control { + + /** + * Create a new zero-initialized buffer. + * @param size number of bytes in the buffer + */ + //% shim=control::createBuffer + function createBuffer(size: int32): Buffer; + + /** + * Create a new buffer with UTF8-encoded string + * @param str the string to put in the buffer + */ + //% shim=control::createBufferFromUTF8 + function createBufferFromUTF8(str: string): Buffer; } // Auto-generated. Do not edit. Really. diff --git a/libs/devices/_locales/devices-strings.json b/libs/devices/_locales/devices-strings.json index bf2e1b5b..9888c18d 100644 --- a/libs/devices/_locales/devices-strings.json +++ b/libs/devices/_locales/devices-strings.json @@ -25,22 +25,6 @@ "MesDeviceInfo.OrientationLandscape|block": "orientation landscape", "MesDeviceInfo.OrientationPortrait|block": "orientation portrait", "MesDeviceInfo.Shaken|block": "shaken", - "MesDpadButtonInfo.ADown|block": "A down", - "MesDpadButtonInfo.AUp|block": "A up", - "MesDpadButtonInfo.BDown|block": "B down", - "MesDpadButtonInfo.BUp|block": "B up", - "MesDpadButtonInfo.CDown|block": "C down", - "MesDpadButtonInfo.CUp|block": "C up", - "MesDpadButtonInfo.DDown|block": "D down", - "MesDpadButtonInfo.DUp|block": "D up", - "MesDpadButtonInfo._1Down|block": "1 down", - "MesDpadButtonInfo._1Up|block": "1 up", - "MesDpadButtonInfo._2Down|block": "2 down", - "MesDpadButtonInfo._2Up|block": "2 up", - "MesDpadButtonInfo._3Down|block": "3 down", - "MesDpadButtonInfo._3Up|block": "3 up", - "MesDpadButtonInfo._4Down|block": "4 down", - "MesDpadButtonInfo._4Up|block": "4 up", "MesRemoteControlEvent.forward|block": "forward", "MesRemoteControlEvent.nextTrack|block": "next track", "MesRemoteControlEvent.pause|block": "pause", diff --git a/libs/devices/devices.cpp b/libs/devices/devices.cpp index 9e672020..abd05076 100644 --- a/libs/devices/devices.cpp +++ b/libs/devices/devices.cpp @@ -85,102 +85,11 @@ enum class MesRemoteControlEvent { volumeDown = MES_REMOTE_CONTROL_EVT_VOLUMEDOWN, }; -enum class MesDpadButtonInfo { - //% block="A down" - ADown = MES_DPAD_BUTTON_A_DOWN, - //% block="A up" - AUp = MES_DPAD_BUTTON_A_UP, - //% block="B down" - BDown = MES_DPAD_BUTTON_B_DOWN, - //% block="B up" - BUp = MES_DPAD_BUTTON_B_UP, - //% block="C down" - CDown = MES_DPAD_BUTTON_C_DOWN, - //% block="C up" - CUp = MES_DPAD_BUTTON_C_UP, - //% block="D down" - DDown = MES_DPAD_BUTTON_D_DOWN, - //% block="D up" - DUp = MES_DPAD_BUTTON_D_UP, - //% block="1 down" - _1Down = MES_DPAD_BUTTON_1_UP, - //% block="1 up" - _1Up = MES_DPAD_BUTTON_1_DOWN, - //% block="2 down" - _2Down = MES_DPAD_BUTTON_2_DOWN, - //% block="2 up" - _2Up = MES_DPAD_BUTTON_2_UP, - //% block="3 down" - _3Down = MES_DPAD_BUTTON_3_DOWN, - //% block="3 up" - _3Up = MES_DPAD_BUTTON_3_UP, - //% block="4 down" - _4Down = MES_DPAD_BUTTON_4_DOWN, - //% block="4 up" - _4Up = MES_DPAD_BUTTON_4_UP, -}; - /** * Control a phone with the BBC micro:bit via Bluetooth. */ -//% color=156 weight=80 +//% color=#008272 weight=80 icon="\uf10b" namespace devices { - static void genEvent(int id, int event) { - MicroBitEvent e(id, event); - } - - /** - * Sends a ``camera`` command to the parent device. - * @param event event description - */ - //% weight=30 help=devices/tell-camera-to - //% blockId=devices_camera icon="\uf030" block="tell camera to|%property" blockGap=8 - void tellCameraTo(MesCameraEvent event) { - genEvent(MES_CAMERA_ID, (int)event); - } - - /** - * Sends a ``remote control`` command to the parent device. - * @param event event description - */ - //% weight=29 help=devices/tell-remote-control-to - //% blockId=devices_remote_control block="tell remote control to|%property" blockGap=14 icon="\uf144" - void tellRemoteControlTo(MesRemoteControlEvent event) { - genEvent(MES_REMOTE_CONTROL_ID, (int)event); - } - - /** - * Sends an ``alert`` command to the parent device. - * @param event event description - */ - //% weight=27 help=devices/raise-alert-to - //% blockId=devices_alert block="raise alert to|%property" icon="\uf0f3" - void raiseAlertTo(MesAlertEvent event) { - genEvent(MES_ALERTS_ID, (int)event); - } - - /** - * Registers code to run when the device notifies about a particular event. - * @param event event description - * @param body code handler when event is triggered - */ - //% help=devices/on-notified weight=26 - //% blockId=devices_device_info_event block="on notified|%event" icon="\uf10a" - void onNotified(MesDeviceInfo event, Action body) { - registerWithDal(MES_DEVICE_INFO_ID, (int)event, body); - } - - /** - * Register code to run when the micro:bit receives a command from the paired gamepad. - * @param name button name - * @param body code to run when button is pressed - */ - //% help=devices/on-gamepad-button weight=40 - //% weight=25 - //% blockId=devices_gamepad_event block="on gamepad button|%NAME" icon="\uf11b" - void onGamepadButton(MesDpadButtonInfo name, Action body) { - registerWithDal(MES_DPAD_CONTROLLER_ID, (int)name, body); - } static int _signalStrength = -1; static void signalStrengthHandler(MicroBitEvent ev) { diff --git a/libs/devices/devices.ts b/libs/devices/devices.ts new file mode 100644 index 00000000..fbf63bc7 --- /dev/null +++ b/libs/devices/devices.ts @@ -0,0 +1,55 @@ + +namespace devices { + /** + * Sends a ``camera`` command to the parent device. + * @param event event description + */ + //% weight=30 help=devices/tell-camera-to + //% blockId=devices_camera icon="\uf030" block="tell camera to|%property" blockGap=8 + export function tellCameraTo(event: MesCameraEvent) { + control.raiseEvent(DAL.MES_CAMERA_ID, event); + } + + /** + * Sends a ``remote control`` command to the parent device. + * @param event event description + */ + //% weight=29 help=devices/tell-remote-control-to + //% blockId=devices_remote_control block="tell remote control to|%property" blockGap=14 icon="\uf144" + export function tellRemoteControlTo(event: MesRemoteControlEvent) { + control.raiseEvent(DAL.MES_REMOTE_CONTROL_ID, event); + } + + /** + * Sends an ``alert`` command to the parent device. + * @param event event description + */ + //% weight=27 help=devices/raise-alert-to + //% blockId=devices_alert block="raise alert to|%property" icon="\uf0f3" + export function raiseAlertTo(event: MesAlertEvent) { + control.raiseEvent(DAL.MES_ALERTS_ID, event); + } + + /** + * Registers code to run when the device notifies about a particular event. + * @param event event description + * @param body code handler when event is triggered + */ + //% help=devices/on-notified weight=26 + //% blockId=devices_device_info_event block="on notified|%event" icon="\uf10a" + export function onNotified(event: MesDeviceInfo, body: () => void) { + control.onEvent(DAL.MES_DEVICE_INFO_ID, event, body); + } + + /** + * Register code to run when the micro:bit receives a command from the paired gamepad. + * @param name button name + * @param body code to run when button is pressed + */ + //% help=devices/on-gamepad-button weight=40 + //% weight=25 + //% blockId=devices_gamepad_event block="on gamepad button|%NAME" icon="\uf11b" + export function onGamepadButton(name: MesDpadButtonInfo, body: () => void) { + control.onEvent(DAL.MES_DPAD_CONTROLLER_ID, name, body); + } +} \ No newline at end of file diff --git a/libs/devices/enums.d.ts b/libs/devices/enums.d.ts index d784422f..9eeabbe1 100644 --- a/libs/devices/enums.d.ts +++ b/libs/devices/enums.d.ts @@ -85,42 +85,6 @@ //% block="volume down" volumeDown = 9, // MES_REMOTE_CONTROL_EVT_VOLUMEDOWN } - - - declare const enum MesDpadButtonInfo { - //% block="A down" - ADown = 1, // MES_DPAD_BUTTON_A_DOWN - //% block="A up" - AUp = 2, // MES_DPAD_BUTTON_A_UP - //% block="B down" - BDown = 3, // MES_DPAD_BUTTON_B_DOWN - //% block="B up" - BUp = 4, // MES_DPAD_BUTTON_B_UP - //% block="C down" - CDown = 5, // MES_DPAD_BUTTON_C_DOWN - //% block="C up" - CUp = 6, // MES_DPAD_BUTTON_C_UP - //% block="D down" - DDown = 7, // MES_DPAD_BUTTON_D_DOWN - //% block="D up" - DUp = 8, // MES_DPAD_BUTTON_D_UP - //% block="1 down" - _1Down = 10, // MES_DPAD_BUTTON_1_UP - //% block="1 up" - _1Up = 9, // MES_DPAD_BUTTON_1_DOWN - //% block="2 down" - _2Down = 11, // MES_DPAD_BUTTON_2_DOWN - //% block="2 up" - _2Up = 12, // MES_DPAD_BUTTON_2_UP - //% block="3 down" - _3Down = 13, // MES_DPAD_BUTTON_3_DOWN - //% block="3 up" - _3Up = 14, // MES_DPAD_BUTTON_3_UP - //% block="4 down" - _4Down = 15, // MES_DPAD_BUTTON_4_DOWN - //% block="4 up" - _4Up = 16, // MES_DPAD_BUTTON_4_UP - } declare namespace devices { } diff --git a/libs/devices/pxt.json b/libs/devices/pxt.json index 13325b48..3624e880 100644 --- a/libs/devices/pxt.json +++ b/libs/devices/pxt.json @@ -1,24 +1,18 @@ { "name": "devices", - "description": "The BLE specific services", + "description": "BETA - Camera, remote control and other Bluetooth services. App required.", "files": [ "README.md", "enums.d.ts", "shims.d.ts", - "devices.cpp" + "devices.cpp", + "devices.ts" ], + "icon": "./static/packages/devices/icon.png", "public": true, "dependencies": { - "core": "file:../core" - }, - "yotta": { - "config": { - "microbit-dal": { - "bluetooth": { - "enabled": 1 - } - } - } + "core": "file:../core", + "bluetooth": "file:../bluetooth" }, "installedVersion": "ljipgq" } \ No newline at end of file diff --git a/libs/devices/shims.d.ts b/libs/devices/shims.d.ts index 9b152593..7860dc4a 100644 --- a/libs/devices/shims.d.ts +++ b/libs/devices/shims.d.ts @@ -4,58 +4,15 @@ /** * Control a phone with the BBC micro:bit via Bluetooth. */ - //% color=156 weight=80 + //% color=#008272 weight=80 icon="\uf10b" declare namespace devices { - /** - * Sends a ``camera`` command to the parent device. - * @param event event description - */ - //% weight=30 help=devices/tell-camera-to - //% blockId=devices_camera icon="\uf030" block="tell camera to|%property" blockGap=8 shim=devices::tellCameraTo - function tellCameraTo(event: MesCameraEvent): void; - - /** - * Sends a ``remote control`` command to the parent device. - * @param event event description - */ - //% weight=29 help=devices/tell-remote-control-to - //% blockId=devices_remote_control block="tell remote control to|%property" blockGap=14 icon="\uf144" shim=devices::tellRemoteControlTo - function tellRemoteControlTo(event: MesRemoteControlEvent): void; - - /** - * Sends an ``alert`` command to the parent device. - * @param event event description - */ - //% weight=27 help=devices/raise-alert-to - //% blockId=devices_alert block="raise alert to|%property" icon="\uf0f3" shim=devices::raiseAlertTo - function raiseAlertTo(event: MesAlertEvent): void; - - /** - * Registers code to run when the device notifies about a particular event. - * @param event event description - * @param body code handler when event is triggered - */ - //% help=devices/on-notified weight=26 - //% blockId=devices_device_info_event block="on notified|%event" icon="\uf10a" shim=devices::onNotified - function onNotified(event: MesDeviceInfo, body: () => void): void; - - /** - * Register code to run when the micro:bit receives a command from the paired gamepad. - * @param name button name - * @param body code to run when button is pressed - */ - //% help=devices/on-gamepad-button weight=40 - //% weight=25 - //% blockId=devices_gamepad_event block="on gamepad button|%NAME" icon="\uf11b" shim=devices::onGamepadButton - function onGamepadButton(name: MesDpadButtonInfo, body: () => void): void; - /** * Returns the last signal strength reported by the paired device. */ //% help=devices/signal-strength weight=24 //% blockId=devices_signal_strength block="signal strength" blockGap=14 icon="\uf012" blockGap=14 shim=devices::signalStrength - function signalStrength(): number; + function signalStrength(): int32; /** * Registers code to run when the device notifies about a change of signal strength. diff --git a/libs/hello/hello.ts b/libs/hello/hello.ts index 1954fb0e..a1c168a9 100644 --- a/libs/hello/hello.ts +++ b/libs/hello/hello.ts @@ -1,15 +1,7 @@ -basic.setLedColor(Colors.Blue) -basic.pause(500) -basic.setLedColor(Colors.Red) -basic.pause(500) -basic.setLedColor(Colors.Green) -basic.pause(500) -basic.setLedColor(0); -basic.setLedColor(Colors.Violet) -basic.pause(100) -led.plot(0, 0) -basic.pause(1000); -basic.forever(() => { - const a = input.acceleration(Dimension.X); - led.plotBarGraph(a, 1023) -}) +basic.plotLeds(` +# # . # # +. . # . . +. . # . . +# . . . # +. # # # . +`); diff --git a/libs/hello/pxt.json b/libs/hello/pxt.json index b18eb115..7ca396d5 100644 --- a/libs/hello/pxt.json +++ b/libs/hello/pxt.json @@ -6,6 +6,7 @@ ], "public": true, "dependencies": { - "core": "file:../core" + "core": "file:../core", + "radio": "file:../radio" } } diff --git a/libs/radio-broadcast/_locales/radio-broadcast-jsdoc-strings.json b/libs/radio-broadcast/_locales/radio-broadcast-jsdoc-strings.json new file mode 100644 index 00000000..70202ac8 --- /dev/null +++ b/libs/radio-broadcast/_locales/radio-broadcast-jsdoc-strings.json @@ -0,0 +1,6 @@ +{ + "radio": "Communicate data using radio packets", + "radio.onReceivedMessage": "Registers code to run for a particular message", + "radio.onReceivedMessage|param|msg": "@param handler ", + "radio.sendMessage": "Broadcasts a message over radio" +} \ No newline at end of file diff --git a/libs/radio-broadcast/_locales/radio-broadcast-strings.json b/libs/radio-broadcast/_locales/radio-broadcast-strings.json new file mode 100644 index 00000000..cd7928a6 --- /dev/null +++ b/libs/radio-broadcast/_locales/radio-broadcast-strings.json @@ -0,0 +1,6 @@ +{ + "radio.onReceivedMessage|block": "on radio $msg received", + "radio.sendMessage|block": "radio send $msg", + "radio|block": "radio", + "{id:category}Radio": "Radio" +} \ No newline at end of file diff --git a/libs/radio-broadcast/docs/reference/radio/on-received-message.md b/libs/radio-broadcast/docs/reference/radio/on-received-message.md new file mode 100644 index 00000000..8946d0fd --- /dev/null +++ b/libs/radio-broadcast/docs/reference/radio/on-received-message.md @@ -0,0 +1,45 @@ +# on Received Message + +Run part of a program when the @boardname@ receives a +message over ``radio``. + +```sig +radio.onReceivedMessage(0, function() {}) +``` + +## Parameters + +* **msg**: The message to listen for. See [send message](/reference/radio/send-message) + +## Examples + +## Example: Broadcasting heart or skull + +Sends a ``heart`` message when ``A`` is pressed, ``skull`` when ``B`` is pressed. On the side, display heart or skull for the message. + +```blocks +enum RadioMessage { + heart, + skull +} +input.onButtonPressed(Button.A, function () { + radio.sendMessage(RadioMessage.heart) +}) +input.onButtonPressed(Button.B, function () { + radio.sendMessage(RadioMessage.skull) +}) +radio.onReceivedMessage(RadioMessage.heart, function () { + basic.showIcon(IconNames.Heart) +}) +radio.onReceivedMessage(RadioMessage.skull, function () { + basic.showIcon(IconNames.Skull) +}) +``` + +## See also + +[send message](/reference/radio/send-message), + +```package +radio-broadcast +``` diff --git a/libs/radio-broadcast/docs/reference/radio/send-message.md b/libs/radio-broadcast/docs/reference/radio/send-message.md new file mode 100644 index 00000000..e8dd9619 --- /dev/null +++ b/libs/radio-broadcast/docs/reference/radio/send-message.md @@ -0,0 +1,43 @@ +# send Message + +Broadcast a coded message to other @boardname@s connected via ``radio``. + +```sig +radio.sendMessage(0); +``` + +## Parameters + +* **msg**: a coded message. + + +## Example: Broadcasting heart or skull + +Sends a ``heart`` message when ``A`` is pressed, ``skull`` when ``B`` is pressed. On the side, display heart or skull for the message. + +```blocks +enum RadioMessage { + heart, + skull +} +input.onButtonPressed(Button.A, function () { + radio.sendMessage(RadioMessage.heart) +}) +input.onButtonPressed(Button.B, function () { + radio.sendMessage(RadioMessage.skull) +}) +radio.onReceivedMessage(RadioMessage.heart, function () { + basic.showIcon(IconNames.Heart) +}) +radio.onReceivedMessage(RadioMessage.skull, function () { + basic.showIcon(IconNames.Skull) +}) +``` + +## See also + +[on received number](/reference/radio/on-received-number) + +```package +radio-broadcast +``` \ No newline at end of file diff --git a/libs/radio-broadcast/pxt.json b/libs/radio-broadcast/pxt.json new file mode 100644 index 00000000..b24a64b3 --- /dev/null +++ b/libs/radio-broadcast/pxt.json @@ -0,0 +1,12 @@ +{ + "name": "radio-broadcast", + "description": "Adds new blocks for message communication in the radio category", + "files": [ + "pxt.json", + "radio-broadcast.ts" + ], + "dependencies": { + "core": "file:../core", + "radio": "file:../radio" + } +} diff --git a/libs/radio-broadcast/radio-broadcast.ts b/libs/radio-broadcast/radio-broadcast.ts new file mode 100644 index 00000000..c8b71835 --- /dev/null +++ b/libs/radio-broadcast/radio-broadcast.ts @@ -0,0 +1,39 @@ +namespace radio { + /** + * Gets the message code + */ + //% blockHidden=1 shim=ENUM_GET + //% blockId=radioMessageCode block="$msg" enumInitialMembers="message1" + //% enumName=RadioMessage enumMemberName=msg enumPromptHint="e.g. Start, Stop, Jump..." + //% enumIsHash=1 + export function __message(msg: number): number { + return msg; + } + + /** + * Broadcasts a message over radio + * @param msg + */ + //% blockId=radioBroadcastMessage block="radio send $msg" + //% msg.shadow=radioMessageCode draggableParameters + //% weight=200 + //% blockGap=8 + //% help=radio/send-message + export function sendMessage(msg: number): void { + // 0 is MICROBIT_EVT_ANY, shifting by 1 + radio.raiseEvent(DAL.MES_BROADCAST_GENERAL_ID, msg + 1); + } + + /** + * Registers code to run for a particular message + * @param msg + * @param handler + */ + //% blockId=radioOnMessageReceived block="on radio $msg received" + //% msg.shadow=radioMessageCode draggableParameters + //% weight=199 + //% help=radio/on-received-message + export function onReceivedMessage(msg: number, handler: () => void) { + control.onEvent(DAL.MES_BROADCAST_GENERAL_ID, msg + 1, handler); + } +} \ No newline at end of file diff --git a/libs/radio/_locales/de/radio-jsdoc-strings.json b/libs/radio/_locales/de/radio-jsdoc-strings.json deleted file mode 100644 index b9a7803b..00000000 --- a/libs/radio/_locales/de/radio-jsdoc-strings.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "radio": "Daten mithilfe von Funk-Paketen übertragen", - "radio.onDataPacketReceived": "Registriert Funktionen, die ausgeführt werden, wenn das Radio ein Datenpaket empfängt. Entnimmt das empfangene Paket aus der Warteschlange des Radios.", - "radio.onDataReceived": "Registriert Code der ausgeführt wird, wenn ein Paket über Funk empfangen wird.", - "radio.receiveNumber": "Liest das nächste Paket aus der Funk-Warteschlange und gibt die Paketnummer oder 0 aus, wenn das Paket keine Nummer enthält.", - "radio.receiveString": "Liest das nächste Paket aus der Funk-Warteschlange und gibt die enthaltene Zeichenfolge oder die leere Zeichenfolge aus, wenn das Paket keine Zeichenfolge enthält.", - "radio.receivedNumber": "Extrahiert eine Zahl aus dem Inhalt des letzten Datenpakets, welches aus der Warteschlange des Radios (via ``Zahl empfangen``, ``Zeichenkette empfangen``, etc) entnommen wurde oder eine 0, wenn das Paket keine Zahl enthält.", - "radio.receivedSerial": "Extrahiert die Seriennummer des Calliope mini Senders aus dem Inhalt des letzten Datenpakets, welches aus der Warteschlange des Radios entnommen wurde oder eine 0, wenn der Absender keine Seriennummer gesendet hat.", - "radio.receivedSignalStrength": "Ruft den empfangenen Signalstärkeindikator (RSSI) aus dem letzten Paket aus der Funk-Warteschlange aus (via ``receiveNumber``, ``receiveString``, etc). Wird im Simulator nicht unterstützt.\nnamespace=radio", - "radio.receivedString": "Extrahiert die Zeichenkette aus dem Inhalt des letzten Datenpakets, welches aus der Warteschlange des Radios (via ``Zahl empfangen``, ``Zeichenkette empfangen``, etc) entnommen wurde oder eine leere Zeichenkette, wenn das Paket keine Zeichenkette enthält.", - "radio.receivedTime": "Extrahiert die Systemzeit des Absenders aus dem Inhalt des letzten Datenpakets, welches aus der Warteschlange des Radios (via ``Zahl empfangen``, ``Zeichenkette empfangen``, etc) entnommen wurde.", - "radio.sendNumber": "Überträgt eine Nummer über Funk an jeden angeschlossenen mini in der Gruppe.", - "radio.sendString": "Überträgt eine Zeichenfolge über Funk mit Seriennummer des Geräts und Laufzeit an jeden angeschlossenen mini in der Gruppe.", - "radio.sendValue": "Sendet ein Name / Wert-Paar zusammen mit der Seriennummer des Geräts und die Laufzeit auf alle angeschlossenen minis in der Gruppe.", - "radio.sendValue|param|value": "der numerische Wert", - "radio.setGroup": "Setzt die Gruppen-ID für Funkverbindungen. Ein mini kann nur ein Gruppen-ID hören.\nDie Gruppen-ID zwischen liegt zwischen 0 und 255, z.B. 1", - "radio.setTransmitPower": "Ändere die Ausgabeleistung des Senders auf den angegebenen Wert.", - "radio.setTransmitPower|param|power": "ein Wert im Bereich 0.. 7, wo 0 die niedrigste Leistung und 7 ist ist die höchste. z.B. 7", - "radio.setTransmitSerialNumber": "Stelle den Dunk so ein, dass die Seriennummer in jeder Nachricht übertragen wird.", - "radio.setTransmitSerialNumber|param|transmit": "Wert, der anzeigt, ob die Seriennummer übertragen wird, z.B. wahr", - "radio.writeReceivedPacketToSerial": "Schreibt das letzte empfangene Paket als JSON auf Seriell. Sollte in einem ´´onDataPacketReceived``-Callback aufgerufen werden.", - "radio.writeValueToSerial": "Liest das nächste Paket aus der Funk-Warteschlange und schreibt dieses als JSON auf Seriell." -} \ No newline at end of file diff --git a/libs/radio/_locales/de/radio-strings.json b/libs/radio/_locales/de/radio-strings.json deleted file mode 100644 index bb23dd55..00000000 --- a/libs/radio/_locales/de/radio-strings.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "radio.onDataPacketReceived|block": "wenn Datenpaket empfangen", - "radio.onDataReceived|block": "Funk auf empfangenen Daten", - "radio.receiveNumber|block": "empfange Nummer über Funk", - "radio.receiveString|block": "empfange Zeichenfolge über Funk", - "radio.receivedSignalStrength|block": "über Funk empfangene Signalstärke", - "radio.sendNumber|block": "sende Nummer %value über Funk", - "radio.sendString|block": "sende Zeichenfolge %msg über Funk", - "radio.sendValue|block": "schicke |Wert %name|= %value über Funk", - "radio.setGroup|block": "setze Gruppe %ID über Funk", - "radio.setTransmitPower|block": "setze Übertragungsstärke %power über Funk", - "radio.setTransmitSerialNumber|block": "setze Übertragungsseriennummer %transmit über Funk", - "radio.writeReceivedPacketToSerial|block": "schreibe das über Funk übertragene Paket auf Seriell", - "radio.writeValueToSerial|block": "schreibe Wert über Funk auf Seriell", - "radio|block": "Funk", - "{id:category}Radio": "Funk" -} \ No newline at end of file diff --git a/libs/radio/_locales/radio-jsdoc-strings.json b/libs/radio/_locales/radio-jsdoc-strings.json index 5a1e3f8c..b4f635f1 100644 --- a/libs/radio/_locales/radio-jsdoc-strings.json +++ b/libs/radio/_locales/radio-jsdoc-strings.json @@ -1,25 +1,46 @@ { "radio": "Communicate data using radio packets", + "radio.Packet.receivedBuffer": "The buffer payload if a buffer was sent in this packet\nor the empty buffer", "radio.Packet.receivedNumber": "The number payload if a number was sent in this packet (via ``sendNumber()`` or ``sendValue()``)\nor 0 if this packet did not contain a number.", "radio.Packet.receivedString": "The string payload if a string was sent in this packet (via ``sendString()`` or ``sendValue()``)\nor the empty string if this packet did not contain a string.", "radio.Packet.serial": "The serial number of the sender of the packet or 0 if the sender did not sent their serial number.", "radio.Packet.signal": "The received signal strength indicator (RSSI) of the packet.", "radio.Packet.time": "The system time of the sender of the packet at the time the packet was sent.", - "radio.onDataPacketReceived": "Registers code to run when the radio receives a packet. Also takes the\nreceived packet from the radio queue.", + "radio._packetProperty": "Gets a packet property.", + "radio._packetProperty|param|type": "the packet property type, eg: PacketProperty.time", + "radio.onDataPacketReceived": "Deprecated. Use onDataReceived() instead\nRegisters code to run when the radio receives a packet. Also takes the\nreceived packet from the radio queue.", "radio.onDataReceived": "Registers code to run when a packet is received over radio.", + "radio.onReceivedBuffer": "Registers code to run when the radio receives a buffer.", + "radio.onReceivedBufferDeprecated": "Registers code to run when the radio receives a buffer. Deprecated, use\nonReceivedBuffer instead.", + "radio.onReceivedNumber": "Registers code to run when the radio receives a number.", + "radio.onReceivedNumberDeprecated": "Registers code to run when the radio receives a number. Deprecated, use\nonReceivedNumber instead.", + "radio.onReceivedString": "Registers code to run when the radio receives a string.", + "radio.onReceivedStringDeprecated": "Registers code to run when the radio receives a string. Deprecated, use\nonReceivedString instead.", + "radio.onReceivedValue": "Registers code to run when the radio receives a key value pair.", + "radio.onReceivedValueDeprecated": "Registers code to run when the radio receives a key value pair. Deprecated, use\nonReceivedValue instead.", + "radio.raiseEvent": "Sends an event over radio to neigboring devices", + "radio.readRawPacket": "Internal use only. Takes the next packet from the radio queue and returns its contents + RSSI in a Buffer", "radio.receiveNumber": "Reads the next packet from the radio queue and returns the packet's number\npayload or 0 if the packet did not contain a number.", "radio.receiveString": "Reads the next packet from the radio queue and returns the packet's string\npayload or the empty string if the packet did not contain a string.", + "radio.receivedBuffer": "Returns the buffer payload from the last packet taken from the radio queue\n(via ``receiveNumber``, ``receiveString``, etc) or the empty string if that\npacket did not contain a string.", "radio.receivedNumber": "Returns the number payload from the last packet taken from the radio queue\n(via ``receiveNumber``, ``receiveString``, etc) or 0 if that packet did not\ncontain a number.", + "radio.receivedPacket": "Returns properties of the last radio packet received.", + "radio.receivedPacket|param|type": "the type of property to retrieve from the last packet", "radio.receivedSerial": "Returns the serial number of the sender micro:bit from the last packet taken\nfrom the radio queue (via ``receiveNumber``, ``receiveString``, etc) or 0 if\nthat packet did not send a serial number.", - "radio.receivedSignalStrength": "Gets the received signal strength indicator (RSSI) from the last packet taken\nfrom the radio queue (via ``receiveNumber``, ``receiveString``, etc). Not supported in simulator.\nnamespace=radio", + "radio.receivedSignalStrength": "Gets the received signal strength indicator (RSSI) from the last packet taken\nfrom the radio queue (via ``receiveNumber``, ``receiveString``, etc). Not supported in simulator.", "radio.receivedString": "Returns the string payload from the last packet taken from the radio queue\n(via ``receiveNumber``, ``receiveString``, etc) or the empty string if that\npacket did not contain a string.", "radio.receivedTime": "Returns the system time of the sender micro:bit at the moment when it sent the\nlast packet taken from the radio queue (via ``receiveNumber``,\n``receiveString``, etc).", + "radio.sendBuffer": "Broadcasts a buffer (up to 19 bytes long) along with the device serial number\nand running time to any connected micro:bit in the group.", "radio.sendNumber": "Broadcasts a number over radio to any connected micro:bit in the group.", + "radio.sendRawPacket": "Internal use only. Sends a raw packet through the radio (assumes RSSI appened to packet)", "radio.sendString": "Broadcasts a string along with the device serial number\nand running time to any connected micro:bit in the group.", - "radio.sendValue": "Broadcasts a name / value pair along with the device serial number\nand running time to any connected micro:bit in the group.", - "radio.sendValue|param|name": "the field name (max 12 characters), eg: \"name\"", - "radio.sendValue|param|value": "the numberic value", - "radio.setGroup": "Sets the group id for radio communications. A micro:bit can only listen to one group ID at any time.\n@ param id the group id between ``0`` and ``255``, 1 eg", + "radio.sendValue": "Broadcasts a name / value pair along with the device serial number\nand running time to any connected micro:bit in the group. The name can\ninclude no more than 8 characters.", + "radio.sendValue|param|name": "the field name (max 8 characters), eg: \"name\"", + "radio.sendValue|param|value": "the numeric value", + "radio.setFrequencyBand": "Change the transmission and reception band of the radio to the given channel", + "radio.setFrequencyBand|param|band": "a frequency band in the range 0 - 83. Each step is 1MHz wide, based at 2400MHz.", + "radio.setGroup": "Sets the group id for radio communications. A micro:bit can only listen to one group ID at any time.", + "radio.setGroup|param|id": "the group id between ``0`` and ``255``, eg: 1", "radio.setTransmitPower": "Change the output power level of the transmitter to the given value.", "radio.setTransmitPower|param|power": "a value in the range 0..7, where 0 is the lowest power and 7 is the highest. eg: 7", "radio.setTransmitSerialNumber": "Set the radio to transmit the serial number in each message.", diff --git a/libs/radio/_locales/radio-strings.json b/libs/radio/_locales/radio-strings.json index c113d9a8..85346e90 100644 --- a/libs/radio/_locales/radio-strings.json +++ b/libs/radio/_locales/radio-strings.json @@ -1,12 +1,27 @@ { + "RadioPacketProperty.SerialNumber|block": "serial number", + "RadioPacketProperty.SignalStrength|block": "signal strength", + "RadioPacketProperty.Time|block": "time", + "radio._packetProperty|block": "%note", "radio.onDataPacketReceived|block": "on radio received", "radio.onDataReceived|block": "radio on data received", + "radio.onReceivedBufferDeprecated|block": "on radio received", + "radio.onReceivedBuffer|block": "on radio received", + "radio.onReceivedNumberDeprecated|block": "on radio received", + "radio.onReceivedNumber|block": "on radio received", + "radio.onReceivedStringDeprecated|block": "on radio received", + "radio.onReceivedString|block": "on radio received", + "radio.onReceivedValueDeprecated|block": "on radio received", + "radio.onReceivedValue|block": "on radio received", + "radio.raiseEvent|block": "radio raise event|from source %src=control_event_source_id|with value %value=control_event_value_id", "radio.receiveNumber|block": "radio receive number", "radio.receiveString|block": "radio receive string", + "radio.receivedPacket|block": "received packet %type=radio_packet_property", "radio.receivedSignalStrength|block": "radio received signal strength", "radio.sendNumber|block": "radio send number %value", "radio.sendString|block": "radio send string %msg", "radio.sendValue|block": "radio send|value %name|= %value", + "radio.setFrequencyBand|block": "radio set frequency band %band", "radio.setGroup|block": "radio set group %ID", "radio.setTransmitPower|block": "radio set transmit power %power", "radio.setTransmitSerialNumber|block": "radio set transmit serial number %transmit", diff --git a/libs/radio/deprecated.ts b/libs/radio/deprecated.ts new file mode 100644 index 00000000..3677a650 --- /dev/null +++ b/libs/radio/deprecated.ts @@ -0,0 +1,188 @@ +namespace radio { + export class Packet { + /** + * The number payload if a number was sent in this packet (via ``sendNumber()`` or ``sendValue()``) + * or 0 if this packet did not contain a number. + */ + public receivedNumber: number; + /** + * The string payload if a string was sent in this packet (via ``sendString()`` or ``sendValue()``) + * or the empty string if this packet did not contain a string. + */ + public receivedString: string; + /** + * The buffer payload if a buffer was sent in this packet + * or the empty buffer + */ + public receivedBuffer: Buffer; + /** + * The system time of the sender of the packet at the time the packet was sent. + */ + public time: number; + /** + * The serial number of the sender of the packet or 0 if the sender did not sent their serial number. + */ + public serial: number; + /** + * The received signal strength indicator (RSSI) of the packet. + */ + public signal: number; + } + + /** + * Deprecated. Use onDataReceived() instead + * Registers code to run when the radio receives a packet. Also takes the + * received packet from the radio queue. + */ + //% help=radio/on-data-packet-received blockHandlerKey="radioreceived" deprecated=true + //% mutate=objectdestructuring + //% mutateText=Packet + //% mutateDefaults="receivedNumber;receivedString:name,receivedNumber:value;receivedString" + //% blockId=radio_on_packet block="on radio received" blockGap=8 + export function onDataPacketReceived(cb: (packet: Packet) => void) { + onDataReceived(() => { + receiveNumber(); + const packet = new Packet(); + packet.receivedNumber = receivedNumber(); + packet.time = receivedTime(); + packet.serial = receivedSerial(); + packet.receivedString = receivedString(); + packet.receivedBuffer = receivedBuffer(); + packet.signal = receivedSignalStrength(); + cb(packet) + }); + } + + /** + * Registers code to run when the radio receives a number. Deprecated, use + * onReceivedNumber instead. + */ + //% help=radio/on-received-number blockHandlerKey="radioreceived" + //% blockId=radio_on_number block="on radio received" blockGap=16 + //% useLoc="radio.onDataPacketReceived" deprecated=1 + export function onReceivedNumberDeprecated(cb: (receivedNumber: number) => void) { + onReceivedNumber(cb); + } + + /** + * Registers code to run when the radio receives a key value pair. Deprecated, use + * onReceivedValue instead. + */ + //% help=radio/on-received-value blockHandlerKey="radioreceived" + //% blockId=radio_on_value block="on radio received" blockGap=16 + //% useLoc="radio.onDataPacketReceived" deprecated=1 + export function onReceivedValueDeprecated(cb: (name: string, value: number) => void) { + onReceivedValue(cb); + } + + /** + * Registers code to run when the radio receives a string. Deprecated, use + * onReceivedString instead. + */ + //% help=radio/on-received-string blockHandlerKey="radioreceived" + //% blockId=radio_on_string block="on radio received" blockGap=16 + //% useLoc="radio.onDataPacketReceived" deprecated=1 + export function onReceivedStringDeprecated(cb: (receivedString: string) => void) { + onReceivedString(cb); + } + + /** + * Registers code to run when the radio receives a buffer. Deprecated, use + * onReceivedBuffer instead. + */ + //% help=radio/on-received-buffer blockHandlerKey="radioreceived" blockHidden=1 + //% blockId=radio_on_buffer block="on radio received" blockGap=16 + //% useLoc="radio.onDataPacketReceived" deprecated=1 + export function onReceivedBufferDeprecated(cb: (receivedBuffer: Buffer) => void) { + onReceivedBuffer(cb); + } + + /** + * Reads the next packet from the radio queue and and writes it to serial + * as JSON. + */ + //% help=radio/write-value-to-serial + //% weight=3 + //% blockId=radio_write_value_serial block="radio write value to serial" + //% deprecated=true + export function writeValueToSerial() { + const p = RadioPacket.getPacket(radio.readRawPacket()); + writeToSerial(p); + } + + /** + * Returns the number payload from the last packet taken from the radio queue + * (via ``receiveNumber``, ``receiveString``, etc) or 0 if that packet did not + * contain a number. + */ + //% help=radio/received-number deprecated=1 + export function receivedNumber(): number { + return (lastPacket ? lastPacket.numberPayload : 0) || 0; + } + + /** + * Returns the serial number of the sender micro:bit from the last packet taken + * from the radio queue (via ``receiveNumber``, ``receiveString``, etc) or 0 if + * that packet did not send a serial number. + */ + //% help=radio/received-serial deprecated=1 + export function receivedSerial(): number { + return lastPacket ? lastPacket.serial : 0; + } + + /** + * Returns the string payload from the last packet taken from the radio queue + * (via ``receiveNumber``, ``receiveString``, etc) or the empty string if that + * packet did not contain a string. + */ + //% help=radio/received-string deprecated=1 + export function receivedString(): string { + return (lastPacket ? lastPacket.stringPayload : "") || ""; + } + + /** + * Returns the buffer payload from the last packet taken from the radio queue + * (via ``receiveNumber``, ``receiveString``, etc) or the empty string if that + * packet did not contain a string. + */ + //% help=radio/received-buffer deprecated=1 + export function receivedBuffer(): Buffer { + return (lastPacket ? lastPacket.bufferPayload : null) || control.createBuffer(0); + } + + /** + * Returns the system time of the sender micro:bit at the moment when it sent the + * last packet taken from the radio queue (via ``receiveNumber``, + * ``receiveString``, etc). + */ + //% help=radio/received-time deprecated=1 + export function receivedTime(): number { + return lastPacket ? lastPacket.time : 0; + } + + /** + * Reads the next packet from the radio queue and returns the packet's number + * payload or 0 if the packet did not contain a number. + */ + //% help=radio/receive-number + //% weight=46 + //% blockId=radio_datagram_receive block="radio receive number" blockGap=8 + //% deprecated=true + export function receiveNumber(): number { + lastPacket = RadioPacket.getPacket(readRawPacket()); + return receivedNumber(); + } + + /** + * Reads the next packet from the radio queue and returns the packet's string + * payload or the empty string if the packet did not contain a string. + */ + //% blockId=radio_datagram_receive_string block="radio receive string" blockGap=8 + //% weight=44 + //% help=radio/receive-string + //% deprecated=true + export function receiveString(): string { + lastPacket = RadioPacket.getPacket(readRawPacket()); + return receivedString(); + } +} \ No newline at end of file diff --git a/libs/radio/pxt.json b/libs/radio/pxt.json index 07019ae2..9a1374cc 100644 --- a/libs/radio/pxt.json +++ b/libs/radio/pxt.json @@ -7,9 +7,9 @@ "enums.d.ts", "radio.cpp", "radio.ts", - "_locales/de/radio-jsdoc-strings.json", - "_locales/de/radio-strings.json" + "deprecated.ts" ], + "icon": "./static/packages/radio/icon.png", "public": true, "dependencies": { "core": "file:../core" diff --git a/libs/radio/radio.cpp b/libs/radio/radio.cpp index 836926e6..b4b324de 100644 --- a/libs/radio/radio.cpp +++ b/libs/radio/radio.cpp @@ -2,44 +2,10 @@ using namespace pxt; -#define MAX_FIELD_NAME_LENGTH 12 -#define MAX_PAYLOAD_LENGTH 20 -#define PACKET_PREFIX_LENGTH 9 -#define VALUE_PACKET_NAME_LEN_OFFSET 13 - - -// Packet Spec: -// | 0 | 1 ... 4 | 5 ... 8 | 9 ... 28 -// ---------------------------------------------------------------- -// | packet type | system time | serial number | payload -// -// Serial number defaults to 0 unless enabled by user - -// payload: number (9 ... 12) -#define PACKET_TYPE_NUMBER 0 - -// payload: number (9 ... 12), name length (13), name (14 ... 26) -#define PACKET_TYPE_VALUE 1 - -// payload: string length (9), string (10 ... 28) -#define PACKET_TYPE_STRING 2 - -//% color=270 weight=34 +//% color=#E3008C weight=96 icon="\uf012" namespace radio { - // ------------------------------------------------------------------------- - // Radio - // ------------------------------------------------------------------------- bool radioEnabled = false; - bool transmitSerialNumber = false; - - PacketBuffer packet; - - uint8_t type; - uint32_t time; - uint32_t serial; - int value; - StringData* msg; int radioEnable() { int r = uBit.radio.enable(); @@ -49,224 +15,56 @@ namespace radio { } if (!radioEnabled) { uBit.radio.setGroup(pxt::programHash()); + uBit.radio.setTransmitPower(6); // start with high power by default radioEnabled = true; } return r; } - void broadcastMessage(int message) { - if (radioEnable() != MICROBIT_OK) return; - uBit.radio.event.eventReceived(MicroBitEvent(MES_BROADCAST_GENERAL_ID, message, CREATE_ONLY)); - } - - void onBroadcastMessageReceived(int message, Action f) { - if (radioEnable() != MICROBIT_OK) return; - registerWithDal(MES_BROADCAST_GENERAL_ID, message, f); - } - - void setPacketPrefix(uint8_t* buf, int type) { - // prefix: type (0), time (1..4), serial (5..8) - uint32_t t = system_timer_current_time(); - uint32_t sn = transmitSerialNumber ? microbit_serial_number() : 0; - - buf[0] = (uint8_t) type; - memcpy(buf + 1, &t, 4); - memcpy(buf + 5, &sn, 4); - } - - uint8_t copyStringValue(uint8_t* buf, StringData* data, uint8_t maxLength) { - ManagedString s(data); - uint8_t len = min(maxLength, s.length()); - - // One byte for length of the string - buf[0] = len; - - if (len > 0) { - memcpy(buf + 1, s.toCharArray(), len); - } - return len + 1; - } - - StringData* getStringValue(uint8_t* buf, uint8_t maxLength) { - // First byte is the string length - uint8_t len = min(maxLength, buf[0]); - - if (len) { - char name[maxLength + 1]; - memcpy(name, buf + 1, len); - name[len] = 0; - return ManagedString(name).leakData(); - } - return ManagedString().leakData(); - } - - void writePacketAsJSON(uint8_t tp, int v, int s, int t, StringData* m) { - // Convert the packet to JSON and send over serial - uBit.serial.send("{"); - uBit.serial.send("\"t\":"); - uBit.serial.send(t); - uBit.serial.send(",\"s\":"); - uBit.serial.send(s); - if (tp == PACKET_TYPE_STRING || tp == PACKET_TYPE_VALUE) { - uBit.serial.send(",\"n\":\""); - uBit.serial.send(m); - uBit.serial.send("\""); - } - if (tp == PACKET_TYPE_NUMBER || tp == PACKET_TYPE_VALUE) { - uBit.serial.send(",\"v\":"); - uBit.serial.send(v); - } - uBit.serial.send("}\r\n"); - } - /** - * Takes a packet from the micro:bit radio queue. - * @param writeToSerial if true, write the received packet to serial without updating the global packet; - if false, update the global packet instead - */ - void receivePacket(bool writeToSerial) { - PacketBuffer p = uBit.radio.datagram.recv(); - - uint8_t* buf = p.getBytes(); - uint8_t tp; - int t; - int s; - int v; - StringData* m; - - - memcpy(&tp, buf, 1); - memcpy(&t, buf + 1, 4); - memcpy(&s, buf + 5, 4); - - if (tp == PACKET_TYPE_STRING) { - v = 0; - m = getStringValue(buf + PACKET_PREFIX_LENGTH, MAX_PAYLOAD_LENGTH - 1); - } - else { - memcpy(&v, buf + 9, 4); - if (tp == PACKET_TYPE_VALUE) { - m = getStringValue(buf + VALUE_PACKET_NAME_LEN_OFFSET, MAX_FIELD_NAME_LENGTH); - } - else { - m = ManagedString().leakData(); - } - } - - if (!writeToSerial) { - // Refresh global packet - packet = p; - type = tp; - time = t; - serial = s; - value = v; - msg = m; - } - else { - writePacketAsJSON(tp, v, s, t, m); - } - } - - /** - * Broadcasts a number over radio to any connected micro:bit in the group. - */ - //% help=radio/send-number - //% weight=60 - //% blockId=radio_datagram_send block="radio send number %value" blockGap=8 - void sendNumber(int value) { - if (radioEnable() != MICROBIT_OK) return; - uint8_t length = PACKET_PREFIX_LENGTH + sizeof(uint32_t); - uint8_t buf[length]; - memset(buf, 0, length); - - setPacketPrefix(buf, PACKET_TYPE_NUMBER); - memcpy(buf + PACKET_PREFIX_LENGTH, &value, 4); - - uBit.radio.datagram.send(buf, length); - } - - /** - * Broadcasts a name / value pair along with the device serial number - * and running time to any connected micro:bit in the group. - * @param name the field name (max 12 characters), eg: "name" - * @param value the numberic value + * Sends an event over radio to neigboring devices */ - //% help=radio/send-value - //% weight=59 - //% blockId=radio_datagram_send_value block="radio send|value %name|= %value" blockGap=8 - void sendValue(StringData* name, int value) { - if (radioEnable() != MICROBIT_OK) return; - - ManagedString n(name); - uint8_t buf[32]; - memset(buf, 0, 32); - - setPacketPrefix(buf, PACKET_TYPE_VALUE); - memcpy(buf + PACKET_PREFIX_LENGTH, &value, 4); - - int stringLen = copyStringValue(buf + VALUE_PACKET_NAME_LEN_OFFSET, name, MAX_FIELD_NAME_LENGTH); - - uBit.radio.datagram.send(buf, VALUE_PACKET_NAME_LEN_OFFSET + stringLen); - } - - /** - * Broadcasts a string along with the device serial number - * and running time to any connected micro:bit in the group. - */ - //% help=radio/send-string - //% weight=58 - //% blockId=radio_datagram_send_string block="radio send string %msg" - void sendString(StringData* msg) { - if (radioEnable() != MICROBIT_OK) return; - - uint8_t buf[32]; - memset(buf, 0, 32); - - setPacketPrefix(buf, PACKET_TYPE_STRING); - int stringLen = copyStringValue(buf + PACKET_PREFIX_LENGTH, msg, MAX_PAYLOAD_LENGTH - 1); - - uBit.radio.datagram.send(buf, PACKET_PREFIX_LENGTH + stringLen); - } - - /** - * Reads the next packet from the radio queue and and writes it to serial - * as JSON. - */ - //% help=radio/write-value-to-serial - //% weight=3 - //% blockId=radio_write_value_serial block="radio write value to serial" - //% deprecated=true - void writeValueToSerial() { - if (radioEnable() != MICROBIT_OK) return; - receivePacket(true); - } - - /** - * Writes the last received packet to serial as JSON. This should be called - * within an ``onDataPacketReceived`` callback. - */ - //% help=radio/write-received-packet-to-serial - //% weight=3 - //% blockId=radio_write_packet_serial block="radio write received packet to serial" + //% blockId=radioRaiseEvent block="radio raise event|from source %src=control_event_source_id|with value %value=control_event_value_id" + //% blockExternalInputs=1 //% advanced=true - void writeReceivedPacketToSerial() { + //% weight=1 + //% help=radio/raise-event + void raiseEvent(int src, int value) { if (radioEnable() != MICROBIT_OK) return; - writePacketAsJSON(type, value, (int) serial, (int) time, msg); + + uBit.radio.event.eventReceived(MicroBitEvent(src, value, CREATE_ONLY)); } /** - * Reads the next packet from the radio queue and returns the packet's number - * payload or 0 if the packet did not contain a number. + * Internal use only. Takes the next packet from the radio queue and returns its contents + RSSI in a Buffer */ - //% help=radio/receive-number - //% weight=46 - //% blockId=radio_datagram_receive block="radio receive number" blockGap=8 - //% deprecated=true - int receiveNumber() - { - if (radioEnable() != MICROBIT_OK) return 0; - receivePacket(false); - return value; + //% + Buffer readRawPacket() { + if (radioEnable() != MICROBIT_OK) return mkBuffer(NULL, 0); + + PacketBuffer p = uBit.radio.datagram.recv(); + if (p == PacketBuffer::EmptyPacket) + return mkBuffer(NULL, 0); + + int rssi = p.getRSSI(); + uint8_t buf[MICROBIT_RADIO_MAX_PACKET_SIZE + sizeof(int)]; // packet length + rssi + memset(buf, 0, sizeof(buf)); + memcpy(buf, p.getBytes(), p.length()); // data + memcpy(buf + MICROBIT_RADIO_MAX_PACKET_SIZE, &rssi, sizeof(int)); // RSSi - assumes Int32LE layout + return mkBuffer(buf, sizeof(buf)); + } + + /** + * Internal use only. Sends a raw packet through the radio (assumes RSSI appened to packet) + */ + //% async + void sendRawPacket(Buffer msg) { + if (radioEnable() != MICROBIT_OK || NULL == msg) return; + + // don't send RSSI data; and make sure no buffer underflow + int len = msg->length - sizeof(int); + if (len > 0) + uBit.radio.datagram.send(msg->data, len); } /** @@ -278,49 +76,22 @@ namespace radio { //% deprecated=true void onDataReceived(Action body) { if (radioEnable() != MICROBIT_OK) return; + registerWithDal(MICROBIT_ID_RADIO, MICROBIT_RADIO_EVT_DATAGRAM, body); - // make sure the receive buffer has a free spot - receiveNumber(); - } - - - /** - * Reads the next packet from the radio queue and returns the packet's string - * payload or the empty string if the packet did not contain a string. - */ - //% blockId=radio_datagram_receive_string block="radio receive string" blockGap=8 - //% weight=44 - //% help=radio/receive-string - //% deprecated=true - StringData* receiveString() { - if (radioEnable() != MICROBIT_OK) return ManagedString().leakData(); - receivePacket(false); - return msg; - } - - /** - * Gets the received signal strength indicator (RSSI) from the last packet taken - * from the radio queue (via ``receiveNumber``, ``receiveString``, etc). Not supported in simulator. - * namespace=radio - */ - //% help=radio/received-signal-strength - //% weight=40 - //% blockId=radio_datagram_rssi block="radio received signal strength" - //% deprecated=true - int receivedSignalStrength() { - if (radioEnable() != MICROBIT_OK) return 0; - return packet.getRSSI(); + uBit.radio.datagram.recv(); // wake up read code } /** * Sets the group id for radio communications. A micro:bit can only listen to one group ID at any time. - * @ param id the group id between ``0`` and ``255``, 1 eg + * @param id the group id between ``0`` and ``255``, eg: 1 */ //% help=radio/set-group - //% weight=10 blockGap=8 advanced=true + //% weight=100 //% blockId=radio_set_group block="radio set group %ID" + //% id.min=0 id.max=255 void setGroup(int id) { if (radioEnable() != MICROBIT_OK) return; + uBit.radio.setGroup(id); } @@ -331,66 +102,25 @@ namespace radio { //% help=radio/set-transmit-power //% weight=9 blockGap=8 //% blockId=radio_set_transmit_power block="radio set transmit power %power" + //% power.min=0 power.max=7 //% advanced=true void setTransmitPower(int power) { if (radioEnable() != MICROBIT_OK) return; + uBit.radio.setTransmitPower(power); } /** - * Set the radio to transmit the serial number in each message. - * @param transmit value indicating if the serial number is transmitted, eg: true - */ - //% help=radio/set-transmit-serial-number + * Change the transmission and reception band of the radio to the given channel + * @param band a frequency band in the range 0 - 83. Each step is 1MHz wide, based at 2400MHz. + **/ + //% help=radio/set-frequency-band //% weight=8 blockGap=8 - //% blockId=radio_set_transmit_serial_number block="radio set transmit serial number %transmit" + //% blockId=radio_set_frequency_band block="radio set frequency band %band" + //% band.min=0 band.max=83 //% advanced=true - void setTransmitSerialNumber(bool transmit) { + void setFrequencyBand(int band) { if (radioEnable() != MICROBIT_OK) return; - transmitSerialNumber = transmit; - } - - /** - * Returns the number payload from the last packet taken from the radio queue - * (via ``receiveNumber``, ``receiveString``, etc) or 0 if that packet did not - * contain a number. - */ - //% help=radio/received-number - int receivedNumber() { - if (radioEnable() != MICROBIT_OK) return 0; - return value; - } - - /** - * Returns the serial number of the sender micro:bit from the last packet taken - * from the radio queue (via ``receiveNumber``, ``receiveString``, etc) or 0 if - * that packet did not send a serial number. - */ - //% help=radio/received-serial - uint32_t receivedSerial() { - if (radioEnable() != MICROBIT_OK) return 0; - return serial; - } - - /** - * Returns the string payload from the last packet taken from the radio queue - * (via ``receiveNumber``, ``receiveString``, etc) or the empty string if that - * packet did not contain a string. - */ - //% help=radio/received-string - StringData* receivedString() { - if (radioEnable() != MICROBIT_OK) return ManagedString().leakData(); - return msg; - } - - /** - * Returns the system time of the sender micro:bit at the moment when it sent the - * last packet taken from the radio queue (via ``receiveNumber``, - * ``receiveString``, etc). - */ - //% help=radio/received-time - uint32_t receivedTime() { - if (radioEnable() != MICROBIT_OK) return 0; - return time; + uBit.radio.setFrequencyBand(band); } } diff --git a/libs/radio/radio.ts b/libs/radio/radio.ts index 4a5b1a71..2f564e8c 100644 --- a/libs/radio/radio.ts +++ b/libs/radio/radio.ts @@ -1,52 +1,444 @@ + +enum RadioPacketProperty { + //% blockIdentity=radio._packetProperty + //% block="signal strength" + SignalStrength = 2, + //% blockIdentity=radio._packetProperty + //% block="time" + Time = 0, + //% block="serial number" + //% blockIdentity=radio._packetProperty + SerialNumber = 1 +} + /** * Communicate data using radio packets */ -//% color=#E3008C weight=34 icon="\uf012" +//% color=#E3008C weight=96 icon="\uf012" namespace radio { - export class Packet { - /** - * The number payload if a number was sent in this packet (via ``sendNumber()`` or ``sendValue()``) - * or 0 if this packet did not contain a number. - */ - public receivedNumber: number; - /** - * The string payload if a string was sent in this packet (via ``sendString()`` or ``sendValue()``) - * or the empty string if this packet did not contain a string. - */ - public receivedString: string; - /** - * The system time of the sender of the packet at the time the packet was sent. - */ - public time: number; - /** - * The serial number of the sender of the packet or 0 if the sender did not sent their serial number. - */ - public serial: number; - /** - * The received signal strength indicator (RSSI) of the packet. - */ - public signal: number; + + const MAX_FIELD_DOUBLE_NAME_LENGTH = 8; + const MAX_PAYLOAD_LENGTH = 20; + const PACKET_PREFIX_LENGTH = 9; + const VALUE_PACKET_NAME_LEN_OFFSET = 13; + const DOUBLE_VALUE_PACKET_NAME_LEN_OFFSET = 17; + + // Packet Spec: + // | 0 | 1 ... 4 | 5 ... 8 | 9 ... 28 + // ---------------------------------------------------------------- + // | packet type | system time | serial number | payload + // + // Serial number defaults to 0 unless enabled by user + + // payload: number (9 ... 12) + const PACKET_TYPE_NUMBER = 0; + // payload: number (9 ... 12), name length (13), name (14 ... 26) + const PACKET_TYPE_VALUE = 1; + // payload: string length (9), string (10 ... 28) + const PACKET_TYPE_STRING = 2; + // payload: buffer length (9), buffer (10 ... 28) + const PACKET_TYPE_BUFFER = 3; + // payload: number (9 ... 16) + const PACKET_TYPE_DOUBLE = 4; + // payload: number (9 ... 16), name length (17), name (18 ... 26) + const PACKET_TYPE_DOUBLE_VALUE = 5; + + let transmittingSerial: boolean; + let initialized = false; + + export let lastPacket: RadioPacket; + let onReceivedNumberHandler: (receivedNumber: number) => void; + let onReceivedValueHandler: (name: string, value: number) => void; + let onReceivedStringHandler: (receivedString: string) => void; + let onReceivedBufferHandler: (receivedBuffer: Buffer) => void; + + function init() { + if (initialized) return; + initialized = true; + onDataReceived(handleDataReceived); + } + + function handleDataReceived() { + let buffer: Buffer = readRawPacket(); + while (buffer && buffer.length) { + lastPacket = RadioPacket.getPacket(buffer); + switch (lastPacket.packetType) { + case PACKET_TYPE_NUMBER: + case PACKET_TYPE_DOUBLE: + if (onReceivedNumberHandler) + onReceivedNumberHandler(lastPacket.numberPayload); + break; + case PACKET_TYPE_VALUE: + case PACKET_TYPE_DOUBLE_VALUE: + if (onReceivedValueHandler) + onReceivedValueHandler(lastPacket.stringPayload, lastPacket.numberPayload); + break; + case PACKET_TYPE_BUFFER: + if (onReceivedBufferHandler) + onReceivedBufferHandler(lastPacket.bufferPayload); + break; + case PACKET_TYPE_STRING: + if (onReceivedStringHandler) + onReceivedStringHandler(lastPacket.stringPayload); + break; + } + + // read next packet if any + buffer = readRawPacket(); + } } /** - * Registers code to run when the radio receives a packet. Also takes the - * received packet from the radio queue. + * Registers code to run when the radio receives a number. */ - //% help=radio/on-data-packet-received - //% mutate=objectdestructuring - //% mutateText=Packet - //% mutateDefaults="receivedNumber;receivedString:name,receivedNumber:value;receivedString" - //% blockId=radio_on_packet block="on radio received" blockGap=8 - export function onDataPacketReceived(cb: (packet: Packet) => void) { - onDataReceived(() => { - receiveNumber(); - const packet = new Packet(); - packet.receivedNumber = receivedNumber(); - packet.time = receivedTime(); - packet.serial = receivedSerial(); - packet.receivedString = receivedString(); - packet.signal = receivedSignalStrength(); - cb(packet) - }); + //% help=radio/on-received-number + //% blockId=radio_on_number_drag block="on radio received" blockGap=16 + //% useLoc="radio.onDataPacketReceived" draggableParameters=reporter + export function onReceivedNumber(cb: (receivedNumber: number) => void) { + init(); + onReceivedNumberHandler = cb; } -} + + /** + * Registers code to run when the radio receives a key value pair. + */ + //% help=radio/on-received-value + //% blockId=radio_on_value_drag block="on radio received" blockGap=16 + //% useLoc="radio.onDataPacketReceived" draggableParameters=reporter + export function onReceivedValue(cb: (name: string, value: number) => void) { + init(); + onReceivedValueHandler = cb; + } + + /** + * Registers code to run when the radio receives a string. + */ + //% help=radio/on-received-string + //% blockId=radio_on_string_drag block="on radio received" blockGap=16 + //% useLoc="radio.onDataPacketReceived" draggableParameters=reporter + export function onReceivedString(cb: (receivedString: string) => void) { + init(); + onReceivedStringHandler = cb; + } + + /** + * Registers code to run when the radio receives a buffer. + */ + //% help=radio/on-received-buffer blockHidden=1 + //% blockId=radio_on_buffer_drag block="on radio received" blockGap=16 + //% useLoc="radio.onDataPacketReceived" draggableParameters=reporter + export function onReceivedBuffer(cb: (receivedBuffer: Buffer) => void) { + init(); + onReceivedBufferHandler = cb; + } + + /** + * Returns properties of the last radio packet received. + * @param type the type of property to retrieve from the last packet + */ + //% help=radio/received-packet + //% weight=11 blockGap=8 + //% blockId=radio_received_packet block="received packet %type=radio_packet_property" blockGap=16 + export function receivedPacket(type: number) { + if (lastPacket) { + switch (type) { + case RadioPacketProperty.Time: return lastPacket.time; + case RadioPacketProperty.SerialNumber: return lastPacket.serial; + case RadioPacketProperty.SignalStrength: return lastPacket.signal; + } + } + return 0; + } + + /** + * Gets a packet property. + * @param type the packet property type, eg: PacketProperty.time + */ + //% blockId=radio_packet_property block="%note" + //% shim=TD_ID blockHidden=1 + export function _packetProperty(type: RadioPacketProperty): number { + return type; + } + + export class RadioPacket { + public static getPacket(data: Buffer) { + // last 4 bytes is RSSi + return new RadioPacket(data); + } + + public static mkPacket(packetType: number) { + const res = new RadioPacket(); + res.data[0] = packetType; + return res; + } + + private constructor(public readonly data?: Buffer) { + if (!data) this.data = control.createBuffer(DAL.MICROBIT_RADIO_MAX_PACKET_SIZE + 4); + } + + get signal() { + return this.data.getNumber(NumberFormat.Int32LE, this.data.length - 4); + } + + get packetType() { + return this.data[0]; + } + + get time() { + return this.data.getNumber(NumberFormat.Int32LE, 1); + } + + set time(val: number) { + this.data.setNumber(NumberFormat.Int32LE, 1, val); + } + + get serial() { + return this.data.getNumber(NumberFormat.Int32LE, 5); + } + + set serial(val: number) { + this.data.setNumber(NumberFormat.Int32LE, 5, val); + } + + get stringPayload() { + const offset = getStringOffset(this.packetType) as number; + return offset ? this.data.slice(offset + 1, this.data[offset]).toString() : undefined; + } + + set stringPayload(val: string) { + const offset = getStringOffset(this.packetType) as number; + if (offset) { + const buf = control.createBufferFromUTF8(truncateString(val, getMaxStringLength(this.packetType))); + this.data[offset] = buf.length; + this.data.write(offset + 1, buf); + } + } + + get numberPayload() { + switch (this.packetType) { + case PACKET_TYPE_NUMBER: + case PACKET_TYPE_VALUE: + return this.data.getNumber(NumberFormat.Int32LE, PACKET_PREFIX_LENGTH); + case PACKET_TYPE_DOUBLE: + case PACKET_TYPE_DOUBLE_VALUE: + return this.data.getNumber(NumberFormat.Float64LE, PACKET_PREFIX_LENGTH); + } + return undefined; + } + + set numberPayload(val: number) { + switch (this.packetType) { + case PACKET_TYPE_NUMBER: + case PACKET_TYPE_VALUE: + this.data.setNumber(NumberFormat.Int32LE, PACKET_PREFIX_LENGTH, val); + break; + case PACKET_TYPE_DOUBLE: + case PACKET_TYPE_DOUBLE_VALUE: + this.data.setNumber(NumberFormat.Float64LE, PACKET_PREFIX_LENGTH, val); + break; + } + } + + get bufferPayload() { + const len = this.data[PACKET_PREFIX_LENGTH]; + return this.data.slice(PACKET_PREFIX_LENGTH + 1, len); + } + + set bufferPayload(b: Buffer) { + const len = Math.min(b.length, MAX_PAYLOAD_LENGTH - 1); + this.data[PACKET_PREFIX_LENGTH] = len; + this.data.write(PACKET_PREFIX_LENGTH + 1, b.slice(0, len)); + } + + hasString() { + return this.packetType === PACKET_TYPE_STRING || + this.packetType === PACKET_TYPE_VALUE || + this.packetType === PACKET_TYPE_DOUBLE_VALUE; + } + + hasNumber() { + return this.packetType === PACKET_TYPE_NUMBER || + this.packetType === PACKET_TYPE_DOUBLE || + this.packetType === PACKET_TYPE_VALUE || + this.packetType === PACKET_TYPE_DOUBLE_VALUE; + } + } + + + /** + * Broadcasts a number over radio to any connected micro:bit in the group. + */ + //% help=radio/send-number + //% weight=60 + //% blockId=radio_datagram_send block="radio send number %value" blockGap=8 + export function sendNumber(value: number) { + let packet: RadioPacket; + + if (value === (value | 0)) { + packet = RadioPacket.mkPacket(PACKET_TYPE_NUMBER); + } + else { + packet = RadioPacket.mkPacket(PACKET_TYPE_DOUBLE); + } + + packet.numberPayload = value; + sendPacket(packet); + } + + /** + * Broadcasts a name / value pair along with the device serial number + * and running time to any connected micro:bit in the group. The name can + * include no more than 8 characters. + * @param name the field name (max 8 characters), eg: "name" + * @param value the numeric value + */ + //% help=radio/send-value + //% weight=59 + //% blockId=radio_datagram_send_value block="radio send|value %name|= %value" blockGap=8 + export function sendValue(name: string, value: number) { + let packet: RadioPacket; + + if (value === (value | 0)) { + packet = RadioPacket.mkPacket(PACKET_TYPE_VALUE); + } + else { + packet = RadioPacket.mkPacket(PACKET_TYPE_DOUBLE_VALUE); + } + + packet.numberPayload = value; + packet.stringPayload = name; + sendPacket(packet); + } + + /** + * Broadcasts a string along with the device serial number + * and running time to any connected micro:bit in the group. + */ + //% help=radio/send-string + //% weight=58 + //% blockId=radio_datagram_send_string block="radio send string %msg" + //% msg.shadowOptions.toString=true + export function sendString(value: string) { + const packet = RadioPacket.mkPacket(PACKET_TYPE_STRING); + packet.stringPayload = value; + sendPacket(packet); + } + + /** + * Broadcasts a buffer (up to 19 bytes long) along with the device serial number + * and running time to any connected micro:bit in the group. + */ + //% help=radio/send-buffer + //% weight=57 + //% advanced=true + export function sendBuffer(msg: Buffer) { + const packet = RadioPacket.mkPacket(PACKET_TYPE_BUFFER); + packet.bufferPayload = msg; + sendPacket(packet); + } + + /** + * Writes the last received packet to serial as JSON. This should be called + * within an ``onDataPacketReceived`` callback. + */ + //% help=radio/write-received-packet-to-serial + //% weight=3 + //% blockId=radio_write_packet_serial block="radio write received packet to serial" + //% advanced=true + export function writeReceivedPacketToSerial() { + if (lastPacket) writeToSerial(lastPacket) + } + + /** + * Set the radio to transmit the serial number in each message. + * @param transmit value indicating if the serial number is transmitted, eg: true + */ + //% help=radio/set-transmit-serial-number + //% weight=8 blockGap=8 + //% blockId=radio_set_transmit_serial_number block="radio set transmit serial number %transmit" + //% advanced=true + export function setTransmitSerialNumber(transmit: boolean) { + transmittingSerial = transmit; + } + + /** + * Gets the received signal strength indicator (RSSI) from the last packet taken + * from the radio queue (via ``receiveNumber``, ``receiveString``, etc). Not supported in simulator. + */ + //% help=radio/received-signal-strength + //% weight=40 + //% blockId=radio_datagram_rssi block="radio received signal strength" + //% deprecated=true blockHidden=true + export function receivedSignalStrength(): number { + return lastPacket ? lastPacket.signal : 0; + } + + export function writeToSerial(packet: RadioPacket) { + serial.writeString("{"); + serial.writeString("\"t\":"); + serial.writeString("" + packet.time); + serial.writeString(",\"s\":"); + serial.writeString("" + packet.serial); + + if (packet.hasString()) { + serial.writeString(",\"n\":\""); + serial.writeString(packet.stringPayload); + serial.writeString("\""); + } + if (packet.packetType == PACKET_TYPE_BUFFER) { + serial.writeString(",\"b\":\""); + // TODO: proper base64 encoding + serial.writeString(packet.bufferPayload.toString()); + serial.writeString("\""); + } + if (packet.hasNumber()) { + serial.writeString(",\"v\":"); + serial.writeString("" + packet.numberPayload); + } + + serial.writeString("}\r\n"); + } + + function sendPacket(packet: RadioPacket) { + packet.time = input.runningTime(); + packet.serial = transmittingSerial ? control.deviceSerialNumber() : 0; + radio.sendRawPacket(packet.data); + } + + function truncateString(str: string, bytes: number) { + str = str.substr(0, bytes); + let buff = control.createBufferFromUTF8(str); + + while (buff.length > bytes) { + str = str.substr(0, str.length - 1); + buff = control.createBufferFromUTF8(str); + } + + return str; + } + + function getStringOffset(packetType: number) { + switch (packetType) { + case PACKET_TYPE_STRING: + return PACKET_PREFIX_LENGTH; + case PACKET_TYPE_VALUE: + return VALUE_PACKET_NAME_LEN_OFFSET; + case PACKET_TYPE_DOUBLE_VALUE: + return DOUBLE_VALUE_PACKET_NAME_LEN_OFFSET; + default: + return undefined; + } + } + + function getMaxStringLength(packetType: number) { + switch (packetType) { + case PACKET_TYPE_STRING: + return MAX_PAYLOAD_LENGTH - 2; + case PACKET_TYPE_VALUE: + case PACKET_TYPE_DOUBLE_VALUE: + return MAX_FIELD_DOUBLE_NAME_LENGTH; + default: + return undefined; + } + } +} \ No newline at end of file diff --git a/libs/radio/shims.d.ts b/libs/radio/shims.d.ts index 0aeaa862..e7983bad 100644 --- a/libs/radio/shims.d.ts +++ b/libs/radio/shims.d.ts @@ -2,66 +2,30 @@ - //% color=270 weight=34 + //% color=#E3008C weight=96 icon="\uf012" declare namespace radio { /** - * Broadcasts a number over radio to any connected micro:bit in the group. + * Sends an event over radio to neigboring devices */ - //% help=radio/send-number - //% weight=60 - //% blockId=radio_datagram_send block="radio send number %value" blockGap=8 shim=radio::sendNumber - function sendNumber(value: number): void; + //% blockId=radioRaiseEvent block="radio raise event|from source %src=control_event_source_id|with value %value=control_event_value_id" + //% blockExternalInputs=1 + //% advanced=true + //% weight=1 + //% help=radio/raise-event shim=radio::raiseEvent + function raiseEvent(src: int32, value: int32): void; /** - * Broadcasts a name / value pair along with the device serial number - * and running time to any connected micro:bit in the group. - * @param name the field name (max 12 characters), eg: "name" - * @param value the numberic value + * Internal use only. Takes the next packet from the radio queue and returns its contents + RSSI in a Buffer */ - //% help=radio/send-value - //% weight=59 - //% blockId=radio_datagram_send_value block="radio send|value %name|= %value" blockGap=8 shim=radio::sendValue - function sendValue(name: string, value: number): void; + //% shim=radio::readRawPacket + function readRawPacket(): Buffer; /** - * Broadcasts a string along with the device serial number - * and running time to any connected micro:bit in the group. + * Internal use only. Sends a raw packet through the radio (assumes RSSI appened to packet) */ - //% help=radio/send-string - //% weight=58 - //% blockId=radio_datagram_send_string block="radio send string %msg" shim=radio::sendString - function sendString(msg: string): void; - - /** - * Reads the next packet from the radio queue and and writes it to serial - * as JSON. - */ - //% help=radio/write-value-to-serial - //% weight=3 - //% blockId=radio_write_value_serial block="radio write value to serial" - //% deprecated=true shim=radio::writeValueToSerial - function writeValueToSerial(): void; - - /** - * Writes the last received packet to serial as JSON. This should be called - * within an ``onDataPacketReceived`` callback. - */ - //% help=radio/write-received-packet-to-serial - //% weight=3 - //% blockId=radio_write_packet_serial block="radio write received packet to serial" - //% advanced=true shim=radio::writeReceivedPacketToSerial - function writeReceivedPacketToSerial(): void; - - /** - * Reads the next packet from the radio queue and returns the packet's number - * payload or 0 if the packet did not contain a number. - */ - //% help=radio/receive-number - //% weight=46 - //% blockId=radio_datagram_receive block="radio receive number" blockGap=8 - //% deprecated=true shim=radio::receiveNumber - function receiveNumber(): number; + //% async shim=radio::sendRawPacket + function sendRawPacket(msg: Buffer): void; /** * Registers code to run when a packet is received over radio. @@ -72,35 +36,15 @@ declare namespace radio { //% deprecated=true shim=radio::onDataReceived function onDataReceived(body: () => void): void; - /** - * Reads the next packet from the radio queue and returns the packet's string - * payload or the empty string if the packet did not contain a string. - */ - //% blockId=radio_datagram_receive_string block="radio receive string" blockGap=8 - //% weight=44 - //% help=radio/receive-string - //% deprecated=true shim=radio::receiveString - function receiveString(): string; - - /** - * Gets the received signal strength indicator (RSSI) from the last packet taken - * from the radio queue (via ``receiveNumber``, ``receiveString``, etc). Not supported in simulator. - * namespace=radio - */ - //% help=radio/received-signal-strength - //% weight=40 - //% blockId=radio_datagram_rssi block="radio received signal strength" - //% deprecated=true shim=radio::receivedSignalStrength - function receivedSignalStrength(): number; - /** * Sets the group id for radio communications. A micro:bit can only listen to one group ID at any time. - * @ param id the group id between ``0`` and ``255``, 1 eg + * @param id the group id between ``0`` and ``255``, eg: 1 */ //% help=radio/set-group - //% weight=10 blockGap=8 advanced=true - //% blockId=radio_set_group block="radio set group %ID" shim=radio::setGroup - function setGroup(id: number): void; + //% weight=100 + //% blockId=radio_set_group block="radio set group %ID" + //% id.min=0 id.max=255 shim=radio::setGroup + function setGroup(id: int32): void; /** * Change the output power level of the transmitter to the given value. @@ -109,50 +53,20 @@ declare namespace radio { //% help=radio/set-transmit-power //% weight=9 blockGap=8 //% blockId=radio_set_transmit_power block="radio set transmit power %power" + //% power.min=0 power.max=7 //% advanced=true shim=radio::setTransmitPower - function setTransmitPower(power: number): void; + function setTransmitPower(power: int32): void; /** - * Set the radio to transmit the serial number in each message. - * @param transmit value indicating if the serial number is transmitted, eg: true - */ - //% help=radio/set-transmit-serial-number + * Change the transmission and reception band of the radio to the given channel + * @param band a frequency band in the range 0 - 83. Each step is 1MHz wide, based at 2400MHz. + **/ + //% help=radio/set-frequency-band //% weight=8 blockGap=8 - //% blockId=radio_set_transmit_serial_number block="radio set transmit serial number %transmit" - //% advanced=true shim=radio::setTransmitSerialNumber - function setTransmitSerialNumber(transmit: boolean): void; - - /** - * Returns the number payload from the last packet taken from the radio queue - * (via ``receiveNumber``, ``receiveString``, etc) or 0 if that packet did not - * contain a number. - */ - //% help=radio/received-number shim=radio::receivedNumber - function receivedNumber(): number; - - /** - * Returns the serial number of the sender micro:bit from the last packet taken - * from the radio queue (via ``receiveNumber``, ``receiveString``, etc) or 0 if - * that packet did not send a serial number. - */ - //% help=radio/received-serial shim=radio::receivedSerial - function receivedSerial(): number; - - /** - * Returns the string payload from the last packet taken from the radio queue - * (via ``receiveNumber``, ``receiveString``, etc) or the empty string if that - * packet did not contain a string. - */ - //% help=radio/received-string shim=radio::receivedString - function receivedString(): string; - - /** - * Returns the system time of the sender micro:bit at the moment when it sent the - * last packet taken from the radio queue (via ``receiveNumber``, - * ``receiveString``, etc). - */ - //% help=radio/received-time shim=radio::receivedTime - function receivedTime(): number; + //% blockId=radio_set_frequency_band block="radio set frequency band %band" + //% band.min=0 band.max=83 + //% advanced=true shim=radio::setFrequencyBand + function setFrequencyBand(band: int32): void; } // Auto-generated. Do not edit. Really. diff --git a/libs/radio/test.ts b/libs/radio/test.ts new file mode 100644 index 00000000..78182f64 --- /dev/null +++ b/libs/radio/test.ts @@ -0,0 +1,349 @@ +/** + * Tests for the radio. Press A on mbit 1 and B on mbit 2 to run the tests. + * Sends random ints, doubles, strings, and buffers and checks them on + * the other side + */ + +class FastRandom { + private lfsr: number; + public seed: number; + + constructor(seed?: number) { + if (seed === undefined) seed = Math.randomRange(0x0001, 0xFFFF); + this.seed = seed; + this.lfsr = seed; + } + + next(): number { + return this.lfsr = (this.lfsr >> 1) ^ ((-(this.lfsr & 1)) & 0xb400); + } + + randomRange(min: number, max: number): number { + return min + (max > min ? this.next() % (max - min + 1) : 0); + } + + reset() { + this.lfsr = this.seed; + } +} + +enum TestStage { + Integer, + String, + Double, + IntValue, + DblValue, + Buffer +} + +const TEST_COUNT = 30; + +radio.setGroup(78) +const rand = new FastRandom(1234); + +let stage = TestStage.Integer; + +function initSender() { + let lastReceived: number; + let lastString: string; + let testIndex = 0; + let lastBuf: Buffer; + + let lastAck = -1; + + rand.reset(); + basic.clearScreen(); + + // Send loop + control.inBackground(function () { + while (true) { + for (let i = 0; i < TEST_COUNT; i++) { + toggle(testIndex); + + if (stage === TestStage.Integer) { + lastReceived = getNextInt(); + } + else if (stage === TestStage.Double) { + lastReceived = getNextDouble(); + } + else if (stage === TestStage.IntValue) { + lastString = getNextName(); + console.log(truncateString(lastString, 8)) + lastReceived = getNextInt(); + } + else if (stage === TestStage.DblValue) { + lastString = getNextName(); + lastReceived = getNextDouble(); + } + else if (stage === TestStage.String) { + lastString = getNextString(); + console.log(truncateString(lastString, 19)) + } + else if (stage === TestStage.Buffer) { + lastBuf = getNextBuffer(); + } + + while (lastAck !== testIndex) { + if (stage === TestStage.Integer || stage === TestStage.Double) { + radio.sendNumber(lastReceived) + } + else if (stage === TestStage.IntValue || stage === TestStage.DblValue) { + radio.sendValue(lastString, lastReceived) + } + else if (stage === TestStage.String) { + radio.sendString(lastString); + } + else if (stage === TestStage.Buffer) { + radio.sendBuffer(lastBuf); + } + basic.pause(10); + } + testIndex++; + } + + stage++; + if (stage > TestStage.Buffer) { + basic.showIcon(IconNames.Yes); + return; + } + } + }) + + radio.onReceivedNumber(function (receivedNumber: number) { + if (receivedNumber > lastAck) { + lastAck = receivedNumber; + } + }); +} + +let lastReceived: number; +let lastString: string; +let testIndex = -1; +let running = true; +let lastBuf: Buffer; + +let lastPacket = new radio.Packet(); +let currentPacket = new radio.Packet(); + +function truncateString(str: string, bytes: number) { + str = str.substr(0, bytes); + let buff = control.createBufferFromUTF8(str); + + while (buff.length > bytes) { + str = str.substr(0, str.length - 1); + buff = control.createBufferFromUTF8(str); + } + + return str; +} + +function initReceiver() { + + rand.reset(); + + basic.clearScreen(); + + radio.onDataReceived(function () { + radio.receiveNumber(); + + currentPacket.receivedNumber = radio.receivedNumber(); + currentPacket.receivedString = radio.receivedString(); + currentPacket.receivedBuffer = radio.receivedBuffer(); + + if (currentPacket.receivedNumber === lastPacket.receivedNumber && + currentPacket.receivedString === lastPacket.receivedString && + checkBufferEqual(currentPacket.receivedBuffer, lastPacket.receivedBuffer)) { + return; + } + + lastPacket.receivedNumber = currentPacket.receivedNumber + lastPacket.receivedString = currentPacket.receivedString + lastPacket.receivedBuffer = currentPacket.receivedBuffer + + switch (stage) { + case TestStage.Integer: + verifyInt(radio.receivedNumber()); + break; + case TestStage.Double: + verifyDouble(radio.receivedNumber()); + break; + case TestStage.IntValue: + verifyIntValue(radio.receivedString(), radio.receivedNumber()); + break; + case TestStage.DblValue: + verifyDblValue(radio.receivedString(), radio.receivedNumber()); + break; + case TestStage.String: + verifyString(radio.receivedString()); + break; + case TestStage.Buffer: + verifyBuffer(radio.receivedBuffer()); + break; + } + }) + + control.inBackground(function () { + while (running) { + radio.sendNumber(testIndex); + basic.pause(10) + } + }) +} + +function nextTest() { + testIndex++; + toggle(testIndex); + console.log(`test ${testIndex}`) + if (((testIndex + 1) % TEST_COUNT) === 0) { + stage++; + + if (stage > TestStage.Buffer) { + basic.showIcon(IconNames.Yes) + running = false; + } + } +} + +function verifyInt(int: number) { + if (int === lastReceived) return; + lastReceived = int; + if (lastReceived != getNextInt()) fail(); + nextTest() +} + +function verifyDouble(dbl: number) { + if (dbl === lastReceived) return; + lastReceived = dbl; + if (lastReceived != getNextDouble()) fail(); + nextTest() +} + +function verifyIntValue(name: string, val: number) { + if (val === lastReceived) return; + lastReceived = val; + + if (name != truncateString(getNextName(), 8) || lastReceived != getNextInt()) fail(); + nextTest() +} + +function verifyDblValue(name: string, val: number) { + if (val === lastReceived) return; + lastReceived = val; + + if (name != truncateString(getNextName(), 8) || lastReceived != getNextDouble()) fail(); + nextTest() +} + +function verifyString(str: string) { + if (!str || str === lastString) return; + + lastString = str; + let next = truncateString(getNextString(), 19); + + if (lastString !== next) { + console.log(`got ${control.createBufferFromUTF8(lastString).toHex()} expected ${control.createBufferFromUTF8(next).toHex()}`) + } + nextTest() +} + +function verifyBuffer(buf: Buffer) { + if (checkBufferEqual(lastBuf, buf)) return; + + lastBuf = buf; + + if (!checkBufferEqual(lastBuf, getNextBuffer())) { + fail(); + } + nextTest() +} + +function fail() { + control.panic(testIndex); +} + + +let _lastInt: number; +let _lastDbl: number; +let _lastStr: string; +let _lastBuf: Buffer; +let _lastNam: string; + +function getNextInt(): number { + let res = rand.next(); + if (!res || res === _lastInt) return getNextInt(); + _lastInt = res; + return res; +} + +function getNextDouble(): number { + let res = rand.next() / rand.next(); + if (res === _lastDbl) return getNextDouble(); + _lastDbl = res; + return res; +} + +function getNextString(): string { + let len = rand.randomRange(1, 19); + let res = ""; + for (let i = 0; i < len; i++) { + res += String.fromCharCode(rand.next() & 0xbfff); + } + + if (res === _lastStr) return getNextString(); + + _lastStr = res; + return res; +} + +function getNextName(): string { + let len = rand.randomRange(1, 8); + let res = ""; + for (let i = 0; i < len; i++) { + res += String.fromCharCode(rand.next() & 0xbfff); + } + + if (res === _lastNam) return getNextName(); + + _lastNam = res; + return res; +} + +function getNextBuffer(): Buffer { + let len = rand.randomRange(0, 8); + let res = control.createBuffer(len); + + for (let i = 0; i < len; i++) { + res[i] = rand.next() & 0xff; + } + + if (checkBufferEqual(_lastBuf, res)) return getNextBuffer(); + + _lastBuf = res; + return res; +} + +function checkBufferEqual(a: Buffer, b: Buffer) { + if (a === b) return true; + if ((!a && b) || (a && !b)) return false; + if (a.length != b.length) return false; + for (let i = 0; i < a.length; i++) { + if (a[i] !== b[i]) return false; + } + return true; +} + +input.onButtonPressed(Button.A, function () { + basic.showString("S"); + initSender(); +}) + +input.onButtonPressed(Button.B, function () { + basic.showString("R"); + initReceiver(); +}) + +function toggle(index: number) { + const x = index % 5; + const y = Math.idiv(index, 5) % 5; + led.toggle(x, y); +} diff --git a/microbit.code-workspace b/microbit.code-workspace new file mode 100644 index 00000000..c925e61c --- /dev/null +++ b/microbit.code-workspace @@ -0,0 +1,13 @@ +{ + "folders": [ + { + "path": "../pxt" + }, + { + "path": "../pxt-common-packages" + }, + { + "path": "." + } + ] +} \ No newline at end of file diff --git a/olddocs/js/bits.md b/olddocs/js/bits.md deleted file mode 100644 index 0789cbcc..00000000 --- a/olddocs/js/bits.md +++ /dev/null @@ -1,67 +0,0 @@ -# Bits Library - -Functions in the Bits library. - -### @parent td/language - -The binary numeral system represents numeric values using values 0 and 1. This is how almost all modern computers store data. Each 0 or 1 digit is called a binary digit, or bit for short. - -The Bits library includes functions for bit-level manipulation of integers. In the [Touch Develop editor](/js/editor), click `bits` to see the following bit functions: - -## Bitwise and, or, and xor functions - -#### Syntax - -bits `->` *and/or/xor* uint32 (x : [Number](/reference/types/number), y : [Number](/reference/types/number)) *returns* [Number](/reference/types/number) - -#### Parameters - -* x - an unsigned 32 bit integer [Number](/reference/types/number) -* y - another unsigned 32 bit integer [Number](/reference/types/number) - -### and uint32 - -performs bitwise AND; returns `1` at position i if both bits *x[i]* and *y[i]* are `1`, otherwise returns `0`. - -### or uint32 - -performs bitwise OR; returns `1` at position *i* if either bit *x[i]* or *y[i]* is `1`, otherwise returns `0`. - -### xor uint32 - -performs bitwise exclusive XOR; returns `1` at position *i* if *x[i]=1 and y[i]=0* or *x[i] = 0 and y[i] =1*; returns `0` otherwise - -## Rotate left and rotate right - -Rotate bits to the left or the right, by the specified number of positions. - -#### Syntax - -bits `->` rotate left unint32 (x : [Number](/reference/types/number), bits : [Number](/reference/types/number)) *returns* [Number](/reference/types/number) - -bits `->` rotate right unint32 (x : [Number](/reference/types/number), bits : [Number](/reference/types/number)) *returns* [Number](/reference/types/number) - -#### Parameters - -* x - [Number](/reference/types/number); -* bits - [Number](/reference/types/number); - -## Shift left and shift right - -Shift bits to the left or the right, by the specified number of positions. - -#### Syntax - -bits `->` shift left unint32 (x : [Number](/reference/types/number), bits : [Number](/reference/types/number)) *returns* [Number](/reference/types/number) - -bits `->` shift right unint32 (x : [Number](/reference/types/number), bits : [Number](/reference/types/number)) *returns* [Number](/reference/types/number) - -#### Parameters - -* x - [Number](/reference/types/number); -* bits - [Number](/reference/types/number); - -### See also - -[statements and operators](/js/statements), [math functions](/js/math), [Number](/reference/types/number) - diff --git a/olddocs/js/break.md b/olddocs/js/break.md deleted file mode 100644 index e318720f..00000000 --- a/olddocs/js/break.md +++ /dev/null @@ -1,33 +0,0 @@ -# Break - -Break statement; exit a for or while loop. - -### @parent js/language - - -Exit a [while](/js/while) or [for](/reference/loops/for) loop before the loop is complete. - -### Touch Develop syntax - -**break** - -### Example: count to a random number - -The following example counts from 0 to a random number from 0-9. When the for loop counter equals the random number (`i = x`), the `break` statement exits the loop: - -``` -let x = Math.random(10) -for (let i = 0; i < 10; i++) { - if (i == x) { - break - } else { - basic.showNumber(i, 0) - basic.pause(500) - } -} -``` - -### See also - -[for](/reference/loops/for), [while](/js/while) - diff --git a/olddocs/js/call.md b/olddocs/js/call.md deleted file mode 100644 index 42822e1f..00000000 --- a/olddocs/js/call.md +++ /dev/null @@ -1,63 +0,0 @@ -# Call a Function - -How to call a function in your code. - -### @parent js/language - - -Type a function name in your code to call an existing [function](/js/function) in your script. - -### Call a function - -1. In the Touch Develop editor, click a line of code to open the on-screen [Code Keyboard](/js/editor). - -2. Click `code` to see the functions in your script. - -2. Click the function that you want to call. - -3. Click `store in var` to store the return value in a variable. - -### Example: the square function - -Here's a function called `square`, with a [Number](/reference/types/number) input parameter: - -``` -/** - * // returns the square of the input parameter x - * @param x TODO - */ -export function square(x: number) : number { - let result: number - return x * x - return result -} -``` - -The following code calls the `square` function, passing it an input parameter (`x`), and storing the return value in the `result` variable: - -### ~hide - -``` -let x1 = 2 -``` - -### ~ - -``` -let result1 = square(x1) -``` - -Or this code, which displays the result of the `square` function (without first storing the value in a variable): - -``` -basic.showNumber(square(x1), 150) -``` - -### See all your functions - -To see a list of the functions in a script, open the script and then click `script` (in the upper-right corner). All of the functions appear under the **code** heading. Click on a function to open it in the editor. - -### See also - -[function parameters](/js/functionparameters), [create a function](/js/function), [return statement](/js/return) - diff --git a/olddocs/js/code.md b/olddocs/js/code.md deleted file mode 100644 index ea35a75a..00000000 --- a/olddocs/js/code.md +++ /dev/null @@ -1,31 +0,0 @@ -# function - -A function with inputs and outputs. - -### @parent js/language - - -To add a **functions** to your script, click the `script` button, then click the `+` `add new function` button - -### functions - -A **function** takes [inputs](/actionparameters), runs code and (optionally) returns an output. - -TouchDevelop functions are similar to `mathematical functions`. Consider the function that computes the square of `x`: `square(x) = x*x`. In code, it would look like this: - -``` -export function square(x: number) : number { - let result: number - return x * x - return result -} -``` - -### private function - -An function can be marked as **private** in the properties. A private function is not visible outside a library (if the script is a library) - -### documentation - -The comment(s) at the beginning of a function used to provide a description of its purpose. This text will show in the help area when the function is called from the code editor. This is particularly useful for [libraries](/libraries). - diff --git a/olddocs/js/collections.md b/olddocs/js/collections.md deleted file mode 100644 index a71ed987..00000000 --- a/olddocs/js/collections.md +++ /dev/null @@ -1,111 +0,0 @@ -# The Collections Library - -#docs - -A collection allows you to store an arbitrary number of elements. If you have a collection of numbers, you can add new numbers to the collection; remove numbers; check if a number is in there; iterate over all the numbers in the collection. - -## Creation - -A collection is created as follows. Note that we are providing the *type* of the elements that are meant to go in the collection. - -``` -let c = ([]) -``` - -At the moment, you can create collections of numbers, booleans, strings, and any of the object types that you defined. - -**Important:** if your collection is a global variable, make sure you initialise it at the beginning of your script. - -``` -c = ([]) -``` - -Trying to use an uninitialised collection will crash the simulator, and display a sad face on the device. - -## Adding and finding elements; counting - -``` -c.push(3) -``` - -The line above just added the number `3` to the collection. One can think of a collection as a list, where `add` appends the element at the end of the list. - -At this stage, our collection has size `1`, meaning that the line below will display `1`. - -``` -basic.showNumber(c.length, 150) -``` - -We can add another number as follows. - -``` -c.push(5) -``` - -At this stage, the count of elements in the collection is `2`. We mentioned earlier that a collection is like a list: adding elements appends them at the end of the list. This means that, at this point in the program, the first element in the list is 3 (we added it earlier), and the second element in the list is 5 (we just added it). - -``` -basic.showNumber(c[0], 150) -``` - -Can you guess what the line above does? Remember that in computing, indexing starts at zero. This function takes the *first element* in the list. This means that the line above displays `3`. - -We can ask questions such as: "what is the index of this element"? The line below displays `1`, meaning that the number `5` is first found at index `1` (it is the *second* element in the list). - -``` -basic.showNumber(c.indexOf(5, 0), 150) -``` - -## Iterating over the elements - -A classic pattern consists in iterating over all the elements in the collection. Here's one way to do it: - -``` -for (let i = 0; i < c.length; i++) { - basic.showString("The element at index " + i.toString() + " is " + c[i].toString(), 150) -} -``` - -The code above will first print `The element at index 0 is 3`, then `The element at index 1 is 5`. - -## Modifying and removing elements - -One can modify an existing collection using `set at`, which changes the element *at a given index*. - -``` -c[0] = 7 -``` - -The line above modifies the collection `c` so that, after the line above, the first element of the collection is now `7`. - -Removing elements can be done in two different ways. We can remove the *first occurrence* of an element. - -``` -c.remove(5) -``` - -This removes the first occurrence of `5` in the list. At this point in the program, our list now has just one element (at index 0). If we wish, we can use `remove at` to remove the element at a given index. - -``` -c.splice(0, 1) -``` - -Now, the collection is empty. - -## Complete example - -This program will record the current acceleration measured on `x` when you press `A`; when you press `B`, the program will print out all the acceleration values that were measured, then will clear the collection. - -``` -let accelerations = ([]) -input.onButtonPressed(Button.A, () => { - accelerations.push(input.acceleration("x")) -}) -input.onButtonPressed(Button.B, () => { - for (let i1 = 0; i1 < accelerations.length; i1++) { - basic.showString(accelerations[i1].toString(), 150) - } - accelerations.clear() -}) -``` - diff --git a/olddocs/js/comment.md b/olddocs/js/comment.md deleted file mode 100644 index 19f1afe3..00000000 --- a/olddocs/js/comment.md +++ /dev/null @@ -1,68 +0,0 @@ -# Comment - -A note in code. - -### @parent js/statement - - -A comment is a line of code that contains text, usually an explanation or a note. All comments are ignored during script execution. - -### Block - -Right click on any block and add a comment - -### Touch Develop syntax - -To insert a comment in a Touch Develop script: - -1. Click a line in your script. - -2. Click `+`. - -3. Click `// comment` and then type some text (your comment). - - -### Sample function with comments - -This function has comments that describe the purpose of the function: - -``` -/** - * // square function : - * // returns the square of the input parameter x - * @param x TODO - */ -export function square(x: number) : number { - return x * x -} -``` - -### Commenting out code - -During the debugging process, you may want to comment out a section of your code so that it doesn't run. - -To comment out a block of code: - -1. Click the first line of code that you want to comment out. - -2. Press and hold the Shift key, and then press the Down arrow key to select a block of code. - -3. In the block editing window, scroll down to **surround with** and click `comment out`. This adds an [if](/blocks/logic/if) statement around your code, like this: - -``` -if (false) { - // the commented code here... -} -``` - -When you want to uncomment your code, click the `if false then` statement in your code, and then click `uncomment`. - -### Library and function comments - -* Use [comments](/js/comment) at the beginning of a library to describe the library -* Use [comments](/js/comment) at the beginning of a [function](/js/function) to describe a function. The comment will appear in the help area of the Touch Develop editor when you insert the function - -### See also - -[markdown syntax](/js/markdown), [Touch Develop editor](/js/editor) - diff --git a/olddocs/js/compiler.md b/olddocs/js/compiler.md deleted file mode 100644 index 1df3cb3a..00000000 --- a/olddocs/js/compiler.md +++ /dev/null @@ -1,30 +0,0 @@ -# In-browser compiler - -The @boardname@ pins. - -## We listened to your feedback! - -Following the feedback from teachers, the following improvements were made: - -* compile without signing in -* compile offline -* save and load code using files - -## A new in-browser compiler - -The compilation from a script to ARM machine code is now done entirely in the browser (read the [in depth story](https://www.touchdevelop.com/docs/touch-develop-in-208-bits) about building the compiler). The new compiler is used by the Block Editor, Touch Develop and Code Kingdoms to create a .hex file solely within the confines of your web browser (no Internet connection is needed). The @boardname@ compilation process (see page 10 in the Quick Start book) has been updated below to reflect the new compiler architecture, shown below. - -![](/static/mb/offline-2.png) - -The C++ compiler now only is used to compile the @boardname@ runtime - this is done offline by the @boardname@ team and the precompiled runtime linked with your compiled script in the browser. - -## Save and load code using files - -![](/static/mb/offline-0.png) - -The @boardname@ automatically saves and synchronizes scripts for signed in users through the cloud. Unfortunately, this scenario would not work always so we decided to also support files. Users are now able to import and export scripts as files. For example, they can simply email it or submit them in their classroom portal. - -![](/static/mb/offline-1.png) - -Compiled .hex files can also be imported back into the web site. This make it easy for a teacher to review the source of a script by simply drag and dropping the file into the editor. - diff --git a/olddocs/js/contents.md b/olddocs/js/contents.md deleted file mode 100644 index f26cd013..00000000 --- a/olddocs/js/contents.md +++ /dev/null @@ -1,211 +0,0 @@ -# @boardname@/JavaScript Documentation - -JavaScript docs for the @boardname@ - -### @section full - -### @parent reference - -### @short JavaScript - -### ~hint - -**Spotty internet? No problem!** (1) When online, go to https://www.microbit.co.uk/app/ and bookmark this URL; (2) use the bookmark to reload the web app, even without the internet. - -### ~ - -Welcome to the Touch Develop home page for the @boardname@. Below you will find resources about the Touch Develop programming language and code editor. Good places to start include: - -* [the Touch Develop Editor](/js/editor) -* [30+ @boardname@ lessons](/lessonss) -* [offline support](/offline) - -### ~column - -## Language {#pconst} - -### Variables - -* [local variables](/reference/variables/var) -* [global variables ](/js/data) - -### Types - -* [Number](/reference/types/number) -* [Boolean](/reference/types/boolean) -* [String](/reference/types/string) -* [Image](/reference/images/image) - -### Statements and control structures - -* [assignment operator](/reference/variables/assign) `:=` -* [if](/reference/logic/if) -* [for](/reference/loops/for) -* [while](/js/while) -* [break](/js/break) -* [forever](/reference/basic/forever) -* [in background](/reference/control/in-background) -* [function](/js/function) -* [return](/js/return) - -### Maths - -* arithmetic operators (`+`, `-`, `*`, `/`, mod) on [Numbers](/reference/types/number) -* comparison operators (such as `>`, `=`) on [Numbers](/reference/types/number) -* the [math](/js/math) library -* the [bits](/js/bits) library - -### Logical - -* [Boolean](/reference/types/boolean) values `true` and `false` -* Operations (`not`, `or`, `and`) on [Booleans](/reference/types/boolean) - -### Strings - -* [string functions](/reference/types/string-functions) - -### Functions - -* [create a function](/js/function) -* [function parameters](/js/functionparameters) -* [call a function](/js/call) - -### Collections - -* read the [collections tutorial](/js/collections) - -### Custom object types - -* see the [object types tutorial](/js/object-types) -* read the [object disclaimer](/js/object-disclaimer) if you're an advanced user - -### Libraries - -* [create and use libraries](/js/libraries) - -### Documentation - -* [comments](/js/comment) -* [markdown syntax](/js/markdown) - -### ~ - -### ~column - -## @boardname@ functions - -### Basic - -* [clear screen](/reference/basic/clear-screen) -* [forever](/reference/basic/forever) -* [pause](/reference/basic/pause) -* [show leds](/reference/basic/show-leds) -* [show animation](/reference/basic/show-animation) -* [show number](/reference/basic/show-number) -* [show string](/reference/basic/show-string) - -### LED - -* [brightness](/reference/led/brightness) -* [fade in](/reference/led/fade-in) -* [fade out](/reference/led/fade-out) -* [plot](/reference/led/plot) -* [plot all](/reference/led/plot-all) -* [point](/reference/led/point) -* [screenshot](/functions/screenshot) -* [set display mode](/functions/set-display-mode) -* [set brightness](/reference/led/set-brightness) -* [stop animation](/reference/led/stop-animation) -* [toggle](/reference/led/toggle) -* [toggle all](/reference/led/toggle-all) -* [unplot](/reference/led/unplot) - -### Input - -* [acceleration](/reference/input/acceleration) -* [rotation](/functions/rotation) -* [button is pressed](/reference/input/button-is-pressed) -* [compass heading](/reference/input/compass-heading) -* [temperature](/reference/input/temperature) -* [running time](/reference/input/running-time) -* [on shake](/reference/input/on-gesture) -* [on button pressed](/reference/input/on-button-pressed) -* [on pin pressed](/reference/input/on-pin-pressed) -* [pin is pressed](/reference/input/pin-is-pressed) - -### Image - -* [create image](/reference/images/create-image) -* [clear](/reference/basic/clear-screen) -* [pixel](/reference/images/pixel) -* [plot frame](/reference/led/plot-frame) -* [plot image](/reference/led/plot-image) -* [scroll image](/reference/images/scroll-image) -* [show frame](/functions/show-frame) -* [set pixel](/reference/images/set-pixel) -* [show image](/reference/images/show-image) -* [width](/functions/width) - -### Music - -* [play note](/functions/play-note) -* [note](/functions/note) -* [ring](/reference/music/ring) - -### Pins - -* [digital read pin](/reference/pins/digital-read-pin) -* [digital write pin](/reference/pins/digital-write-pin) -* [analog read pin](/reference/pins/analog-read-pin) -* [analog write pin](/reference/pins/analog-write-pin) -* [analog set period](/reference/pins/analog-set-period) -* [analog pitch](/reference/pins/analog-pitch) -* [analog set pitch pin](/reference/pins/analog-set-pitch-pin) -* [servo write pin](/reference/pins/servo-write-pin) -* [servo set pulse](/reference/pins/servo-set-pulse) -* [map](/functions/map) - -### Control - -* [in background](/reference/control/in-background) -* [reset](/functions/reset) - -### Devices - -Functions in this category require to be connected to a remote device. - -* [tell camera to](/reference/devices/tell-camera-to) -* [tell remote control to](/reference/devices/tell-remote-control-to) -* [raise alert to](/reference/devices/raise-alert-to) -* [on notified](/reference/devices/on-notified) - -### Libraries - -* [serial library](/js/serial-library) - -### ~ - -### ~column - -## Run - -* [scripts in the browser](/js/simulator) -* [scripts on your @boardname@](/device/usb) - -## Debugging - -* use the [serial library](/js/serial-library) to print data from your @boardname@ on your computer -* learn about the [device error codes](/device/errors) that are displayed when sad faces occur - -## Edit/Publish - -* [the Touch Develop Editor](/js/editor) -* [publish a script](/js/publishing) - -## Creating Tutorials - -* [create a tutorial](/js/create-tutorials) -* [markdown syntax](/js/markdown) - -### ~ - diff --git a/olddocs/js/event-handler.md b/olddocs/js/event-handler.md deleted file mode 100644 index 842ee066..00000000 --- a/olddocs/js/event-handler.md +++ /dev/null @@ -1,58 +0,0 @@ -# event handler - -Event handlers - how they work. - -An event handler is code that is associated with a particular event, such as "button A pressed". You create (or register) the association between an event and an event handler by calling a function named "on ". After registering an event handler with an event, then whenever that event occurs, the event handler code executes. - -### Registering an event handler - -Functions named "on " create an association between an event and the event handler code. For example, the following code registers the event handler (the code between the `do` and `end` keywords) with the event of a press of button A: - -``` -input.onButtonPressed(Button.A, () => { - basic.showString("hello", 150) -}) -``` - -After this code executes, then whenever button A is pressed in the future, the string "hello" will be printed. - -### Event handlers are active for the entire program execution - -Once you have registered an event handler for an event, like above, that event handler is active for the rest of the program execution. If you want to stop the string "hello" from printing each time button A is pressed then you need to arrange for the following code to execute: - -``` -input.onButtonPressed(Button.A, () => { -}) -``` - -The above code associated an event handler that does nothing with the event of a press of button A. - -### There is only one event handler per event - -The above example also illustrates that there is only one event handler for each event. What is the result of the following code? - -``` -input.onButtonPressed(Button.A, () => { - basic.showString("hello", 150) -}) -input.onButtonPressed(Button.A, () => { - basic.showString("goodbye", 150) -}) -``` - -The answer is that whenever button A is pressed, the string "goodbye" will be printed. If you want both the strings "hello" and "goodbye" to be printed, you need to write the code like this: - -``` -input.onButtonPressed(Button.A, () => { - basic.showString("hello", 150) - basic.showString("goodbye", 150) -}) -``` - -### To learn more - -To learn more about how the @boardname@ queues up and schedules event handlers, see [the @boardname@ - a reactive system](/device/reactive) - -### see also - -[on button pressed](/reference/input/on-button-pressed) diff --git a/olddocs/js/events.md b/olddocs/js/events.md deleted file mode 100644 index f24bb09d..00000000 --- a/olddocs/js/events.md +++ /dev/null @@ -1,79 +0,0 @@ -# Events Library - -The functions in the events namespace allow the @boardname@ to communicate with a separate (remote) device, such as a smartphone, over Bluetooth (Smart). The set of supported events will depend on the remote device and the @boardname@ apps available for the remote device. The events accessible from Touch Develop are listed below. - -### Remote control - -Control the presentation of media content available on a remote device using the `remote control` function - -``` -export function remoteControl(event: string) -``` - -The remote control specific events include: - -* play -* pause -* stop -* next track -* previous track -* forward -* rewind -* volume up -* volume down - -### Camera - -Access the photo/video-taking functionality of a remote device using the *camera* function: - -``` -export function camera(event: string) -``` - -The camera-specific events include: - -* toggle front-rear -* launch photo mode -* take photo -* stop photo mode -* launch video mode -* start video capture -* stop video capture -* stop video mode - -### Alert - -Raise an alert on a remote device using the `alert` function - -``` -export function alert(event: string) -``` - -The set of alerting-specific events include: - -* display toast -* vibrate -* play sound -* play ringtone -* find my phone -* alarm 1 -* alarm 2 -* alarm 3 -* alarm 4 -* alarm 5 -* alarm 6 - -### Audio recorder - -Access the audio recording capabilities of the device using the `audio recording` function - -``` -export function audioRecorder(event: string) -``` - -The set of audio recorder events include: - -* launch -* start capture -* end capture -* stop diff --git a/olddocs/js/for.md b/olddocs/js/for.md deleted file mode 100644 index f219c572..00000000 --- a/olddocs/js/for.md +++ /dev/null @@ -1,81 +0,0 @@ -# For - -Repeat code a preset number of times. - -### @parent js/language - - -Repeat code a fixed number of times. - -### Block Editor - -The Block Editor *for* loop is different than the Touch Develop *for* loop in an important way. The above for loop will iterate *five* times, with the loop variable *i* taking on values 0, 1, 2, 3, and 4. The Touch Develop for loop shown below will iterate four times: - -``` -for (let k = 0; k < 4; k++) { -} -``` - -### Touch Develop - -### ~hide - -``` -let upper = 5 -``` - -### ~ - -``` -for (let k1 = 0; k1 < upper; k1++) { - // Add code to repeat here, also called the `loop body` -} -``` - -where - -* `0` is initial value of the loop index variable `k` -* the value of `k` increases by 1 after each execution of the `loop body` -* `upper` is the number of times the loop body will repeat - -In other words, the index variable (`k`) starts at 0 and increases by 1 each time the `loop body` executes, until `k = upper`. - -### Example: count to 5 - -The following example displays numbers 1 through 5 on the LED screen: - -``` -for (let i = 0; i < 5; i++) { - basic.showNumber(i + 1, 100) - basic.pause(500) -} -``` - -### Example: draw a box - -The [LED screen](/device/screen) has a fixed number of rows and columns (5x5), which is ideal for a for loop. This example uses a for loop to turn on the LEDs along the edge of the screen, making a square. - -``` -for (let i1 = 0; i1 < 5; i1++) { - led.plot(0, i1) - led.plot(4, i1) - led.plot(i1, 0) - led.plot(i1, 4) - basic.pause(500) -} -``` - -### ~hint - -Want to exit a loop early? The [break](/js/break) statement exits a loop before the end value is reached. - -### ~ - -### Lessons - -[looper](/lessons/looper), [strobe light](/lessons/strobe-light) - -### See also - -[while](/js/while), [break](/js/break), [if](/reference/logic/if) - diff --git a/olddocs/js/function.md b/olddocs/js/function.md deleted file mode 100644 index c9b052d9..00000000 --- a/olddocs/js/function.md +++ /dev/null @@ -1,117 +0,0 @@ -# Create a Function - -How to define a function with input and output parameters. - -### @parent js/language - - -A function is a unit of code that performs a specific task and returns a result. - -Functions are ideal when you need to perform an action multiple times. Instead of repeating a block of code in your script, you can put the code in a function and simply [call the function](/js/call) when needed. - -*Why use functions?* Functions makes your code easier to read, debug, and update. - -### Add a function - -To add a function to a Touch Develop script: - -1. Open a script and then click `script` (in the upper-right corner). - -2. Click `+` **add new**. - -3. Click **function()**. - -A new function appears, like this: - -``` -export function doStuff(p: number) { -} -``` - -Functions begin with the `function` keyword and end with `end function`. The function name appears after the `function` keyword (in this case, `do stuff`). - -### ~hint - -Click the function name to edit the function properties (i.e. change the name or add parameters - see below). - -### ~ - -### Function components - -Functions have three parts: - -* [input and output parameters](/js/functionparameters) -* the function *body* (the code that performs a task) - -- one or more [return](/js/return) statements (the output of the function) - -#### Example function - -``` -/** - * // returns the square of the input parameter x - * @param x TODO - */ -export function square(x: number) : number { - let result: number - return x * x - return result -} -``` - -In the above code... - -* ``x `` is the [input parameter](/js/functionparameters) ([Number](/reference/types/number) type) -* ``result`` is the [output parameter](/js/functionparameters) ([Number](/reference/types/number) type) -* `return x * x` is the function body (which returns the value of the expression `x * x`) - -### Add function parameters - -1. Open your function (if needed). To do this, open your script and then click `script` (in the upper-right corner). - -2. Under **code** click your function name. - -3. Click the function name in the code window. This opens the function panel. - -4. Click **add input parameter** or **add output parameter**. The parameter is added to your function. - -Click the parameter name to rename it and click the [type](/js/types) to change the variable type. For more info, see [function parameters](/js/functionparameters). - -### ~hide - -### Extract code into a function - -If you've already written some code that you'd like to have in a function, you can extract the code. Here's how: - -1. Click the first line of code that you want to extract. - -2. Press and hold the Shift key, and then press the Down arrow on your keyboard to select multiple lines of code. - -3. In the block editing window, scroll down to **extract selection into function** and click `extract`. - -### ~ - -### Function documentation - -Use a [comment](/js/comment) at the beginning of your functions to describe the function. When you insert a function into your code, the comment text appears in the help area of the Code Keyboard. - -### See all your functions - -To see all the functions in a script, open the script and then click `script` (in the upper-right corner). All of the functions in your script appear under **code**. - -### ~hide - -### Private functions - -If you don't want people to see the code in your function, you can make the function private. To do this, open the function, click the function name, and then mark the **private function** check box. Private functions have a locked icon instead of a play icon. - -### ~ - -### Lessons - -[digital pet](/lessons/digital-pet) - -### See also - -[function parameters](/js/functionparameters), [call a function](/js/call), [return from a function](/js/return) - diff --git a/olddocs/js/functionparameters.md b/olddocs/js/functionparameters.md deleted file mode 100644 index 26ae4272..00000000 --- a/olddocs/js/functionparameters.md +++ /dev/null @@ -1,66 +0,0 @@ -# Function Parameters - -How to use parameters to pass info in and out of an function. - -### @parent js/function - - -A [function](/js/function) can have multiple input parameters and/or a single output parameter. The parameters must be one of the supported variable [types](/js/types). - -When you first [create a function](/js/function), it looks like this: -``` -export function doStuff() { -} -``` - -### Add a function parameter - -1. Open your script (if needed) and then click `script` in the upper-right corner. - -2. Under **code** click your function name. - -3. Click the function name in your code (this opens the function panel). - -4. Click **add input parameter** or **add output parameter**. The parameter is added to your function. - -#### Input parameters - -The default type for an input parameter is [Number](/reference/types/number): - -``` -export function oneInput(p: number) { -} -``` - -To change the default type, click the type ([Number](/reference/types/number) in this case) and change it to [String](/reference/types/string), [Boolean](/reference/types/boolean), or [Image](/reference/image/image). You can add multiple input parameters to a function. - -#### Output parameter - -the default type for an output parameter is [Number](/reference/types/number): - -``` -export function output() : number { - let r: number - return 42 - return r -} -``` - -To change the default type, click the type ([Number](/reference/types/number) in this case) and change it to [String](/reference/types/string), [Boolean](/reference/types/boolean), or [Image](/reference/image/image). - -### Inputs and output function - -The following sample function has two inputs and one output parameter (all are the Number type): - -``` -export function inputsAndOutput(p: number, q: number) : number { - let r: number - return p + q - return r -} -``` - -### See also - -[call a function](/js/call), [create a function](/js/function), [return](/js/return) - diff --git a/olddocs/js/gallery.md b/olddocs/js/gallery.md deleted file mode 100644 index e4595981..00000000 --- a/olddocs/js/gallery.md +++ /dev/null @@ -1,105 +0,0 @@ -# Gallery - -Overview of Touch Develop lessons for the @boardname@. - -### @short Gallery - -### ~column - - -## Maker - -* [Telegraph](/pzeagwoudd), play the telegraph game between 2 @boardname@s -* [Ornament Chain](/rnvpgo), play the ornament chain game between 2 @boardname@s - -### ~hide - -* [The Watch](/lessons/the-watch), design and create The Watch -* [Hack your headphones](/lessons/hack-your-headphones), create music on the @boardname@ by hacking your headphones -* [Banana Keyboard](/lessons/banana-keyboard), create music with fruits - -### ~ - -## Beginner - -* [Night light](/vltwrzuqto), dim the LEDs with set brightness -* [Beautiful image](/nudwzmphyx), show a beautiful image with show LEDs -* [Smiley,](/zsohipimef) smiley and frowney with show animation -* [Lucky 7](/rqhxxqppqu), show a number on the LED screen with show number -* [Answering machine](/bnkmeqymuh), show a text message with show string -* [Snowflake fall](/zhcfmiejlg), repeat an animation with forever -* [Screen wipe](/hlnitnqjjk), turn off the LEDs with clear screen -* [Flashing heart](/bwmxfwqswx), display images with a pause -* [Blink](/jbbutifslm), turn an LED on and off with plot - -### ~hide - -* [Magic logo](/lessons/magic-logo), show an image on logo up -* [Glowing sword](/lessons/glowing-sword), make a glowing sword with fade in and fade out - -### ~ - -### ~column - -## Intermediate - -* [Zoomer](/fwrohhjqql), measure the force with acceleration -* [Strobe light](/jguqlzeayr), develop shapes with a nested for loops -* [Digi yoyo](/lppocrbpys), create a counter with a while loop -* [Die roll](/lzblatmknq), spin with more if statements -* [Spinner](/dzijduruek), spin the arrow with multiple if statements -* [Truth or dare](/filuzbwauo), a game that forces each player to reveal a secret or do something funny with if statement -* [Love meter](/rrmlrvojfa), create a love meter with on pin pressed -* [Guess the number](/ftsenbvqwz), guess a random number with random -* [Magic 8](/fyjinpjuqu), a fortune teller game with the @boardname@ -* [Counter](/rerlmjgjut), display a number with a variable -* [Glowing pendulum](/xrnsveuwxj), construct a pendulum that glows using acceleration -* [Looper](/nxcddtbizi), display a series of numbers with a for loop index - -### ~hide - -* [Rotation animation](/lessons/rotation-animation), control an animation with a boolean variable -* [Offset image](/lessons/offset-image), shift an image horizontally with image offset -* [Compass](/lessons/compass), displays the direction the @boardname@ is pointing - -### ~ - -### ~column - -## Advanced - -* [Rock paper scissors](/tnmtbvyyma), use image offsets with local variables -* [Digital pet](/vefocoajpb), a display of pet images with sub-functions -* [Catch the egg](/reczlreqob), catch falling eggs in a basket with an acceleration controller -* [Headbands](/bzrusu), create a charades game with a collection of strings that hold the words -* [Prank WiFi](/dceikq), create fake WiFi to trick your friends -* [Flipping bird](/lbhvywjzkv), use modulo with a conditional -* [Runaway pac man](/loafab), construct the game pac man with the @boardname@ -* [Line of Fire](/fzcoly), make a game to test hand-eye coordination -* [The hat game](/njynsd), make a game to test your focus on the moving ball -* [Pong](/xcenyy), a light bouncing from left to right -* [Meteorite](/zaidka), a game where meteorites are coming for you one by one -* [Minesweeper](/jaeeve), make a game to test your memory for placing a LED mine then finding the hidden LED mine -* [Bop it](/zlpndm), a game where you have to keep up with the commands -* [Letter Up](/ftlqjo), a guessing game with string operators with string at -* [Racing Buttons](/hcuxid), racing game to determine if player 1 presses Button A faster or if player 2 presses Button B faster - -### ~hide - -* [Transformers](/lessons/transformers), use functions to return values -* [Speed button](/lessons/speed-button), code a speed game with running time -* [Jailbreak](/lessons/jailbreak), break out of a counting loop by pressing button "A" -* [2 player pong](/bzycll), collaborate with a classmate to develop Pong on multiple @boardname@s - -### ~ - -### ~hide - -* [Number psych](/lessons/number-psych), collaborate with multiple classmates to develop a game on multiple @boardname@s and a breadboard - -### ~ - -### @section full - -The lessons promote computational thinking and computer science literacy[ read more...](/lessons/teach) - diff --git a/olddocs/js/game-library.md b/olddocs/js/game-library.md deleted file mode 100644 index 3b3fca02..00000000 --- a/olddocs/js/game-library.md +++ /dev/null @@ -1,153 +0,0 @@ -# Game Library - -The game library supports simple single-player time-based games. The player has a number of **lives** and a **score**. The game has a number of **levels** and a **countdown clock**. The general goal of a game will be to achieve a top score before time runs out or the number of lives goes to zero. - -## Touch Develop - -The code below shows a simple game where the user gets to press the button ``A`` as much times as possible in 10 seconds. - -``` -input.onButtonPressed(Button.A, () => { - game.addScore(1) -}) -game.startCountdown(10000) -``` - -### [Countdown](/js/game-library/start-countdown) - -If your game has a time limit, you can start a countdown in which case `game->current time` returns the remaining time. - -* start a countdown with the maximum duration of the game in milliseconds. - -``` -export function startCountdown(ms: number) -``` - -### [Game over](/js/game-library/game-over) - -If the `life` reaches zero or the time expires (see countdown), the game enters the **game over** mode. When the game is over, `game->is running` returns false - -* check if the game still running. - -``` -export function isRunning() : boolean -``` - -Indicates if the game is display the game over sequence. - -``` -export function isGameOver() : boolean -``` - -You can also end the game by calling the `game -> game over` function: - -``` -export function gameOver() -``` - -### Score - -When a player achieves a goal, you can increase the game score - -[Add Point to Score](/js/game-library/add-point-to-score) - -* add score points to the current score - -``` -export function addScore(points: number) -``` - -[Score](/js/game-library/score) - -* set the current score to a particular value. - -``` -export function setScore(value: number) -``` - -* get the current score value - -``` -export function score() : number -``` - -### Life - -Manage the player lives. When the life count reaches 0 or less, the game is over. - -* remove one or more lives - -``` -export function removeLife(life: number) -``` - -* add lives - -``` -export function addLife(lives: number) -``` - -* set the life to a particular value - -``` -export function setLife(value: number) -``` - -* get the current life value - -``` -export function life() : number -``` - -### Levels - -When the game increases in difficulty, you can increase the level and use that value in your game logic. - -* increase the level by 1 - -``` -export function levelUp() -``` - -* get the current level - -``` -export function level() : number -``` - -### Time - -The game immediately starts tracking the time from the moment the device started. - -* get the current time - -``` -export function currentTime() : number -``` - -You can start the time again by using `game->start stopwatch`. - -* start the game timer - -``` -game.startStopwatch() -``` - -### Blink - -Reports the blink duration of a `sprite` . - -``` -export function blink(_this: micro_bitSprites.LedSprite) : number -``` - -Sets the blink duration interval in milliseconds . - -``` -export function setBlink(sprite: micro_bitSprites.LedSprite, ms: number) -``` - -### Lessons - -[bop it](/lessons/bop-it) | [game of chance](/lessons/game-of-chance) | [game counter](/lessons/game-counter) - diff --git a/olddocs/js/game.md b/olddocs/js/game.md deleted file mode 100644 index 66691bbd..00000000 --- a/olddocs/js/game.md +++ /dev/null @@ -1,11 +0,0 @@ -# game - -A #microbit game library. - -Gets the current score - -``` -init() -return _score -``` - diff --git a/olddocs/js/games.md b/olddocs/js/games.md deleted file mode 100644 index a201a2f3..00000000 --- a/olddocs/js/games.md +++ /dev/null @@ -1,88 +0,0 @@ -# Game Tutorials - -Overview of Games for the @boardname@. - -### @short Games - -### ~column - -## Beginner Games - -* [The Watch](/lessons/the-watch/activity), design and create The Watch -* [Banana Keyboard](/lessons/banana-keyboard), create music with fruits - -### ~hide - -* [Smiley,](/lessons/smiley) smiley and frowney with show animation -* [Lucky 7](/lessons/lucky-7), show a number on the LED screen with show number -* [Snowflake fall](/lessons/snowflake-fall), repeat an animation with forever -* [Answering machine](/lessons/answering-machine), show a text message with show string -* [Magic logo](/lessons/magic-logo), show an image on logo up -* [Screen wipe](/lessons/screen-wipe), turn off the LEDs with clear screen -* [Blink](/lessons/blink), turn an LED on and off with plot -* [Flashing heart](/lessons/flashing-heart/tutorial), display images with a pause - -### ~ - -* [Night light](/lessons/night-light/tutorial), dim the LEDs with set brightness -* [Glowing sword](/lessons/glowing-sword/tutorial), make a glowing sword with fade in and fade out -* [Guess the number](/lessons/guess-the-number/tutorial), guess a random number with random -* [Rock paper scissors](/lessons/rock-paper-scissors/tutorial), use image offsets with local variables -* [Counter](/lessons/counter/tutorial), display a number with a variable -* [Love meter](/lessons/love-meter/tutorial), create a love meter with on pin pressed - -### ~column - -## Intermediate Games - -* [Truth or dare](/lessons/truth-or-dare/tutorial), a game that forces each player to reveal a secret or do something funny with if statement -* [Spinner](/lessons/spinner/tutorial), spin the arrow with multiple if statements -* [Die roll](/lessons/die-roll/tutorial), spin with more if statements -* [Looper](/lessons/looper/tutorial), display a series of numbers with a for loop index -* [Strobe light](/lessons/strobe-light/tutorial), develop shapes with a nested for loops -* [Digi yoyo](/lessons/digi-yoyo/tutorial), create a counter with a while loop -* [Magic 8](/lessons/magic-8/tutorial), a fortune teller game with the @boardname@ -* [Compass](/lessons/compass/tutorial), displays the direction the @boardname@ is pointing -* [Speed button](/lessons/speed-button/tutorial), code a speed game with running time - -### ~hide - -* [Zoomer](/lessons/zoomer/tutorial), measure the force with acceleration -* [Rotation animation](/lessons/rotation-animation/tutorial), control an animation with a boolean variable -* [Offset image](/lessons/offset-image/tutorial), shift an image horizontally with image offset - -### ~ - -### ~column - -## Advanced Games - -### ~hide - -* [Digital pet](/lessons/digital-pet/tutorial), a display of pet images with sub-functions -* [Jailbreak](/lessons/jailbreak/tutorial), break out of a counting loop by pressing button "A" -* [Transformers](/lessons/transformers/tutorial), use functions to return values -* [Flipping bird](/lessons/flipping-bird/tutorial), use modulo with a conditional - -### ~ - -* [Catch the egg](/lessons/catch-the-egg-game/tutorial), catch falling eggs in a basket with an acceleration controller -* [Headbands](/lessons/headbands/tutorial), create a charades game with a collection of strings that hold the words -* [Pong](/lessons/pong/tutorial), a light bouncing from left to right -* [Meteorite](/lessons/meteorite/tutorial), a game where meteorites are coming for you one by one -* [Minesweeper](/lessons/minesweeper/tutorial), make a game to test your memory for placing a LED mine then finding the hidden LED mine -* [Bop it](/lessons/bop-it/tutorial), a game where you have to keep up with the commands -* [Letter Up](/lessons/letter-up/tutorial), a guessing game with string operators with string at -* [Prank WiFi](/lessons/prank-wifi/tutorial), create fake WiFi to trick your friends -* [Runaway pac man](/lessons/runaway-pacman/tutorial), construct the game pac man with the @boardname@ -* [The hat game](/lessons/the-hat-game/tutorial), make a game to test your focus on the moving ball -* [2 player pong](/lessons/2-player-pong/tutorial), collaborate with a classmate to develop Pong on multiple @boardname@s - -### ~hide - -* [Glowing pendulum](/lessons/glowing-pendulum/tutorial), construct a pendulum that glows using acceleration -* [Line of Fire](/lessons/line-of-fire/tutorial), make a game to test hand-eye coordination -* [Number psych](/lessons/number-psych/tutorial), collaborate with multiple classmates to develop a game on multiple @boardname@s and a breadboard - -### ~ - diff --git a/olddocs/js/guides/basic-led-show.md b/olddocs/js/guides/basic-led-show.md deleted file mode 100644 index e6267462..00000000 --- a/olddocs/js/guides/basic-led-show.md +++ /dev/null @@ -1,84 +0,0 @@ -# basic LED show. - -### Challenge 0 - -You have successfully following the [guided tutorial] (https://live.microbit.co.uk/td/tutorials/blink). If not, we should make sure the @boardname@ script displays a blinking script on screen. We want to plot the x and y coordinates to 2, 2. Additionally, you will pause by 100 milliseconds then you will clear the screen of the @boardname@. Let's give it a go! - -``` -while (true) { - led.plot(2, 2) - basic.pause(200) - basic.clearScreen() - basic.pause(200) - -} -``` - -### Challenge 1 - -Use `basic->show string`  to display text after the blink. You will be writing a series of letters to display a series of letters. Try to unravel this secret code word: HELP. This line of code is within the  while  scope - -Make sure to add this line of code within the `while` scope! - -``` -while (true) { - led1.plot(2, 2) - basic1.pause(200) - basic1.clearScreen() - basic1.pause(200) - basic1.showString("HELP", 150) // *** -} -``` - -* run the code and see that it works as expected - -### Challenge 2 - -You can also display a number on screen using `basic‐>show number`. Add code under `basic‐>show string` to display the emergency number to call in the United Kingdom. (NOTE: 999 is the historic emergency number for the United Kingdom. All calls are answered by 999 operators. Calls are always free.) - -``` -while (true) { - led2.plot(2, 2) - basic2.pause(200) - basic2.clearScreen() - basic2.pause(200) - basic2.showString("HELP", 150) - basic2.showNumber(999, 150) // *** -} -``` - -Awesome! You have designed your message and a number to call in case of an emergency. - -### Challenge 3 - -* tap the `run` button to view the updated script on the simulator - -Add an associated animation after the emergency number . You can also create a cool animation on screen using `basic->show animation`. Add code under `basic->show number` to display an animation. - -``` -while (true) { - led3.plot(2, 2) - basic3.pause(200) - basic3.clearScreen() - basic3.pause(200) - basic3.showString("HELP", 150) - basic3.showNumber(999, 150) - basic3.showAnimation(` -# # . # # -. # . # . -. . # . . -# . . . # -# # # # # -`, 400) // *** -} -``` - -Awesome! We have implemented a string, number, and animation - -* run the code and see that it works as expected. - -### Challenge 4 - -Use the same logic `basic->string`, `basic->number`, or `basic->animation` to turn on the LEDs and display information!!! - -* run the code and see that it works as expected diff --git a/olddocs/js/guides/blink-symbols.md b/olddocs/js/guides/blink-symbols.md deleted file mode 100644 index 8d3b3bd1..00000000 --- a/olddocs/js/guides/blink-symbols.md +++ /dev/null @@ -1,109 +0,0 @@ -# blink symbols. - -### Challenge 0 - -You have successfully following the [blink tutorial](/hcwxud). If not, then let's start the tutorial now. Your @boardname@ script should start by displaying a blinking script on screen. We want to plot the x and y coordinates to 2, 2. Additionally, you will pause by 100 milliseconds then clear the screen of the @boardname@. - -Let's give it a go! - -``` -while (true) { - led.plot(2, 2) - basic.pause(200) - basic.clearScreen() - basic.pause(200) - -} -``` - -### Challenge 1 - -Make a `>` greater than symbol. Start in the upper left corner of the simulator when you plot coordinates. Make sure to add the line of code `led->plot (0,0)` under the last line of code - -``` -while (true) { - led1.plot(2, 2) - basic1.pause(200) - basic1.clearScreen() - basic1.pause(200) - led1.plot(0, 0) // *** -} -``` - -Design the top half of the `>` symbol by connecting a LED to the original center coordinate `2,2` and the upper left coordinate `0,0` Make sure to add the line of code `led->plot (1,1)` under the last line of code - -``` -while (true) { - led2.plot(2, 2) - basic2.pause(200) - basic2.clearScreen() - basic2.pause(200) - led2.plot(0, 0) - led2.plot(1, 1) // *** -} -``` - -Awesome! You have designed half of the `>` symbol. Now we should finish the lower half of the `>` symbol - -* tap the `run` button to view the updated script on the simulator - -Add the bottom half of the `>` symbol by plotting the most bottom - left LED first. Make sure to add the line of code `led->plot (0,5)` - -``` -while (true) { - led3.plot(2, 2) - basic3.pause(200) - basic3.clearScreen() - basic3.pause(200) - led3.plot(0, 0) - led3.plot(1, 1) - led3.plot(0, 4) // *** -} -``` - -Awesome! Now we must connect a LED to the original center coordinate `2,2` and the lower left coordinate `0,5` Make sure to add the line of code `led->plot (1,4)` - -Your `main` function should look like this: - -``` -while (true) { - led4.plot(2, 2) - basic4.pause(200) - basic4.clearScreen() - basic4.pause(200) - led4.plot(0, 0) - led4.plot(1, 1) - led4.plot(0, 4) - led4.plot(1, 3) // *** -} -``` - -* `run` the script and see that the program works as expected - -Congratulations! You made a `>` symbol. - -### Challenge 2 - -Use `led->plot` to create a exclamation design `!` Your `main` function should look like this. (notice the notation of `...` represents previous code in **Challenge 0** and **Challenge 1** - -Make sure to add these lines of code within the `while` loop - -Your `main` function should look like this: - -``` -while (true) { - // ... - led5.plot(4, 0) // *** - led5.plot(4, 1) // *** - led5.plot(4, 2) // *** - led5.plot(4, 4) // *** -} -``` - -* run the code and see that it works as expected. - -### Challenge 3 - -Use the same logic `led->plot` to turn on all the LED lights!!! - -* run the code and see that it works as expected diff --git a/olddocs/js/guides/light-column-cascade-activity.md b/olddocs/js/guides/light-column-cascade-activity.md deleted file mode 100644 index d2437b04..00000000 --- a/olddocs/js/guides/light-column-cascade-activity.md +++ /dev/null @@ -1,43 +0,0 @@ -# Light Column Cascade Worksheet - -My script. #docs - -**Challenge 0** - -Great Job! You have completed the Light Column Cascade tutorial having a nested for loop that plots each individual LED by column adding a delay between lighting each LED. - -``` -for (let i = 0; i < 5; i++) { - for (let j = 0; j < 5; j++) { - led.plot(i, j) - basic.pause(200) - } -} -``` - -**Challenge 1** - -Make the board light up faster by making the pause less time. - -``` -for (let i1 = 0; i1 < 5; i1++) { - for (let j1 = 0; j1 < 5; j1++) { - led1.plot(i1, j1) - basic1.pause(100) // *** - } -} -``` - -**Challenge 2** - -Make the board light up by rows instead of by columns by changing the i to the y position and j to the x position. - -``` -for (let i2 = 0; i2 < 5; i2++) { - for (let j2 = 0; j2 < 5; j2++) { - led2.plot(j2, i2) // *** - basic2.pause(100) - } -} -``` - diff --git a/olddocs/js/guides/light-column-cascade.md b/olddocs/js/guides/light-column-cascade.md deleted file mode 100644 index b4100ffc..00000000 --- a/olddocs/js/guides/light-column-cascade.md +++ /dev/null @@ -1,43 +0,0 @@ -# Light Column Cascade Activity - -My script. #docs - -**Challenge 0** - -Great Job! You have completed the Light Column Cascade tutorial having a nested for loop that plots each individual LED by column adding a delay between lighting each LED. - -``` -for (let i = 0; i < 5; i++) { - for (let j = 0; j < 5; j++) { - led.plot(i, j) - basic.pause(200) - } -} -``` - -**Challenge 1** - -Make the board light up faster by making the pause less time. - -``` -for (let i1 = 0; i1 < 5; i1++) { - for (let j1 = 0; j1 < 5; j1++) { - led1.plot(i1, j1) - basic1.pause(100) // *** - } -} -``` - -**Challenge 2** - -Make the board light up by rows instead of by columns by changing the i to the y position and j to the x position. - -``` -for (let i2 = 0; i2 < 5; i2++) { - for (let j2 = 0; j2 < 5; j2++) { - led2.plot(j2, i2) // *** - basic2.pause(100) - } -} -``` - diff --git a/olddocs/js/guides/scroll-image-docs.md b/olddocs/js/guides/scroll-image-docs.md deleted file mode 100644 index a5fd3616..00000000 --- a/olddocs/js/guides/scroll-image-docs.md +++ /dev/null @@ -1,22 +0,0 @@ -# Scroll Image Docs - -My script. #docs - -**Challenge 0** - -This [guided tutorial](/xuhkviyyxa) introduces how to make an image look like it's scrolling across the @boardname@! - -We can use an animation to make an image look like its moving! - -``` -basic.forever() -``` - -**Challenge 1** - -Now, let's reverse the animation so it looks like the bar is bouncing off the right edge of the display. - -``` -basic1.forever() -``` - diff --git a/olddocs/js/guides/touchdevelop-lessons.md b/olddocs/js/guides/touchdevelop-lessons.md deleted file mode 100644 index e3bba877..00000000 --- a/olddocs/js/guides/touchdevelop-lessons.md +++ /dev/null @@ -1,135 +0,0 @@ -# TouchDevelop Lessons - -Overview of TouchDevelop lessons for the @boardname@. - -### @section full - -### ~column - -### LED screen - -* [plot guided](/hcwxud) `guided tutorial ` `video available` -* [plots an LED](/njuzbvocit) [guided tutorial] -* [blink symbols](/rfchtfjmag) `docs` -* [clear screen](/jwqywu) -* [point](/reference/led/point) -* [set brightness](/tfrmcgdtxk) - -## @boardname@ - -## functions - -### Basic - -* [show number](/doxhko) -* [show string](/hgsfxg) -* [forever - show image](/bniyze) `guided tutorial` -* [forever - show animation - two frames 1a](/rwsjmubtaa) -* [forever - show animation - two frames 1c](/fomtaxxdkk) -* [forever - show animation - two frames 1 d](/huguhgjmmn) -* [forever - show animation - multliple frames](/tweyhx) - -## Language {#pconst} - -### Variables - -* [global variables ](/nkecii) `guided tutorial` -* [local variable - create image, show image](/dcvnwv) -* data types: [number](/reference/types/number), [boolean](/reference/types/boolean), [string](/reference/types/string), [image](/reference/image/image) - -### Statements and control structures - -* [if](/reference/logic/if) -* [for](/reference/loops/for) -* [for loop nested - plot](/vpvhdnaqfm) **script** -* [while](/js/while) -* [while - show string, show number, show animation](/bidtzqdips) `docs` -* [while - create image ](/bnqbom) -* [return](/js/return) -* [break](/js/break) -* [function](/js/function) -* [assignment operation](/reference/variables/assign) `:=` - -### Maths - -* arithmetic operators (`+`, `-`, `*`, `/`, mod) on [numbers](/reference/types/number) -* comparison operators (such as `>`, `=`) on [numbers](/reference/types/number) -* the [math](/js/math) library -* the [bits](/js/bits) library - -### Logical - -* boolean operators (`not`, `or`, `and`) on [booleans](/reference/types/boolean) - -### Strings - -* concat operator combines [strings](/reference/types/string) - -### ~ - -### ~column - -### Input - -* [button is pressed](/reference/input/button-is-pressed) -* [on button pressed](/reference/input/on-button-pressed) -* [acceleration](/reference/input/acceleration) -* [compass heading](/reference/input/compass-heading) -* [calibrate](/functions/calibrate) -* [running time](/reference/input/running-time) - -### ~ - -### ~column - -### Authoring & Other Bits - -* [TouchDevelop editor](/js/editor) -* [markdown](/js/markdown) -* [creating interactive tutorials](/js/creatinginteractivetutorials) -* [run scripts in a web browser](/js/simulator) -* [run scripts on your @boardname@](/usb) -* [libraries](/js/libraries) - -### Functions and libraries - -* [creating functions](/js/function) -* [function parameters](/js/functionparameters) -* [calling functions](/js/call) -* [libraries](/js/libraries) - -### Images - -* [create image](/reference/images/create-image) -* [clear](/reference/basic/clear-screen) -* [set pixel](/reference/images/set-pixel) -* [pixel](/reference/images/pixel) -* [show image](/reference/images/show-image) -* [scroll image](/reference/images/scroll-image) -* [width](/functions/width) -* [show animation](/reference/basic/show-animation) - -### Pins - -* [analog read pin](/reference/pins/analog-read-pin) -* [analog write pin](/reference/pins/analog-write-pin) -* [digital read pin](/reference/pins/digital-read-pin) -* [digital write pin](/reference/pins/digital-write-pin) - -### Accessories - -* [forever](/reference/basic/forever) -* [in background](/reference/control/in-background) - -## Tutorials - -* [Blink](/script:hcwxud) -* [Button](/script:rxqgzy) -* [Compass](/script:fhhhwl) -* [Counter](/script:bqrria) -* [Digital pet](/script:lsqwsk) -* [Flashing heart](/script:bniyze) -* [Glowing image](/script:hydyrp) - -### ~ - diff --git a/olddocs/js/hourofcode.md b/olddocs/js/hourofcode.md deleted file mode 100644 index afd7d89d..00000000 --- a/olddocs/js/hourofcode.md +++ /dev/null @@ -1,60 +0,0 @@ -# Hour of Code - -learn how to run an Hour Of Code with the @boardname@. #docs - -The @boardname@ can be used to run an Hour Of Code™ events for beginner of all ages. This document provides a detailed guidance on how to prepare and deliver the event in your school. - -## preparing the room - -1) Computers - -* Ensure that each participant will have **a computer connected to a @boardname@ board via a micro-USB cable**. - -2) Internet - -* Ensure that each computer has access to **internet**. - -3) Website Access - -* [https://www.microbit.co.uk](https://www.microbit.co.uk) - -4) Raffle tickets and prizes (optional) - -* Reward students with raffle tickets to keep them engaged. Finishing an activity or challenge on paper should equal a raffle ticket. Perform a raffle throughout the hour and give away lots of cheap prizes (candy is always a nice choice). - -5) Music (optional) - -* We recommend playing the latest hits (loudly) while the students are coding. It creates a playful atmosphere and makes the entire experience more enjoyable. Many web sites offer streaming music, but be sure to try it in advance as certain sites may be blocked on your network. - -## preparing the student handouts - -Print the following **activities** (1 handout per student): - -* [answering machine](/lessons/answering-machine/activity) -* [happy birthday](/lessons/happy-birthday/activity) -* [love meter](/lessons/love-meter/activity) - -Print the following **challenges** (1 handout per student): - -* [answering machine](/lessons/answering-machine/challenges) -* [happy birthday](/lessons/happy-birthday/challenges) -* [love meter](/lessons/love-meter/challenges) - -## Timeline - -* ``00:00`` students enter the website address (see step 3) -* ``10:00`` [answering machine](/lessons/answering-machine/activity) -* ``25:00`` [happy birthday](/lessons/happy-birthday/activity) -* ``35:00`` [love meter](/lessons/love-meter/activity) -* ``55:00`` raffle -* ``60:00`` that's it! - -## Follow up - -After your Hour Of Code™, you will want to provide plenty of material for students to continue learning about coding. Here are some good places to start: - -* [more challenges](/js/games) are available with @boardname@ Tutorials -* [the Quick Start Guide for Teachers](http://www.slideshare.net/Microsofteduk/bbc-microbit-guide-from-hodder-education) are available within @boardname@ - -The 'Hour of Code™' is a nationwide initiative by [Computer Science Education Week](http://csedweek.org) and [Code.org](http://code.org) to introduce millions of students to one hour of computer science and computer programming. - diff --git a/olddocs/js/hourofcode/notes.md b/olddocs/js/hourofcode/notes.md deleted file mode 100644 index 2a0ff6c2..00000000 --- a/olddocs/js/hourofcode/notes.md +++ /dev/null @@ -1,48 +0,0 @@ -# Hour of Code notes - -learn how to run an Hour Of Code with the @boardname@. #docs - -The @boardname@ can be used to run an Hour Of Code™ event for beginner of all ages. This document provides a detailed guidance on how to prepare and deliver the event in your school. - -## Preparation - -1) Computers - -Each participant has **a computer connected to a @boardname@ via micro-USB**. - -2) Internet - -Ensure that each computer has access to **internet**. - -3) Accounts - -Create a classroom in https://www.microbit.co.uk and pre-populate the classroom with student accounts. **Print the student passwords** and cut out each password. - -4) Print the activity challenges (1 copy per participant): - -* [hour of code](/js/hourofcode/challenges) - -4) (optional) Raffle tickets and prizes - -Reward students with raffle tickets to keep them engaged. Finishing a tutorial or challenge on paper should equal a raffle ticket. Perform a raffle throughout the hour and give away lots of cheap prizes (candy is always a nice choice). - -5) (optional) Music - -Bring more energy in the room by playing music. - -## Timeline - -* ``00:00`` student sign in using **printed passwords** (see step 3) -* ``10:00`` [hour of code tutorial](/js/hourofcode) -* ``40:00`` raffle and demoes -* ``50:00`` that's it! - -## Follow up - -After your Hour Of Code™, you will want to provide plenty of material for students to continue learning about coding. Here are some good places to start: - -* [more challenges](/lessonss) are available for @boardname@ -* [the Quick Start Guide for Teachers](http://www.slideshare.net/Microsofteduk/bbc-microbit-guide-from-hodder-education) are available within @boardname@ - -_The Hour of Code™ is a nationwide initiative by [Computer Science Education Week](http://csedweek.org) and [Code.org](http://code.org) to introduce millions of students to one hour of computer science and computer programming._ - diff --git a/olddocs/js/if.md b/olddocs/js/if.md deleted file mode 100644 index 2411694d..00000000 --- a/olddocs/js/if.md +++ /dev/null @@ -1,99 +0,0 @@ -# If - -Run code based on a condition. - -### @parent js/language - - -Conditionally run code depending on whether a [Boolean](/reference/types/boolean) condition is true or false. - -### Block Editor - -In the Block Editor, click on the dark blue gear icon (see above) to add an *else* or *if* to the current block. - -### Touch Develop - -### ~hide - -``` -let condition = true -``` - -### ~ - -``` -if (condition) { - // this code runs if `condition` is `true` -} else { - // this code runs if `condition` is `false` -} -``` - -### Example: adjusting screen brightness - -If the screen [brightness](/reference/led/brightness) is `< 100`, this code sets the brightness to `255`: - -``` -if (led.brightness() < 100) { - led.setBrightness(255) -} -``` - -You can leave the `then` or `else` blocks empty if they aren't needed. - -### Else if: multiple if statements - -You can chain together if statements by using `else if`. Like this: - -### ~hide - -``` -let otherCondition = true -``` - -### ~ - -``` -if (condition) { - // this code runs if `condition` is `true` -} else if (otherCondition) { - // this code runs if `other condition` is `true` -} -else { - // this code runs if neither `condition` or `other condition` are `true` -} -``` - -### Example: compass heading - -The following example gets the [compass heading](/reference/input/compass-heading) and then uses ``if-then-else`` statements to display a letter on the screen (N for north, E for East, S for South, and W for West). - -``` -while (true) { - let degrees = input.compassHeading() - if (degrees < 45) { - basic.showString("N", 100) - } else if (degrees < 135) { - basic.showString("E", 100) - } - else if (degrees < 225) { - basic.showString("S", 100) - } - else { - basic.showString("W", 100) - } -} -``` - -### Drag and drop - -You can move an entire ``if`` block by clicking the ``if`` keyword and dragging and dropping. - -### Lessons - -[love meter](/lessons/love-meter), [zoomer](/lessons/zoomer), [offset image](/lessons/offset-image) - -### See also - -[while loop](/js/while), [for](/reference/loops/for), [boolean](/reference/types/boolean) - diff --git a/olddocs/js/image.md b/olddocs/js/image.md deleted file mode 100644 index 4d877104..00000000 --- a/olddocs/js/image.md +++ /dev/null @@ -1,70 +0,0 @@ -# Image - -An image for the @boardname@ screen. - -### @parent js/language - -An *Image* is a matrix of pixels to show on the [LED screen](/device/screen) - -### Touch Develop editor: plot an image - -To display an image using the [Touch Develop editor](/js/editor): - -* click `image` , `plot image`, and then `edit` -* click the rectangles to create an image -* when you're done, click **ok** to return to your code - -![](/static/mb/plot-leds-0.png) - -You should see code similar to this: - -``` -basic.plotImage(` -. . . . . -. # . # . -. . # . . -. # . # . -. . . . . -`) -``` - -### Creating an image - -To create an image that you can later modify, see the [create image](/reference/images/create-image) function. - -### Block editor: create and show images - -To create images using the [Block editor](/blocks/editor): - -1. Click the **Images** category on the left. - -2. Drag and drop the **show image** block into your code. - -3. Drag and drop the **create image** or **create big image** block onto the **show image** block so that they connect. - -4. Make an image on the **create image** block by clicking on the squares. - -### Global image variables - -Images that you create in the [Touch Develop editor](/js/editor) are [local variables](/reference/variables/var). To promote a local image variable to a global variable, select the local image variable and click `promote to data`. The *var* keyword changes to the [data](/js/data) symbol `data->`. - -### Image functions - -* [create image](/reference/images/create-image): create an image from a series of on/off LED states -* [clear](/reference/basic/clear-screen): turn off all the pixels in an image -* [set pixel](/reference/images/set-pixel): set the state of a pixel in an image -* [pixel](/reference/images/pixel): get the state of a pixel in an image -* [plot-image](/reference/led/plot-image): show a single-frame image on the LED screen -* [show animation](/reference/basic/show-animation): show a series of image frames -* [show image](/reference/images/show-image): show an image on the screen -* [scroll image](/reference/images/scroll-image): scroll an image on the screen -* [width](/functions/width): get the width of an image - -### Lessons - -* [offset image](/lessons/offset-image) - -### See also - -[plot image](/reference/led/plot-image), [create image](/reference/images/create-image), [show image](/reference/images/show-image), [LED screen](/device/screen) - diff --git a/olddocs/js/lessons.md b/olddocs/js/lessons.md deleted file mode 100644 index 287da301..00000000 --- a/olddocs/js/lessons.md +++ /dev/null @@ -1,91 +0,0 @@ -# Touch Develop Lessons - -Overview of Touch Develop lessons for the @boardname@. - -### @short Lessons - -### ~column - -## Maker - -* [The Watch](/lessons/the-watch), design and create The Watch -* [Hack your Headphones](/lessons/hack-your-headphones), create music on the @boardname@ by hacking your headphones -* [Banana Keyboard](/lessons/banana-keyboard), create music with fruits -* [Telegraph](/lessons/telegraph), play the telegraph game between 2 @boardname@s -* [Ornament Chain](/lessons/ornament-chain), play the ornament chain game between 2 @boardname@s - -## Beginner - -* [Beautiful Image](/lessons/beautiful-image), show a beautiful image with show LEDs -* [Smiley,](/lessons/smiley) smiley and frowney with show animation -* [Lucky 7](/lessons/lucky-7), show a number on the LED screen with show number -* [Answering Machine](/lessons/answering-machine), show a text message with show string -* [Snowflake Fall](/lessons/snowflake-fall), repeat an animation with forever - -* [Magic Logo](/lessons/magic-logo), show an image on logo up -* [Screen Wipe](/lessons/screen-wipe), turn off the LEDs with clear screen -* [Flashing Heart](/lessons/flashing-heart), display images with a pause -* [Blink](/lessons/blink), turn an LED on and off with plot -* [Night Light](/lessons/night-light), dim the LEDs with set brightness -* [Glowing Sword](/lessons/glowing-sword), make a glowing sword with fade in and fade out - -### ~column - -## Intermediate - -* [Magic 8](/lessons/magic-8), a fortune teller game with the @boardname@ -* [Guess the Number](/lessons/guess-the-number), guess a random number with random -* [Rock Paper Scissors](/lessons/rock-paper-scissors), use image offsets with local variables -* [Counter](/lessons/counter), display a number with a variable -* [Love meter](/lessons/love-meter), create a love meter with on pin pressed -* [Zoomer](/lessons/zoomer), measure the force with acceleration -* [Glowing Pendulum](/lessons/glowing-pendulum), construct a pendulum that glows using acceleration -* [Truth or Dare](/lessons/truth-or-dare), a game that forces each player to reveal a secret or do something funny with if statement -* [Spinner](/lessons/spinner), spin the arrow with multiple if statements -* [Die Roll](/lessons/die-roll), spin with more if statements -* [Looper](/lessons/looper), display a series of numbers with a for loop index -* [Strobe Light](/lessons/strobe-light), develop shapes with a nested for loops -* [Digi Yoyo](/lessons/digi-yoyo), create a counter with a while loop -* [Rotation Animation](/lessons/rotation-animation), control an animation with a boolean variable -* [Offset Image](/lessons/offset-image), shift an image horizontally with image offset -* [Compass](/lessons/compass), displays the direction the @boardname@ is pointing - -### ~ - -### ~column - -## Advanced - -* [Digital Pet](/lessons/digital-pet), a display of pet images with sub-functions -* [Transformers](/lessons/transformers), use functions to return values -* [Speed Button](/lessons/speed-button), code a speed game with running time -* [Catch the Egg](/lessons/catch-the-egg-game), catch falling eggs in a basket with an acceleration controller -* [Headbands](/lessons/headbands), create a charades game with a collection of strings that hold the words -* [Prank WiFi](/lessons/prank-wifi), create fake WiFi to trick your friends -* [Jailbreak](/lessons/jailbreak), break out of a counting loop by pressing button "A" -* [Flipping Bird](/lessons/flipping-bird), use modulo with a conditional -* [Runaway Pac Man](/lessons/runaway-pacman), construct the game pac man with the @boardname@ -* [Line of Fire](/lessons/line-of-fire), make a game to test hand-eye coordination -* [The Hat Game](/lessons/the-hat-game), make a game to test your focus on the moving ball -* [2 Player Pong](/lessons/2-player-pong), collaborate with a classmate to develop Pong on multiple @boardname@s - -### Games - -* [Pong](/lessons/pong), a light bouncing from left to right -* [Meteorite](/lessons/meteorite), a game where meteorites are coming for you one by one -* [Minesweeper](/lessons/minesweeper), make a game to test your memory for placing a LED mine then finding the hidden LED mine -* [Bop it](/lessons/bop-it), a game where you have to keep up with the commands -* [Letter up](/lessons/letter-up), a guessing game with string operators with string at - -### ~ - -### ~hide - -* [Number Psych](/lessons/number-psych), collaborate with multiple classmates to develop a game on multiple @boardname@s and a breadboard - -### ~ - -### @section full - -The lessons promote computational thinking and computer science literacy[ read more...](/lessons/teach) - diff --git a/olddocs/js/lessons/2-player-pong.md b/olddocs/js/lessons/2-player-pong.md deleted file mode 100644 index 64422230..00000000 --- a/olddocs/js/lessons/2-player-pong.md +++ /dev/null @@ -1,103 +0,0 @@ -# 2 player pong lesson - -make a game to test your focus on the moving ball. - -## Topic - -Functions - -## Quick Links - -* [tutorial](/lessons/2-player-pong/tutorial) - -## Class - -Year 7 - -## Prior learning/place of lesson in scheme of work - -Learn how to create **functions**, `function()` as a unit of code that performs a specific task and returns a result. We will be learning how to create the hat game app using functions, global variables, input on button pressed, if (conditionals), mod, random, Boolean, as well as simple commands such as show animation. - -## What the teacher needs to know/QuickStart Computing Glossary - -* Algorithm: An unambiguous set of rules or a precise step-bystep guide to solve a problem or achieve a particular objective. -* Command: An instruction for the computer to execute, written in a particular programming language. -* Data: A structured set of numbers, possibly representing digitised text, images, sound or video, which can be processed or transmitted by a computer, also used for numerical (quantitative) information. -* Hardware: The physical systems and components of digital devices; see also software. -* Input: Data provided to a computer system, such as via a keyboard, mouse, microphone, camera or physical sensors. -* Programmable toys: Robots designed for children to use, accepting input, storing short sequences of simple instructions and moving according to this stored program. -* Program: A stored set of instructions encoded in a language understood by the computer that does some form of computation, processing input and/or stored data to generate output. -* Repetition: Executing a section of computer code a number of times as part of the program. -* Script: A computer program typically executed one line at a time through an interpreter, such as the instructions for a Scratch character. -* Selection: A programming construct in which one section of code or another is executed depending on whether a particular condition is met. -* Sequence: To place program instructions in order, with each executed one after the other. -* Simulation: Using a computer to model the state and behaviour of real-world (or imaginary) systems, including physical or social systems; an integral part of most computer games. -* Variables: A way in which computer programs can store, retrieve or change data, such as a score, the time left, or the user’s name. - -## Documentation - -* **functions** : [read more...](/js/function) -* **on button pressed** : [read more...](/reference/input/on-button-pressed) -* **for** : [read more...](/reference/loops/for) -* **if** : [read more...](/reference/logic/if) -* **show animation** : [read more...](/reference/basic/show-animation) - -## Resources - -* Activity: [tutorial](/lessons/2-player-pong/tutorial) - -## Objectives - -* learn how to create a global variable as a place where you can store data so that you can use it later in your code, accessible across functions and in nested code blocks -* learn how to learn how to conditionally run code depending on whether a condition is true or no -* learn how to show a series of image frames on the LED screen -* learn how to run code when an input button is pressed - -## Links to the National Curriculum Programmes of Study for Computing - -## Progression Pathways / Computational Thinking Framework - -#### Algorithms - -* Designs solutions (algorithms) that use repetition and two-way selection, ie if, then and else.(AL) -* Uses diagrams to express solutions.(AB) -* Uses logical reasoning to predict outputs, showing an awareness of inputs (AL) -* Represents solutions using a structured notation (AL) (AB) - -#### Programming & Development - -* Creates programs that implement algorithms to achieve given goals (AL) -* Declares and assigns variables(AB) -* Uses post-tested loop e.g.‘until’,and a sequence of selection statements in programs,including an if,then and else statement(AL) -* Understands the difference between, and appropriately uses if and if, then and else statements(AL) -* Uses a variable and relational operators within a loop to govern termination (AL) (GE) -* Uses a range of operators and expressions e.g. Boolean, and applies them in the context of program control. (AL) -* Selects the appropriate data types(AL) (AB - -#### Data & Data Representation - -* Understands the difference between data and information(AB) -* Performs more complex searches for information e.g. using Boolean and relational operators(AL) (GE) (EV) -* Defines data types: real numbers and Boolean (AB) - -#### Hardware & Processing - -* Knows that computers collect data from various input devices, including sensors and application software (AB) - -#### Information Technology - -* Collects, organizes, and presents data and information in digital content (AB) -* Makes appropriate improvements to solutions based on feedback received, and can comment on the success of the solution (EV) -* Recognises ethical issues surrounding the application of information technology beyond school. - -Computational Thinking Concept: AB = Abstraction; DE = Decomposition; AL = Algorithmic Thinking; EV = Evaluation; GE = Generalisation - -## Activity - -* time: 20 min. -* [tutorial](/lessons/2-player-pong/tutorial) - -## Intended follow on - -Publish script to the classroom. - diff --git a/olddocs/js/lessons/2-player-pong/quiz-answers.md b/olddocs/js/lessons/2-player-pong/quiz-answers.md deleted file mode 100644 index f2a09273..00000000 --- a/olddocs/js/lessons/2-player-pong/quiz-answers.md +++ /dev/null @@ -1,91 +0,0 @@ -# 2 player pong quiz answers - -a two-player game of Pong using TWO @boardname@s!. - -## Name - -## Directions - -Use this activity document to guide your work in the [2 player pong tutorial](/lessons/2-player-pong/tutorial) - -Answer the questions while completing the tutorial. Pay attention to the dialogues! - -## 1. Write the two global variables that record if the player has the ball and if the game is running, and assign these variables to their initial values. - -
- -``` -hasBall = false -gameRunning = false -``` - -## 2. Write the global variable that keeps track of the game state in which whoever presses button A first will get to start the ball. Assign this variable to its initial value. - -
- -``` -claimBall = true -``` - -## 3. Write the code that creates a condition to know when Button A is pressed. Then write the 'If statement' to ensure that 'claim ball' is true. If the claim ball is true, then write the code that sets P0 to 1 to signal to the other device that the player has claimed the ball. - -
- -``` -input.onButtonPressed(Button.A, () => { - if (claimBall) { - pins.digitalWritePin("P0", 1) - } -}) -``` - -## 4. Write the code to move the paddle right when button B is pressed. Be sure to check if the game is running and if the paddle is not already on the rightmost edge. - -
- -``` -if (gameRunning) { - if (paddleX != 0) { - led.unplot(paddleX, 4) - paddleX = paddleX - 1 - led.plot(paddleX, 4) - } -} -``` - -## 5. What are the three pieces of information that we send to the other device when transferring the ball? (Hint: look in your "transfer ball" function, and look for any places that contain "transfer byte"). - -
- -The device first transfers a bit of 1 to indicate that the device is going to transfer the data of the ball. After that, the device transfers the x-coordinate of the ball, and then the x-velocity of the ball. - -## 6. Using the function "read velocity", write the code that reads the x-coordinate and the x-velocity of the ball. (Hint: look at the function "read ball".) - -
- -``` -ballX = micro_bitTransfer.readByte() -ballXVelocity = readVelocity() -``` - -## 7. Write the code that updates 'ball x velocity'. (Hint: look at the "update velocity" function.) - -
- -``` -if (ballX == 0 || ballX == 4) { - ballXVelocity = ballXVelocity * (-1) -} -``` - -## 8. Write the code to move the ball. To move the ball, unplot the ball's original position, update its position variables, and then plot the ball's new position. - -
- -``` -led.unplot(ballX, 0) -ballX = ballX + ballXVelocity -ballY = ballY + ballYVelocity -led.plot(ballX, ballY) -``` - diff --git a/olddocs/js/lessons/2-player-pong/quiz.md b/olddocs/js/lessons/2-player-pong/quiz.md deleted file mode 100644 index e55976a4..00000000 --- a/olddocs/js/lessons/2-player-pong/quiz.md +++ /dev/null @@ -1,70 +0,0 @@ -# 2 player pong quiz - -a two-player game of Pong using TWO @boardname@s!. - -## Name - -## Directions - -Use this activity document to guide your work in the [2 player pong tutorial](/lessons/2-player-pong/tutorial) - -Answer the questions while completing the tutorial. Pay attention to the dialogues! - -## 1. Write the two global variables that record if the player has the ball and if the game is running, and assign these variables to their initial values. - -
- -
- -## 2. Write the global variable that keeps track of the game state in which whoever presses button A first will get to start the ball. Assign this variable to its initial value. - -
- -## 3. Write the code that creates a condition to know when Button A is pressed. Then write the 'If statement' to ensure that 'claim ball' is true. If the 'claim ball' is true, then write the code that sets P0 to 1 to signal to the other device that the player has claimed the ball. - -
- -
- -
- -
- -## 4. Write the code to move the paddle right when button B is pressed. Be sure to check if the game is running and if the paddle is not already on the rightmost edge. - -
- -
- -
- -
- -## 5. What are the three pieces of information that we send to the other device when transferring the ball? (Hint: look in your "transfer ball" function, and look for any places that contain "transfer byte"). - -
- -
- -## 6. Using the function "read velocity", write the code that reads the x-coordinate and the x-velocity of the ball. (Hint: look at the function "read ball".) - -
- -
- -
- -## 7. Write the code that updates 'ball x velocity'. (Hint: look at the "update velocity" function.) - -
- -
- -## 8. Write the code to move the ball. To move the ball, unplot the ball's original position, update its position variables, and then plot the ball's new position. - -
- -
- -
- diff --git a/olddocs/js/lessons/accelerometer/challenges.md b/olddocs/js/lessons/accelerometer/challenges.md deleted file mode 100644 index bb231f60..00000000 --- a/olddocs/js/lessons/accelerometer/challenges.md +++ /dev/null @@ -1,59 +0,0 @@ -# zoomer challenges - -The acceleration function. - -**Challenge 0** - -Great job! You have successfully completed the [zoomer tutorial](https://test.microbit.co.uk/td/lessons/zoomer/challenges) . You have created a script that measures the acceleration on the @boardname@ in the "z" direction of a 3D world. - -``` -basic.forever(() => { - let millig = input.acceleration("z") - basic.showNumber(millig, 150) - basic.pause(100) -}) -``` - -**Challenge 1** - -Create a new variable called milliX that holds the acceleration in the "x" direction or the horizontal direction. - -``` -basic.forever(() => { - let millig1 = input.acceleration("z") - basic.showNumber(millig1, 150) - basic.pause(100) - let milliX = input.acceleration("x") // *** -}) -``` - -* Run the code to see if it works as expected. - -**Challenge 2** - -If Button `A` is pressed, we want to show the acceleration in the "x" direction by adding an if statement that checks to see if Button `A` is pressed and then calling the show number method passing in milliX as the number. - -``` -basic.forever(() => { - let millig2 = input.acceleration("z") - basic.showNumber(millig2, 150) - basic.pause(100) - let milliX1 = input.acceleration("x") - if (input.buttonIsPressed("A")) { - basic.showNumber(milliX1, 150) // *** - } -}) -``` - -* Run the code to see if it works as expected. - -### Challenge 3 - -If Button `B` is pressed, program the @boardname@ to display the acceleration in the "y" direction. - -You can do this by storing the acceleration in a variable: `var milliY := input->acceleration("y")`. - -Then add an `if` statement that checks if Button `B` is pressed: `if input-> button is pressed ("B") then`. - -Inside of the `if` statement, add `basic->show number(milliY, 150)`, which will display the acceleration in the "y" direction. - diff --git a/olddocs/js/lessons/blinks-rectangle/challenges.md b/olddocs/js/lessons/blinks-rectangle/challenges.md deleted file mode 100644 index d676e6dc..00000000 --- a/olddocs/js/lessons/blinks-rectangle/challenges.md +++ /dev/null @@ -1,79 +0,0 @@ -# rectangle explosion challenges - -These challenges will allow you to make an exploding rectangle. #docs - -**Challenge 0** - -This [guided tutorial](https://test.microbit.co.uk/td/lessons/blinks-rectangle/tutorial) will help you show an animation forever! - -First, let's make a small rectangle blink forever. - -```blocks -basic.forever(() => { - basic.showAnimation(` -. . . . . . . . . . -. # # # . . . . . . -. # # # . . . . . . -. . . . . . . . . . -. . . . . . . . . . -`, 400) -}) -``` - -**Challenge 1** - -Let's begin creating our explosion effect by adding another rectangle animation that displays a slightly larger rectangle after the first one. - -``` -basic.forever(() => { - basic.showAnimation(` -. . . . . . . . . . -. # # # . . . . . . -. # # # . . . . . . -. . . . . . . . . . -. . . . . . . . . . -`, 400) - basic.showAnimation(` -. . . . . . . . . . -# # # # # . . . . . -# # # # # . . . . . -# # # # # . . . . . -. . . . . . . . . . -`, 400) -}) -``` - -**Challenge 2** - -To finalize our explosion effect, let's add a rectangle that is bigger than the last two we have created. - -``` -basic.forever(() => { - basic.showAnimation(` -. . . . . . . . . . -. # # # . . . . . . -. # # # . . . . . . -. . . . . . . . . . -. . . . . . . . . . -`, 400) - basic.showAnimation(` -. . . . . . . . . . -# # # # # . . . . . -# # # # # . . . . . -# # # # # . . . . . -. . . . . . . . . . -`, 400) - basic.showAnimation(` -# # # # # . . . . . -# # # # # . . . . . -# # # # # . . . . . -# # # # # . . . . . -# # # # # . . . . . -`, 400) -}) -``` - -**Challenge 3** - -If you notice, the rectangle explodes fairly slow. Let's make it explode faster by decreasing the intervals of the animation from 400 to 200. - diff --git a/olddocs/js/lessons/boolean-fun/challenges.md b/olddocs/js/lessons/boolean-fun/challenges.md deleted file mode 100644 index 6767689c..00000000 --- a/olddocs/js/lessons/boolean-fun/challenges.md +++ /dev/null @@ -1,91 +0,0 @@ -# speed button challenges - -This challenging script will create a game in which the user needs to press button A fast enough. You will get practice with using booleans in "if" statements. #docs - -### Challenge 0 - -Welcome! This [guided tutorial](https://live.microbit.co.uk/td/lessons/speed-button/tutorial) will help you begin creating this game! - -``` -counter = 0 -fastPress = false -input.onButtonPressed(Button.A, () => { - counter = counter + 1 -}) -``` - -### Challenge 1 - -We need to know when the user has hit button `A` 15 times. The user wins when he/she is able to accomplish this in less than 3500 milliseconds (3.5 seconds). We can check for both conditions by using an `and` operator. When using an `and` operator, both conditions need to be true in order for the condition to be true. - -``` -counter = 0 -fastPress = false -input.onButtonPressed(Button.A, () => { - counter = counter + 1 - if (counter == 15 && input.runningTime() < 3500) { - } -}) -``` - -Next, if the user has won, let's set our boolean to true. This indicates that he or she has won. - -``` -counter = 0 -fastPress = false -input.onButtonPressed(Button.A, () => { - counter = counter + 1 - if (counter == 15 && input.runningTime() < 3500) { - fastPress = true // *** - } -}) -``` - -### Challenge 2 - -We want to set `fastPress` to false if the user was too slow. To do so, we need another condition to see if the user took more than 3500 milliseconds (3.5 seconds). In the `if` statement, set `fastPress` to false. - -``` -counter = 0 -fastPress = false -input.onButtonPressed(Button.A, () => { - counter = counter + 1 - if (counter == 15 && input.runningTime() < 3500) { - fastPress = true - } - if (counter == 15 && input.runningTime() > 3499) { - fastPress = false // *** - } -}) -``` - -### Challenge 3 - -Now let's display if the user won or lost. To do so, we need to check the status of `fastPress` when the game is finished, and then show the correct message. - -``` -counter = 0 -fastPress = false -input.onButtonPressed(Button.A, () => { - counter = counter + 1 - if (counter == 15 && input.runningTime() < 3500) { - fastPress = true - } - if (counter == 15 && input.runningTime() > 3499) { - fastPress = false - } - if (counter == 15 && fastPress) { - basic.showString("YOU WIN!", 150) // *** - } - if (counter == 15 && ! fastPress) { - basic.showString("TOO SLOW!", 150) // *** - } -}) -``` - -* Click the `run` button to see if the code runs properly. - -### Challenge 4 - -Modify the code to change the difficulty level. Increasing the time will make it easier, while decreasing the time will make it harder. For example, changing the 3500 milliseconds to 4500 milliseconds will make the difficulty easier. - diff --git a/olddocs/js/lessons/boxer-mania/challenges.md b/olddocs/js/lessons/boxer-mania/challenges.md deleted file mode 100644 index c17bf7f1..00000000 --- a/olddocs/js/lessons/boxer-mania/challenges.md +++ /dev/null @@ -1,85 +0,0 @@ -# boxer mania challenges - -My script. #docs - -This [guided tutorial](/lessons/boxer-mania/tutorial) will help you create an animation! - -**Challenge 0** - -Let's create and show a series of frames on the LED screen; this is an animation! - -We will use multiple frames to make it look like a square is rotating on the @boardname@ screen! - -``` -basic.showAnimation(` -. # . . . -# . . . . -. # . . . -. . # . # -. . . # . -`, 400) -``` - -**Challenge 1** - -Let's create the next frame to make it look like the square is spinning clock-wise! - -``` -basic.showAnimation(` -. # . . . -# . . . . -. # . . . -. . # . # -. . . # . -`, 400) -basic.showAnimation(` -# # # # # -# . . . # -# . . . # -# . . . # -# # # # # -`, 400) // *** -``` - -**Challenge 2** - -Add the next two frames to show a complete rotation for the square! - -``` -basic.showAnimation(` -. # . . . -# . . . . -. # . . . -. . # . # -. . . # . -`, 400) -basic.showAnimation(` -# # # # # -# . . . # -# . . . # -# . . . # -# # # # # -`, 400) -basic.showAnimation(` -. # . . . # # # # # -# . # . . # . . . # -. . . # . # . . . # -. . . . # # . . . # -. . . # . # # # # # -`, 400) // *** -``` - -**Challenge 3** - -Do you want to show the same animation with fewer lines of codes? We can do this by combining all the frames into one show animation function call! - -``` -basic.showAnimation(` -. # . . . # # # # # . # . . . # # # # # -# . . . . # . . . # # . # . . # . . . # -. # . . . # . . . # . . . # . # . . . # -. . # . # # . . . # . . . . # # . . . # -. . . # . # # # # # . . . # . # # # # # -`, 400) // *** -``` - diff --git a/olddocs/js/lessons/break/challenges.md b/olddocs/js/lessons/break/challenges.md deleted file mode 100644 index 4c4caf65..00000000 --- a/olddocs/js/lessons/break/challenges.md +++ /dev/null @@ -1,86 +0,0 @@ -# break challenges - -This guide will show you how to use a break statement within a while loop. #docs - -### Challenge 0 - -Welcome! This [guided tutorial](/lessons/break/tutorial) will assist you with this activity. - -``` -count = 0 -shouldBreak = false -input.onButtonPressed(Button.A, () => { - shouldBreak = true -}) -while (true) { - if (shouldBreak) { - basic.showString("I'M OUT!", 150) - images.createImage(` -# . . . # -# . . . # -. . # . . -# . . . # -. # # # . -`).showImage(0) - break - } - count = count + 1 - basic.showNumber(count, 150) - basic.pause(1000) -} -``` - -### Challenge 1 - -Try to remove the `break` in the `if` loop. What problem does this create? - -### Challenge 2 - -Now let's resume the timer again once button `B` is pressed! To do so, begin by creating a condition to know when button `B` is pressed. - -``` -// **. . .** -while (true) { - if (shouldBreak) { - basic.showString("I'M OUT!", 150) - break - } - count = count + 1 - basic.showNumber(count, 150) - basic.pause(1000) -} -input.onButtonPressed(Button.B, () => { -}) // *** -``` - -Next, set `shouldBreak` back to false to indicate we want to run the `while` loop again. - -``` -// **. . .** -input.onButtonPressed(Button.B, () => { - shouldBreak = false // *** -}) -``` - -And now copy the code from the previous while loop into the condition of `input->on button pressed("B")`. This will resume the counter. - -``` -// **. . .** -input.onButtonPressed(Button.B, () => { - shouldBreak = false - while (true) { - if (shouldBreak) { - basic.showString("I'M OUT!", 150) // *** - break // *** - } - count = count + 1 // *** - basic.showNumber(count, 150) // *** - basic.pause(1000) // *** - } -}) -``` - -### Challenge 3 - -Notice that the two `while` loops are identical. Clean up this redundancy in your code by creating another method and then placing the `while` loop in the method. - diff --git a/olddocs/js/lessons/button/challenges.md b/olddocs/js/lessons/button/challenges.md deleted file mode 100644 index 441ff77a..00000000 --- a/olddocs/js/lessons/button/challenges.md +++ /dev/null @@ -1,52 +0,0 @@ -# button challenges - -My script. #docs - -### Challenge 0 - -Howdy! This [guided tutorial](/rxqgzy) will help you complete this activity! - -In this guide, you will learn how to use buttons and show text on the screen. Let's start by adding to respond **when the left button is pressed**. - -``` -input.onButtonPressed(Button.A, () => { -}) -``` - -All the code inside `input->on button pressed` runs when the button is pressed. Let's add the code to show some text. - -``` -input.onButtonPressed(Button.A, () => { - basic.showString("hello", 150) -}) -``` - -### Challenge 1 - -Let's add an event handler for Button `B`. - -``` -input.onButtonPressed(Button.A, () => { - basic.showString("hello", 150) -}) -input.onButtonPressed(Button.B, () => { -}) -``` - -### Challenge 2 - -Display `bye` when the `B` button is pressed. - -``` -input.onButtonPressed(Button.A, () => { - basic.showString("hello", 150) -}) -input.onButtonPressed(Button.B, () => { - basic.showString("bye", 150) -}) -``` - -### Challenge 3 - -Change the strings so that they display some other text. In order to do so, you will need to edit what is inside the quotation marks in `basic->show string`. - diff --git a/olddocs/js/lessons/cascade/quiz.md b/olddocs/js/lessons/cascade/quiz.md deleted file mode 100644 index 734cca53..00000000 --- a/olddocs/js/lessons/cascade/quiz.md +++ /dev/null @@ -1,128 +0,0 @@ -# strobe lightquiz - -Learn how to create a blinking LED script with a for loop. - -## Name - -## Directions - -Use this activity document to guide your work in the [light column cascade tutorial](/js/light-column-cascade/tutorial). - -Answer the questions below while working on or after you finish the tutorial. Pay attention to the dialogs! - -## 1. What is a for loop? - -## 2. Consider the following code - -``` -for (let i = 0; i < 5; i++) { - for (let j = 0; j < 5; j++) { - led.plot(i, j) - } -} -``` - -If the rectangle below represents a board that is 5 LEDs wide and 5 LEDs tall, place an X approximately all the locations where the LED is lighted. Explain why the LED is lighted there. - -![](/static/mb/empty-microbit.png) - -## 3. Consider the following code - -``` -for (let i1 = 0; i1 < 3; i1++) { - for (let j1 = 0; j1 < 3; j1++) { - led.plot(i1, j1) - } -} -``` - -If the rectangle below represents a board that is 5 LEDs wide and 5 LEDs tall, place an X approximately all the locations where the LED is lighted. Explain why the LED is lighted there. - -![](/static/mb/empty-microbit.png) - -## 4. Consider the following code - -``` -for (let i2 = 0; i2 < 2; i2++) { - for (let j2 = 0; j2 < 2; j2++) { - led.plot(i2, j2) - } -} -``` - -If the rectangle below represents a board that is 5 LEDs wide and 5 LEDs tall, place an X approximately where the LED is lighted. Explain why the LED is lighted there. - -![](/static/mb/empty-microbit.png) - -****************************** - -## ANSWER KEY - -## Directions - -Answer the questions below while working on or after you finish the tutorial. - -## 1. What is a for loop? - -Answers will vary. In general, for loop refers to the code that repeats for a fixed number of times. We specify the LED using x, y coordinates. - -## 2. Consider the following code - -``` -for (let i3 = 0; i3 < 5; i3++) { - for (let j3 = 0; j3 < 5; j3++) { - led.plot(i3, j3) - } -} -``` - -If the rectangle below represents a board that is 5 LEDs wide and 5 LEDs tall, place an X approximately where the LED is lighted. Explain why the LED is lighted there. - -![](/static/mb/lessons/cascade-0.png) - -This code turns on specific LED. Plot turns on the specified LED on the LED screen. We specify the LED using x, y coordinates. The code lights on the LEDs - -x - the x coordinate or horizontal position (0,1,2,3,4) - -y - the y coordinate or vertical position (0,1,2,3,4) - -## 3. Consider the following code - -``` -for (let i4 = 0; i4 < 3; i4++) { - for (let j4 = 0; j4 < 3; j4++) { - led.plot(i4, j4) - } -} -``` - -If the rectangle below represents a board that is 5 LEDs wide and 5 LEDs tall, place an X approximately where the LED is lighted. Explain why the LED is lighted there. - -![](/static/mb/lessons/cascade-1.png) - -This code turns on specific LED. Plot turns on the specified LED on the LED screen. We specify the LED using x, y coordinates. - -x - the x coordinate or horizontal position (0,1,2) - -y - the y coordinate or vertical position (0,1,2) - -## 4. Consider the following code - -``` -for (let i5 = 0; i5 < 2; i5++) { - for (let j5 = 0; j5 < 2; j5++) { - led.plot(i5, j5) - } -} -``` - -If the rectangle below represents a board that is 5 LEDs wide and 5 LEDs tall, place an X approximately where the LED is lighted. Explain why the LED is lighted there. - -![](/static/mb/lessons/cascade-2.png) - -This code turns on specific LED. Plot turns on the specified LED on the LED screen. We specify the LED using x, y coordinates. - -x - the x coordinate or horizontal position (0,1) - -y - the y coordinate or vertical position (0,1) - diff --git a/olddocs/js/lessons/clear-screen/challenges.md b/olddocs/js/lessons/clear-screen/challenges.md deleted file mode 100644 index 6cc12e92..00000000 --- a/olddocs/js/lessons/clear-screen/challenges.md +++ /dev/null @@ -1,77 +0,0 @@ -# clear screen challenges - -My script. #docs - -### Challenge 0 - -Welcome! This [guided tutorial](/hzckbb) will help you create the script to clear the screen! - -Your goal is to clear the screen after displaying an animation. Begin by showing and displaying an animation. Remember that the `show animation` is in the `basic` namespace. We then need to detect when the "A" button is pressed. Finally, clear the screen by typing in `basic->clear screen`. - -Your main function should look like this: - -``` -basic.showAnimation(` -# # # # # # # # # # . . . . . . . . . . -# # # # # # # # # # . . . . . . . . . . -. . . . . # # # # # # # # # # . . . . . -. . . . . # # # # # # # # # # # # # # # -. . . . . . . . . . . . . . . # # # # # -`, 400) -input.onButtonPressed(Button.A, () => { - basic.clearScreen() -}) -``` - -* tap the `run` button to view the script on the monitor. - -### Challenge 1 - -Create an event handler for Button "B". - -``` -basic.showAnimation(` -# # # # # # # # # # . . . . . . . . . . -# # # # # # # # # # . . . . . . . . . . -. . . . . # # # # # # # # # # . . . . . -. . . . . # # # # # # # # # # # # # # # -. . . . . . . . . . . . . . . # # # # # -`, 400) -input.onButtonPressed(Button.A, () => { - basic.clearScreen() -}) -input.onButtonPressed(Button.B, () => { -}) -``` - -### Challenge 2 - -Replay the animation when the "B" button is pressed by typing in `basic->show animation(..., 400)`. - -``` -basic.showAnimation(` -# # # # # # # # # # . . . . . . . . . . -# # # # # # # # # # . . . . . . . . . . -. . . . . # # # # # # # # # # . . . . . -. . . . . # # # # # # # # # # # # # # # -. . . . . . . . . . . . . . . # # # # # -`, 400) -input.onButtonPressed(Button.A, () => { - basic.clearScreen() -}) -input.onButtonPressed(Button.B, () => { - basic.showAnimation(` -# # # # # # # # # # . . . . . . . . . . -# # # # # # # # # # . . . . . . . . . . -. . . . . # # # # # # # # # # . . . . . -. . . . . # # # # # # # # # # # # # # # -. . . . . . . . . . . . . . . # # # # # -`, 400) // *** -}) -``` - -### Challenge 3 - -Show an animation that scrolls back up when you press button "B". - -* tap the `run` button to view your final product! diff --git a/olddocs/js/lessons/column/quiz.md b/olddocs/js/lessons/column/quiz.md deleted file mode 100644 index b9ccf639..00000000 --- a/olddocs/js/lessons/column/quiz.md +++ /dev/null @@ -1,128 +0,0 @@ -# cascade quiz - -Learn how to create a blinking LED script with a for loop. - -## Name - -## Directions - -Use this activity document to guide your work in the [light column cascade tutorial](/js/light-column-cascade/tutorial). - -Answer the questions below while working on or after you finish the tutorial. Pay attention to the dialogs! - -## 1. What is a for loop? - -## 2. Consider the following code - -``` -for (let i = 0; i < 5; i++) { - for (let j = 0; j < 5; j++) { - led.plot(i, j) - } -} -``` - -If the rectangle below represents a board that is 5 LEDs wide and 5 LEDs tall, place an X approximately all the locations where the LED is lighted. Explain why the LED is lighted there. - -![](/static/mb/empty-microbit.png) - -## 3. Consider the following code - -``` -for (let i1 = 0; i1 < 3; i1++) { - for (let j1 = 0; j1 < 3; j1++) { - led.plot(i1, j1) - } -} -``` - -If the rectangle below represents a board that is 5 LEDs wide and 5 LEDs tall, place an X approximately all the locations where the LED is lighted. Explain why the LED is lighted there. - -![](/static/mb/empty-microbit.png) - -## 4. Consider the following code - -``` -for (let i2 = 0; i2 < 2; i2++) { - for (let j2 = 0; j2 < 2; j2++) { - led.plot(i2, j2) - } -} -``` - -If the rectangle below represents a board that is 5 LEDs wide and 5 LEDs tall, place an X approximately where the LED is lighted. Explain why the LED is lighted there. - -![](/static/mb/empty-microbit.png) - -****************************** - -## KEY - -## Directions - -Answer the questions below while working on or after you finish the tutorial. - -## 1. What is a for loop? - -Answers will vary. In general, for loop refers to the code that repeats for a fixed number of times. We specify the LED using x, y coordinates. - -## 2. Consider the following code - -``` -for (let i3 = 0; i3 < 5; i3++) { - for (let j3 = 0; j3 < 5; j3++) { - led.plot(i3, j3) - } -} -``` - -If the rectangle below represents a board that is 5 LEDs wide and 5 LEDs tall, place an X approximately where the LED is lighted. Explain why the LED is lighted there. - -![](/static/mb/lessons/cascade-0.png) - -This code turns on specific LED. Plot turns on the specified LED on the LED screen. We specify the LED using x, y coordinates. The code lights on the LEDs - -x - the x coordinate or horizontal position (0,1,2,3,4) - -y - the y coordinate or vertical position (0,1,2,3,4) - -## 3. Consider the following code - -``` -for (let i4 = 0; i4 < 3; i4++) { - for (let j4 = 0; j4 < 3; j4++) { - led.plot(i4, j4) - } -} -``` - -If the rectangle below represents a board that is 5 LEDs wide and 5 LEDs tall, place an X approximately where the LED is lighted. Explain why the LED is lighted there. - -![](/static/mb/lessons/column-0.png) - -This code turns on specific LED. Plot turns on the specified LED on the LED screen. We specify the LED using x, y coordinates. - -x - the x coordinate or horizontal position (0,1,2) - -y - the y coordinate or vertical position (0,1,2) - -## 4. Consider the following code - -``` -for (let i5 = 0; i5 < 1; i5++) { - for (let j5 = 0; j5 < 1; j5++) { - led.plot(i5, j5) - } -} -``` - -If the rectangle below represents a board that is 5 LEDs wide and 5 LEDs tall, place an X approximately where the LED is lighted. Explain why the LED is lighted there. - -![](/static/mb/lessons/column-1.png) - -This code turns on specific LED. Plot turns on the specified LED on the LED screen. We specify the LED using x, y coordinates. - -x - the x coordinate or horizontal position (0,1) - -y - the y coordinate or vertical position (0,1) - diff --git a/olddocs/js/lessons/compare-machine/challenges.md b/olddocs/js/lessons/compare-machine/challenges.md deleted file mode 100644 index 70155fb0..00000000 --- a/olddocs/js/lessons/compare-machine/challenges.md +++ /dev/null @@ -1,79 +0,0 @@ -# compare machine challenges - -These challenges allow you to set the value of a counter to 1 when button B is pressed. #docs - -### Challenge 0 - -Welcome! This [guided tutorial](/lessons/comparison/tutorial) will assist you with using the comparison operator. - -``` -counter = 0 -input.onButtonPressed(Button.A, () => { - counter = counter + 1 - if (counter == 10) { - counter = 1 - } - basic.showNumber(counter, 150) -}) -``` - -### Challenge 1 - -Now let's do something special when the @boardname@ reaches the number `5`. Instead of just showing the number `5`, let's show the string `HALF WAY!`. Begin by setting an if statement to know when `counter = 5`. - -``` -counter = 0 -input.onButtonPressed(Button.A, () => { - counter = counter + 1 - if (counter == 10) { - counter = 1 - } - if (counter == 5) { - } - basic.showNumber(counter, 150) -}) -``` - -### Challenge 2 - -Let's continue our plan of displaying `HALF WAY!` when `counter = 5`. To do so, add the following line of code inside the if statement. - -``` -counter = 0 -input.onButtonPressed(Button.A, () => { - counter = counter + 1 - if (counter == 10) { - counter = 1 - } - if (counter == 5) { - basic.showString("HALF WAY!", 150) // *** - } - basic.showNumber(counter, 150) -}) -``` - -* Run your code to see if it works as expected. - -### Challenge 3 - -You may notice a problem right now. When `counter = 5`, the @boardname@ will show both the message `HALF WAY!` and the number `5`. In order to fix this problem, let's take advantage of the `else` at the end of the if statement. - -``` -counter = 0 -input.onButtonPressed(Button.A, () => { - counter = counter + 1 - if (counter == 10) { - counter = 1 - } - if (counter == 5) { - basic.showString("HALF WAY!", 150) - } else { - basic.showNumber(counter, 150) // *** - } -}) -``` - -### Challenge 4 - -When `counter = 8`, display the message `ALMOST THERE!` on the @boardname@. You will need to add an `else if` after the if statement of `counter = 5`. - diff --git a/olddocs/js/lessons/digital-pet.md b/olddocs/js/lessons/digital-pet.md deleted file mode 100644 index 6a618386..00000000 --- a/olddocs/js/lessons/digital-pet.md +++ /dev/null @@ -1,131 +0,0 @@ -# digital pet lesson - -a display of pet images for the @boardname@. - -## Topic - -Functions - -## Quick Links - -* [tutorial](/lessons/digital-pet/tutorial) -* [quiz](/lessons/digital-pet/quiz) -* [quiz answers](/lessons/digital-pet/quiz-answers) -* [challenges](/lessons/digital-pet/challenges) - -## Class - -Year 7 - -## Prior learning/place of lesson in scheme of work - -Learn how to create **functions**, `function()` that perform a specific task and returns a result. We will be learning how to create a digital pet app using functions, global variables, forever loop, input button in pressed, input on shake as well as simple commands, such as show string, show number, and pause. - -## What the teacher needs to know - -* Algorithm: An unambiguous set of rules or a precise step-bystep guide to solve a problem or achieve a particular objective. -* Command: An instruction for the computer to execute, written in a particular programming language. -* Data: A structured set of numbers, possibly representing digitised text, images, sound or video, which can be processed or transmitted by a computer, also used for numerical (quantitative) information. -* Hardware: The physical systems and components of digital devices; see also software. -* Input: Data provided to a computer system, such as via a keyboard, mouse, microphone, camera or physical sensors. -* Output: The information produced by a computer system for its user, typically on a screen, through speakers or on a printer, but possibly through the control of motors in physical systems. -* Programmable toys: Robots designed for children to use, accepting input, storing short sequences of simple instructions and moving according to this stored program. -* Program: A stored set of instructions encoded in a language understood by the computer that does some form of computation, processing input and/or stored data to generate output. -* Script: A computer program typically executed one line at a time through an interpreter, such as the instructions for a Scratch character. -* Selection: A programming construct in which one section of code or another is executed depending on whether a particular condition is met. -* Sequence: To place program instructions in order, with each executed one after the other. -* Simulation: Using a computer to model the state and behaviour of real-world (or imaginary) systems, including physical or social systems; an integral part of most computer games. -* Variables: A way in which computer programs can store, retrieve or change data, such as a score, the time left, or the user’s name. - -**QuickStart Computing Glossary - -## Documentation - -* **function** : [read more...](/js/function) -* **call** : [read more...](/js/call) -* **global variable** : [read more...](/js/data) -* **assignment operator** : [read more...](/reference/variables/assign) -* **forever** : [read more...](/reference/basic/forever) -* **button is pressed** : [read more...](/reference/input/button-is-pressed) -* **show string** : [read more...](/reference/basic/show-string) -* **show number** : [read more...](/reference/basic/show-number) -* **create image** : [read more...](/reference/images/create-image) -* **show image** : [read more...](/reference/images/show-image) -* **pause** : [read more...](/reference/basic/pause) - -## Resources - -* Activity: [tutorial](/lessons/digital-pet/tutorial) -* Activity: [quiz](/lessons/digital-pet/quiz) -* Extended Activity: [challenges](/lessons/digital-pet/challenges) - -## Objectives - -* learn how to create a function as a unit of code that performs a specific task and returns a result -* learn how to call an existing function in your script -* learn how to create a global variable as a place where you can store data so that you can use it later in your code, accessible across functions and in nested code blocks -* learn how to set or change the value of a global variable -* learn how to repeat code in the background forever -* learn how to get the state of an input button -* learn how to show a number on the @boardname@'s LED screen -* learn how to show a string on the @boardname@'s LED screen -* learn how to create an image to show on the @boardname@'s LED screen -* learn how to show an image on the @boardname@'s LED screen -* learn how to pause your code for the specified number of milliseconds - -## Links to the National Curriculum Programmes of Study for Computing - -## Progression Pathways / Computational Thinking Framework - -#### Algorithms - -* Designs solutions (algorithms) that use repetition and two-way selection, ie if, then and else.(AL) -* Uses diagrams to express solutions.(AB) -* Uses logical reasoning to predict outputs, showing an awareness of inputs (AL) -* Represents solutions using a structured notation (AL) (AB) - -#### Programming & Development - -* Creates programs that implement algorithms to achieve given goals (AL) -* Declares and assigns variables(AB) -* Uses post-tested loop e.g.‘until’,and a sequence of selection statements in programs,including an if,then and else statement(AL) -* Understands the difference between, and appropriately uses if and if, then and else statements(AL) -* Uses a variable and relational operators within a loop to govern termination (AL) (GE) -* Uses a range of operators and expressions e.g. Boolean, and applies them in the context of program control. (AL) -* Selects the appropriate data types(AL) (AB - -#### Data & Data Representation - -* Defines data types: real numbers and Boolean (AB) - -#### Communication Networks - -* Demonstrates responsible use of technologies and online services, and knows a range of ways to report concerns Understands how search engines rank search results (AL) - -#### Information Technology - -* Collects, organizes, and presents data and information in digital content (AB) -* Makes appropriate improvements to solutions based on feedback received, and can comment on the success of the solution (EV) -* Uses criteria to evaluate the quality of solutions, can identify improvements making some refinements to the solution, and future solutions (EV) - -Computational Thinking Concept: AB = Abstraction; DE = Decomposition; AL = Algorithmic Thinking; EV = Evaluation; GE = Generalisation - -## Activity - -* time: 20 min. -* [tutorial](/lessons/digital-pet/tutorial) -* [quiz](/lessons/digital-pet/quiz) - -## Extended Activity - -* time: 20 min. -* [challenges](/lessons/digital-pet/challenges) - -## Homework - -* Extended Activity: [challenges](/lessons/digital-pet/challenges) - -## Intended follow on - -Publish script to the classroom. - diff --git a/olddocs/js/lessons/digital-pet/challenges.md b/olddocs/js/lessons/digital-pet/challenges.md deleted file mode 100644 index 8b87cacc..00000000 --- a/olddocs/js/lessons/digital-pet/challenges.md +++ /dev/null @@ -1,123 +0,0 @@ -# digital pet challenges - -Coding challenges for the digital pet tutorial. - -## Before we get started - -Complete the following guided tutorial: - -* [tutorial](/lessons/digital-pet/tutorial) - -At the end of the tutorial, click `keep editing`. Your code should look like this: - -``` -basic.forever(() => { - if (input.buttonIsPressed("A")) { - setSleep() - basic.pause(5000) - } else { - setAwake() - } -}) -``` - -### Challenge 1 - -Now let's feed the pet! Add an **ELSE IF** statement that checks if button `B` is pressed. Click on the **ELSE** and type **IF** next to it to get the **ELSE IF**. - -``` -basic.forever(() => { - if (input.buttonIsPressed("A")) { - setSleep() - basic.pause(5000) - } else if (input.buttonIsPressed("B")) { - - } - else { - setAwake() - } -}) -``` - -### Challenge 2 - -Now we want to show your eating pet! Let's create a function called `set eat` that will do create an image. Store that image in a variable and then show it. - -``` -export function setEat() { - let img = images.createImage(` -. # . # . -. . # . . -. . # . . -. # . # . -. . # . . -`) - img.showImage(0) -} -``` - -Once you create the function `set eat`, call it in the **ELSE IF** statement that checks if button `B` is pressed. - -``` -basic.forever(() => { - if (input.buttonIsPressed("A")) { - setSleep() - basic.pause(5000) - } else if (input.buttonIsPressed("B")) { - setEat() - } - else { - setAwake() - } -}) -``` - -### Challenge 3 - -Have your pet tell you when it is going to sleep! Do this inside of the **IF** statement that checks if button `A` is pressed before you call the function `set sleep`. - -``` -basic.forever(() => { - if (input.buttonIsPressed("A")) { - basic.showString("I am going to sleep.", 150) // *** - setSleep() - basic.pause(5000) - } else if (input.buttonIsPressed("B")) { - setEat() - } - else { - setAwake() - } -}) -``` - -### Challenge 4 - -Now, how about we keep track of how many times our pet eats? Add a global variable called `feed` that keeps track of how many times you feed your pet. If button `B` is pressed, increment `feed` by one. Add a condition `on shake` to check your total. - -``` -feed = 0 // *** -basic.forever(() => { - if (input.buttonIsPressed("A")) { - basic.showString("I am going to sleep.", 150) - setSleep() - basic.pause(5000) - } else if (input.buttonIsPressed("B")) { - feed = feed + 1 // *** - setEat() - } - else { - setAwake() - } -}) -input.onGesture(Gesture.Shake, () => { - basic.showNumber(feed, 150) // *** -}) // *** -``` - -### Challenge 5 - -Program your pet to say that it is hungry after 60 seconds. - -**Hint**: use `input->running time` - diff --git a/olddocs/js/lessons/digital-pet/quiz-answers.md b/olddocs/js/lessons/digital-pet/quiz-answers.md deleted file mode 100644 index 254ef8c5..00000000 --- a/olddocs/js/lessons/digital-pet/quiz-answers.md +++ /dev/null @@ -1,60 +0,0 @@ -# digital pet quiz answers - -A display of pet images for the @boardname@ - -## Name - -## Directions - -Use this activity document to guide your work in the [digital pet tutorial](/lessons/digital-pet/tutorial) - -Answer the questions while completing the tutorial. Pay attention to the dialogues! - -## 1. What is a 'function'? - -
- -A function is a unit of code that performs a specific task and may return a result. - -## 2. Write the steps to create the function called set awake() - -
- -Click on "+ add new" and then "function". Click on the function name (by default it is "set awake"), and rename it to "set awake()". - -## 3. Write the code inside the function "set awake()" that shows an image of the pet awake - -
- -``` -let img = images.createImage(` -. # . # . -. . # . . -. . . . . -. # # # . -. . . . . -`) -img.showImage(0) -``` - -## 4. Write the steps to create the function called set sleep, function set sleep() - -
- -Click on "+ add new" and then "function". Click on the function name (by default it is "set sleep"), and rename it to "set sleep()". - -## 5. Write the code inside the function "set sleep()" that shows an image of the pet asleep - -
- -``` -img = images.createImage(` -# # . # # -. . # . . -. . . . . -. # # # . -. . . . . -`) -img.showImage(0) -``` - diff --git a/olddocs/js/lessons/digital-pet/quiz.md b/olddocs/js/lessons/digital-pet/quiz.md deleted file mode 100644 index 63936dab..00000000 --- a/olddocs/js/lessons/digital-pet/quiz.md +++ /dev/null @@ -1,32 +0,0 @@ -# digital pet quiz - -A display of pet images for the @boardname@ - -## Name - -## Directions - -Use this activity document to guide your work in the [digital pet tutorial](/lessons/digital-pet/tutorial) - -Answer the questions while completing the tutorial. Pay attention to the dialogues! - -## 1. What is a 'function'? - -
- -## 2. Write the steps to create the function called set awake() - -
- -## 3. Write the code inside the function "set awake()" that shows an image of the pet awake - -
- -## 4. Write the steps to create the function called set sleep, function set sleep() - -
- -## 5. Write the code inside the function "set sleep()" that shows an image of the pet asleep - -
- diff --git a/olddocs/js/lessons/flipping-bird/challenges.md b/olddocs/js/lessons/flipping-bird/challenges.md deleted file mode 100644 index 0108fec6..00000000 --- a/olddocs/js/lessons/flipping-bird/challenges.md +++ /dev/null @@ -1,85 +0,0 @@ -# flipping bird challenges - -Coding challenges for flipping bird. #docs - -## Before we get started - -Complete the following guided tutorial: - -* [tutorial](/lessons/flipping-bird/tutorial) - -At the end of the tutorial, click `keep editing`. Your code should look like this: - -``` -counter = 0 -input.onGesture(Gesture.Shake, () => { - counter = counter + 1 - if (math.mod(counter, 2) == 1) { - basic.plotImage(` -# # . # # -. . # . . -. . . . . -. . . . . -. . . . . -`) - } -}) -``` - -### Challenge 1 - -We handled the case of when `math->mod(counter,2) = 1`. We haven't done anything when the remainder is 0! Add an if statement to handle this case. - -``` -counter = 0 -input.onGesture(Gesture.Shake, () => { - counter = counter + 1 - if (math.mod(counter, 2) == 1) { - basic.plotImage(` -# # . # # -. . # . . -. . . . . -. . . . . -. . . . . -`) - } - if (math.mod(counter, 2) == 0) { - } -}) -``` - -### Challenge 2 - -Inside of that `if` statement you created in challenge 1, add `basic->plot image()` and display an upside down flying bird. - -``` -counter = 0 -input.onGesture(Gesture.Shake, () => { - counter = counter + 1 - if (math.mod(counter, 2) == 1) { - basic.plotImage(` -# # . # # -. . # . . -. . . . . -. . . . . -. . . . . -`) - } - if (math.mod(counter, 2) == 0) { - basic.plotImage(` -. . . . . -. . . . . -. . . . . -. . # . . -# # . # # -`) // *** - } -}) -``` - -* `Run` the code to see if it works as expected. - -**Challenge 3** - -Display a check mark and question mark instead of flipping birds. Or better yet, come up with your own pair of opposites to display! - diff --git a/olddocs/js/lessons/flipping-bird/quiz-answers.md b/olddocs/js/lessons/flipping-bird/quiz-answers.md deleted file mode 100644 index 2dcfef42..00000000 --- a/olddocs/js/lessons/flipping-bird/quiz-answers.md +++ /dev/null @@ -1,50 +0,0 @@ -# flipping bird quiz answers - -use modulo with a conditional. - -This is the answer key for the [flipping bird quiz](/lessons/flipping-bird/quiz). - -## 1. What does "modulo" mean in math? - -
- -Modulo (or Mod) is the remainder of a division problem. - -## 2. Consider the following code - -If the rectangle below represents the @boardname@, shade in the LEDs that show the value being stored into the **global variable**, `count`. Explain why that particular area is shaded. - -``` -count = 1 -count_ = count_ + 2 -``` - -
- -
- -![](/static/mb/lessons/flipping-bird-0.png) - -The variable `count` is now equal to 3. - -
- -## 3. Consider the following directions - -Modulo (Mod) tells us what the remainder of a division is. For example, `15 mod 4 is 3` since 15 divided by 4 has a remainder of 3. - -``` -count = 12 -count = math.mod(count, 5) -``` - -If the rectangle below represents the @boardname@, shade in the LEDs that show the value being stored into the **global variable**, `count`. Explain why that particular area is shaded. - -
- -
- -![](/static/mb/lessons/flipping-bird-1.png) - -The display will show `2` because the remainder of 12 divided by 5 is 2. - diff --git a/olddocs/js/lessons/flipping-bird/quiz.md b/olddocs/js/lessons/flipping-bird/quiz.md deleted file mode 100644 index 9ede676a..00000000 --- a/olddocs/js/lessons/flipping-bird/quiz.md +++ /dev/null @@ -1,60 +0,0 @@ -# flipping bird quiz - -use modulo with a conditional. - -## Name - -## Directions - -Use this activity document to guide your work in the [flipping bird tutorial](/lessons/flipping-bird/tutorial). - -Answer the questions while completing the tutorial. Pay attention to the dialogues! - -## 1. What does "modulo" mean in math? - -## 2. Consider the following directions - -If the rectangle below represents the @boardname@, shade in the LEDs that show the value being stored into the **global variable**, `count`. - -``` -count = 1 -``` - -![](/static/mb/empty-microbit.png) - -
- -
- -## 3. Consider the following code - -If the rectangle below represents the @boardname@, shade in the LEDs that show the value being stored into the **global variable**, `count`. Explain why that particular area is shaded. - -``` -count = 1 -count_ = count_ + 2 -``` - -![](/static/mb/empty-microbit.png) - -
- -
- -## 4. Consider the following directions - -Modulo (Mod) tells us what the remainder of a division is. For example, `15 mod 4 is 3` since 15 divided by 4 has a remainder of 3. - -``` -count = 12 -count = math.mod(count, 5) -``` - -If the rectangle below represents the @boardname@, shade in the LEDs that show the value being stored into the **global variable**, `count`. Explain why that particular area is shaded. - -![](/static/mb/empty-microbit.png) - -
- -
- diff --git a/olddocs/js/lessons/for-loop/challenges.md b/olddocs/js/lessons/for-loop/challenges.md deleted file mode 100644 index 470d7f6c..00000000 --- a/olddocs/js/lessons/for-loop/challenges.md +++ /dev/null @@ -1,41 +0,0 @@ -# looper challenges - -These challenges will allow you to create a counter from 0-5 and then from 5-0. #docs - -### Challenge 0 - -Welcome! This [guided tutorial](/bcvgkf) will assist you with the following activity: - -``` -for (let i = 0; i < 6; i++) { - led.showNumber(i, 150) - basic.pause(2000) -} -``` - -### Challenge 1 - -Go through the loop faster by changing the length of the pause. This is the line you will be editing: `basic->pause(2000)` - -``` -for (let i1 = 0; i1 < 6; i1++) { - basic.showNumber(i1, 150) - basic.pause(500) // *** -} -``` - -### Challenge 2 - -Now, let's count down from 5 instead of counting up to 5. Change the line `basic->show number(i, 150)` to `basic->show number(5 - i, 150)`. - -``` -for (let i2 = 0; i2 < 6; i2++) { - basic.showNumber(5 - i2, 150) // *** - basic.pause(2000) -} -``` - -### Challenge 3 - -Have the number count up in 2's from zero. It should go: 0, 2, 4, 6, 8, 10. - diff --git a/olddocs/js/lessons/glowing-image/challenges.md b/olddocs/js/lessons/glowing-image/challenges.md deleted file mode 100644 index fb62fd4d..00000000 --- a/olddocs/js/lessons/glowing-image/challenges.md +++ /dev/null @@ -1,56 +0,0 @@ -# glowing mountain challenges - -These challenges will help you display a glowing image that fades in and out at different speeds. #docs - -**Challenge 0** - -[This guided tutorial](https://test.microbit.co.uk/td/lessons/glowing-mountain/tutorial) will teach you how to create a mountain that fades out. - -``` -images.createImage(` -. . . . . -. . # . . -. # # # . -# # # # # -# # # # # -`).showImage(0) -led.fadeOut(700) -``` - -**Challenge 1** - -Now, let's add `basic->pause(1000)` after the fade in so that there will be a 1000 millisecond delay after the fade out. - -``` -images.createImage(` -. . . . . -. . # . . -. # # # . -# # # # # -# # # # # -`).showImage(0) -led.fadeOut(700) -basic.pause(1000) // *** -``` - -**Challenge 2** - -After the pause, let's add `led->fade in(2000)` so that we can create a glowing effect. - -``` -images.createImage(` -. . . . . -. . # . . -. # # # . -# # # # # -# # # # # -`).showImage(0) -led.fadeOut(700) -basic.pause(1000) -led.fadeIn(2000) // *** -``` - -**Challenge 3** - -Now add another `basic->pause(1000)` and `led->fade out(900)` so that the mountain can fade out again. - diff --git a/olddocs/js/lessons/glowing-mountain/challenges.md b/olddocs/js/lessons/glowing-mountain/challenges.md deleted file mode 100644 index da15ec76..00000000 --- a/olddocs/js/lessons/glowing-mountain/challenges.md +++ /dev/null @@ -1,60 +0,0 @@ -# glowing sword challenges - -These challenges will help you display a glowing image that fades in and out at different speeds. #docs - -**Challenge 0** - -[This guided tutorial](https://test.microbit.co.uk/td/lessons/glowing-mountain/tutorial) will teach you how to create a mountain that fades out. - -``` -images.createImage(` -. . . . # -# . . # . -# # # . . -. # # . . -# . # # . -`).showImage(0) -led.fadeOut(700) -``` - -**Challenge 1** - -Now, let's add `basic->pause(1000)` after the fade in so that there will be a 1000 millisecond delay after the fade out. - -``` -images.createImage(` -. . . . # -# . . # . -# # # . . -. # # . . -# . # # . -`).showImage(0) -led.fadeOut(700) -basic.pause(1000) // *** -``` - -* Run the code to see if it works as expected. - -### Challenge 2 - -After the pause, let's add `led->fade in(2000)` so that we can create a glowing effect. - -``` -images.createImage(` -. . . . # -# . . # . -# # # . . -. # # . . -# . # # . -`).showImage(0) -led.fadeOut(700) -basic.pause(1000) -led.fadeIn(2000) // *** -``` - -* Run the code to see if it works as expected. - -**Challenge 3** - -Now add another `basic->pause(1000)` and `led->fade out(900)` so that the mountain can fade out again. - diff --git a/olddocs/js/lessons/glowing-sword.md b/olddocs/js/lessons/glowing-sword.md deleted file mode 100644 index bae73c16..00000000 --- a/olddocs/js/lessons/glowing-sword.md +++ /dev/null @@ -1,95 +0,0 @@ -# glowing sword lesson - -make a glowing sword. - -## Topic - -Fade Out - -## Quick Links - -* [activity](/lessons/glowing-sword/activity) -* [quiz](/lessons/glowing-sword/quiz) -* [quiz answers](/lessons/glowing-sword/quiz-answers) -* [challenges](/lessons/glowing-sword/challenges) -* [tutorial](/lessons/glowing-sword/tutorial) - -## Class - -Year 7 - -## Prior learning/place of lesson in scheme of work - -Learn how to manipulate an image through **fade out**, `led->fade out` to gradually decrease the LED screen brightness until the LED lights are turned off. We will be learning how to fade an image using simple commands, such as plot image, fade out, pause, and fade in. - -## What the teacher needs to know/QuickStart Computing Glossary - -* Algorithm: An unambiguous set of rules or a precise step-bystep guide to solve a problem or achieve a particular objective. -* Computational thinking: Thinking about systems or problems in a way that allows computer systems to be used to model or solve these. -* Hardware: The physical systems and components of digital devices; see also software. -* Programmable toys: Robots designed for children to use, accepting input, storing short sequences of simple instructions and moving according to this stored program. -* Script: A computer program typically executed one line at a time through an interpreter, such as the instructions for a Scratch character. -* Sequence: To place program instructions in order, with each executed one after the other. -* Simulation: Using a computer to model the state and behaviour of real-world (or imaginary) systems, including physical or social systems; an integral part of most computer games. - -## Documentation - -* **plot image** : [read more...](/reference/led/plot-image) -* **fade out** : [read more...](/reference/led/fade-out) -* **pause** : [read more...](/reference/basic/pause) -* **fade in** : [read more...](/reference/led/fade-in) - -## Resources - -* Activity: [tutorial](/lessons/glowing-sword/tutorial) -* Activity: [quiz](/lessons/glowing-sword/quiz) -* Extended Activity: [challenges](/lessons/glowing-sword/challenges) - -## Objectives - -* learn how to plot an image -* learn how to gradually decrease the LED screen brightness until the LED lights are turned off -* pause your code for the specified number of milliseconds -* learn how to gradually increase the LED screen brightness until the LED lights are turned on - -## Links to the National Curriculum Programmes of Study for Computing - -## Progression Pathways / Computational Thinking Framework - -#### Algorithms - -* Uses diagrams to express solutions.(AB) -* Represents solutions using a structured notation (AL) (AB) - -#### Programming & Development - -* Creates programs that implement algorithms to achieve given goals (AL) -* Selects the appropriate data types(AL) (AB) - -#### Information Technology - -* Collects, organizes, and presents data and information in digital content (AB) -* Makes appropriate improvements to solutions based on feedback received, and can comment on the success of the solution (EV) -* Recognises ethical issues surrounding the application of information technology beyond school. - -Computational Thinking Concept: AB = Abstraction; DE = Decomposition; AL = Algorithmic Thinking; EV = Evaluation; GE = Generalisation - -## Activity - -* time: 20 min. -* [tutorial](/lessons/glowing-sword/tutorial) -* [quiz](/lessons/lucky-7/quiz) - -## Extended Activity - -* time: 20 min. -* [challenges](/lessons/glowing-sword/challenges) - -## Homework - -* Extended Activity: [challenges](/lessons/glowing-sword/challenges) - -## Intended follow on - -Publish script to the classroom. - diff --git a/olddocs/js/lessons/glowing-sword/activity.md b/olddocs/js/lessons/glowing-sword/activity.md deleted file mode 100644 index 1f5bc850..00000000 --- a/olddocs/js/lessons/glowing-sword/activity.md +++ /dev/null @@ -1,61 +0,0 @@ -# glowing sword activity - -Make glowing sword. - -### ~avatar avatar - -In this activity, we will learn how to fade in and out the screen to create a glowing animation. Let's get started! - -### ~ - -Let's start by adding the code to display an image. Use `basic->plot image` to draw your favorite image. - -``` -basic.plotImage(` -. . . . # -# . . # . -. # # . . -. # # . . -# . . # . -`) // *** -``` - -We can control the brightness of the LED screen with code. That's just what we need to create a **glowing** animation: first we **fade out**, then **fade in**. Add a new line of code to **fade out** the screen. - -``` -basic.plotImage(` -. . . . # -# . . # . -. # # . . -. # # . . -# . . # . -`) -led.fadeOut(700) // *** -``` - -Run your script to make sure it works as expected then add another line of code to **fade in** the screen. - -``` -led.fadeIn(700) -``` - -Finally, add a `basic->forever` loop and move the fade out and fade in code into the forever to repeat the glow pattern. - -``` -basic.plotImage(` -. . . . # -# . . # . -. # # . . -. # # . . -# . . # . -`) -led.fadeOut(700) // *** -led.fadeIn(700) // *** -``` - -### ~avatar boothing - -Excellent, you're ready to continue with the [challenges](/lessons/glowing-sword/challenges)! - -### ~ - diff --git a/olddocs/js/lessons/glowing-sword/challenges.md b/olddocs/js/lessons/glowing-sword/challenges.md deleted file mode 100644 index 7fafb951..00000000 --- a/olddocs/js/lessons/glowing-sword/challenges.md +++ /dev/null @@ -1,60 +0,0 @@ -# glowing sword challenges - -Coding challenges for the glowing sword tutorial. #docs - -## Before we get started - -Complete the [glowing sword](/lessons/glowing-sword/activity) activity and your code will look like this: - -``` -basic.plotImage(` -. . . . # -# . . # . -. # # . . -. # # . . -# . . # . -`) -led.fadeOut(700) -``` - -### Challenge 1 - -Now, let's add `basic->pause(1000)` after the fade in so that there will be a 1000 millisecond (1 second) delay after the fade out. - -``` -basic.plotImage(` -. . . . # -# . . # . -. # # . . -. # # . . -# . . # . -`) -led.fadeOut(700) -basic.pause(1000) // *** -``` - -* `run main` the code to see if it works as expected. - -### Challenge 2 - -After the pause, let's add `led->fade in(2000)` so that we can create a glowing effect. - -``` -basic.plotImage(` -. . . . # -# . . # . -. # # . . -. # # . . -# . . # . -`) -led.fadeOut(700) -basic.pause(1000) -led.fadeIn(2000) // *** -``` - -* `run main` the code to see if it works as expected. - -### Challenge 3 - -Now add another `basic->pause(1000)` and `led->fade out(900)` so that the sword can fade out again. - diff --git a/olddocs/js/lessons/glowing-sword/quiz-answers.md b/olddocs/js/lessons/glowing-sword/quiz-answers.md deleted file mode 100644 index f06bcf94..00000000 --- a/olddocs/js/lessons/glowing-sword/quiz-answers.md +++ /dev/null @@ -1,48 +0,0 @@ -# glowing sword quiz answers - -The answers for the glowing sword quiz. - -This is the answer key for the [glowing sword quiz](/lessons/glowing-sword/quiz). - -## 1. What is "fade out" ? - -Fade out is a method that gradually decreases the LED screen brightness until the LED lights are turned off. - -## 2. Consider the following code - -``` -basic.plotImage(` -. . . . # -# . . # . -. # # . . -. # # . . -# . . # . -`) -led.fadeOut(700) -``` - -Rewrite the second line of code to decrease the speed of the fade out for the longest amount of time (Hint: 1000 milliseconds is longest amount of time for a fade out). - -
- -led->fade out(1000) - -## 4. Consider the following code - -``` -basic.plotImage(` -. . . . # -# . . # . -. # # . . -. # # . . -# . . # . -`) -led.fadeOut(1000) -``` - -What will cause the image to fade back in twice as fast as it faded out? - -
- -led->fade in(500) - diff --git a/olddocs/js/lessons/glowing-sword/quiz.md b/olddocs/js/lessons/glowing-sword/quiz.md deleted file mode 100644 index 1f50ec2e..00000000 --- a/olddocs/js/lessons/glowing-sword/quiz.md +++ /dev/null @@ -1,46 +0,0 @@ -# glowing sword quiz - -make a glowing sword. - -## Name - -## Directions - -Use this activity document to guide your work in the [glowing sword tutorial](/lessons/glowing-sword/tutorial) - -Answer the questions while completing the tutorial. Pay attention to the dialogues! - -## 1. Describe what "led -> fade out" does? - -
- -## 2. Rewrite the second line of code to decrease the speed of the fade out for the longest amount of time Hint: 1000 milliseconds is longest amount of time for a fade out. - -``` -basic.plotImage(` -. . . . # -# . . # . -. # # . . -. # # . . -# . . # . -`) -led.fadeOut(700) -``` - -
- -## 3. What will cause the image to fade back in twice as fast as it faded out? - -``` -basic.plotImage(` -. . . . # -# . . # . -. # # . . -. # # . . -# . . # . -`) -led.fadeOut(1000) -``` - -
- diff --git a/olddocs/js/lessons/hack-your-headphones.md b/olddocs/js/lessons/hack-your-headphones.md deleted file mode 100644 index 296f0b9e..00000000 --- a/olddocs/js/lessons/hack-your-headphones.md +++ /dev/null @@ -1,24 +0,0 @@ -# hack your headphones lesson - -display beautiful images on the @boardname@. - -## Topic - -Hack your headphone - -## Quick Links - -* [activity](/lessons/hack-your-headphones/activity) - -## Class - -Year 7 - -## Prior learning/place of lesson in scheme of work - -Learn how to convert your @boardname@ into a music player using pins P0 and GND, headphones (or speakers), as well as crocodile clips (or spring clips). - -## Objectives - -* learn how to setup the @boardname@ with headphones to play music - diff --git a/olddocs/js/lessons/jailbreak.md b/olddocs/js/lessons/jailbreak.md deleted file mode 100644 index 58040f0c..00000000 --- a/olddocs/js/lessons/jailbreak.md +++ /dev/null @@ -1,106 +0,0 @@ -# jailbreak lesson - -Break out of a counting loop by pressing button "A". - -## Topic - -Break - -## Quick Links - -* [tutorial](/lessons/jailbreak/tutorial) -* [quiz](/lessons/jailbreak/quiz) -* [quiz answers](/lessons/jailbreak/quiz-answers) -* [challenges](/lessons/jailbreak/challenges) - -## Class - -Year 7 - -## Prior learning/place of lesson in scheme of work - -Learn how to create a **break**, `break` to exit a while or for loop before the loop is complete. We will be learning how to create a break using global variables, Boolean, If (conditionals), a While Loop as well as simple commands, such as show string, plot image, show number, and pause. - -## Documentation - -* **Global Variable** : [read more...](/js/data) -* **Boolean** : [read more...](/reference/types/boolean) -* **On Button Pressed** : [read more...](/reference/input/on-button-pressed) -* **While Loop** : [read more...](/js/while) -* **Break** : [read more...](/js/break) -* **If (Conditional)** : [read more...](/reference/logic/if) -* **Show String** : [read more...](/reference/basic/show-string) -* **Plot Image ** : [read more...](/reference/led/plot-image) -* **Show Number** : [read more...](/reference/basic/show-number) -* **Pause** : [read more...](/reference/basic/pause) - -## Objectives - -* learn how to create global variables to store data so that you can use it later in your code, functions, and in nested code blocks -* learn how to use the variables to declare a new local Boolean variable that will have one of two possible values: true or false -* learn how to run code when an input button is pressed -* learn how to repeat code while a condition is true -* learn how to exit a while loop before the loop is complete -* learn how to conditionally run code depending on whether a condition is true or not -* learn how to show a string on the LED screen one character at a time -* learn how to turn on LED lights on the LED screen -* learn how to show a number on the LED screen, one digit at a time -* learn how to pause your code for the specified number of milliseconds - -## Progression Pathways / Computational Thinking Framework - -#### Algorithms - -* Designs solutions (algorithms) that use repetition and two-way selection, ie if, then and else.(AL) -* Uses diagrams to express solutions.(AB) -* Uses logical reasoning to predict outputs, showing an awareness of inputs (AL) -* Recognises that different solutions exist for the same problem (AL) (AB) Understands that iteration is the repetition of a process such as a loop (AL) -* Recognises that different algorithms exist for the same problem (AL) (GE) -* Represents solutions using a structured notation (AL) (AB) - -#### Programming & Development - -* Creates programs that implement algorithms to achieve given goals (AL) -* Declares and assigns variables(AB) -* Uses post-tested loop e.g.‘until’,and a sequence of selection statements in programs,including an if,then and else statement(AL) -* Understands the difference between, and appropriately uses if and if, then and else statements(AL) -* Uses a variable and relational operators within a loop to govern termination (AL) (GE) -* Uses a range of operators and expressions e.g. Boolean, and applies them in the context of program control. (AL) -* Selects the appropriate data types(AL) (AB - -#### Data & Data Representation - -* Performs more complex searches for information e.g. using Boolean and relational operators(AL) (GE) (EV) -* Defines data types: real numbers and Boolean (AB) - -#### Hardware & Processing - -* Knows that computers collect data from various input devices, including sensors and application software (AB) - -#### Communication Networks - -* Demonstrates responsible use of technologies and online services, and knows a range of ways to report concerns Understands how search engines rank search results (AL) - -#### Information Technology - -* Collects, organizes, and presents data and information in digital content (AB) -* Makes appropriate improvements to solutions based on feedback received, and can comment on the success of the solution (EV) -* Recognises ethical issues surrounding the application of information technology beyond school. - -Computational Thinking Concept: AB = Abstraction; DE = Decomposition; AL = Algorithmic Thinking; EV = Evaluation; GE = Generalisation - -## Activity - -* time: 20 min. -* [tutorial](/lessons/jailbreak/tutorial) -* [quiz](/lessons/jailbreak/quiz) - -## Extended Activity - -* time: 20 min. -* [challenges](/lessons/jailbreak/challenges) - -## Homework - -* Extended Activity: [challenges](/lessons/jailbreak/challenges) - diff --git a/olddocs/js/lessons/jailbreak/challenges.md b/olddocs/js/lessons/jailbreak/challenges.md deleted file mode 100644 index e3821667..00000000 --- a/olddocs/js/lessons/jailbreak/challenges.md +++ /dev/null @@ -1,104 +0,0 @@ -# jailbreak challenges - -Coding challenges for the jailbreak tutorial.#docs - -## Before we get started - -Complete the following guided tutorial: - -* [tutorial](/lessons/jailbreak/tutorial) - -At the end of the tutorial, click `keep editing`. Your code should look like this: - -``` -count = 0 -shouldBreak = false -input.onButtonPressed(Button.A, () => { - shouldBreak = true -}) -while (true) { - if (shouldBreak) { - basic.showString("I'M OUT!", 150) - basic.plotImage(` -. # . # . -. # . # . -. . . . . -# . . . # -. # # # . -`) - break - } - count = count + 1 - basic.showNumber(count, 150) - basic.pause(1000) -} -``` - -**Challenge 1** - -Try to remove the `break` in the `if` loop. What problem does this create? - -**Challenge 2** - -Now let's resume the timer again once button `B` is pressed! To do so, begin by creating a condition to know when button `B` is pressed. - -``` -// **. . .** -while (true) { - if (shouldBreak) { - basic.showString("I'M OUT!", 150) - basic.plotImage(` -. # . # . -. # . # . -. . . . . -# . . . # -. # # # . -`) - break - } - count = count + 1 - basic.showNumber(count, 150) - basic.pause(1000) -} -input.onButtonPressed(Button.B, () => { -}) // *** -``` - -Next, set `should break` back to false to indicate we want to run the `while` loop again. - -``` -// **. . .** -input.onButtonPressed(Button.B, () => { - shouldBreak = false // *** -}) -``` - -And now copy the code from the previous while loop into the condition of `input->on button pressed("B")`. This will resume the counter. - -``` -// **. . .** -input.onButtonPressed(Button.B, () => { - shouldBreak = false - while (true) { - if (shouldBreak) { - basic.showString("I'M OUT!", 150) // *** - basic.plotImage(` -. # . # . -. # . # . -. . . . . -# . . . # -. # # # . -`) // *** - break // *** - } - count = count + 1 // *** - basic.showNumber(count, 150) // *** - basic.pause(1000) // *** - } -}) -``` - -**Challenge 3** - -Notice that the two `while` loops are identical. Clean up this redundancy in your code by creating another method and then placing the `while` loop in the method. - diff --git a/olddocs/js/lessons/jailbreak/quiz-answers.md b/olddocs/js/lessons/jailbreak/quiz-answers.md deleted file mode 100644 index c4a2b03f..00000000 --- a/olddocs/js/lessons/jailbreak/quiz-answers.md +++ /dev/null @@ -1,46 +0,0 @@ -# jailbreak quiz answers - -break out of a counting loop by pressing button "A". - -This is the answer key for the [jailbreak quiz](/lessons/jailbreak/quiz). - -## 1. What does a 'break' statement do to a 'loop' ? - -Exit a while or for loop before the loop is complete. - -## 2. Consider the following directions - -Write the line of code that will initialize a number `variable` to 0. Then create a second `variable` that tells us when we should `break` out of the loop. Set the `break` to false. - -``` -count = 0 -shouldBreak = false -``` - -## 3. Consider the following directions - -Write the line of code to stop incrementing `count` when the button is pressed. (Hint: This will set `should break` to true). - -``` -input.onButtonPressed(Button.A, () => { - shouldBreak = true -}) -``` - -## 4. Consider the following directions - -Add an `if` statement to determine whether or not we should break out of the loop. Then include the message "I'm Out!" and a smiley face **image** displayed. This will happen right before you `break` from the `while` loop. **Do not include the break ** - -``` -if (shouldBreak) { - basic.showString("I'M OUT!", 150) - images.createImage(` -. # . # . -. # . # . -. . . . . -# . . . # -. # # # . -`).showImage(0) -} -``` - diff --git a/olddocs/js/lessons/jailbreak/quiz.md b/olddocs/js/lessons/jailbreak/quiz.md deleted file mode 100644 index a33bd51e..00000000 --- a/olddocs/js/lessons/jailbreak/quiz.md +++ /dev/null @@ -1,34 +0,0 @@ -# jailbreak quiz - -break out of a counting loop by pressing button "A". - -## Name - -## Directions - -Use this activity document to guide your work in the [jailbreak tutorial](/lessons/jailbreak/tutorial) - -Answer the questions while completing the tutorial. Pay attention to the dialogues! - -## 1. What does a 'break' statement do to a 'loop' ? - -## 2. Consider the following directions - -Write the line of code that will initialize a number variable to 0. Then create a second variable that tells us when we should `break` out of the loop. Set the `break` to false. - -
- -## 3. Consider the following directions - -Write the line of code to stop incrementing `count` when the button is pressed. (Hint: This will set `should break` to true). - -
- -## 4. Consider the following directions - -Add an `if` statement to determine whether or not we should break out of the loop. Then include the message "I'm Out!" and a smiley face **image** displayed. This will happen right before you `break` from the `while` loop. **Do not include the break ** - -
- -
- diff --git a/olddocs/js/lessons/landslide.md b/olddocs/js/lessons/landslide.md deleted file mode 100644 index bf071d87..00000000 --- a/olddocs/js/lessons/landslide.md +++ /dev/null @@ -1,8 +0,0 @@ -# landslide - -Turn a LED on and off. #docs - -Detect and show an image when the @boardname@ falls. - -* [tutorial](/lessons/landslide/tutorial) -* [challenges](/lessons/landslide/challenges) diff --git a/olddocs/js/lessons/landslide/challenges.md b/olddocs/js/lessons/landslide/challenges.md deleted file mode 100644 index a6faf1b2..00000000 --- a/olddocs/js/lessons/landslide/challenges.md +++ /dev/null @@ -1,77 +0,0 @@ -# landslide challenges - -Coding challenges for the landslide tutorial. - -### ~avatar avatar fail - -Don't drop me on the ground without protection! I'm very fragile. Ouch! - -### ~ - -## Before we get started - -Complete the following guided tutorial: - -* [tutorial](/lessons/landslide/tutorial) - -At the end of the tutorial, click `keep editing`. Your code should look like this: - -``` -input.onFall(() => { - images.createImage(` -. . # . . -. . # . . -. . # . . -. . . . . -. . # . . -`).showImage(0) // *** -}) -``` - -### Challenge 1 - -Add a pause within `input->on fall` after displaying `!`. This will allow us to display another image in the next challenge. - -``` -input.onFall(() => { - images.createImage(` -. . # . . -. . # . . -. . # . . -. . . . . -. . # . . -`).showImage(0) - basic.pause(2000) // *** -}) -``` - -### Challenge 2 - -Create and show an `X` image after the pause from Challenge 1. - -``` -input.onFall(() => { - images.createImage(` -. . # . . -. . # . . -. . # . . -. . . . . -. . # . . -`).showImage(0) - basic.pause(2000) - images.createImage(` -# . . . # -. # . # . -. . # . . -. # . # . -# . . . # -`).showImage(0) // *** -}) -``` - -* `Run` the program to see if it works as expected. - -### Challenge 3 - -Now let's display a third image when the @boardname@ falls! First, add `basic->pause(2000)` followed by another image of your choice. Be creative! - diff --git a/olddocs/js/lessons/letter-up.md b/olddocs/js/lessons/letter-up.md deleted file mode 100644 index b3baa480..00000000 --- a/olddocs/js/lessons/letter-up.md +++ /dev/null @@ -1,112 +0,0 @@ -# letter up lesson - -create a guessing game that can be played with your friends. - -## Topic - -String Functions - -## Quick Links - -* [tutorial](/lessons/letter-up/tutorial) - -## Class - -Year 7 - -## Prior learning/place of lesson in scheme of work - -Learn how to create a guessing game with **global variables** `var str: "this is a string" ` and **strings functions**, ` var first char := str -> at(0) ` , to develop a sequence of characters and get a character within a string . We will be learning how to create a guessing game using local variables, strings functions, input on logo up, string related functions, on screen up, the game library as well as simple commands, such as show string and show number. - -## What the teacher needs to know - -* Algorithm: An unambiguous set of rules or a precise step-bystep guide to solve a problem or achieve a particular objective. -* Command: An instruction for the computer to execute, written in a particular programming language. -* Data: A structured set of numbers, possibly representing digitised text, images, sound or video, which can be processed or transmitted by a computer, also used for numerical (quantitative) information. -* Decomposing: The process through which problems or systems are broken down into their component parts, each of which may then be considered separately. -* Input: Data provided to a computer system, such as via a keyboard, mouse, microphone, camera or physical sensors. -* Output: The information produced by a computer system for its user, typically on a screen, through speakers or on a printer, but possibly through the control of motors in physical systems. -* Programmable toys: Robots designed for children to use, accepting input, storing short sequences of simple instructions and moving according to this stored program. -* Program: A stored set of instructions encoded in a language understood by the computer that does some form of computation, processing input and/or stored data to generate output. -* Script: A computer program typically executed one line at a time through an interpreter, such as the instructions for a Scratch character. -* Selection: A programming construct in which one section of code or another is executed depending on whether a particular condition is met. -* Sequence: To place program instructions in order, with each executed one after the other. -* Simulation: Using a computer to model the state and behaviour of real-world (or imaginary) systems, including physical or social systems; an integral part of most computer games. -* Variables: A way in which computer programs can store, retrieve or change data, such as a score, the time left, or the user’s name. - -**QuickStart Computing Glossary - -## Documentation - -* **string** : [read more...](/reference/types/string) -* **string functions** : [read more...](/reference/types/string-functions) -* **show string** : [read more...](/reference/basic/show-string) -* **local variables** : [read more...](/reference/variables/var) -* **assignment operator** : [read more...](/reference/variables/assign) -* **math random** : [read more...](/js/math) - -## Resources - -* Activity: [tutorial](/lessons/letter-up/tutorial) - -## Objectives - -* learn how to create a sequences of characters -* learn how to get a character within a string, using the specified index -* learn how to show a string on the LED screen -* learn how to create a local variable to store data so that you can use it later in your code -* learn how to set and change the value of a local variable -* learn how to register an event handler that executes whenever the LED screen is perpendicular to the ground and the @boardname@ logo is above the LED screen -* learn how to register an event handler that executes whenever the LED screen is facing the floor -* learn how to register an event handler that executes whenever the LED screen is facing the ceiling/sky -* learn how to return a random number -* learn how to use the game library to set the score, lives, and countdown - -## Links to the National Curriculum Programmes of Study for Computing - -## Progression Pathways / Computational Thinking Framework - -#### Algorithms - -* Uses logical reasoning to predict outputs, showing an awareness of inputs (AL) -* Represents solutions using a structured notation (AL) (AB) - -#### Programming & Development - -* Creates programs that implement algorithms to achieve given goals (AL) -* Declares and assigns variables(AB) -* Uses a variable and relational operators within a loop to govern termination (AL) (GE) -* Has practical experience of a high-level textual language, including using standard libraries when programming(AB) (AL) -* Uses a range of operators and expressions e.g. Boolean, and applies them in the context of program control. (AL) -* Selects the appropriate data types(AL) (AB - -#### Data & Data Representation - -* Understands the difference between data and information(AB) -* Performs more complex searches for information e.g. using Boolean and relational operators(AL) (GE) (EV) - -#### Hardware & Processing - -* Knows that computers collect data from various input devices, including sensors and application software (AB) - -#### Communication Networks - -* Demonstrates responsible use of technologies and online services, and knows a range of ways to report concerns Understands how search engines rank search results (AL) - -#### Information Technology - -* Collects, organizes, and presents data and information in digital content (AB) -* Makes appropriate improvements to solutions based on feedback received, and can comment on the success of the solution (EV) -* Uses criteria to evaluate the quality of solutions, can identify improvements making some refinements to the solution, and future solutions (EV) - -Computational Thinking Concept: AB = Abstraction; DE = Decomposition; AL = Algorithmic Thinking; EV = Evaluation; GE = Generalisation - -## Activity - -* time: 20 min. -* [tutorial](/lessons/letter-up/tutorial) - -## Intended follow on - -Publish script to the classroom. - diff --git a/olddocs/js/lessons/light-column-cascade/quiz.md b/olddocs/js/lessons/light-column-cascade/quiz.md deleted file mode 100644 index b9ccf639..00000000 --- a/olddocs/js/lessons/light-column-cascade/quiz.md +++ /dev/null @@ -1,128 +0,0 @@ -# cascade quiz - -Learn how to create a blinking LED script with a for loop. - -## Name - -## Directions - -Use this activity document to guide your work in the [light column cascade tutorial](/js/light-column-cascade/tutorial). - -Answer the questions below while working on or after you finish the tutorial. Pay attention to the dialogs! - -## 1. What is a for loop? - -## 2. Consider the following code - -``` -for (let i = 0; i < 5; i++) { - for (let j = 0; j < 5; j++) { - led.plot(i, j) - } -} -``` - -If the rectangle below represents a board that is 5 LEDs wide and 5 LEDs tall, place an X approximately all the locations where the LED is lighted. Explain why the LED is lighted there. - -![](/static/mb/empty-microbit.png) - -## 3. Consider the following code - -``` -for (let i1 = 0; i1 < 3; i1++) { - for (let j1 = 0; j1 < 3; j1++) { - led.plot(i1, j1) - } -} -``` - -If the rectangle below represents a board that is 5 LEDs wide and 5 LEDs tall, place an X approximately all the locations where the LED is lighted. Explain why the LED is lighted there. - -![](/static/mb/empty-microbit.png) - -## 4. Consider the following code - -``` -for (let i2 = 0; i2 < 2; i2++) { - for (let j2 = 0; j2 < 2; j2++) { - led.plot(i2, j2) - } -} -``` - -If the rectangle below represents a board that is 5 LEDs wide and 5 LEDs tall, place an X approximately where the LED is lighted. Explain why the LED is lighted there. - -![](/static/mb/empty-microbit.png) - -****************************** - -## KEY - -## Directions - -Answer the questions below while working on or after you finish the tutorial. - -## 1. What is a for loop? - -Answers will vary. In general, for loop refers to the code that repeats for a fixed number of times. We specify the LED using x, y coordinates. - -## 2. Consider the following code - -``` -for (let i3 = 0; i3 < 5; i3++) { - for (let j3 = 0; j3 < 5; j3++) { - led.plot(i3, j3) - } -} -``` - -If the rectangle below represents a board that is 5 LEDs wide and 5 LEDs tall, place an X approximately where the LED is lighted. Explain why the LED is lighted there. - -![](/static/mb/lessons/cascade-0.png) - -This code turns on specific LED. Plot turns on the specified LED on the LED screen. We specify the LED using x, y coordinates. The code lights on the LEDs - -x - the x coordinate or horizontal position (0,1,2,3,4) - -y - the y coordinate or vertical position (0,1,2,3,4) - -## 3. Consider the following code - -``` -for (let i4 = 0; i4 < 3; i4++) { - for (let j4 = 0; j4 < 3; j4++) { - led.plot(i4, j4) - } -} -``` - -If the rectangle below represents a board that is 5 LEDs wide and 5 LEDs tall, place an X approximately where the LED is lighted. Explain why the LED is lighted there. - -![](/static/mb/lessons/column-0.png) - -This code turns on specific LED. Plot turns on the specified LED on the LED screen. We specify the LED using x, y coordinates. - -x - the x coordinate or horizontal position (0,1,2) - -y - the y coordinate or vertical position (0,1,2) - -## 4. Consider the following code - -``` -for (let i5 = 0; i5 < 1; i5++) { - for (let j5 = 0; j5 < 1; j5++) { - led.plot(i5, j5) - } -} -``` - -If the rectangle below represents a board that is 5 LEDs wide and 5 LEDs tall, place an X approximately where the LED is lighted. Explain why the LED is lighted there. - -![](/static/mb/lessons/column-1.png) - -This code turns on specific LED. Plot turns on the specified LED on the LED screen. We specify the LED using x, y coordinates. - -x - the x coordinate or horizontal position (0,1) - -y - the y coordinate or vertical position (0,1) - diff --git a/olddocs/js/lessons/line-of-fire.md b/olddocs/js/lessons/line-of-fire.md deleted file mode 100644 index 374478f8..00000000 --- a/olddocs/js/lessons/line-of-fire.md +++ /dev/null @@ -1,94 +0,0 @@ -# line of fire lesson - -Create a game that relies on precise instincts and timing reflexes #if #. - -## Topic - -Functions - -## Quick Links - -* [tutorial](/lessons/line-of-fire/tutorial) -* [quiz](/lessons/line-of-fire/quiz) -* [quiz answers](/lessons/line-of-fire/quiz-answers) - -## Class - -Year 7 - -## Prior learning/place of lesson in scheme of work - -Learn how to create **functions**, `function()` that perform a specific task and returns a result. We will be learning how to create a pong game using functions, global variable forever loop, global variables, Boolean, for loop, input on button pressed, if statements, as well as simple commands, such as plot, unplot and pause. - -## Documentation - -* **function** : [read more...](/js/function) -* **return** : [read more...](/js/return) -* **call** : [read more...](/js/call) -* **global variable** : [read more...](/js/data) -* **arithmetic operator** : [read more...](/reference/types/number) -* **Boolean** : [read more...](/reference/types/boolean) -* **forever** : [read more...](/reference/basic/forever) -* **on button pressed** : [read more...](/reference/input/on-button-pressed) -* **if** : [read more...](/reference/logic/if) -* **clear screen** : [read more...](/reference/basic/clear-screen) -* **show string** : [read more...](/reference/basic/show-string) -* **plot** : [read more...](/reference/led/plot) -* **unplot** : [read more...](/reference/led/unplot) -* **pause** : [read more...](/reference/basic/pause) - -## Objectives - -* learn how to create a function as a unit of code that performs a specific task and returns a result -* learn how a return statement exits a function and returns a value to the code -* learn how to call an existing function in your script -* learn how to create a global variable as a place where you can store data so that you can use it later in your code, accessible across functions and in nested code blocks -* learn how arithmetic operators operate on numbers and return a number -* learn how a Boolean type has one of two possible values: true or false -* learn how to repeat code in the background forever -* learn how to conditionally run code depending on whether a condition is true or not -* learn how to run code when an input button is pressed -* learn how to show a string on the @boardname@'s LED screen -* learn how to turn on a LED light on the LED screen. Learn how to specify which LED using x, y coordinates -* learn how to turn off a LED light on the LED screen. Learn how to specify which LED using x, y coordinates -* learn how to pause your code for the specified number of milliseconds - -## Progression Pathways / Computational Thinking Framework - -#### Algorithms - -* Designs solutions (algorithms) that use repetition and two-way selection, ie if, then and else.(AL) -* Uses diagrams to express solutions.(AB) -* Uses logical reasoning to predict outputs, showing an awareness of inputs (AL) -* Represents solutions using a structured notation (AL) (AB) - -#### Programming & Development - -* Creates programs that implement algorithms to achieve given goals (AL) -* Declares and assigns variables(AB) -* Uses post-tested loop e.g.‘until’,and a sequence of selection statements in programs,including an if,then and else statement(AL) -* Understands the difference between, and appropriately uses if and if, then and else statements(AL) -* Uses a variable and relational operators within a loop to govern termination (AL) (GE) -* Uses a range of operators and expressions e.g. Boolean, and applies them in the context of program control. (AL) -* Selects the appropriate data types(AL) (AB - -#### Data & Data Representation - -* Defines data types: real numbers and Boolean (AB) - -Computational Thinking Concept: AB = Abstraction; DE = Decomposition; AL = Algorithmic Thinking; EV = Evaluation; GE = Generalisation - -## Activity - -* time: 20 min. -* [tutorial](/lessons/line-of-fire/tutorial) - -## Extended Activity - -* time: 20 min. -* [quiz](/lessons/line-of-fire/quiz) - -## Homework - -* Extended Activity: [quiz](/lessons/line-of-fire/quiz) - diff --git a/olddocs/js/lessons/line-of-fire/quiz-answers.md b/olddocs/js/lessons/line-of-fire/quiz-answers.md deleted file mode 100644 index eb4f8de0..00000000 --- a/olddocs/js/lessons/line-of-fire/quiz-answers.md +++ /dev/null @@ -1,140 +0,0 @@ -# line of fire quiz answers - -create a game that relies on precise instincts and timing reflexes. - -## Name - -## Directions - -Use this activity document to guide your work in the [line of fire tutorial](/lessons/line-of-fire/tutorial) - -Answer the questions while completing the tutorial. Pay attention to the dialogues! - -## 1. Write the names of the two Global Variable used to store the mode of the game. Which of these variables is set to true when we are displaying the score? - -
- -``` -dotRunning = true -displayingStats = false -``` - -`displaying stats` is set to `true` when we are displaying the score. - -## 2. Write the name of the Global Variable that represents the velocity and assign it to its initial value. Next, write the name of the Global Variable that represents the position of the dot and assign it to its initial value. - -
- -``` -dotX = 2 -dotXVelocity = 1 -``` - -## 3. Write the name of the two variables that keep track of the score, and assign them to their initial values. - -
- -``` -wins = 0 -losses = 0 -``` - -## 4. Write the For Loop that will plot the 'line of fire'. - -
- -``` -for (let i = 0; i < 5; i++) { - led.plot(2, i) -} -``` - -## 5. If the dot is running, write the 'nested If statements' that will see when to change the direction by flipping the sign of the velocity. This occurs if the dot is on the edge of the board. - -
- -**Questions 6-8 concern with moving the dot.** - -## 6. Write the code to unplot the dot's current position. NOTE- if dotX was originally 2, then we must plot instead of unplot the dot's original position. - -
- -Solution 1: - -``` -if (dotX == 2) { - led.plot(dotX, 2) -} else { - led.unplot(dotX, 2) -} -``` - -Alternative Solution: - -``` -if (dotX != 2) { - led.unplot(dotX, 2) -} else { - led.plot(dotX, 2) -} -``` - -## 7. Update its position variables by adding the velocity to the dot's current position. - -
- -``` -dotX = dotX + dotXVelocity -``` - -## 8. Finally, plot the dot's new position. NOTE- if dotX is now 2, then we must unplot instead of plot the dot's new position. - -
- -Solution 1: - -``` -led.plot(dotX, 2) -if (dotX == 2) { - led.unplot(dotX, 2) -} -``` - -Alternative Solution: - -``` -if (dotX == 2) { - led.unplot(dotX, 2) -} else { - led.plot(dotX, 2) -} -``` - -## 9. Write the code that plots and unplots the dot 10 times when button A is pressed. Pause for 60 milliseconds in between plotting and unplotting the dot. (Don't include any if statements, and don't worry about updating 'dot running'.) - -
- -``` -for (let j = 0; j < 10; j++) { - led.plot(dotX, 2) - basic.pause(60) - led.unplot(dotX, 2) - basic.pause(60) -} -``` - -## 10. Write the code that will display the score when button B is pressed. (Don't include any IF statements, and don't worry about updating 'dot running' and 'displaying stats'.) - -
- -``` -input.onButtonPressed(Button.B, () => { - basic.showString("WINS", 150) - basic.showNumber(wins, 150) - basic.pause(500) - basic.showString("LOSSES", 150) - basic.showNumber(losses, 150) - basic.pause(500) -}) -``` - diff --git a/olddocs/js/lessons/line-of-fire/quiz.md b/olddocs/js/lessons/line-of-fire/quiz.md deleted file mode 100644 index ab5574c3..00000000 --- a/olddocs/js/lessons/line-of-fire/quiz.md +++ /dev/null @@ -1,84 +0,0 @@ -# line of fire quiz - -create a game that relies on precise instincts and timing reflexes. - -## Name - -## Directions - -Use this activity document to guide your work in the [line of fire tutorial](/lessons/line-of-fire/tutorial) - -Answer the questions while completing the tutorial. Pay attention to the dialogues! - -## 1. Write the names of the two Global Variable used to store the mode of the game. Which of these variables is set to true when we are displaying the score? - -
- -
- -## 2. Write the name of the Global Variable that represents the velocity and assign it to its initial value. Next, write the name of the Global Variable that represents the position of the dot and assign it to its initial value. - -
- -
- -## 3. Write the name of the two variables that keep track of the score, and assign them to their initial values. - -
- -
- -## 4. Write the For Loop that will plot the 'line of fire'. - -
- -
- -
- -## 5. If the dot is running, write the 'nested If statements' that will see when to change the direction by flipping the sign of the velocity. This occurs if the dot is on the edge of the board. - -
- -**Questions 6-8 concern with moving the dot.** - -## 6. Write the code to unplot the dot's current position. NOTE- if dot x was originally 2, then we must plot instead of unplot the dot's original position. - -
- -
- -
- -## 7. Update its position variables by adding the velocity to the dot's current position. - -
- -## 8. Finally, plot the dot's new position. NOTE- if dot x is now 2, then we must unplot instead of plot the dot's new position. - -
- -
- -
- -## 9. Write the code that plots and unplots the dot 10 times when button A is pressed. Pause for 60 milliseconds in between plotting and unplotting the dot. (Don't include any if statements, and don't worry about updating 'dot running'.) - -
- -
- -
- -## 10. Write the code that will display the score when button B is pressed. (Don't include any IF statements, and don't worry about updating 'dot running' and 'displaying stats'.) - -
- -
- -
- -
- -
- diff --git a/olddocs/js/lessons/logo-pointer/challenges.md b/olddocs/js/lessons/logo-pointer/challenges.md deleted file mode 100644 index 88885494..00000000 --- a/olddocs/js/lessons/logo-pointer/challenges.md +++ /dev/null @@ -1,71 +0,0 @@ -# magic logo challenges - -These challenges will help you show arrows that point which way the logo is pointing! #docs - -## Challenge 0 - -This [guided tutorial](/zysycw) will help you display an arrow pointing the direction the logo is oriented! - -Let's display and upward pointing arrow when the logo is up! - -``` -input.onLogoUp(() => { - images.createImage(` -. . # . . -. # # # . -# # # # # -. . # . . -. . # . . -`).showImage(0) -}) -``` - -**Challenge 1** - -How about when the logo is down? We should display the arrow pointing downward! - -Let's start by adding a condition for if the logo is down. - -``` -input.onLogoUp(() => { - images.createImage(` -. . # . . -. # # # . -# # # # # -. . # . . -. . # . . -`).showImage(0) -}) -input.onLogoDown(() => { -}) // *** -``` - -## Challenge 2 - -Now we need to display the arrow! - -``` -input.onLogoUp(() => { - images.createImage(` -. . # . . -. # # # . -# # # # # -. . # . . -. . # . . -`).showImage(0) -}) -input.onLogoDown(() => { - images.createImage(` -. . # . . -. . # . . -# # # # # -. # # # . -. . # . . -`).showImage(0) // *** -}) -``` - -**Challenge 3** - -Let's show a spinning arrow when the @boardname@ is shaken. We can do this by adding an on shake condition and showing an animation of the arrow spinning! - diff --git a/olddocs/js/lessons/looper/challenges.md b/olddocs/js/lessons/looper/challenges.md deleted file mode 100644 index 8836b5d4..00000000 --- a/olddocs/js/lessons/looper/challenges.md +++ /dev/null @@ -1,75 +0,0 @@ -# looper challenges - -Coding challenges for the looper tutorial. #docs - -## Before we get started - -Complete the following guided tutorial: - -* [tutorial](/lessons/looper/tutorial) - -At the end of the tutorial, click `keep editing`. Your code should look like this: - -``` -for (let i = 0; i < 6; i++) { - basic.showNumber(i, 150) - basic.pause(2000) -} -``` - -### Challenge 1 - -What if we want to count up to lucky number 7 instead? Let's do that by changing the ending value to `8` instead of `6`. - -``` -for (let i1 = 0; i1 < 8; i1++) { - basic.showNumber(i1, 150) // *** - basic.pause(2000) -} -``` - -* Run the program now to see your changes. - -### Challenge 2 - -What about 9? Let's do that by changing the ending value to `10`. - -``` -for (let i2 = 0; i2 < 10; i2++) { - basic.showNumber(i2, 150) - basic.pause(2000) -} -``` - -* Run your code to see the new counter. - -### Challenge 3 - -Now let's start counting from `3` instead! Our for loop will always start at `0` so we simply add `3` to the `i` variable when passing it to `basic->show number`. - -``` -for (let i3 = 0; i3 < 8; i3++) { - basic.showNumber(i3 + 3, 150) // *** - basic.pause(2000) -} -``` - -Run it on the simulator! - -### Challenge 4 - -Now, let's **count down from 9**. Change the line `basic->show number(i + 3, 150)` to `basic->show number(9 - i, 150)`. - -``` -for (let i4 = 0; i4 < 10; i4++) { - basic.showNumber(9 - i4, 150) // *** - basic.pause(2000) -} -``` - -* Run the code to make sure it is doing what is expected. - -### Challenge 5 - -After counting down from `9` let's show the string `BOOOM`! - diff --git a/olddocs/js/lessons/looper/lesson.md b/olddocs/js/lessons/looper/lesson.md deleted file mode 100644 index b9cb016c..00000000 --- a/olddocs/js/lessons/looper/lesson.md +++ /dev/null @@ -1,103 +0,0 @@ -# looper lesson - -Learn to control blinking LEDs. - -## Topic - -For loop - Blinking LED - -## Quick links - -* [tutorial](/lessons/looper/tutorial) -* [quiz](/lessons/looper/quiz) -* [quiz answers](/lessons/looper/quiz-answers) -* [challenges](/lessons/looper/challenges) - -## Class - -Year 7 - -## Prior learning/place of lesson in scheme of work - -Learn how to control a blinking LED. We will be learning how to create a blinking app using the for loop as well as simple commands, such as plot and pause. - -## What the teacher needs to know - -**Program:** A stored set of instructions encoded in a language understood by the computer that does some form of computation, processing input and/or stored data to generate output.** - -**Algorithm:** An unambiguous set of rules or a precise step-by-step guide to solve a problem or achieve a particular objective. The guided tutorial follows a algorithm and is a precise step-by-step guide to solve a problem** - -**Loop:** A block of code repeated automatically under the program’s control. ** The blink program introduces a While Loop. While Loop is a while loop that will repeat code forever while - true. - -**Command:** An instruction for the computer to execute, written in a particular programming language.** - -**QuickStart Computing Glossary - -## Documentation - -* **plot**: [read more...](/reference/led/plot) -* **pause**: [read more...](/reference/basic/pause) -* **for**: [read more...](/reference/loops/for) - -## Resources - -* Activity: [tutorial](/lessons/looper/tutorial) -* Activity: [quiz](/lessons/looper/quiz) -* Extended Activity: [challenges](/lessons/looper/challenges) - -## Objectives - -* learn how to blink a light -* create a for loop that will loop through each x-value, y-value from 0 to 4. -* learn how to pause the light on and off -* learn how to repeat turning on and off the light - -## Links to the National Curriculum Programmes of Study for Computing - -## Progression Pathways / Computational Thinking Framework - -#### Algorithms - -* Uses logical reasoning to predict outputs, showing an awareness of inputs. (AL) -* Understands that iteration is the repetition of a process such as a loop. (AL) -* Represents solutions using a structured notation. (AL) (AB) - -#### Programming & Development - -* Creates programs that implement algorithms to achieve given goals. (AL) -* Uses a variable and relational operators within a loop to govern termination. (AL) (GE) -* Uses a range of operators and expressions e.g. Boolean, and applies them in the context of program control. (AL) - -#### Data & Data Representation - -* Understands the difference between data and information. (AB) -* Defines data types: real numbers and Boolean. (AB) - -#### Information Technology - -* Collects, organises and presents data and information in digital content. (AB) -* Makes appropriate improvements to solutions based on feedback received, and can comment on the success of the solution. (EV) - -Computational Thinking Concept: AB = Abstraction; DE = Decomposition; AL = Algorithmic Thinking; EV = Evaluation; GE = Generalisation - -## Activity - -* time: 10 min. -* [tutorial](/lessons/looper/tutorial) -* [quiz](/lessons/looper/quiz) -* assessment opportunities: loops, plot, pause, clear screen - -## Extended Activity - -* time: 20 min. -* [challenges](/lessons/looper/challenges) -* assessment opportunities: loops, plot, pause, clear screen - -## Homework - -* Extended Activity: [challenges](/lessons/looper/challenges) - -## Intended follow on - -Publish script to the classroom. - diff --git a/olddocs/js/lessons/meteorite.md b/olddocs/js/lessons/meteorite.md deleted file mode 100644 index 41d66616..00000000 --- a/olddocs/js/lessons/meteorite.md +++ /dev/null @@ -1,99 +0,0 @@ -# meteorite lesson - -a game in which you must dodge the meteorites with your ship. - -## Topic - -Functions - -## Quick Links - -* [tutorial](/lessons/meteorite/tutorial) -* [quiz](/lessons/meteorite/quiz) -* [quiz answers](/lessons/meteorite/quiz-answers) - -## Class - -Year 7 - -## Prior learning/place of lesson in scheme of work - -Learn how to create **functions**, `function()` that perform a specific task and returns a result. We will be learning how to create a meteorite game using functions, forever loop, global variables, for loop, input on button pressed, if statements, math random, input on shake as well as simple commands, such as show string, show number, and pause. - -## Documentation - -* **function** : [read more...](/js/function) -* **call** : [read more...](/js/call) -* **global variable** : [read more...](/js/data) -* **arithmetic operators** : [read more...](/reference/types/number) -* **math random** : [read more...](/js/math) -* **forever** : [read more...](/reference/basic/forever) -* **for** : [read more...](/reference/loops/for) -* **fade out** : [read more...](/reference/led/fade-out) -* **fade in** : [read more...](/reference/led/fade-in) -* **on button pressed** : [read more...](/reference/input/on-button-pressed) -* **if** : [read more...](/reference/logic/if) -* **show string** : [read more...](/reference/basic/show-string) -* **show number** : [read more...](/reference/basic/show-number) -* **show string** : [read more...](/reference/basic/show-string) -* **plot** : [read more...](/reference/led/plot) -* **plot all** : [read more...](/reference/led/plot-all) -* **pause** : [read more...](/reference/basic/pause) - -## Objectives - -* learn how to create a function as a unit of code that performs a specific task and returns a result -* learn how to call an existing function in your script -* learn how to create a global variable as a place where you can store data so that you can use it later in your code, accessible across functions and in nested code blocks -* learn how arithmetic operators operate on numbers and return a number -* learn how to return a random number -* learn how to repeat code in the background forever -* learn how to gradually decrease the LED screen brightness until the LED lights are turned off -* learn how to gradually increase the LED screen brightness until the LED lights are turned on -* learn how to conditionally run code depending on whether a condition is true or not -* learn how to run code when an input button is pressed -* learn how to show a number on the @boardname@'s LED screen -* learn how to show a string on the @boardname@'s LED screen -* learn how to turn on a LED light on the LED screen. Learn how to specify which LED using x, y coordinates -* learn how to turn on all the 25 LEDs on the LED screen -* learn how to pause your code for the specified number of milliseconds - -## Progression Pathways / Computational Thinking Framework - -#### Algorithms - -* Designs solutions (algorithms) that use repetition and two-way selection, ie if, then and else.(AL) -* Uses diagrams to express solutions.(AB) -* Uses logical reasoning to predict outputs, showing an awareness of inputs (AL) -* Represents solutions using a structured notation (AL) (AB) - -#### Programming & Development - -* Creates programs that implement algorithms to achieve given goals (AL) -* Declares and assigns variables(AB) -* Uses post-tested loop e.g.‘until’,and a sequence of selection statements in programs,including an if,then and else statement(AL) -* Understands the difference between, and appropriately uses if and if, then and else statements(AL) -* Uses a variable and relational operators within a loop to govern termination (AL) (GE) -* Uses a range of operators and expressions e.g. Boolean, and applies them in the context of program control. (AL) -* Selects the appropriate data types(AL) (AB - -#### Data & Data Representation - -* Defines data types: real numbers and Boolean (AB) - -Computational Thinking Concept: AB = Abstraction; DE = Decomposition; AL = Algorithmic Thinking; EV = Evaluation; GE = Generalisation - -## Activity - -* time: 20 min. -* [tutorial](/lessons/meteorite/tutorial) - -## Extended Activity - -* time: 20 min. -* [quiz](/lessons/meteorite/quiz) - -## Homework - -* Extended Activity: [quiz](/lessons/meteorite/quiz) - diff --git a/olddocs/js/lessons/meteorite/quiz-answers.md b/olddocs/js/lessons/meteorite/quiz-answers.md deleted file mode 100644 index 944b5a46..00000000 --- a/olddocs/js/lessons/meteorite/quiz-answers.md +++ /dev/null @@ -1,88 +0,0 @@ -# meteorite quiz answers - -create the game meteorite. - -## Name - -## Directions - -This is the answer key for the [meteorite quiz](/lessons/meteorite/quiz) - -## 1. Write the code that sets up the position variables of meteorite 1. (Hint: look inside the function "initialize game".) - -
- -``` -meteorite_1X = Math.random(5) -meteorite_1Y = -4 -``` - -## 2. Write the code that plots the initial position of the ship. (Hint: look inside the function "initialize game".) - -
- -``` -led.plot(shipLeftX, 4) -led.plot(shipLeftX + 1, 4) -``` - -## 3. Write the code that will detect if a meteorite 1 collided with the ship. (Hint: look inside the function "move meteorite 1". - -
- -``` -if (meteorite_1X == 4 && (shipLeftX == meteorite_1X || shipLeftX + 1 == meteorite_1X)) { - gameOver() -} -``` - -## 4. Write the code that increase the difficulty by making the game run faster. - -
- -``` -pauseDifficulty = (pauseDifficulty * 49) / 50 -``` - -## 5. Write the code that moves the ship left. - -
- -``` -led.unplot(shipLeftX + 1, 4) -shipLeftX = shipLeftX - 1 -led.plot(shipLeftX, 4) -``` - -## 6. Write the code that moves the ship right. - -
- -``` -led.unplot(shipLeftX, 4) -shipLeftX = shipLeftX + 1 -led.plot(shipLeftX + 1, 4) -``` - -## 7. Write the function that checks if moving the ship resulted in a collision with meteorite 1. - -
- -``` -if (shipLeftX == meteorite_1X && meteorite_1Y == 4) { - gameOver() -} -``` - -## 8. Write the code that flashes all the LEDs thee times to create the effect of a crash. (Hint: look at the function "game over".) - -
- -``` -led.plotAll() -for (let i = 0; i < 3; i++) { - led.fadeIn(400) - led.fadeOut(400) -} -``` - diff --git a/olddocs/js/lessons/meteorite/quiz.md b/olddocs/js/lessons/meteorite/quiz.md deleted file mode 100644 index 4b4f5a6e..00000000 --- a/olddocs/js/lessons/meteorite/quiz.md +++ /dev/null @@ -1,44 +0,0 @@ -# meteorite quiz - -create the game meteorite. - -## Name - -## Directions - -Use this activity document to guide your work in the [meteorite tutorial](/lessons/meteorite/tutorial) - -Answer the questions while completing the tutorial. Pay attention to the dialogues! - -## 1. Write the code that sets up the position variables of meteorite 1. (Hint: look inside the function "initialize game".) - -
- -## 2. Write the code that plots the initial position of the ship. (Hint: look inside the function "initialize game".) - -
- -## 3. Write the code that will detect if a meteorite 1 collided with the ship. (Hint: look inside the function "move meteorite 1". - -
- -## 4. Write the code that increase the difficulty by making the game run faster. - -
- -## 5. Write the code that moves the ship left. - -
- -## 6. Write the code that moves the ship right. - -
- -## 7. Write the function that checks if moving the ship resulted in a collision with meteorite 1. - -
- -## 8. Write the code that flashes all the LEDs thee times to create the effect of a crash. (Hint: look at the function "game over".) - -
- diff --git a/olddocs/js/lessons/minesweeper.md b/olddocs/js/lessons/minesweeper.md deleted file mode 100644 index 22df7175..00000000 --- a/olddocs/js/lessons/minesweeper.md +++ /dev/null @@ -1,110 +0,0 @@ -# minesweeper lesson - -A game that tests your memory for placing a LED mine then finding the hidden LED mine. - -## Topic - -Global Variables - -## Quick Links - -* [tutorial](/lessons/minesweeper/tutorial) -* [quiz](/lessons/minesweeper/quiz) -* [quiz answers](/lessons/minesweeper/quiz-answers) - -## Class - -Year 7 - -## Prior learning/place of lesson in scheme of work - -Learn how to create a minesweeper game with **plot**, `led->plot` , **unplot**, `led->unplot`, **global variables** to keep track of the coordinates that the player is selecting. We will be learning how to create a minesweeper game using global variables, if (conditionals), input on button pressed, math random as well as simple commands such as led plot, led unplot, show string, and pause. - -## What the teacher needs to know - -* Algorithm: An unambiguous set of rules or a precise step-bystep guide to solve a problem or achieve a particular objective. -* Command: An instruction for the computer to execute, written in a particular programming language. -* Data: A structured set of numbers, possibly representing digitised text, images, sound or video, which can be processed or transmitted by a computer, also used for numerical (quantitative) information. -* Decomposing: The process through which problems or systems are broken down into their component parts, each of which may then be considered separately. -* Input: Data provided to a computer system, such as via a keyboard, mouse, microphone, camera or physical sensors. -* Output: The information produced by a computer system for its user, typically on a screen, through speakers or on a printer, but possibly through the control of motors in physical systems. -* Programmable toys: Robots designed for children to use, accepting input, storing short sequences of simple instructions and moving according to this stored program. -* Program: A stored set of instructions encoded in a language understood by the computer that does some form of computation, processing input and/or stored data to generate output. -* Selection: A programming construct in which one section of code or another is executed depending on whether a particular condition is met. -* Sequence: To place program instructions in order, with each executed one after the other. -* Simulation: Using a computer to model the state and behaviour of real-world (or imaginary) systems, including physical or social systems; an integral part of most computer games. -* Variables: A way in which computer programs can store, retrieve or change data, such as a score, the time left, or the user’s name. - -**QuickStart Computing Glossary - -## Documentation - -* **global variables** : [read more...](/js/data) -* **math random number** : [read more...](/js/math) -* **plot** : [read more...](/reference/led/plot) -* **unplot** : [read more...](/reference/led/unplot) -* **on button pressed** : [read more...](/reference/input/on-button-pressed) -* **if** : [read more...](/reference/logic/if) -* **show string** : [read more...](/reference/basic/show-string) -* **pause** : [read more...](/reference/basic/pause) - -## Resources - -* Activity: [tutorial](/lessons/minesweeper/tutorial) -* Activity: [quiz](/lessons/minesweeper/quiz) - -## Objectives - -* learn how to create a global variable as a place where you can store data so that you can use it later in your code, accessible across functions and in nested code blocks -* learn how to return a random number -* learn how to turn on a LED light on the LED screen -* learn how to turn off a LED light on the LED screen -* learn how to run code when an input button is pressed -* learn how to conditionally run code depending on whether a condition is true or not -* learn how to show a string of the LED screen one character at a time (scrolling left to right) -* learn how to pause your code for the specified number of milliseconds - -## Links to the National Curriculum Programmes of Study for Computing - -## Progression Pathways / Computational Thinking Framework - -#### Algorithms - -* Designs solutions (algorithms) that use repetition and two-way selection, ie if, then and else.(AL) -* Uses logical reasoning to predict outputs, showing an awareness of inputs (AL) -* Represents solutions using a structured notation (AL) (AB) - -#### Programming & Development - -* Creates programs that implement algorithms to achieve given goals (AL) -* Declares and assigns variables(AB) -* Understands the difference between, and appropriately uses if and if, then and else statements(AL) -* Uses a range of operators and expressions e.g. Boolean, and applies them in the context of program control. (AL) -* Selects the appropriate data types(AL) (AB - -#### Data & Data Representation - -* Understands the difference between data and information(AB) -* Performs more complex searches for information e.g. using Boolean and relational operators(AL) (GE) (EV) - -#### Hardware & Processing - -* Knows that computers collect data from various input devices, including sensors and application software (AB) - -#### Communication Networks - -* Demonstrates responsible use of technologies and online services, and knows a range of ways to report concerns Understands how search engines rank search results (AL) - -#### Information Technology - -* Collects, organizes, and presents data and information in digital content (AB) -* Uses criteria to evaluate the quality of solutions, can identify improvements making some refinements to the solution, and future solutions (EV) - -Computational Thinking Concept: AB = Abstraction; DE = Decomposition; AL = Algorithmic Thinking; EV = Evaluation; GE = Generalisation - -## Activity - -* time: 20 min. -* [tutorial](/lessons/minesweeper/tutorial) -* [quiz](/lessons/minesweeper/quiz) - diff --git a/olddocs/js/lessons/minesweeper/quiz-answers.md b/olddocs/js/lessons/minesweeper/quiz-answers.md deleted file mode 100644 index b4b01533..00000000 --- a/olddocs/js/lessons/minesweeper/quiz-answers.md +++ /dev/null @@ -1,55 +0,0 @@ -# minesweeper quiz answers - -make a game to test your memory for placing a LED mine then finding the hidden LED mine. - -## Name - -## Directions - -Use this activity document to guide your work in the [minesweeper tutorial](/lessons/minesweeper/tutorial). - -Answer the questions while completing the tutorial. Pay attention to the dialogues! - -## 1. Write the code that randomly generates a number between 0 and 4 and stores that value in a global variable called 'mine x'. - -
- -``` -mineX = Math.random(5) -``` - -## 2. Write the code to plot the point with coordinates of (select x, select y) as shown. Your code should apply the concept of `led->plot ( , )` - -![](/static/mb/lessons/blink-1.png) - -
- -``` -selectX = 0 -selectY = 0 -led.plot(selectX, selectY) -``` - -## 3. Write the code to plot the point with coordinates of (select x, select y) as shown. Your code should apply the concept of `led->plot ( , )` - -![](/static/mb/lessons/blink-0.png) - -
- -``` -selectX = 2 -selectY = 2 -led.plot(selectX, selectY) -``` - -## 4. How do you check if a dot is one away from given x and y coordinates? - -
- -
- -``` -if (mineX + 2 > selectX && selectX > mineX - 2 && mineY + 2 > selectY && selectY > mineY - 2) { -} -``` - diff --git a/olddocs/js/lessons/minesweeper/quiz.md b/olddocs/js/lessons/minesweeper/quiz.md deleted file mode 100644 index e8dc0476..00000000 --- a/olddocs/js/lessons/minesweeper/quiz.md +++ /dev/null @@ -1,34 +0,0 @@ -# minesweeper quiz - -make a game to test your memory for placing a LED mine then finding the hidden LED mine. - -## Name - -## Directions - -Use this activity document to guide your work in the [minesweeper tutorial](/lessons/minesweeper/tutorial). - -Answer the questions while completing the tutorial. Pay attention to the dialogues! - -## 1. Write the code that randomly generates a number between 0 and 4 and stores that value in a global variable called 'mine x'. - -
- -## 2. Write the code to plot the point with coordinates of (select x, select y) as shown. Your code should apply the concept of `led->plot ( , )` - -![](/static/mb/lessons/blink-1.png) - -
- -## 3. Write the code to plot the point with coordinates of (select x, select y) as shown. Your code should apply the concept of `led->plot ( , )` - -![](/static/mb/lessons/blink-0.png) - -
- -## 4. How do you check if a dot is one away from given x and y coordinates? - -
- -
- diff --git a/olddocs/js/lessons/number-psych/quiz-answers.md b/olddocs/js/lessons/number-psych/quiz-answers.md deleted file mode 100644 index eb676a55..00000000 --- a/olddocs/js/lessons/number-psych/quiz-answers.md +++ /dev/null @@ -1,207 +0,0 @@ -# number psych quiz answers - -a 4-player game in which each player must outwit his opponents. - -## Name - -## Directions - -Use this activity document to guide your work in the [number psych console tutorial](/lessons/number-psych-console/tutorial) and the [number psych controller tutorial](/lessons/number-psych-controller/tutorial). - -Answer the questions while completing the tutorial. Pay attention to the dialogues! - -**Questions 1-9 are concerned with 'number pysch console tutorial'** - -## 1. Create a 'collection of options' and save them in a local variable named 'options'. - -
- -``` -let options = ([]) -``` - -## 2. Add the options '1', '3', and '5' into the local variable 'options'. - -
- -``` -options.push(1) -options.push(3) -options.push(5) -``` - -## 3. Create a collection of scores and add four values of '0' into the collection. - -
- -``` -let scores = ([]) -``` - -## 4. Write the code that reads a byte that indicates a controller is asking for a player number. (Don't bother checking if the byte received is 255.) Next, write the code that transfers the player number to the controller. - -
- -``` -scores = ([]) -for (let i2 = 0; i2 < 4; i2++) { - scores.push(0) -} -``` - -## 5.Write the code that transfers the three options. - -
- -``` -for (let i5 = 0; i5 < 3; i5++) { - micro_bitTransfer.transferByte(options[i5]) - basic.pause(200) -} -``` - -## 6.Write the code that requests each player to send their choice in the player order number. Don't worry about reading their choice. (Hint: look at the four loop with 'k' as the index.) - -
- -``` -for (let k = 0; k < 4; k++) { - micro_bitTransfer.transferByte(101 + k) -} -``` - -## 7.Write the code to create two collections. One collection ("choices") stores all the choices, while the other collection ("has common") stores whether or not the choice is unique. (If the choice is not unique, then "has common" will be set to true for that particular choice.) - -
- -``` -let choices = ([]) -let hasCommon = ([]) -``` - -## 8. Write the code that compares each of the choices with each other. If the two choices are the same, then set the appropriate value inside 'has common' to true. (Hint: look at the for loops with 'l' and 'n' as their indexes.) - -
- -``` -for (let l = 0; l < 4; l++) { - for (let n = 0; n < 4; n++) { - // ### ~avatar avatar - // If the choice at `l` and `n` are the same, assuming `l` isn't equal to `n`, then there is a match. - // {stcode} - // MACRO: stcode - // ### ~ - if (choices[l] == choices[n] && ! (l == n)) { - // ### ~avatar avatar - // Set `has common` at `l` and `n` to true. - // {stcode} - // MACRO: stcode - // ### ~ - hasCommon[l] = true - hasCommon[n] = true - } - } -} -``` - -## 9. For each value inside 'has common', transfer a '1' if there is a match and transfer a '0' if there isn't a match. Add a pause of 100 milliseconds at the beginning of each transfer.) - -
- -``` -for (let i4 = 0; i4 < 4; i4++) { - basic.pause(100) - if (hasCommon[i4]) { - micro_bitTransfer.transferBit(1) - } else { - micro_bitTransfer.transferBit(0) - } -} -``` - -**Questions 10-14 are concerned with 'number pysch controller tutorial'** - -## 10. Write the code that asks for a player number if button 'A' is pressed on the BBC controller @boardname@. - -
- -``` -input.onButtonPressed(Button.A, () => { - if (gameMode == 0 && playerNumber == 0) { - micro_bitTransfer.transferByte(255) - } -}) -``` - -## 11. Write the code that adds the three transferred options to the "options" collection. (Hint: look at the for loop with 'k' as the index.) - -
- -``` -for (let k1 = 0; k1 < 3; k1++) { - options.push(micro_bitTransfer.readByte()) -} -``` - -## 12. Write the code that detects when button 'B' is pressed. Inside this condition, if 'game mode' is 2, set 'game mode' back to 1 and plot a waiting image. - -
- -``` -input.onButtonPressed(Button.B, () => { - if (gameMode == 2) { - gameMode = 1 - basic.plotImage(` -. . . . . -. . . . . -. # # # . -. . . . . -. . . . . -`) - } -}) -``` - -## 13. Create a while loop that first reads which controller the console @boardname@ is requesting data from. Plot a waiting image, and then write an IF statement to check if the request corresponds to the controller. (Don't worry about writing anything inside the if statement). - -
- -``` -while (true) { - let playerRequest = micro_bitTransfer.readByte() - basic.plotImage(` -. . . . . -. . . . . -. # # # . -. . . . . -. . . . . -`) - if (playerRequest == 100 + playerNumber) { - } -} -``` - -## 14. Write the code that displays an "X" on the @boardname@ if 'result' is 1. Otherwise, display a "check mark". - -
- -``` -if (result == 1) { - basic.plotImage(` -# . . . # -. # . # . -. . # . . -. # . # . -# . . . # -`) -} else { - basic.plotImage(` -. . . . . -. . . . # -. . . # . -# . # . . -. # . . . -`) -} -``` - diff --git a/olddocs/js/lessons/number-psych/quiz.md b/olddocs/js/lessons/number-psych/quiz.md deleted file mode 100644 index 4bf034be..00000000 --- a/olddocs/js/lessons/number-psych/quiz.md +++ /dev/null @@ -1,116 +0,0 @@ -# number psych quiz - -a 4-player game in which each player must outwit his opponents. - -## Name - -## Directions - -Use this activity document to guide your work in the [number psych console tutorial](/lessons/number-psych-console/tutorial) and the [number psych controller tutorial](/lessons/number-psych-controller/tutorial). - -Answer the questions while completing the tutorial. Pay attention to the dialogues! - -**Questions 1-9 are concerned with 'number pysch console tutorial'** - -## 1. Create a 'collection of options' and save them in a local variable named 'options'. - -
- -## 2. Add the options '1', '3', and '5' into the local variable 'options'. - -
- -
- -## 3. Create a collection of scores and add four values of '0' into the collection. - -
- -
- -## 4. Write the code that reads a byte that indicates a controller is asking for a player number. (Don't bother checking if the byte received is 255.) Next, write the code that transfers the player number to the controller. - -
- -
- -
- -## 5.Write the code that transfers the three options. - -
- -
- -## 6.Write the code that requests each player to send their choice in the player order number. Don't worry about reading their choice. (Hint: look at the four loop with 'k' as the index.) - -
- -
- -
- -## 7.Write the code to create two collections. One collection ("choices") stores all the choices, while the other collection ("has common") stores whether or not the choice is unique. (If the choice is not unique, then "has common" will be set to true for that particular choice.) - -
- -
- -## 8. Write the code that compares each of the choices with each other. If the two choices are the same, then set the appropriate value inside 'has common' to true. (Hint: look at the for loops with 'l' and 'n' as their indexes.) - -
- -
- -
- -
- -
- -
- -## 9. For each value inside 'has common', transfer a '1' if there is a match and transfer a '0' if there isn't a match. Add a pause of 100 milliseconds at the beginning of each transfer.) - -
- -
- -
- -**Questions 10-14 are concerned with 'number pysch controller tutorial'** - -## 10. Write the code that asks for a player number if button 'A' is pressed on the BBC controller @boardname@. - -
- -
- -## 11. Write the code that adds the three transferred options to the "options" collection. (Hint: look at the for loop with 'k' as the index.) - -
- -
- -
- -## 12. Write the code that detects when button 'B' is pressed. Inside this condition, if 'game mode' is 2, set 'game mode' back to 1 and plot a waiting image. - -
- -
- -## 13. Create a while loop that first reads which controller the console @boardname@ is requesting data from. Plot a waiting image, and then write an IF statement to check if the request corresponds to the controller. (Don't worry about writing anything inside the if statement). - -
- -
- -
- -## 14. Write the code that displays an "X" on the @boardname@ if 'result' is 1. Otherwise, display a "check mark". - -
- -
- diff --git a/olddocs/js/lessons/on-fall/challenges.md b/olddocs/js/lessons/on-fall/challenges.md deleted file mode 100644 index ea67fb72..00000000 --- a/olddocs/js/lessons/on-fall/challenges.md +++ /dev/null @@ -1,69 +0,0 @@ -# landslide challenges - -The on fall function. - -### Challenge 0 - -Welcome! This [guided tutorial](https://live.microbit.co.uk/td/lessons/on-fall/tutorial) will show you how to detect when the @boardname@ is falling. Your goal is to write a program that detects when the @boardname@ falls! - -``` -input.onFall(() => { - images.createImage(` -. . # . . -. . # . . -. . # . . -. . . . . -. . # . . -`).showImage(0) // *** -}) -``` - -### Challenge 1 - -Add a pause within `input->on fall`. This will allow us to display another image in the next challenge. - -``` -input.onFall(() => { - images.createImage(` -. . # . . -. . # . . -. . # . . -. . . . . -. . # . . -`).showImage(0) - basic.pause(2000) // *** -}) -``` - -### Challenge 2 - -Create and display an `X` after the pause from Challenge 1 - -``` -input.onFall(() => { - images.createImage(` -. . # . . -. . # . . -. . # . . -. . . . . -. . # . . -`).showImage(0) - basic.pause(2000) - images.createImage(` -# . . . # -. # . # . -. . # . . -. # . # . -# . . . # -`).showImage(0) // *** -}) -``` - -### Challenge 3 - -Create a loop so that the @boardname@ alternates between the exclamation point and "X" images when the @boardname@ falls. You will need a `forever` loop and a pause at the end of the loop to do this. - -## See Also - -[on shake](/reference/input/on-gesture) - diff --git a/olddocs/js/lessons/on-logo-up-and-down/challenges.md b/olddocs/js/lessons/on-logo-up-and-down/challenges.md deleted file mode 100644 index f7c0f60b..00000000 --- a/olddocs/js/lessons/on-logo-up-and-down/challenges.md +++ /dev/null @@ -1,67 +0,0 @@ -# on logo up and down challenges - -My script. #docs - -**Challenge 0** - -This [guided tutorial](/zysycw) will help you display an arrow pointing the direction the logo is orientated! - -Let's display and upward pointing arrow when the logo is up! - -``` -input.onLogoUp(() => { - images.createImage(` -. . # . . -. # # # . -# # # # # -. . # . . -. . # . . -`).showImage(0) -}) -``` - -**Challenge 1** - -How about when the logo is down? We should display the arrow pointing downward! - -Let's start by adding a condition for if the logo is down. - -``` -input.onLogoUp(() => { - images.createImage(` -. . # . . -. # # # . -# # # # # -. . # . . -. . # . . -`).showImage(0) -}) -input.onLogoDown(() => { -}) -``` - -**Challenge 2** - -Now we need to display the arrow! - -``` -input.onLogoUp(() => { - images.createImage(` -. . # . . -. # # # . -# # # # # -. . # . . -. . # . . -`).showImage(0) -}) -input.onLogoDown(() => { - images.createImage(` -. . # . . -. . # . . -# # # # # -. # # # . -. . # . . -`).showImage(0) // *** -}) -``` - diff --git a/olddocs/js/lessons/on-shake/challenges.md b/olddocs/js/lessons/on-shake/challenges.md deleted file mode 100644 index 3a31b227..00000000 --- a/olddocs/js/lessons/on-shake/challenges.md +++ /dev/null @@ -1,81 +0,0 @@ -# flipping bird challenges - -These challenges will allow you to create and display a flipping image of a bird when the @boardname@ is shaken. #docs - -### Challenge 0 - -Greetings! This [guided tutorial](/lessons/flipping-bird/tutorial) will begin to show you how to flip a bird. - -``` -counter = 0 -input.onGesture(Gesture.Shake, () => { - counter = counter + 1 - if (math.mod(counter, 2) == 1) { - images.createImage(` -# # . # # -. . # . . -. . . . . -. . . . . -. . . . . -`).showImage(0) - } -}) -``` - -### Challenge 1 - -We handled the case of when `math->mod(counter,2) = 1`. We haven't done anything when the remainder is 0! Add an if statement to handle this case. - -``` -counter = 0 -input.onGesture(Gesture.Shake, () => { - counter = counter + 1 - if (math.mod(counter, 2) == 1) { - images.createImage(` -# # . # # -. . # . . -. . . . . -. . . . . -. . . . . -`).showImage(0) - } - if (math.mod(counter, 2) == 0) { - } -}) -``` - -### Challenge 2 - -Inside of that `if` statement you created in challenge 1, add `image->create image()->show image(0)` and display an upside down flying bird. - -``` -counter = 0 -input.onGesture(Gesture.Shake, () => { - counter = counter + 1 - if (math.mod(counter, 2) == 1) { - images.createImage(` -# # . # # -. . # . . -. . . . . -. . . . . -. . . . . -`).showImage(0) - } - if (math.mod(counter, 2) == 0) { - images.createImage(` -. . . . . -. . . . . -. . . . . -. . # . . -# # . # # -`).showImage(0) // *** - } -}) -``` - -* Run the code to see if it works as expected. - -### Challenge 3 - -Display a check mark and question mark instead of flipping birds. Or better yet, come up with your own pair of opposites to display! - diff --git a/olddocs/js/lessons/pong.md b/olddocs/js/lessons/pong.md deleted file mode 100644 index c201d36e..00000000 --- a/olddocs/js/lessons/pong.md +++ /dev/null @@ -1,133 +0,0 @@ -# pong lesson - -code your own game of Pong on the @boardname@. #. - -## Topic - -Functions - -## Quick Links - -* [tutorial](/lessons/pong/tutorial) -* [quiz](/lessons/pong/quiz) -* [quiz answers](/lessons/pong/quiz-answers) - -## Class - -Year 7 - -## Prior learning/place of lesson in scheme of work - -Learn how to create **functions**, `function()` that perform a specific task and returns a result. We will be learning how to create a pong game using functions, global variable forever loop, global variables, Boolean, for loop, input on button pressed, if statements, as well as simple commands, such as plot, unplot and pause. - -## What the teacher needs to know - -* Algorithm: An unambiguous set of rules or a precise step-bystep guide to solve a problem or achieve a particular objective. -* Command: An instruction for the computer to execute, written in a particular programming language. -* Data: A structured set of numbers, possibly representing digitised text, images, sound or video, which can be processed or transmitted by a computer, also used for numerical (quantitative) information. -* Hardware: The physical systems and components of digital devices; see also software. -* Input: Data provided to a computer system, such as via a keyboard, mouse, microphone, camera or physical sensors. -* Output: The information produced by a computer system for its user, typically on a screen, through speakers or on a printer, but possibly through the control of motors in physical systems. -* Programmable toys: Robots designed for children to use, accepting input, storing short sequences of simple instructions and moving according to this stored program. -* Program: A stored set of instructions encoded in a language understood by the computer that does some form of computation, processing input and/or stored data to generate output. -* Script: A computer program typically executed one line at a time through an interpreter, such as the instructions for a Scratch character. -* Selection: A programming construct in which one section of code or another is executed depending on whether a particular condition is met. -* Sequence: To place program instructions in order, with each executed one after the other. -* Simulation: Using a computer to model the state and behaviour of real-world (or imaginary) systems, including physical or social systems; an integral part of most computer games. -* Variables: A way in which computer programs can store, retrieve or change data, such as a score, the time left, or the user’s name. - -**QuickStart Computing Glossary - -## Documentation - -* **function** : [read more...](/js/function) -* **return** : [read more...](/js/return) -* **call** : [read more...](/js/call) -* **global variable** : [read more...](/js/data) -* **arithmetic operator** : [read more...](/reference/types/number) -* **Boolean** : [/td/Boolean]() -* **forever** : [read more...](/reference/basic/forever) -* **on button pressed** : [read more...](/reference/input/on-button-pressed) -* **if** : [read more...](/reference/logic/if) -* **clear screen** : [read more...](/reference/basic/clear-screen) -* **show string** : [read more...](/reference/basic/show-string) -* **plot** : [read more...](/reference/led/plot) -* **unplot** : [read more...](/reference/led/unplot) -* **pause** : [read more...](/reference/basic/pause) - -## Resources - -* Activity: [tutorial](/lessons/pong/tutorial) -* Activity: [quiz](/lessons/pong/quiz) - -## Objectives - -* learn how to create a function as a unit of code that performs a specific task and returns a result -* learn how a return statement exits a function and returns a value to the code -* learn how to call an existing function in your script -* learn how to create a global variable as a place where you can store data so that you can use it later in your code, accessible across functions and in nested code blocks -* learn how arithmetic operators operate on numbers and return a number -* learn how a Boolean type has one of two possible values: true or false -* learn how to repeat code in the background forever -* learn how to conditionally run code depending on whether a condition is true or not -* learn how to run code when an input button is pressed -* learn how to show a string on the @boardname@'s LED screen -* learn how to turn on a LED light on the LED screen. Learn how to specify which LED using x, y coordinates -* learn how to turn off a LED light on the LED screen. Learn how to specify which LED using x, y coordinates -* learn how to pause your code for the specified number of milliseconds - -## Links to the National Curriculum Programmes of Study for Computing - -## Progression Pathways / Computational Thinking Framework - -#### Algorithms - -* Designs solutions (algorithms) that use repetition and two-way selection, ie if, then and else.(AL) -* Uses diagrams to express solutions.(AB) -* Uses logical reasoning to predict outputs, showing an awareness of inputs (AL) -* Represents solutions using a structured notation (AL) (AB) - -#### Programming & Development - -* Creates programs that implement algorithms to achieve given goals (AL) -* Declares and assigns variables(AB) -* Uses post-tested loop e.g.‘until’,and a sequence of selection statements in programs,including an if,then and else statement(AL) -* Understands the difference between, and appropriately uses if and if, then and else statements(AL) -* Uses a variable and relational operators within a loop to govern termination (AL) (GE) -* Uses a range of operators and expressions e.g. Boolean, and applies them in the context of program control. (AL) -* Selects the appropriate data types(AL) (AB - -#### Data & Data Representation - -* Defines data types: real numbers and Boolean (AB) - -#### Communication Networks - -* Demonstrates responsible use of technologies and online services, and knows a range of ways to report concerns Understands how search engines rank search results (AL) - -#### Information Technology - -* Collects, organizes, and presents data and information in digital content (AB) -* Makes appropriate improvements to solutions based on feedback received, and can comment on the success of the solution (EV) -* Uses criteria to evaluate the quality of solutions, can identify improvements making some refinements to the solution, and future solutions (EV) - -Computational Thinking Concept: AB = Abstraction; DE = Decomposition; AL = Algorithmic Thinking; EV = Evaluation; GE = Generalisation - -## Activity - -* time: 20 min. -* [tutorial](/lessons/pong/tutorial) - -## Extended Activity - -* time: 20 min. -* [quiz](/lessons/pong/quiz) - -## Homework - -* Extended Activity: [quiz](/lessons/pong/quiz) - -## Intended follow on - -Publish script to the classroom. - diff --git a/olddocs/js/lessons/pong/activity.md b/olddocs/js/lessons/pong/activity.md deleted file mode 100644 index 2f459fc6..00000000 --- a/olddocs/js/lessons/pong/activity.md +++ /dev/null @@ -1,63 +0,0 @@ -# pong activity - -Building a game of pong with sprites. - -### ~avatar avatar - -Welcome! This tutorial will teach you how to build a simple pong game using sprites. - -### ~ - -The game works as follow: the user moves a paddle on the left of the screen and a ball bounces on the other side. Let's start by creating the 2 sprites. - -``` -let paddle = game.createSprite(0, 2) -let ball = game.createSprite(4, 2) -``` - -Let's make the ball start with an angle. - -``` -ball.setDirection(-45) -``` - -The user will control the paddle by pressing ``A`` to go up and ``B`` to go down. Let's add ``on button pressed`` event handlers to do that. - -``` -input.onButtonPressed(Button.A, () => { - paddle.changeYBy(-1) -}) -input.onButtonPressed(Button.B, () => { - paddle.changeYBy(1) -}) -``` - -Let's add a ``forever`` loop to start the main game logic. - -``` -basic.forever(() => { - // Leave the sprite on screen for a little while. - basic.pause(400) - // Let's move the ball in whatever direction it is currently going. - ball.move(1) - // The ball might be on the left side of the screen (``x = 0``), let's test for that. - if (ball.x() == 0) { - // Let's add a little pause to let the user know that the ball is on the side. - basic.pause(400) - // If the paddle is not at the same ``y`` coordinate, it missed the ball and we can trigger a game over. If not, we add a point to the score. - if (paddle.y() != ball.y()) { - game.gameOver() - } else { - game.addScore(1) - basic.pause(500) - } - } - // The ball moved and might be on a side, let's make sure it bounces. - ball.ifOnEdge_Bounce() - // If the ball is on the left side, slide it forward to change slightly the bouncing mechanics. - if (ball.x() == 0) { - ball.changeXBy(1) - } -}) -``` - diff --git a/olddocs/js/lessons/pong/quiz-answers.md b/olddocs/js/lessons/pong/quiz-answers.md deleted file mode 100644 index 6fc1fa51..00000000 --- a/olddocs/js/lessons/pong/quiz-answers.md +++ /dev/null @@ -1,87 +0,0 @@ -# pong quiz answers - -create the game Pong. - -## Name - -## Directions - -Use this activity document to guide your work in the [pong tutorial](/lessons/pong/tutorial) - -Answer the questions while completing the tutorial. Pay attention to the dialogues! - -## 1. Create two variables that will keep track of the x-position and y-position of the ball, and assign the variables to their initial values. - -
- -``` -ballX = 2 -ballY = 1 -``` - -## 2. Create two variables that keeps track of the velocity (or the speed and direction) of the ball, and assign the variables to their initial values. - -
- -``` -ballXVelocity = 1 -ballYVelocity = 1 -``` - -## 3. Write the code that plots the initial position of the paddle and the ball. - -
- -``` -led.plot(0, paddleY) -led.plot(ballX, ballY) -``` - -## 4. Write the code that moves the paddle up when Button A is pressed. (Don't worry about setting 'game running' to true.) - -
- -``` -input.onButtonPressed(Button.A, () => { - if (paddleNotUp()) { - led.unplot(0, paddleY) - paddleY = paddleY - 1 - led.plot(0, paddleY) - } -}) -``` - -## 5. Write the code that moves the paddle up when Button B is pressed. (Don't worry about setting 'game running' to true.) - -
- -``` -input.onButtonPressed(Button.A, () => { - if (paddleNotDown()) { - led.unplot(0, paddleY) - paddleY = paddleY + 1 - led.plot(0, paddleY) - } -}) -``` - -## 6. Write the code to update the y-velocity. (Hint: look at the function "update y velocity".) - -
- -``` -if (ballY == 4 || ballY == 0) { - ballYVelocity = (-1) * ballYVelocity -} -``` - -## 7. Write the code to move the ball. (Hint: look at the function "move ball".) - -
- -``` -led.unplot(ballX, ballY) -ballX = ballX + ballXVelocity -ballY = ballY + ballYVelocity -``` - diff --git a/olddocs/js/lessons/pong/quiz.md b/olddocs/js/lessons/pong/quiz.md deleted file mode 100644 index e049ac85..00000000 --- a/olddocs/js/lessons/pong/quiz.md +++ /dev/null @@ -1,40 +0,0 @@ -# pong quiz - -create the game Pong. - -## Name - -## Directions - -Use this activity document to guide your work in the [pong tutorial](/lessons/pong/tutorial) - -Answer the questions while completing the tutorial. Pay attention to the dialogues! - -## 1. Create two variables that will keep track of the x-position and y-position of the ball, and assign the variables to their initial values. - -
- -## 2. Create two variables that keeps track of the velocity (or the speed and direction) of the ball, and assign the variables to their initial values. - -
- -## 3. Write the code that plots the initial position of the paddle and the ball. - -
- -## 4. Write the code that moves the paddle up when Button A is pressed. (Don't worry about setting 'game running' to true.) - -
- -## 5. Write the code that moves the paddle up when Button B is pressed. (Don't worry about setting 'game running' to true.) - -
- -## 6. Write the code to update the y-velocity. (Hint: look at the function "update y velocity".) - -
- -## 7. Write the code to move the ball. (Hint: look at the function "move ball".) - -
- diff --git a/olddocs/js/lessons/rectangle-explosion/challenges.md b/olddocs/js/lessons/rectangle-explosion/challenges.md deleted file mode 100644 index d5f73b1d..00000000 --- a/olddocs/js/lessons/rectangle-explosion/challenges.md +++ /dev/null @@ -1,77 +0,0 @@ -# snowflake fall challenges - -These challenges will allow you to make an exploding rectangle. #docs - -**Challenge 0** - -This [guided tutorial](https://test.microbit.co.uk/td/lessons/rectangle-explosion/tutorial) will help you create a snowflake animation! - -``` -basic.forever(() => { - basic.showAnimation(` -. . . . . -. . # . . -. # # # . -. . # . . -. . . . . -`, 400) -}) -``` - -**Challenge 1** - -Let's begin creating our falling effect by adding another snowflake with `show animation` that displays a different snowflake pattern after the first one. - -``` -basic.forever(() => { - basic.showAnimation(` -. . . . . -. . # . . -. # # # . -. . # . . -. . . . . -`, 400) - basic.showAnimation(` -. . . . . . . # . . -. . # . . . # . # . -. # # # . # . . . # -. . # . . . # . # . -. . . . . . . # . . -`, 400) // *** -}) -``` - -**Challenge 2** - -To finalize our snowflake fall, let's add a different snowflake pattern. - -``` -basic.forever(() => { - basic.showAnimation(` -. . . . . -. . # . . -. # # # . -. . # . . -. . . . . -`, 400) - basic.showAnimation(` -. . . . . . . # . . -. . # . . . # . # . -. # # # . # . . . # -. . # . . . # . # . -. . . . . . . # . . -`, 400) - basic.showAnimation(` -. . . . . . . # . . . # . # . -. . # . . . # . # . # # . # # -. # # # . # . . . # . . . . . -. . # . . . # . # . # # . # # -. . . . . . . # . . . # . # . -`, 400) // *** -}) -``` - -**Challenge 3** - -If you notice, we have three `basic->show animation()` functions. Try to create the snowflake fall effect by just using one `basic->show animation()`. - diff --git a/olddocs/js/lessons/return/challenges.md b/olddocs/js/lessons/return/challenges.md deleted file mode 100644 index efcfe8eb..00000000 --- a/olddocs/js/lessons/return/challenges.md +++ /dev/null @@ -1,46 +0,0 @@ -# return challenges - -This script will teach you how to create a function and use an output parameter. #docs - -### Challenge 0 - -Welcome! This [guided tutorial](/lessons/return/tutorial) will help you code the following script! - -``` -let original1 = 5 -input.onButtonPressed(Button.A, () => { - let doubled = doubleIt_(5) - basic.showNumber(doubled, 150) // *** -}) -``` - -### Challenge 1 - -Create a new function called `square` that returns squares the number passed into the function. (Squaring means that you multiply the number by itself.) - -``` -export function squareIt(n: number) : number { - let num: number - return n * n - return num -} -``` - -### Challenge 2 - -Add a condition to know when button `B` is pressed. We will use this condition in the last challenge. - -``` -let original = 5 -input.onButtonPressed(Button.A, () => { - let one = doubleIt_(original) - basic.showNumber(one, 150) -}) -input.onButtonPressed(Button.B, () => { -}) -``` - -### Challenge 3 - -When the `B` button is pressed, display the square of the original value. Use the function `square it`. You should get the value 25. - diff --git a/olddocs/js/lessons/rock-paper-scissors-book-version/challenges.md b/olddocs/js/lessons/rock-paper-scissors-book-version/challenges.md deleted file mode 100644 index 209bc049..00000000 --- a/olddocs/js/lessons/rock-paper-scissors-book-version/challenges.md +++ /dev/null @@ -1,235 +0,0 @@ -# rock paper scissors book version - -My script. #docs - -Welcome! This guide will show you how to complete the challenges for the game of rock, paper, scissors! - -## Challenge 1 - -### Step 16 - -Awesome! You have just created your game of rock paper scissors. However, why don't we add a little more to it? We can keep track of your score against the @boardname@ using global variables. Create a global variable to keep track of the wins against the @boardname@. To do so, click on `add new`, then `Data`, and then `Number`. - -``` -var wins: number = 0 -``` - -### Step 17 - -At the beginning of the game, you don't have any wins against the @boardname@. As a result, let's set the `data->wins` variable to 0 at the top of your main function. - -``` -wins = 0 // *** -input.onGesture(Gesture.Shake, () => { - let img = images.createImage(` -. . . . . # # # # # . . . . # -. # # # . # . . . # # # . # . -. # # # . # . . . # . # # . . -. # # # . # . . . # # # . # . -. . . . . # # # # # . . . . # -`) - let offset = 5 * Math.random(3) - img.showImage(offset) -}) -``` - -### Step 18 - -Now let's keep track of wins by using button `A`. Every time button `A` is pressed, we want to increment `data->wins` by 1. We can begin by adding a condition `input->on button pressed("A")`. - -``` -wins = 0 -input.onGesture(Gesture.Shake, () => { - let img1 = images.createImage(` -. . . . . # # # # # . . . . # -. # # # . # . . . # # # . # . -. # # # . # . . . # . # # . . -. # # # . # . . . # # # . # . -. . . . . # # # # # . . . . # -`) - let offset1 = 5 * Math.random(3) - img1.showImage(offset1) -}) -input.onButtonPressed(Button.A, () => { -}) // *** -``` - -### Step 19 - -Nice! Now that we added the condition for when button `A` is pressed, we can increment `data->wins` by 1. Add the following statement in the condition. - -``` -wins = 0 -input.onGesture(Gesture.Shake, () => { - let img2 = images.createImage(` -. . . . . # # # # # . . . . # -. # # # . # . . . # # # . # . -. # # # . # . . . # . # # . . -. # # # . # . . . # # # . # . -. . . . . # # # # # . . . . # -`) - let offset2 = 5 * Math.random(3) - img2.showImage(offset2) -}) -input.onButtonPressed(Button.A, () => { - wins = wins + 1 // *** -}) -``` - -### Step 20 - -You have tracked the number of wins you have against the @boardname@. However, how will you ever know how many wins you have? After we increment `data->wins`, let's display the total number of wins you have. - -``` -wins = 0 -input.onGesture(Gesture.Shake, () => { - let img3 = images.createImage(` -. . . . . # # # # # . . . . # -. # # # . # . . . # # # . # . -. # # # . # . . . # . # # . . -. # # # . # . . . # # # . # . -. . . . . # # # # # . . . . # -`) - let offset3 = 5 * Math.random(3) - img3.showImage(offset3) -}) -input.onButtonPressed(Button.A, () => { - wins = wins + 1 - basic.showString("WINS:", 150) // *** - basic.showNumber(wins, 150) // *** -}) -``` - -* Tap `run` to run the program on the simulator. Notice the number of wins you have against the @boardname@. - -## Challenge 2 - -### Step 21 - -You have managed to keep score of the number of wins you have against the @boardname@. However, what about losses? Let's begin by creating another global variable to keep track of losses. - -``` -var losses: number = 0 -``` - -### Step 22 - -Add a condition for when button `B` is pressed. When this occurs, we will increment your losses against the @boardname@ by 1. Let's hope that this button will not be pressed too often! - -``` -wins = 0 -input.onGesture(Gesture.Shake, () => { - let img4 = images.createImage(` -. . . . . # # # # # . . . . # -. # # # . # . . . # # # . # . -. # # # . # . . . # . # # . . -. # # # . # . . . # # # . # . -. . . . . # # # # # . . . . # -`) - let offset4 = 5 * Math.random(3) - img4.showImage(offset4) -}) -input.onButtonPressed(Button.A, () => { - wins = wins + 1 - basic.showString("WINS:", 150) - basic.showNumber(wins, 150) -}) -input.onButtonPressed(Button.B, () => { -}) // *** -``` - -### Step 23 - -Now let's continue where we left off. Just as we did for `data->wins` when button `A` is pressed, we need to increment `losses` by 1 when button `B` is pressed. - -``` -wins = 0 -input.onGesture(Gesture.Shake, () => { - let img5 = images.createImage(` -. . . . . # # # # # . . . . # -. # # # . # . . . # # # . # . -. # # # . # . . . # . # # . . -. # # # . # . . . # # # . # . -. . . . . # # # # # . . . . # -`) - let offset5 = 5 * Math.random(3) - img5.showImage(offset5) -}) -input.onButtonPressed(Button.A, () => { - wins = wins + 1 - basic.showString("WINS:", 150) - basic.showNumber(wins, 150) -}) -input.onButtonPressed(Button.B, () => { - losses = losses + 1 // *** -}) -``` - -### Step 24 - -Let's also display the score when button `B` is pressed, just as we have done for button `A`. This will help us keep track of the number of wins and losses you have against the @boardname@. - -``` -wins = 0 -input.onGesture(Gesture.Shake, () => { - let img6 = images.createImage(` -. . . . . # # # # # . . . . # -. # # # . # . . . # # # . # . -. # # # . # . . . # . # # . . -. # # # . # . . . # # # . # . -. . . . . # # # # # . . . . # -`) - let offset6 = 5 * Math.random(3) - img6.showImage(offset6) -}) -input.onButtonPressed(Button.A, () => { - wins = wins + 1 - basic.showString("WINS:", 150) - basic.showNumber(wins, 150) -}) -input.onButtonPressed(Button.B, () => { - losses = losses + 1 - basic.showString("WINS", 150) // *** - basic.showNumber(wins, 150) // *** - basic.showString("LOSSES:", 150) // *** - basic.showNumber(losses, 150) // *** -}) -``` - -### Step 25 - -You have managed to keep track of both the wins and losses you have against the @boardname@! But did you notice that you haven't updated something? Take a look at condition of `input->on button pressed("A")`. - -``` -wins = 0 -input.onGesture(Gesture.Shake, () => { - let img7 = images.createImage(` -. . . . . # # # # # . . . . # -. # # # . # . . . # # # . # . -. # # # . # . . . # . # # . . -. # # # . # . . . # # # . # . -. . . . . # # # # # . . . . # -`) - let offset7 = 5 * Math.random(3) - img7.showImage(offset7) -}) -input.onButtonPressed(Button.A, () => { - wins = wins + 1 - basic.showString("WINS:", 150) - basic.showNumber(wins, 150) - basic.showString("LOSSES:", 150) // *** - basic.showNumber(losses, 150) // *** -}) -input.onButtonPressed(Button.B, () => { - losses = losses + 1 - basic.showString("WINS", 150) - basic.showNumber(wins, 150) - basic.showString("LOSSES:", 150) - basic.showNumber(losses, 150) -}) -``` - -* Tap the `run` button to run your game on the simulator. See if you can get more wins than the @boardname@ can! - -Congratulations! You have successfully created a fully functional game of rock, paper, scissors against the @boardname@. Challenge your friends to see who can get a better score against the @boardname@. - diff --git a/olddocs/js/lessons/rock-paper-scissors-teacher-guide/challenges.md b/olddocs/js/lessons/rock-paper-scissors-teacher-guide/challenges.md deleted file mode 100644 index 1b23ef56..00000000 --- a/olddocs/js/lessons/rock-paper-scissors-teacher-guide/challenges.md +++ /dev/null @@ -1,235 +0,0 @@ -# rock paper scissors teacher guide - -My script. #docs - -Welcome! This guide will show you how to complete the challenges for the game of rock, paper, scissors! - -## Challenge 1 - -### Step 16 - -Awesome! You have just created your game of rock paper scissors. However, why don't we add a little more to it? We can keep track of your score against the @boardname@ using global variables. Create a global variable to keep track of the wins against the @boardname@. To do so, click on `add new`, then `Data`, and then `Number`. - -``` -var wins: number = 0 -``` - -### Step 17 - -At the beginning of the game, you don't have any wins against the @boardname@. As a result, let's set the `data->wins` variable to 0 at the top of your main function. - -``` -wins = 0 // *** -input.onGesture(Gesture.Shake, () => { - let img = images.createImage(` -. . . . . # # # # # . . . . # -. # # # . # . . . # # # . # . -. # # # . # . . . # . # # . . -. # # # . # . . . # # # . # . -. . . . . # # # # # . . . . # -`) - let offset = 5 * Math.random(3) - img.showImage(offset) -}) -``` - -### Step 18 - -Now let's keep track of wins by using button `A`. Every time button `A` is pressed, we want to increment `data->wins` by 1. We can begin by adding a condition `input->on button pressed("A")`. - -``` -wins = 0 -input.onGesture(Gesture.Shake, () => { - let img1 = images.createImage(` -. . . . . # # # # # . . . . # -. # # # . # . . . # # # . # . -. # # # . # . . . # . # # . . -. # # # . # . . . # # # . # . -. . . . . # # # # # . . . . # -`) - let offset1 = 5 * Math.random(3) - img1.showImage(offset1) -}) -input.onButtonPressed(Button.A, () => { -}) // *** -``` - -### Step 19 - -Nice! Now that we added the condition for when button `A` is pressed, we can increment `data->wins` by 1. Add the following statement in the condition. - -``` -wins = 0 -input.onGesture(Gesture.Shake, () => { - let img2 = images.createImage(` -. . . . . # # # # # . . . . # -. # # # . # . . . # # # . # . -. # # # . # . . . # . # # . . -. # # # . # . . . # # # . # . -. . . . . # # # # # . . . . # -`) - let offset2 = 5 * Math.random(3) - img2.showImage(offset2) -}) -input.onButtonPressed(Button.A, () => { - wins = wins + 1 // *** -}) -``` - -### Step 20 - -You have tracked the number of wins you have against the @boardname@. However, how will you ever know how many wins you have? After we increment `data->wins`, let's display the total number of wins you have. - -``` -wins = 0 -input.onGesture(Gesture.Shake, () => { - let img3 = images.createImage(` -. . . . . # # # # # . . . . # -. # # # . # . . . # # # . # . -. # # # . # . . . # . # # . . -. # # # . # . . . # # # . # . -. . . . . # # # # # . . . . # -`) - let offset3 = 5 * Math.random(3) - img3.showImage(offset3) -}) -input.onButtonPressed(Button.A, () => { - wins = wins + 1 - basic.showString("WINS:", 150) // *** - basic.showNumber(wins, 150) // *** -}) -``` - -* Tap `run` to run the program on the simulator. Notice the number of wins you have against the @boardname@. - -## Challenge 2 - -### Step 21 - -You have managed to keep score of the number of wins you have against the @boardname@. However, what about losses? Let's begin by creating another global variable to keep track of losses. - -``` -var losses: number = 0 -``` - -### Step 22 - -Add a condition for when button `B` is pressed. When this occurs, we will increment your losses against the @boardname@ by 1. Let's hope that this button will not be pressed too often! - -``` -wins = 0 -input.onGesture(Gesture.Shake, () => { - let img4 = images.createImage(` -. . . . . # # # # # . . . . # -. # # # . # . . . # # # . # . -. # # # . # . . . # . # # . . -. # # # . # . . . # # # . # . -. . . . . # # # # # . . . . # -`) - let offset4 = 5 * Math.random(3) - img4.showImage(offset4) -}) -input.onButtonPressed(Button.A, () => { - wins = wins + 1 - basic.showString("WINS:", 150) - basic.showNumber(wins, 150) -}) -input.onButtonPressed(Button.B, () => { -}) // *** -``` - -### Step 23 - -Now let's continue where we left off. Just as we did for `data->wins` when button `A` is pressed, we need to increment `losses` by 1 when button `B` is pressed. - -``` -wins = 0 -input.onGesture(Gesture.Shake, () => { - let img5 = images.createImage(` -. . . . . # # # # # . . . . # -. # # # . # . . . # # # . # . -. # # # . # . . . # . # # . . -. # # # . # . . . # # # . # . -. . . . . # # # # # . . . . # -`) - let offset5 = 5 * Math.random(3) - img5.showImage(offset5) -}) -input.onButtonPressed(Button.A, () => { - wins = wins + 1 - basic.showString("WINS:", 150) - basic.showNumber(wins, 150) -}) -input.onButtonPressed(Button.B, () => { - losses = losses + 1 // *** -}) -``` - -### Step 24 - -Let's also display the score when button `B` is pressed, just as we have done for button `A`. This will help us keep track of the number of wins and losses you have against the @boardname@. - -``` -wins = 0 -input.onGesture(Gesture.Shake, () => { - let img6 = images.createImage(` -. . . . . # # # # # . . . . # -. # # # . # . . . # # # . # . -. # # # . # . . . # . # # . . -. # # # . # . . . # # # . # . -. . . . . # # # # # . . . . # -`) - let offset6 = 5 * Math.random(3) - img6.showImage(offset6) -}) -input.onButtonPressed(Button.A, () => { - wins = wins + 1 - basic.showString("WINS:", 150) - basic.showNumber(wins, 150) -}) -input.onButtonPressed(Button.B, () => { - losses = losses + 1 - basic.showString("WINS", 150) // *** - basic.showNumber(wins, 150) // *** - basic.showString("LOSSES:", 150) // *** - basic.showNumber(losses, 150) // *** -}) -``` - -### Step 25 - -You have managed to keep track of both the wins and losses you have against the @boardname@! But did you notice that you haven't updated something? Take a look at condition of `input->on button pressed("A")`. - -``` -wins = 0 -input.onGesture(Gesture.Shake, () => { - let img7 = images.createImage(` -. . . . . # # # # # . . . . # -. # # # . # . . . # # # . # . -. # # # . # . . . # . # # . . -. # # # . # . . . # # # . # . -. . . . . # # # # # . . . . # -`) - let offset7 = 5 * Math.random(3) - img7.showImage(offset7) -}) -input.onButtonPressed(Button.A, () => { - wins = wins + 1 - basic.showString("WINS:", 150) - basic.showNumber(wins, 150) - basic.showString("LOSSES:", 150) // *** - basic.showNumber(losses, 150) // *** -}) -input.onButtonPressed(Button.B, () => { - losses = losses + 1 - basic.showString("WINS", 150) - basic.showNumber(wins, 150) - basic.showString("LOSSES:", 150) - basic.showNumber(losses, 150) -}) -``` - -* Tap the `run` button to run your game on the simulator. See if you can get more wins than the @boardname@ can! - -Congratulations! You have successfully created a fully functional game of rock, paper, scissors against the @boardname@. Challenge your friends to see who can get a better score against the @boardname@. - diff --git a/olddocs/js/lessons/runaway-pacman.md b/olddocs/js/lessons/runaway-pacman.md deleted file mode 100644 index 68884af7..00000000 --- a/olddocs/js/lessons/runaway-pacman.md +++ /dev/null @@ -1,7 +0,0 @@ -# runaway pacman lessons - -make a game to test hand-eye coordination. - -Make a game to test hand-eye coordination - -* [tutorial](/lessons/runaway-pacman/tutorial) diff --git a/olddocs/js/lessons/runaway-pacman/quiz-answers.md b/olddocs/js/lessons/runaway-pacman/quiz-answers.md deleted file mode 100644 index 4c004f22..00000000 --- a/olddocs/js/lessons/runaway-pacman/quiz-answers.md +++ /dev/null @@ -1,117 +0,0 @@ -# runaway pacman quiz answers - -create a game that is inspired by the classic arcade game Pac Man. - -## Name - -## Directions - -Use this activity document to guide your work in the [runaway pacman tutorial](/lessons/runaway-pacman/tutorial) - -Answer the questions while completing the tutorial. Pay attention to the dialogues! - -## 1. Write the the method name created that will set up the game board. - -
- -``` -initializeState() -``` - -## 2. Write the the method name created that will draw the player and the monster(s) - -
- -``` -redraw() -``` - -## 3. Write the code that keeps track of how long a player has been playing. (Don't include any if statements.) - -
- -``` -basic.forever(() => { - levelTime = levelTime + 12 - basic.pause(12) -}) -``` - -## 4. Write the code that will reset the time and continue playing if we have been eaten. - -
- -``` -if ( ! playing) { - levelTime = 0 - playing = true -} -``` - -## 5. Write 'If statement' that will determine if the player has been playing for more than 5 seconds. - -
- -``` -if (levelTime >= 5000) { -} -``` - -## 6. Suspend the game if we are advancing to the next level. (Hint: this requires setting a variable to true.) - -
- -``` -gameSuspended = true -``` - -## 7. Write the code to add a monster. (Hint: look in the function "add monster".) - -
- -``` -let m = new Entity() -monsters.push(m) -totalMonsters = totalMonsters + 1 -``` - -## 8. Write the code that will restart the time to 0 after you begin the next level. - -
- -``` -levelTime = 0 -``` - -## 9. Write the code that makes the player go either North or East when button 'A' is pressed. - -
- -``` -input.onButtonPressed(Button.A, () => { - let temp = math.abs(person.dirX) * (-1) - // {stcode} - // MACRO: stcode - person.dirX = math.abs(person.dirY) * (-1) - // {stcode} - // MACRO: stcode - person.dirY = temp -}) -``` - -## 10. Write the code that makes the player go either South or West when button 'B' is pressed. - -
- -``` -input.onButtonPressed(Button.B, () => { - let temp1 = math.abs(person.dirX) - // {stcode} - // MACRO: stcode - person.dirX = math.abs(person.dirY) - // {stcode} - // MACRO: stcode - person.dirY = temp1 -}) -``` - diff --git a/olddocs/js/lessons/runaway-pacman/quiz.md b/olddocs/js/lessons/runaway-pacman/quiz.md deleted file mode 100644 index 4914634d..00000000 --- a/olddocs/js/lessons/runaway-pacman/quiz.md +++ /dev/null @@ -1,60 +0,0 @@ -# runaway pacman quiz - -create a game that is inspired by the classic arcade game Pac Man. - -## Name - -## Directions - -Use this activity document to guide your work in the [runaway pacman tutorial](/lessons/runaway-pacman/tutorial) - -Answer the questions while completing the tutorial. Pay attention to the dialogues! - -## 1. Write the the method name created that will set up the game board. - -
- -## 2. Write the the method name created that will draw the player and the monster(s) - -
- -## 3. Write the code that keeps track of how long a player has been playing. (Don't include any if statements.) - -
- -## 4. Write the code that will reset the time and continue playing if we have been eaten. - -
- -## 5. Write 'If statement' that will determine if the player has been playing for more than 5 seconds. - -
- -## 6. Suspend the game if we are advancing to the next level. (Hint: this requires setting a variable to true.) - -
- -## 7. Write the code to add a monster. (Hint: look in the function "add monster".) - -
- -## 8. Write the code that will restart the time to 0 after you begin the next level. - -
- -## 9. Write the code that makes the player go either North or East when button 'A' is pressed. - -
- -
- -
- -## 10. Write the code that makes the player go either South or West when button 'B' is pressed. - -
- -
- -
- diff --git a/olddocs/js/lessons/running-time/challenges.md b/olddocs/js/lessons/running-time/challenges.md deleted file mode 100644 index 62fb8280..00000000 --- a/olddocs/js/lessons/running-time/challenges.md +++ /dev/null @@ -1,30 +0,0 @@ -# running time challenges - -My script. #docs - -**Challenge 0** - -Great job! You have successfully completed the [Running Time tutorial](/lessons/running-time/tutorial) . You have a forever loop that declares a variable in it that holds the running time in milliseconds of the @boardname@ and then shows the seconds on the LED screen. - -``` -basic.forever(() => { - let now = input.runningTime() - basic.showNumber(now / 1000, 150) -}) -``` - -**Challenge 1** - -When button A is pressed, reset the time by subtracting the current time from the variable now. - -``` -basic.forever(() => { - let now1 = input.runningTime() - basic.showNumber(now1 / 1000, 150) -}) -if (input.buttonIsPressed("A")) { - let now2 = 0 // *** -} -``` - -* Run the code to see if it works as expected. diff --git a/olddocs/js/lessons/screen-up-and-down/challenges.md b/olddocs/js/lessons/screen-up-and-down/challenges.md deleted file mode 100644 index 06ac19bf..00000000 --- a/olddocs/js/lessons/screen-up-and-down/challenges.md +++ /dev/null @@ -1,64 +0,0 @@ -# screen up and down challenges - -The on screen up function. - -**Challenge 0** - -Congratulations! You have completed the [Screen Up/Down tutorial](/hqjwkb) . You should have an image of a heart created and shown when the screen is moved up. - -``` -input.onScreenUp(() => { - images.createImage(` -# # . # # -# # # # # -# # # # # -. # # # . -. . # . . -`).showImage(0) -}) -``` - -**Challenge 1** - -Now have the @boardname@ do something when the screen is moved downward. You can do this by calling the on screen down method. Do not do anything when you call the on screen down method. - -``` -input.onScreenUp(() => { - images.createImage(` -# # . # # -# # # # # -# # # # # -. # # # . -. . # . . -`).showImage(0) -}) -input.onScreenDown(() => { - -}) -``` - -**Challenge 2** - -When the @boardname@ is moved downward, create and show an image of an upside down heart. - -``` -input.onScreenUp(() => { - images.createImage(` -# # . # # -# # # # # -# # # # # -. # # # . -. . # . . -`).showImage(0) -}) -input.onScreenDown(() => { - images.createImage(` -. . # . . -. # # # . -# # # # # -# # # # # -# # . # # -`).showImage(0) // *** -}) -``` - diff --git a/olddocs/js/lessons/screen-wipe/activity.md b/olddocs/js/lessons/screen-wipe/activity.md deleted file mode 100644 index de3a7a12..00000000 --- a/olddocs/js/lessons/screen-wipe/activity.md +++ /dev/null @@ -1,45 +0,0 @@ -# screen wipe activity - -Clear the screen by pressing buttons on the @boardname@. - -### ~avatar avatar - -This activity will teach how to clear the screen by pressing button ``A`` on the @boardname@. - -### ~ - -You can use the `basic->clear screen` function to turn off all the LED on the screen. Let's illustrate this concept with a small script where the user has to press the button ``A`` to turn off the screen. Let's start by adding the code to show an animation. - -``` -basic.showAnimation(` -# # # # # # # # # # . . . . . . . . . . -# # # # # # # # # # . . . . . . . . . . -. . . . . # # # # # # # # # # . . . . . -. . . . . # # # # # # # # # # # # # # # -. . . . . . . . . . . . . . . # # # # # -`, 400) // *** -``` - -We add another line of code that registers an **event handler** on the `input->on button pressed(A)` and calls `basic->clear screen`. - -``` -basic.showAnimation(` -# # # # # # # # # # . . . . . . . . . . -# # # # # # # # # # . . . . . . . . . . -. . . . . # # # # # # # # # # . . . . . -. . . . . # # # # # # # # # # # # # # # -. . . . . . . . . . . . . . . # # # # # -`, 400) -input.onButtonPressed(Button.A, () => { - basic.clearScreen() // *** -}) // *** -``` - -Run the script in the simulator or on the @boardname@ to see how this works! - -### ~avatar boothing - -Excellent, you're ready to continue with the [challenges](/lessons/screen-wipe/challenges)! - -### ~ - diff --git a/olddocs/js/lessons/screen-wipe/challenges.md b/olddocs/js/lessons/screen-wipe/challenges.md deleted file mode 100644 index 1e7ba2c2..00000000 --- a/olddocs/js/lessons/screen-wipe/challenges.md +++ /dev/null @@ -1,71 +0,0 @@ -# screen wipe challenges - -Coding challenges for the screen wipe tutorial. #docs - -## Before we get started - -Complete the [screen wipe](/lessons/screen-wipe) activity and your code will look like this: - -``` -basic.showAnimation(` -# # # # # # # # # # . . . . . . . . . . -# # # # # # # # # # . . . . . . . . . . -. . . . . # # # # # # # # # # . . . . . -. . . . . # # # # # # # # # # # # # # # -. . . . . . . . . . . . . . . # # # # # -`, 400) -input.onButtonPressed(Button.A, () => { - basic.clearScreen() -}) -``` - -**Challenge 1** - -Create an event handler for Button "B". - -``` -basic.showAnimation(` -# # # # # # # # # # . . . . . . . . . . -# # # # # # # # # # . . . . . . . . . . -. . . . . # # # # # # # # # # . . . . . -. . . . . # # # # # # # # # # # # # # # -. . . . . . . . . . . . . . . # # # # # -`, 400) -input.onButtonPressed(Button.A, () => { - basic.clearScreen() -}) -input.onButtonPressed(Button.B, () => { -}) -``` - -**Challenge 2** - -Replay the animation when the "B" button is pressed by typing in `basic->show animation(..., 400)`. - -``` -basic.showAnimation(` -# # # # # # # # # # . . . . . . . . . . -# # # # # # # # # # . . . . . . . . . . -. . . . . # # # # # # # # # # . . . . . -. . . . . # # # # # # # # # # # # # # # -. . . . . . . . . . . . . . . # # # # # -`, 400) -input.onButtonPressed(Button.A, () => { - basic.clearScreen() -}) -input.onButtonPressed(Button.B, () => { - basic.showAnimation(` -# # # # # # # # # # . . . . . . . . . . -# # # # # # # # # # . . . . . . . . . . -. . . . . # # # # # # # # # # . . . . . -. . . . . # # # # # # # # # # # # # # # -. . . . . . . . . . . . . . . # # # # # -`, 400) // *** -}) -``` - -**Challenge 3** - -Show an animation that scrolls back up when you press button "B". - -* tap the `run` button to view your final product! diff --git a/olddocs/js/lessons/screen-wipe/quiz-answers.md b/olddocs/js/lessons/screen-wipe/quiz-answers.md deleted file mode 100644 index 6c6eb45e..00000000 --- a/olddocs/js/lessons/screen-wipe/quiz-answers.md +++ /dev/null @@ -1,45 +0,0 @@ -# screen wipe quiz answers - -clear the screen by pressing the "A" button after an animation has been played. - -This is the answer key for the [screen wipe quiz](/lessons/screen-wipe/quiz). - -## 1. What does the function "clear screen" do on the @boardname@? - -This function turns off all the LED lights on the LED screen. - -## 2. Write the line of code that creates and displays this animation. - -![](/static/mb/lessons/screen-wipe-0.png) - -
- -``` -basic.showAnimation(` -# # # # . # # # # # . . . . . . . . . . -# # # # # # # # # # . . . . . . . . . . -. . . . . # # # # # # # # # # . . . . . -. . . . . # # # # # # # # # # # # # # # -. . . . . . . . . . . . . . . # # # # # -`, 400) -``` - -## 3. Write the condition that will detect when the @boardname@ is shaken. - -
- -``` -input.onGesture(Gesture.Shake, () => { -}) -``` - -## 4. Write the code that will clear an animation from the screen after shaking the @boardname@. - -
- -``` -input.onGesture(Gesture.Shake, () => { - basic.clearScreen() -}) -``` - diff --git a/olddocs/js/lessons/screen-wipe/quiz.md b/olddocs/js/lessons/screen-wipe/quiz.md deleted file mode 100644 index 7924842c..00000000 --- a/olddocs/js/lessons/screen-wipe/quiz.md +++ /dev/null @@ -1,32 +0,0 @@ -# screen wipe quiz - -clear the screen by pressing the "A" button after an animation has been played. - -## Name - -## Directions - -Use this activity document to guide your work in the [screen wipe tutorial](/lessons/screen-wipe/tutorial) - -Answer the questions while completing the tutorial. Pay attention to the dialogues! - -## 1. What does the function "clear screen" do on the @boardname@? - -
- -## 2. We can show all of these images in one line of code. What method can we use to do this? - -![](/static/mb/lessons/screen-wipe-0.png) - -
- -## 3. How can the @boardname@ detect when it is shaken? - -
- -
- -## 4. Write the code that will clear an animation from the screen after shaking the @boardname@. - -
- diff --git a/olddocs/js/lessons/set-brightness/challenges.md b/olddocs/js/lessons/set-brightness/challenges.md deleted file mode 100644 index ac8af701..00000000 --- a/olddocs/js/lessons/set-brightness/challenges.md +++ /dev/null @@ -1,50 +0,0 @@ -# set brightness challenges - -These challenges will allow you to change the brightness of the @boardname@. docs - -**Challenge 0** - -[This tutorial](/lessons/set-brightness/tutorial) will show you how to set the brightness on the @boardname@. - -``` -led.setBrightness(255) -led.plotAll() -input.onButtonPressed(Button.A, () => { - led.setBrightness(64) -}) -``` - -**Challenge 1** - -What if we want to turn off all the LEDs? Let's do this by setting the brightness to `0` when button `B` is pressed. Add a condition for `input->on button pressed("B")`. - -``` -led.setBrightness(255) -led.plotAll() -input.onButtonPressed(Button.A, () => { - led.setBrightness(64) -}) -input.onButtonPressed(Button.B, () => { -}) // *** -``` - -**Challenge 2** - -Inside of the condition `input->on button pressed("B")`, add `led->set brightness(0)` to turn off the LEDs. - -``` -led.setBrightness(255) -led.plotAll() -input.onButtonPressed(Button.A, () => { - led.setBrightness(64) -}) -input.onButtonPressed(Button.B, () => { - led.setBrightness(0) // *** -}) -``` - -**Challenge 3** - -Now, in the condition `input->on button pressed("B")`, add `basic->pause(1000)` and then set the brightness to a new value! - -* `Run` your script to see the LEDs change brightness. diff --git a/olddocs/js/lessons/show-number/challenges.md b/olddocs/js/lessons/show-number/challenges.md deleted file mode 100644 index ca608ada..00000000 --- a/olddocs/js/lessons/show-number/challenges.md +++ /dev/null @@ -1,39 +0,0 @@ -# show number challenges - -My script. #docs - -### Challenge 0 - -Welcome! This [guided tutorial](/xvogbz) will help you show a number on the LED screen! - -Show a number on the LED screen! One digit will display at a time, scrolling from left to right. - -Make lucky number 7 display on the screen! - -``` -basic.showNumber(7, 150) -``` - -### Challenge 1 - -But we also should pause before showing another number. - -``` -basic.showNumber(7, 150) -basic.pause(500) // *** -``` - -### Challenge 2 - -Let's display the next multiple of 7 on the screen! - -``` -basic.showNumber(7, 150) -basic.pause(500) -basic.showNumber(14, 150) // *** -``` - -### Challenge 3 - -Keep displaying multiples of 7 such as 21 and 28, but don't forget to add pauses between the numbers! - diff --git a/olddocs/js/lessons/show-string/challenges.md b/olddocs/js/lessons/show-string/challenges.md deleted file mode 100644 index 3ebb8c80..00000000 --- a/olddocs/js/lessons/show-string/challenges.md +++ /dev/null @@ -1,38 +0,0 @@ -# show string challenges - -My script. #docs - -**Challenge 0** - -Welcome! This [guided tutorial](/pxjkww) introduces the basic show string method on the @boardname@. - -Let's show the string 'Hello' on the LED screen. The string will scroll one character at a time from left to right. - -``` -basic.showString("Hello ", 150) -``` - -**Challenge 1** - -Now, let's show the string 'World' on the LED screen. - -``` -basic.showString("Hello ", 150) -basic.showString("World", 150) // *** -``` - -**Challenge 2** - -Let's display another string to introduce yourself! - -After 'Hello World' we want to display the string 'My name is '. - -``` -basic.showString("Hello World", 150) -basic.showString("Good Night World ", 150) // *** -``` - -**Challenge 3** - -Add Micro's response to Good Night World! - diff --git a/olddocs/js/lessons/the-hat-game.md b/olddocs/js/lessons/the-hat-game.md deleted file mode 100644 index 2f307eaa..00000000 --- a/olddocs/js/lessons/the-hat-game.md +++ /dev/null @@ -1,71 +0,0 @@ -# the hat game lesson - -make a game to test your focus on the moving ball. - -## Topic - -Functions - -## Quick Links - -* [tutorial](/lessons/the-hat-game/tutorial) -* [quiz](/lessons/the-hat-game/quiz) -* [quiz answers](/lessons/the-hat-game/quiz-answers) -* [challenges](/lessons/the-hat-game/challenges) - -## Class - -Year 7 - -## Prior learning/place of lesson in scheme of work - -Learn how to create **functions**, `function()` as a unit of code that performs a specific task and returns a result. We will be learning how to create the hat game app using functions, global variables, input on button pressed, if (conditionals), mod, random, Boolean, as well as simple commands such as show animation. - -## Documentation - -* **functions** : [read more...](/js/function) -* **on button pressed** : [read more...](/reference/input/on-button-pressed) -* **for** : [read more...](/reference/loops/for) -* **if** : [read more...](/reference/logic/if) -* **mod** : [read more...](/js/math) -* **show animation** : [read more...](/reference/basic/show-animation) - -## Objectives - -* learn how to create a global variable as a place where you can store data so that you can use it later in your code, accessible across functions and in nested code blocks -* learn how to learn how to conditionally run code depending on whether a condition is true or false -* learn how to return the modulus -* learn how to show a series of image frames on the LED screen -* learn how to run code when an input button is pressed - -## Progression Pathways / Computational Thinking Framework - -#### Algorithms - -* Designs solutions (algorithms) that use repetition and two-way selection, ie if, then and else.(AL) -* Uses diagrams to express solutions.(AB) -* Uses logical reasoning to predict outputs, showing an awareness of inputs (AL) -* Represents solutions using a structured notation (AL) (AB) - -#### Programming & Development - -* Creates programs that implement algorithms to achieve given goals (AL) -* Declares and assigns variables(AB) -* Uses post-tested loop e.g.‘until’,and a sequence of selection statements in programs,including an if,then and else statement(AL) -* Understands the difference between, and appropriately uses if and if, then and else statements(AL) -* Uses a variable and relational operators within a loop to govern termination (AL) (GE) -* Uses a range of operators and expressions e.g. Boolean, and applies them in the context of program control. (AL) -* Selects the appropriate data types(AL) (AB - -#### Data & Data Representation - -* Understands the difference between data and information(AB) -* Performs more complex searches for information e.g. using Boolean and relational operators(AL) (GE) (EV) -* Defines data types: real numbers and Boolean (AB) - -#### Hardware & Processing - -* Knows that computers collect data from various input devices, including sensors and application software (AB) - -Computational Thinking Concept: AB = Abstraction; DE = Decomposition; AL = Algorithmic Thinking; EV = Evaluation; GE = Generalisation - diff --git a/olddocs/js/lessons/the-hat-game/challenges.md b/olddocs/js/lessons/the-hat-game/challenges.md deleted file mode 100644 index 44dd1b7d..00000000 --- a/olddocs/js/lessons/the-hat-game/challenges.md +++ /dev/null @@ -1,174 +0,0 @@ -# the hat game challenges - -The all famous Hat Game -- one of 3 hats has the ball, which is revealed at the beginning. The hats then swap with each other. You goal is to chose the hat with the ball after the hats have finished swapping. #docs - -## Before we get started - -Complete the following guided tutorial: - -* [tutorial](/lessons/the-hat-game/tutorial) - -At the end of the tutorial, click `keep editing`. Your code should look like this: - -``` -initializeGame() -playLevel() -input.onButtonPressed(Button.A, () => { - selectHat() -}) -input.onButtonPressed(Button.B, () => { - chooseHat() -}) -``` - -### Challenge 1 - -Modify `play level()` to customize your difficulty levels. Simply increase the `swap speed` to make the game easier, or decrease it to make the game harder. - -``` -/** - * **. . .** - */ -export function playLevel_() { - let swaps = 5 + 10 * level - if (level == 1) { - swaps = 100 // *** - } else if (level == 2) { - swapSpeed = 40 // *** - } - else { - swapSpeed = 20 // *** - } - // **. . .** -} -``` - -### Challenge 2 - -Let's make the game a little more fun and devious! Let's add a `fake swap` function that pretends to swap the hats, but doesn't actually swap them. - -``` -export function fakeSwap(hat_1: number, hat_2: number, pauseDifficulty: number) { - if (hat_1 == 0 && hat_2 == 1) { - basic.showAnimation(` -. . . . . . . . . . # . . . . . # . . . # . . . . . . . . . . . . . . -. . . . . # . . . . . . . . . . . . . . . . . . . # . . . . . . . . . -# . # . # . . . . # . . . . # . . . . # . . . . # . . . . # # . # . # -. . . . . . . # . . . . . . . . . . . . . . . . . . . # . . . . . . . -. . . . . . . . . . . . # . . . # . . . . . # . . . . . . . . . . . . -`, pauseDifficulty) - } - if (hat_1 == 1 && hat_2 == 0) { - basic.showAnimation(` -. . . . . . . . . . . . # . . . # . . . . . # . . . . . . . . . . . . -. . . . . . . # . . . . . . . . . . . . . . . . . . . # . . . . . . . -# . # . # . . . . # . . . . # . . . . # . . . . # . . . . # # . # . # -. . . . . # . . . . . . . . . . . . . . . . . . . # . . . . . . . . . -. . . . . . . . . . # . . . . . # . . . # . . . . . . . . . . . . . . -`, pauseDifficulty) - } - if (hat_1 == 1 && hat_2 == 2) { - basic.showAnimation(` -. . . . . . . . . . . . # . . . . . # . . . # . . . . . . . . . . . . -. . . . . . . # . . . . . . . . . . . . . . . . . . . # . . . . . . . -# . # . # # . . . . # . . . . # . . . . # . . . . # . . . . # . # . # -. . . . . . . . . # . . . . . . . . . . . . . . . . . . . # . . . . . -. . . . . . . . . . . . . . # . . . # . . . . . # . . . . . . . . . . -`, pauseDifficulty) - } - if (hat_1 == 2 && hat_2 == 1) { - basic.showAnimation(` -. . . . . . . . . . . . . . # . . . # . . . . . # . . . . . . . . . . -. . . . . . . . . # . . . . . . . . . . . . . . . . . . . # . . . . . -# . # . # # . . . . # . . . . # . . . . # . . . . # . . . . # . # . # -. . . . . . . # . . . . . . . . . . . . . . . . . . . # . . . . . . . -. . . . . . . . . . . . # . . . . . # . . . # . . . . . . . . . . . . -`, pauseDifficulty) - } - if (hat_1 == 0 && hat_2 == 2) { - basic.showAnimation(` -. . . . . . . . . . # . . . . . # . . . . . # . . . # . . . # . . . . . . . . . . . . . . -. . . . . # . . . . . . . . . . . . . . . . . . . . . . . . . . . . . # . . . . . . . . . -# . # . # . . # . . . . # . . . . # . . . . # . . . . # . . . . # . . . . # . . # . # . # -. . . . . . . . . # . . . . . . . . . . . . . . . . . . . . . . . . . . . . . # . . . . . -. . . . . . . . . . . . . . # . . . # . . . # . . . . . # . . . . . # . . . . . . . . . . -`, pauseDifficulty) - } - if (hat_1 == 2 && hat_2 == 0) { - basic.showAnimation(` -. . . . . . . . . . . . . . # . . . # . . . # . . . . . # . . . . . # . . . . . . . . . . -. . . . . . . . . # . . . . . . . . . . . . . . . . . . . . . . . . . . . . . # . . . . . -# . # . # . . # . . . . # . . . . # . . . . # . . . . # . . . . # . . . . # . . # . # . # -. . . . . # . . . . . . . . . . . . . . . . . . . . . . . . . . . . . # . . . . . . . . . -. . . . . . . . . . # . . . . . # . . . . . # . . . # . . . # . . . . . . . . . . . . . . -`, pauseDifficulty) - } -} -``` - -### Challenge 3 - -Now let's implement our `fake swap` function inside `play level`. Let's make a third of the swaps fake. This can be most efficiently accomplished through mod. - -``` -/** - * **. . .** - */ -export function playLevel_1() { - let swaps = 5 + 10 * level - // **. . .** - for (let i = 0; i < swaps; i++) { - let swapType = Math.random(3) // *** - let not = Math.random(3) - if (swapType < 2) { - swapHats(math.mod(not + 1, 3), math.mod(not + 2, 3), swapSpeed) // *** - } else { - fakeSwap(math.mod(not + 1, 3), math.mod(not + 2, 3), swapSpeed) // *** - } - } - index = -1 - choosingHat = true -} -``` - -### Challenge 4 - -For a swap of two given hats, one of the hats will always go up while the other goes down. For example, if the first and third hats are swapping, the first hat will always go down and the third will go up. Let's randomize the orientation of each swap by switching the parameters of each swap function half the time. - -``` -/** - * **. . .** - */ -export function playLevel_2() { - let swaps = 5 + 10 * level - // **. . .** - for (let i = 0; i < swaps; i++) { - let swapType = Math.random(3) - let not = Math.random(3) - let swapOrientation = Math.random(2) // *** - if (swapType < 2) { - if (swapOrientation == 0) { - swapHats(math.mod(not + 1, 3), math.mod(not + 2, 3), swapSpeed) // *** - } else { - swapHats(math.mod(not + 2, 3), math.mod(not + 1, 3), swapSpeed) // *** - } - } - else { - swapOrientation = Math.random(2) // *** - if (swapOrientation == 0) { - fakeSwap(math.mod(not + 1, 3), math.mod(not + 2, 3), swapSpeed) // *** - } - else { - fakeSwap(math.mod(not + 2, 3), math.mod(not + 1, 3), swapSpeed) // *** - } - } - } - index = -1 - choosingHat = true -} -``` - -### Challenge 5 - -Create your own swap animation. See if you can get all three hats to move at the same time! - diff --git a/olddocs/js/lessons/the-hat-game/quiz-answers.md b/olddocs/js/lessons/the-hat-game/quiz-answers.md deleted file mode 100644 index a9582a3d..00000000 --- a/olddocs/js/lessons/the-hat-game/quiz-answers.md +++ /dev/null @@ -1,87 +0,0 @@ -# the hat game quiz answers - -The all famous Hat Game -- one of 3 hats has the ball, which is revealed at the beginning. The hats then swap with each other. You goal is to chose the hat with the ball after the hats have finished swapping. - -## Name - -## Directions - -Use this activity document to guide your work in the [the hat game tutorial](/lessons/the-hat-game/tutorial) - -Answer the questions while completing the tutorial. Pay attention to the dialogues! - -## 1. What is the name of the first function you created? What does it do? - -
- -Initialize game() is the name of the first function. It helps set up the game state. - -## 2. Write a for loop that plots the points (0, 2), (2, 2), and (4, 2). - -
- -``` -for (let i = 0; i < 3; i++) { - led.plot(i * 2, 2) -} -``` - -## 3. How can you increase the difficulty of the game? - -
- -Decrease the swap speed value. This will reduce the pause between each frame, and will thus make the game run faster. - -## 4. Consider the following code - -``` -cupSelect = "LMR" -index = -1 -``` - -Write the code that displays the next letter of the string in "cup select" when button A is pressed. - -
- -
- -``` -input.onButtonPressed(Button.A, () => { - index = index + 1 - if (index > 2) { - index = 0 - } - basic.showString(cupSelect[index], 150) -}) -``` - -## 5. Write the line of code that shows the swapping animation of two hats swapping if hat 1 = 0 and hat 2 = 2. - -
- -``` -basic.showAnimation(` -. . . . . . . . . . # . . . . . # . . . . . # . . . . . # . . . . . # . . . . . . . . . . -. . . . . # . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . # . . . . . -# . # . # . . # . . . . # . . . . # . . . . # . . . . # . . . . # . . . . # . . # . # . # -. . . . . . . . . # . . . . . . . . . . . . . . . . . . . . . . . . . # . . . . . . . . . -. . . . . . . . . . . . . . # . . . # . . . # . . . # . . . # . . . . . . . . . . . . . . -`, 400) -``` - -## 6. Consider the following code - -``` -let not = Math.random(3) -``` - -Given the hat we are not going to swap, how can we calculate the other two hats that we are going to swap? Use these two values to call "swap hats()" with a swap speed of 50. - -
- -``` -swapHats(math.mod(not + 1, 3), math.mod(not + 2, 3), 50) -``` - -
- diff --git a/olddocs/js/lessons/the-hat-game/quiz.md b/olddocs/js/lessons/the-hat-game/quiz.md deleted file mode 100644 index 7b8a4ac1..00000000 --- a/olddocs/js/lessons/the-hat-game/quiz.md +++ /dev/null @@ -1,59 +0,0 @@ -# the hat game quiz - -The all famous Hat Game -- one of 3 hats has the ball, which is revealed at the beginning. The hats then swap with each other. You goal is to choose the hat with the ball after the hats have finished swapping. - -## Name - -## Directions - -Use this activity document to guide your work in the [the hat game tutorial](/lessons/the-hat-game/tutorial) - -Answer the questions while completing the tutorial. Pay attention to the dialogues! - -## 1. What is the name of the first function you created? What does it do? - -
- -## 2. Write a for loop that plots the points (0, 2), (2, 2), and (4, 2). - -
- -## 3. How can you increase the difficulty of the game? - -
- -## 4. Consider the following code - -``` -cupSelect = "LMR" -index = -1 -``` - -Write the code that displays the next letter of the string in "cup select" when button A is pressed. - -
- -
- -
- -
- -
- -## 5. Write the line of code that shows the swapping animation of two hats swapping if hat 1 = 0 and hat 2 = 2. - -
- -## 6. Consider the following code - -``` -let not = Math.random(3) -``` - -Given the hat we are not going to swap, how can we calculate the other two hats that we are going to swap? Use these two values to call "swap hats()" with a swap speed of 50. - -
- -
- diff --git a/olddocs/js/lessons/timing-game.md b/olddocs/js/lessons/timing-game.md deleted file mode 100644 index aa6a41a0..00000000 --- a/olddocs/js/lessons/timing-game.md +++ /dev/null @@ -1,7 +0,0 @@ -# timing game - -make a game to test hand-eye coordination. - -Make a game to test hand-eye coordination - -* [tutorial](/lessons/timing-game/tutorial) diff --git a/olddocs/js/lessons/transformer/quiz.md b/olddocs/js/lessons/transformer/quiz.md deleted file mode 100644 index 438146a5..00000000 --- a/olddocs/js/lessons/transformer/quiz.md +++ /dev/null @@ -1,44 +0,0 @@ -# transformers quiz - -Use functions to return values. - -## Name - -## Directions - -Use this activity document to guide your work in the [transformer tutorial](/lessons/transformer/tutorial) - -Answer the questions below while working on or after you finish the tutorial. Pay attention to the dialogs! - -## 1. What is a 'function'? - -## 2. Consider the following directions - -Write the line of code to create a number variable that is initially 5. - -
- -## 3. Consider the following directions - -Write the line of code to use the condition 'on button pressed ("A")' - -
- -## 4. Consider the following directions - -Write the code that creates a function. - -
- -## 5. Consider the following directions - -Write the code to call the function that doubles the input number. (the function is going to provide the doubled value after it is called). The code will assign the new value (10) to a variable which we will call `doubled`. - -
- -## 6. Consider the following picture - -Write the code to show number 20 on the @boardname@. Please add the variable called `doubled` Refer to the finished code on the tutorial. - -
- diff --git a/olddocs/js/lessons/transformers.md b/olddocs/js/lessons/transformers.md deleted file mode 100644 index 7e82c8ab..00000000 --- a/olddocs/js/lessons/transformers.md +++ /dev/null @@ -1,123 +0,0 @@ -# transformers lesson - -use functions to return values. - -## Topic - -Return - -## Quick Links - -* [tutorial](/lessons/transformers/tutorial) -* [quiz](/lessons/transformers/quiz) -* [quiz answers](/lessons/transformers/quiz-answers) -* [challenges](/lessons/transformers/challenges) - -## Class - -Year 7 - -## Prior learning/place of lesson in scheme of work - -Learn how to create **functions**, ` function() ` to make your code easier to read, debug, and update. We will be learning how to create functions as well as a global variable, input on button pressed as well simple commands such as show number. - -## What the teacher needs to know - -* Algorithm: An unambiguous set of rules or a precise step-bystep guide to solve a problem or achieve a particular objective. -* Command: An instruction for the computer to execute, written in a particular programming language. -* Data: A structured set of numbers, possibly representing digitised text, images, sound or video, which can be processed or transmitted by a computer, also used for numerical (quantitative) information. -* Decomposing: The process through which problems or systems are broken down into their component parts, each of which may then be considered separately. -* Hardware: The physical systems and components of digital devices; see also software. -* Input: Data provided to a computer system, such as via a keyboard, mouse, microphone, camera or physical sensors. -* Output: The information produced by a computer system for its user, typically on a screen, through speakers or on a printer, but possibly through the control of motors in physical systems. -* Programmable toys: Robots designed for children to use, accepting input, storing short sequences of simple instructions and moving according to this stored program. -* Program: A stored set of instructions encoded in a language understood by the computer that does some form of computation, processing input and/or stored data to generate output. -* Script: A computer program typically executed one line at a time through an interpreter, such as the instructions for a Scratch character. -* Selection: A programming construct in which one section of code or another is executed depending on whether a particular condition is met. -* Sequence: To place program instructions in order, with each executed one after the other. -* Simulation: Using a computer to model the state and behaviour of real-world (or imaginary) systems, including physical or social systems; an integral part of most computer games. -* Variables: A way in which computer programs can store, retrieve or change data, such as a score, the time left, or the user’s name. - -**QuickStart Computing Glossary - -## Documentation - -* **function** : [read more...](/js/function) -* **return** : [read more...](/js/return) -* **call** : [read more...](/js/call) -* **global variable** : [read more...](/js/data) -* **on button pressed** : [read more...](/reference/input/on-button-pressed) -* **local variable** : [read more...](/reference/variables/var) -* **show number** : [read more...](/reference/basic/show-number) - -## Resources - -* Activity: [tutorial](/lessons/transformers/tutorial) -* Activity: [quiz](/lessons/transformers/quiz) -* Extended Activity: [challenges](/lessons/transformers/challenges) - -## Objectives - -* learn how to create a function that performs a specific task to make your code easier to read, debug, and update -* learn how the return statement exits a function and returns a value to the code -* learn how to call an existing function in your script -* learn how to create a global variable to store data so that you can use it later in your code and accessible across functions and in nested code blocks -* learn how to run code when an input button is pressed -* learn how to create a local variable to store data, so that you can use it in your code -* learn how to show a number on the LED screen - -## Links to the National Curriculum Programmes of Study for Computing - -## Progression Pathways / Computational Thinking Framework - -#### Algorithms - -* Uses diagrams to express solutions.(AB) -* Uses logical reasoning to predict outputs, showing an awareness of inputs (AL) -* Designs solutions by decomposing a problem and creates a sub-solution for each of these parts. (DE) (AL) (AB) -* Represents solutions using a structured notation (AL) (AB) - -#### Programming & Development - -* Creates programs that implement algorithms to achieve given goals (AL) -* Declares and assigns variables(AB) -* Uses a variable and relational operators within a loop to govern termination (AL) (GE) -* Uses a range of operators and expressions e.g. Boolean, and applies them in the context of program control. (AL) -* Selects the appropriate data types(AL) (AB - -#### Data & Data Representation - -* Uses filters or can perform single criteria searches for information.(AL) -* Defines data types: real numbers and Boolean (AB) - -#### Hardware & Processing - -* Knows that computers collect data from various input devices, including sensors and application software (AB) - -#### Information Technology - -* Collects, organizes, and presents data and information in digital content (AB) -* Makes appropriate improvements to solutions based on feedback received, and can comment on the success of the solution (EV) -* Recognises ethical issues surrounding the application of information technology beyond school. - -Computational Thinking Concept: AB = Abstraction; DE = Decomposition; AL = Algorithmic Thinking; EV = Evaluation; GE = Generalisation - -## Activity - -* time: 20 min. -* [tutorial](/lessons/transformers/tutorial) -* [quiz](/lessons/transformers/quiz) - -## Extended Activity - -* time: 20 min. -* [challenges](/lessons/transformers/challenges) - -## Homework - -* Extended Activity: [challenges](/lessons/transformers/challenges) - -## Intended follow on - -Publish script to the classroom. - diff --git a/olddocs/js/lessons/transformers/challenges.md b/olddocs/js/lessons/transformers/challenges.md deleted file mode 100644 index 7aa97d3d..00000000 --- a/olddocs/js/lessons/transformers/challenges.md +++ /dev/null @@ -1,52 +0,0 @@ -# transformers challenges - -Coding challenges for the transformers tutorial. #docs - -## Before we get started - -Complete the following guided tutorial: - -* [tutorial](/lessons/transformers/tutorial) - -At the end of the tutorial, click `keep editing`. Your code should look like this: - -``` -let inital = 5 -input.onButtonPressed(Button.A, () => { - let doubled1 = double(initial) - basic.showNumber(doubled1, 150) // *** -}) -``` - -### Challenge 1 - -Create a new function called `square` that returns the square of the number passed into the function. - -(Squaring means that you multiply the number by itself) - -``` -export function square(n: number) : number { - let num: number - return n * n - return num -} -``` - -### Challenge 2 - -Add a condition for when button `B` is pressed. We will use this condition in the last challenge. - -``` -initial = 5 -input.onButtonPressed(Button.A, () => { - let doubled = double(initial) - basic.showNumber(doubled, 150) -}) -input.onButtonPressed(Button.B, () => { -}) // *** -``` - -**Challenge 3** - -When the `B` button is pressed, display the square of the initial value. Use the function `square`. You should get the value 25. - diff --git a/olddocs/js/lessons/transformers/quiz-answers.md b/olddocs/js/lessons/transformers/quiz-answers.md deleted file mode 100644 index f45cd455..00000000 --- a/olddocs/js/lessons/transformers/quiz-answers.md +++ /dev/null @@ -1,65 +0,0 @@ -# transformers quiz answers - -Use functions to return values. - -This is the answer key for the [transformers quiz](/lessons/transformers/quiz). - -## 1. What is a 'function'? - -A function is a unit of code that performs a specific task and returns a result. - -## 2. Write the line of code to create a number variable called "x" is equal to 5. - -
- -``` -let x = 5 -``` - -## 3. Write the line of code to create a condition for 'on button pressed ("A")' - -
- -``` -input.onButtonPressed(Button.A, () => { -}) -``` - -## 4. Write the steps to create a function. - -
- -Click on `script`, then `add new`, and select `function`. - -## 5. Create a function called double that will double whatever input parameter is passed into it. - -
- -``` -export function double(n: number) : number { - let r: number - return n * 2 - return r -} -``` - -## 6. Consider the following directions - -Call the `function` that doubles the variable **x**. (The `function` is going to return the doubled value after it is called). Assign the new value (10) to a variable which we will call `doubled`. - -
- -``` -let doubled = double(x) -``` - -## 7. Refer to Question 6 - -Write the code to call the function that doubles our new `variable` doubled. Assign the new value 20 to a variable we will call doubled twice. - -
- -``` -let doubleTwice = double(doubled) -``` - diff --git a/olddocs/js/lessons/transformers/quiz.md b/olddocs/js/lessons/transformers/quiz.md deleted file mode 100644 index dd4f111e..00000000 --- a/olddocs/js/lessons/transformers/quiz.md +++ /dev/null @@ -1,40 +0,0 @@ -# transformers quiz - -Use functions to return values. - -## Name - -## Directions - -Use this activity document to guide your work in the [transformers tutorial](/lessons/transformers/tutorial) - -Answer the questions while completing the tutorial. Pay attention to the dialogues! - -## 1. What is a 'function'? - -
- -## 2. Write the line of code to create a number variable called **x** that is equal to 5. - -
- -## 3. Write the line of code to create a condition for 'on button pressed ("A")' - -
- -## 4. Write the steps to create a function. - -
- -## 5. Create a function called **double** that will double whatever input parameter is passed into it. - -
- -## 6. Consider the following directions. Call the function that doubles the variable original. The function is going to return the doubled value after it is called. Assign the new value (10) to a variable which we will call doubled. - -
- -## 7. Refer to Question 6. Write the code to call the function that doubles our new variable doubled. Assign the new value 20 to a variable we will call doubled twice. - -
- diff --git a/olddocs/js/lessons/typing-game/challenges.md b/olddocs/js/lessons/typing-game/challenges.md deleted file mode 100644 index 2ac981b5..00000000 --- a/olddocs/js/lessons/typing-game/challenges.md +++ /dev/null @@ -1,80 +0,0 @@ -# typing game challenges - -My script. #docs - -**Challenge 0** - -This [guided tutorial](/lessons/typing-game/tutorial) will teach you how to use the method concat to connect to pieces of text together. - -``` -alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" -index = 0 -name = "" -input.onButtonPressed(Button.A, () => { - led.showString(alphabet.substr(index, 1), 0) - index = index + 1 -}) -if (index > 25) { - index = 0 -} -input.onButtonPressed(Button.B, () => { - name = name.concat(alphabet.substr(index - 1, 1)) -}) -input.onGesture(Gesture.Shake, () => { - led.showString(name, 150) -}) -``` - -**Challenge 1** - -After you have shown the string in the condition `on shake`, make the name variable hold nothing in it again so people can add a new name after they have shaken it. - -``` -alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" -index = 0 -name = "" -input.onButtonPressed(Button.A, () => { - led.showString(alphabet.substr(index, 1), 0) - index = index + 1 -}) -if (index > 25) { - index = 0 -} -input.onButtonPressed(Button.B, () => { - name = name.concat(alphabet.substr(index - 1, 1)) -}) -input.onGesture(Gesture.Shake, () => { - led.showString(name, 150) - name = "" // *** -}) -``` - -**Challenge 2** - -After you have cleared the name variable to hold nothing, make `index := 0` so that when button `A` is pressed, the first letter of the alphabet will be displayed. - -``` -alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" -index = 0 -name = "" -input.onButtonPressed(Button.A, () => { - led.showString(alphabet.substr(index, 1), 0) - index = index + 1 -}) -if (index > 25) { - index = 0 -} -input.onButtonPressed(Button.B, () => { - name = name.concat(alphabet.substr(index - 1, 1)) -}) -input.onGesture(Gesture.Shake, () => { - led.showString(name, 150) - name = "" - index = 0 // *** -}) -``` - -**Challenge 3** - -Give Micro a nickname and display it on the @boardname@! - diff --git a/olddocs/js/lessons/while-counting/challenges.md b/olddocs/js/lessons/while-counting/challenges.md deleted file mode 100644 index 95a5eb17..00000000 --- a/olddocs/js/lessons/while-counting/challenges.md +++ /dev/null @@ -1,61 +0,0 @@ -# digi yoyo challenges - -These challenges will teach you how to create a counter 10 to 1. #docs - -**Challenge 0** - -[This guided tutorial](/lessons/digi-yoyo/tutorial) will teach you how to make a counter from 0-9 using a while loop. - -``` -count = 1 -while (count < 10) { - basic.pause(1000) - basic.showNumber(count, 150) - count = count + 1 -} -``` - -**Challenge 1** - -How about we create a counter that counts backwards from 10 to 1? Let's add a while loop that executes only when `count` is greater than 0. - -``` -count = 1 -while (count < 10) { - basic.pause(1000) - basic.showNumber(count, 150) - count = count + 1 -} -while (count > 0) { -} -``` - -**Challenge 2** - -Inside of the while loop, let's add `pause->(1000)` so that we have a pause between each number as it's counting down. Also, let's show `count`! - -``` -count = 1 -while (count < 10) { - basic.pause(1000) - basic.showNumber(count, 150) - count = count + 1 -} -while (count > 0) { - basic.pause(1000) // *** - basic.showNumber(count, 150) // *** -} -``` - -* Run the code to see if it works as expected. - -**Challenge 3** - -Now, we need `count` to decrease by one after the @boardname@ has displayed the value of `count`. - -We can do this by adding this line: - -``` -count = count - 1 -``` - diff --git a/olddocs/js/lessons/yes-no/challenges.md b/olddocs/js/lessons/yes-no/challenges.md deleted file mode 100644 index 2fdf5c17..00000000 --- a/olddocs/js/lessons/yes-no/challenges.md +++ /dev/null @@ -1,45 +0,0 @@ -# yes no challenges - -My script. #docs - -**Challenge 0** - -This [guided tutorial](/lessons/yes-no/challenges) will show you how to display text on the @boardname@! - -``` -basic.showString("ASK ME A QUESTION", 150) -``` - -**Challenge 1** - -Now we need to reply after someone asks Micro a yes or no question. We want to respond `YES` when button `A` is pressed. Add a condition for button `A` and inside it show the string `YES`. - -``` -basic.showString("ASK ME A QUESTION", 150) -input.onButtonPressed(Button.A, () => { - basic.showString("YES", 150) // *** -}) // *** -``` - -* `Run` the code to see if it works as expected. - -**Challenge 2** - -What if Micro's answer to the question is no? Let's have `NO` be displayed when button `B` is pressed. Add a condition for button `B` and inside it show the string `NO`. - -``` -basic.showString("ASK ME A QUESTION", 150) -input.onButtonPressed(Button.A, () => { - basic.showString("YES", 150) -}) -input.onButtonPressed(Button.B, () => { - basic.showString("NO", 150) // *** -}) // *** -``` - -* `Run` the code to see if it works as expected. - -**Challenge 3** - -When you are asked a yes or no question, do you always say yes or no? Add a condition for `on shake` that displays `MAYBE`. - diff --git a/olddocs/js/libraries.md b/olddocs/js/libraries.md deleted file mode 100644 index 2e402224..00000000 --- a/olddocs/js/libraries.md +++ /dev/null @@ -1,64 +0,0 @@ -# Create and Use Libraries - -Libraries are scripts with functions that you can use in other scripts. - -### @parent js/language - -Libraries are scripts with functions that you can use in other scripts. For example, `game` is a library of game-related functions that you can use in your scripts. - -Benefits of using libraries: - -* **reuse code** between scripts -* **collaborate** with other people on a project by combining scripts into a library - -### Add a library - -To add a library to a script: - -1. Open a script in the [Touch Develop editor](/js/editor) and then click `script` (in the upper-right corner). - -2. Click `+` **add new**. - -3. Click `library`. - -4. Choose the library you want to use or search for a library (such as `game`). - -Once you've added a library to your script, you can use any of the library's non-private [functions](/js/function). Here's how: - -* on the [Code Keyboard](/js/editor) click the button with the library's name (for example, `@boardname@` and `@boardname@ game` are library buttons). The functions in the library have a button on the Code Keyboard. - -### Create a library - -Creating and publishing a script as a library is easy. Here's how: - -1. Open a script in the [Touch Develop editor](/js/editor), and then click `script`. - -2. Click the script name to open the script properties. - -3. Mark the `this script is a library` check box. - -4. Click `script`. - -5. Click `publish`. - -Once a script is marked as a _library_ and published, it's immediately available to other people. - -### Visibility - -The following library items are not accessible by other scripts: - -* data (global variables) -* functions marked as `private` - -If you want to access global library variables from other scripts, you need to create [functions](/js/function) that pass values in and out of the library script. - -### Library and function documentation - -Be sure to document the purpose of your functions and libraries. Add a [comment](/js/comment) at the beginning of a library to describe the purpose of the library. - -Use [comments](/js/comment) at the beginning of your [functions](/js/function) to describe the function's purpose. Comment text shows in the help area of the Code Keyboard when you insert the function. - -### See also - -[functions](/js/function), [Touch Develop Documentation](/js/contents) - diff --git a/olddocs/js/markdown.md b/olddocs/js/markdown.md deleted file mode 100644 index d7059666..00000000 --- a/olddocs/js/markdown.md +++ /dev/null @@ -1,175 +0,0 @@ -# Markdown Syntax - -Syntax to create formatted text in Touch Develop. - -### @parent td/comment - - -Markdown is a popular syntax used by developers to describe and annotate documents. Touch Develop supports a large subset of the markdown syntax, and adds a few new features. Markdown syntax applies to [comments](/js/comment) added using the [Touch Develop editor](/js/editor). - -## Basic markdown syntax - -### Headings - -Use #, ##, or ### at the beginning of a line to specify a heading: - -* ``use # for heading 1`` -* ``use ## for heading 2`` -* ``use ### for heading 3`` - -### Bulleted lists - -Use a * for a bullet: - -``* this is a bullet`` - -### Numbered lists - -Type a number, a period, and a space before each item in a numbered list. Like this: - -> `1. first item` - -> `2. second item` - -> `3. third item` - -The numbers in a numbered list appear as 1. in the Touch Develop editor, however, the numbers will update when the script is previewed or published. - -### Character formatting - -Use a single `*` for italic and `**` for bold: - -``*italic*`` => *italic* - -``**bold**`` => **bold** - -### Links - -* to add a link, type the URL: ``http://touchdevelop.com`` => http://touchdevelop.com -* to specify link text (instead of the URL), put the link text in [ ] brackets and the link in ( ) - -For example: - -``[TouchDevelop website](http://touchdevelop.com)`` => [TouchDevelop website](http://touchdevelop.com) - -### Columns - -To format text into columns, insert ``### ~column `` at the start of each column and ``### ~`` at the end of the column. - -## Touch Develop syntax - -The markdown syntax in this section is non-standard and specific to Touch Develop. - -### Inline code - -Use this syntax: ```basic => show number``` - -To show code like this: `basic-> show number` - -(``->`` is replaced with `->`) - -### HTML entities - -You can use HTML entities like ``&amp;``, ``&lt;``, or ``&#123;``. You can also use ``&`` verbatim if it cannot be confused with HTML entity. - -### Pictures - -You can include pictures in a script by adding an art resource to your script. All pictures must first be uploaded to the Touch Develop cloud before they can be used in a script. Here's how: - -1. Click `script`, **+ add new**, and then click **picture resource**. - -2. You can upload a new picture or search existing pictures. - -3. Give it a name, let's say you call it ``alien``. - -2. In your script, use ``(picture ...)`` with the picture name (in this case, alien) and an optional caption: -WARN: missing picture: ... -WARN: unknown picture: ... - -* ``![](/static/mb/image-0.png)`` - -![](/static/mb/image-0.png) - -By default, pictures are 12x12. You can specify a different size as in `![](/static/mb/image-0.png)`, up to 30x20. - -![](/static/mb/image-0.png) - -To insert a picture inline with text ![](/static/mb/image-0.png), use: `(picture ...)` without any size information. For example: ``![](/static/mb/image-0.png)`` -WARN: missing picture: ... -WARN: unknown picture: ... - -You can skip adding an art resource, and instead use the publication ID of a picture directly. - -### Declarations - -Any named declaration from a script can be rendered in a script using `{decl:name}`. For example, you can render global variables, functions, etc... -WARN: no such decl: name - -* ` -``` -var v: number = 0 -``` - -` where `v` is a global variable in the script: - -``` -var v: number = 0 -``` - -### Code snippets - -Any code that is not a comment is treated as a snippet. - -You can use ``{highlight}`` comment to start highlighting statements in the snippet. Use ``{/highlight}`` to stop. The comment needs to have ``{highlight}`` or ``{/highlight}`` and nothing else. -MACRO: highlightMACRO: /highlightMACRO: highlightMACRO: /highlight - -If you want to render some comments inside the snippets as comments (and not regular text), then surround the snippet with ``{code}`` ... ``{/code}``, for example: -MACRO: codeMACRO: /code - -``` -let theAnswer = 42 // *** -// and now show the answer: -basic.showNumber(theAnswer, 150) -``` - -Note that comments inside block structures are always rendered as regular comments, not text. For example: - -``` -if (false) { - // This code is never executed. -} -``` - -### Boxes and frames - -You can use `### ~ ` and `### ~` (each on separate comment line) to enclose a block of text in a coloured box. For example: - -### ~hint - -This is how `### ~hint ` looks like. Some helpful information goes here. - -### ~ - -The following box types are supported: - -* `hint`, `exercise`, `example` - self-explanatory -* `nointernet` - block with heading "no internet?" for giving instructions for offline operations -* `screen` - does not show in print -* `print` - does not show when not printing -* `portrait` - shows (with no frame or heading) when device is held in portrait orientation; in print it shows with heading "device in portrait" and a frame -* `landscape` - likewise - -### Special tutorial features - -You'll use markdown syntax when creating Touch Develop tutorials. See [create a tutorial](/js/create-tutorials) for more info. - -### ~hide - -### Embedding videos - -* any video: ``{video::}`` where ```` is a screenshot of the video, and ```` is the video url that plays -MACRO: video -If you want to include documents, slides, and videos from other sites, just use regular `http://...` link. - -### ~ - diff --git a/olddocs/js/math.md b/olddocs/js/math.md deleted file mode 100644 index 955e856a..00000000 --- a/olddocs/js/math.md +++ /dev/null @@ -1,101 +0,0 @@ -# Math Library - -Functions in the math library. - -### @parent js/language - -The math library includes math related functions that you can use with [Numbers](/reference/types/number). - -* In the [TouchDevelop editor](/js/editor), click `math` to access the functions described below -* In the [Block editor](/blocks/editor), click **maths** on the left to see the available blocks - -The functions available in Touch Develop are: - -### abs - -math `->` abs (x : [Number](/reference/types/number)) *returns* [Number](/reference/types/number) - -returns the absolute value of input parameter `x` - -``` -basic.showNumber(math.abs(-7), 150) -``` - -### clamp - -math `->` clamp (min : [Number](/reference/types/number), max : [Number](/reference/types/number), value : [Number](/reference/types/number)) *returns* [Number](/reference/types/number) - -limits a number to a range (between a min and max number); returns `min` if `value` is < `min`; returns `max` if `value` is > `max`; otherwise, returns `value`. - -``` -basic.showNumber(td.clamp(5, 9, 12), 150) -``` - -### max - -math `->` max (x : [Number](/reference/types/number), y : [Number](/reference/types/number)) *returns* [Number](/reference/types/number) - -returns the larger of two input numbers (`x` and `y`) - -``` -basic.showNumber(Math.max(9, 7), 150) -``` - -### min - -math `->` min (x : [Number](/reference/types/number), y : [Number](/reference/types/number)) *returns* [Number](/reference/types/number) - -returns the smaller of two input numbers (`x` and `y`) - -``` -basic.showNumber(Math.min(9, 7), 150) -``` - -### mod - -math `->` mod (x : [Number](/reference/types/number), y : [Number](/reference/types/number)) *returns* [Number](/reference/types/number) - -returns the integer modulus/remainder resulting from the division of the number `x` by the number `y` - -``` -basic.showNumber(math.mod(9, 7), 150) -``` - -### pow - -math `->` pow (base : [Number](/reference/types/number), exp : [Number](/reference/types/number)) *returns* [Number](/reference/types/number) - -returns the value of the number `base` raised to the power `exp` - -``` -basic.showNumber(math.pow(3, 3), 150) -``` - -### random - -math `->` random (limit : [Number](/reference/types/number)) *returns* [Number](/reference/types/number) - -returns a random [Number](/reference/types/number) between 0 and the parameter *limit* - 1 - -``` -basic.showNumber(Math.random(10), 150) -``` - -### sign - -math `->` sign (x : [Number](/reference/types/number)) *returns* [Number](/reference/types/number) - -returns the sign of input parameter `x` - -``` -basic.showNumber(math.sign(-7), 150) -``` - -### Lessons - -[flipping bird](/lessons/flipping-bird), [catch the egg game](/lessons/catch-the-egg-game) - -### See also - -[Bits library](/js/bits), [TouchDevelop documentation](/js/contents), [Number](/reference/types/number) - diff --git a/olddocs/js/micro-bit-api.md b/olddocs/js/micro-bit-api.md deleted file mode 100644 index e4cec462..00000000 --- a/olddocs/js/micro-bit-api.md +++ /dev/null @@ -1,69 +0,0 @@ -# @boardname@ - -The @boardname@ device api. #microbit - -Initialize the library. - -{shim:} -MACRO: shim - -``` -if (board == null) { - compassHeadingValue = (null) - startTime = new Date() - board = media.createPortraitBoard(612, 498 + 100) - wall.setBackground(colors.transparent()) - let picture = microbitSchema.clone() - let padding = 27 - let left = 205 - let top = 156 - picture.fillRect(left - padding, top, 205 + padding + 4, 200 + padding + 4, 0, colors.black()) - picture.fillRect(274, 74, 63, 16, 0, colors.black()) - bkg = board.createPicture(picture) - bkg.width() = board.width() - bkg.left() = 0 - bkg.top() = 0 - createButtons() - finger = board.createEllipse(20, 20) - finger.setOpacity(0) - ledOnColor = "#ff4f4f".toColor() - ledOffColor = colors.transparent() - boardColor = colors.fromRgb(0.85, 0.95, 0.85) - backLeds = board.createSpriteSet() - leds = board.createSpriteSet() - let backLedColor = "#202020".toColor() - let ledOpacity = 127 / 255 - let ledW = 10 - let ledOffset = 48 - let ledH = 20 - for (let i = 0; i < 5; i++) { - let ledTop = i * ledOffset + top - for (let j = 0; j < 5; j++) { - let ledLeft = j * ledOffset + left - let backLed = board.createRectangle(ledW, ledH) - backLed.setColor(backLedColor) - let led = board.createRectangle(ledW + 8, ledH + 8) - backLed.left() = ledLeft - backLed.top() = ledTop - led.x() = backLed.x() - led.y() = backLed.y() - led.setOpacity(ledOpacity) - led.setColor(ledOffColor) - led.setShadow(10, colors.red(), 0, 0) - ledIndexAnim(backLed, j, i) - backLeds.add(backLed) - leds.add(led) - } - } - initEyes() - initAxis() - initPins() - updateAxis() - backgroundAnimation() - board.onEveryFrame(() => { - updateBoard() - }) - board.postToWall() -} -``` - diff --git a/olddocs/js/number.md b/olddocs/js/number.md deleted file mode 100644 index 7b81dc68..00000000 --- a/olddocs/js/number.md +++ /dev/null @@ -1,84 +0,0 @@ -# Number - -An integer number. - -### @parent js/language - -A *Number* is an integer such as `42` or `-42`. More precisely, a *Number* is a signed 32-bit integer (two's complement). - -### Declare a number variable - -Use the [var statement](/reference/variables/var) and the [assignment operator](/reference/variables/assign) `:=` to declare a *local* number variable. Like this: - -``` -let number1 = 2 -let number2 = 2 -``` - -To declare a *global* number variable, see [global variables](/js/data). - -### Arithmetic operators - -The following arithmetic operators work on numbers and return a [Number](/reference/types/number): - -* addition: `1 + 3` -* subtraction: `1 - 3 ` -* multiplication: `3 * 2` -* integer division: `7 / 3` -* modulo is available through the [math library](/js/math) - -### Relational operators - -The following relational operators work on numbers and return a [Boolean](/reference/types/boolean): - -* equality: `(3 + 1) = 4` -* inequality: `3 != 4` -* less or equal than: `3 <= 4` -* less than: `3 < 4` -* greater or equal than : `4 >= 3` -* greater than: `4 > 3` - -### Show number - -The [show number](/reference/basic/show-number) function displays a number on the [LED screen](/device/screen). For example, this code displays the number 42: - -``` -basic.showNumber(42, 100) -``` - -### Functions that return a number - -Some functions return a number, which you can store in a variable. For example the following code gets the display brightness (using the [brightness function](/reference/led/brightness)) and stores the value in a variable named `brightness`: - -``` -let brightness = led.brightness() -``` - -### Math functions - -The [math library](/js/math) includes math related functions. In the [Touch Develop editor](/js/editor), click `math` on the Code Keyboard to see the math functions. For example, the `mod` function returns the modulus (division of one number by another number): - -``` -number1 = math.mod(4, 3) -``` - -### Convert a number to a string - -The `to string` function converts a Number into a [String](/reference/types/string). The following code converts `number1` to a string and stores the string in the `str` variable: - -``` -let str = number1.toString() -``` - -### Bit-level manipulation - -The [bits library](/js/bits) includes functions for bit-level manipulation of integers. In the [Touch Develop editor](/js/editor), click `bits` on the Code Keyboard to see these functions. - -### Lessons - -[counter](/lessons/counter), [love meter](/lessons/love-meter), [flipping bird](/lessons/flipping-bird), [catch the egg game](/lessons/catch-the-egg-game) - -### See also - -[math library](/js/math), [var](/reference/variables/var), [bits library](/js/bits), [Boolean](/reference/types/boolean), [show number](/reference/basic/show-number) - diff --git a/olddocs/js/object-disclaimer.md b/olddocs/js/object-disclaimer.md deleted file mode 100644 index 7fa13223..00000000 --- a/olddocs/js/object-disclaimer.md +++ /dev/null @@ -1,25 +0,0 @@ -# Objects disclaimer - -Touch Develop docs for the @boardname@. - -### Memory management on the micro-bit - -New user-defined object types are allocated on the heap and are ref-counted. Our ref-counting algorithm does *not* have a cycle collector. (See Wikipedia.) - -### Practical consequences - -This means that the following script will result in an out-of-memory error. - -![](/static/mb/object-disclaimer-0.png) - -``` -while (true) { - let l = new List() - l.next = l -} -``` - -### How to avoid this? - -Don't do it. It's bad. - diff --git a/olddocs/js/object-types.md b/olddocs/js/object-types.md deleted file mode 100644 index d63ed65b..00000000 --- a/olddocs/js/object-types.md +++ /dev/null @@ -1,57 +0,0 @@ -# Custom object types - -Touch Develop docs for the @boardname@. - -### What is an object? - -An object allows you to bundle several related pieces of data. For instance, if you have a player on the screen, there are two pieces of data that make up the object: its `x` position, and its `y` position. Therefore, we will define a player to be an *object* with two *fields*: the `x` field and the `y` field. By grouping related variables together in a single object, you reduce confusion in your script and eliminate some errors. - -### What is an object type? - -In order to use objects, we must first define an object type. More concretely, in order to create a new player, we must define what a player *is*. In our case, the type of players is the type of objects with two fields `x` and `y` of type `Number`. - -Creating an object type is done in the following manner. Hit "add new", then hit "object type". - -![](/static/mb/object-types-0.png)(picture foobar2) -WARN: unknown picture: foobar2 - -You can change the name of the type by clicking on it (i.e. replace `Thing` with `Player`). You can also add two fields of type number. Once this is done, here's what you should see. - -![](/static/mb/object-types-1.png) - -We have now defined what a player is (it has an `x` field and a `y` field). `Player` is a type, just like `Number` and `String`. However, we have not created any player yet. - -### Creating objects and using them - -To create a new *variable* of a given type, you can call the `create` operation on `Player`. - -``` -let p = new Player() -``` - -Just like `var x := 3` creates a new variable (`x`) of type `Number`, the line above creates a new variable (`p`) of type `Player`. We say that `p` is an *instance* of `Player`. - -If you want to *modify* (mutate) `p`, here's how you do it. - -``` -p.x = 5 -``` - -You can read the *fields* of `p` as follows. - -``` -basic.showString("My player is at x = ", 150) -basic.showNumber(p.x, 150) -``` - -That is, the generic syntax for accessing a field `x` of an object `p` is `p → x`. - -If there are multiple players in your game, you may want to create a collection of them. - -``` -let c = ([]) -c.push(new Player()) -``` - -A good example of using objects is in the game pac-man runaway. Search for it, read it and clone it! - diff --git a/olddocs/js/operators.md b/olddocs/js/operators.md deleted file mode 100644 index 51ee5ce2..00000000 --- a/olddocs/js/operators.md +++ /dev/null @@ -1,9 +0,0 @@ -# Operators - -Built-in operators. - -### @parent js/language - - -### to be removed: has been combined into [statements and operators](/js/statements) - diff --git a/olddocs/js/orientation.md b/olddocs/js/orientation.md deleted file mode 100644 index 24d3f796..00000000 --- a/olddocs/js/orientation.md +++ /dev/null @@ -1,46 +0,0 @@ -# @boardname@ orientation - -A #microbit library that exposes accelerometer events. - -A simple library that exposes events to detect - -* detect that the screen is facing up and the board is horizontal - -``` -onScreenUp(() => { - micro_bit.showString("screen up", 100) -}) -``` - -* detect that the screen is facing down and the board is horizontal - -``` -onScreenDown(() => { - micro_bit.showString("screen down", 100) -}) -``` - -* detect when the logo is up and the board is vertical - -``` -onLogoUp(() => { - micro_bit.showString("logo up", 100) -}) -``` - -* detect when the logo is down and the board is vertical - -``` -onLogoDown(() => { - micro_bit.showString("r", 100) -}) -``` - -* detect that the device is shaken - -``` -onShake(() => { - micro_bit.showString("shake", 100) -}) -``` - diff --git a/olddocs/js/publishing.md b/olddocs/js/publishing.md deleted file mode 100644 index 05069fdd..00000000 --- a/olddocs/js/publishing.md +++ /dev/null @@ -1,52 +0,0 @@ -# Publish a Script - -How to publish scripts. - -### @parent js/contents - - -Scripts that you create are periodically saved in the cloud, but only published scripts can be seen by other people. Once you publish a script, other people can run your script, post comments on it, tweak and re-publish it, or rate your script with a heart. - -### How to publish a script - -To publish a script from the TouchDevelop Editor: - -* when you're editing a script, click `script` and then click `publish` - -To publish a script from `My Scripts`: - -* go to **My Scripts* -* click a script on the left and then click `Publish` on the right - -**Publish options:** - -**Share with everyone**: click `publish` to publish your script so that anyone can find it using search or by browsing scripts. - -**Share with people you choose**: click `publish as hidden` to publish your script in a way that it is not discoverable by search (users will need to know your script's id to access it). - -When you publish a script, a url with a unique script id is created so that you can share your script with other people. To share a *publish as hidden* script, copy the url and give it to select people. There is also a `share` button in [script options](/js/editor). - -You can add a short publication note if you'd like. This note appears with the publishing history (on the script overview page). - -### Hidden scripts - -A hidden script is - -* not indexed by the search (so are never visible in search results) -* hidden from various lists, unless the person viewing the list is the user who created the script -* accessible to anyone who knows the hidden script's id -* accessible when it is the base of a public script - -The lists include: - -* list of scripts by the user -* list of derived scripts - -### Published scripts are public! - -**Do not store passwords or other confidential information** in your script code. Everyone will be able to see your script on the Internet forever once it is published. - -### Updates - -If you are working on a script, you might want to publish multiple updates of the same script. As long as you do not change the script name (and you are the author of the previous version), the published version will automatically be considered as the latest version of this script. - diff --git a/olddocs/js/quick-start.md b/olddocs/js/quick-start.md deleted file mode 100644 index 34c279cb..00000000 --- a/olddocs/js/quick-start.md +++ /dev/null @@ -1,34 +0,0 @@ -# The Quick Start Guide for Teachers - -The Quick Start Guide for Teachers #docs - -### ~hint - -**Spotty internet? No problem!** (1) When online, go to https://www.microbit.co.uk/app/ and bookmark this URL; (2) use the bookmark to reload the web app, even without the internet. - -### ~ - -The Quick Start Guide for Teachers is available in [PDF](https://microbit0.blob.core.windows.net/pub/tovulwsd/Quick-Start-Guide-for-Teachers.pdf). - -### Resources - -The currently available on-line resources from the Quick Start Guide are the - -* [scroll text tutorial](/js/tutorials/scroll-text) -* [flashing heart tutorial](/js/tutorials/flashing-heart) -* [button light tutorial](/js/tutorials/button-light) -* [digital key chain tutorial](/js/tutorials/digital-key-chain) -* [rock paper scissors tutorial](/lessons/rock-paper-scissors/tutorial) and [rock paper scissors challenges](/lessons/rock-paper-scissors/challenges) -* [digital pet tutorial](/lessons/digital-pet/tutorial) and [digital pet challenges](/lessons/digital-pet/challenges) -* [catch the egg game tutorial](/lessons/catch-the-egg-game/tutorial) and [catch the egg game challenges](/lessons/catch-the-egg-game/challenges) - -### Errata - -* compilation to the @boardname@ now works [off line](/offline), based on a new compiler in the web browser. The text and picture below replaces the text and picture on page 10 of the Guide: - -### How does my program get onto the @boardname@? - -For your program to work on the @boardname@, first it has to be compiled. Compiling means to translate a program into a more efficient computer language. When you hit the compile button on the Microsoft Touch Develop Editor interface, your program is compiled into a hex file that contains the machine code in the instruction set used by the ARM processor that is on your @boardname@. Compiling to ARM machine code actually happens in the web browser, where the code from script is joined with the machine code of the @boardname@ runtime. - -![](/static/mb/quick-start-0.png) - diff --git a/olddocs/js/reactive.md b/olddocs/js/reactive.md deleted file mode 100644 index a92f01af..00000000 --- a/olddocs/js/reactive.md +++ /dev/null @@ -1,149 +0,0 @@ -# The @boardname@ - a reactive system - -The @boardname@ is a reactive system. #docs - -### Computing systems - -What sort of a *computing system* is the @boardname@? - -### ~hint - -There are different types of computing systems, to address different kinds of problems that arise in practice: *transaction processing systems* are used by banks to handle huge numbers of financial transactions by their customers; *distributed systems* make a set of networked computers appear as one big computer (like Google’s search engine); there are also *parallel systems*, such as graphic cards, which perform a huge number of primitive operations simultaneously, using a great number of small processing cores. - -### ~ - -The @boardname@ is a *reactive system* – it reacts continuously to external events, such as a person pressing the A button of the @boardname@ or shaking the device. The reaction to an event may be to perform a computation, update variables, and change the display. After the device reacts to an event, it is ready to react to the next one. If this sounds like a computer game, that’s because most computer games are reactive systems too! - -### Responsiveness - -We want reactive systems to be responsive, which means to react in a timely manner to events. For example, when you play a computer game, it’s frustrating if you press a button to make a character jump, but it doesn’t immediately jump. A delay in reacting, or lack of responsiveness , can be the difference between life and death, both in the real and virtual worlds. - -Let’s consider a simple example: you want to program your @boardname@ to accurately count the number of times the A button has been pressed and continuously display the current count on the 5x5 [LED screen](/device/screen). Because the LED screen is small, we can only display one digit of a number at a time on it. The [show number](/reference/basic/show-number) function will scroll the digits of a number across the screen so you can read it. - -Let’s say that the current count is 42 and the number 42 is scrolling across the LED screen. This means there is some code executing to perform the scroll. So, what should happen if you press the A button during the scroll? It would be a bad idea to ignore the button press, so some code should record the occurrence of the button press. But we just said there already is code running in order to scroll the number 42! If we wait until the code scrolling the 42 has finished to look for a button press, we will miss the button press. We want to avoid this sort of unresponsiveness. - -### Concurrency - -To be responsive, a reactive system needs to be able to do several things at the same time (concurrently), just like you can. But the @boardname@ only has one CPU for executing your program, which means it can only execute one program instruction at a time. On the other hand, it can execute millions of instructions in a single second. This points the way to a solution. - -Think about how a motion picture projector works - it projects only 24 frames per second, yet this is good enough to provide the illusion of fluid motion on the screen. The @boardname@ can execute millions of instructions per second, so it seems quite possible for the device to both to smoothly scroll the number 42 across the LED screen while looking for button presses and counting them. - -Let’s think about three sequences of instructions: - -* Sequence S1 contains the instructions (let’s say several hundred thousand or so) that scroll the number 42 across the LED screen; -* Sequence S2 contains a few instructions to check if button A is pressed; -* Sequence S3 contains a few instructions to increment a counter. - -In order to be responsive, we would like to *interrupt* the execution of sequence S1 *periodically* to execute the sequence S2, which will check if button A is pressed, which looks like: - -![](/static/mb/device/reactive-0.png) - -The result is that it takes sequence S1 a little longer to complete, due to the interruptions to execute sequence S2, but we are checking often enough to detect a press of button A . When S2 detects a press of button A, then the sequence S3 can be executed before S1 resumes: - -![](/static/mb/device/reactive-1.png) - -As we’ll soon see, there are other choices for how the sequences can be ordered to achieve the desired result. - -### The @boardname@ scheduler and queuing up subprograms - -The @boardname@’s *scheduler* provides the capability to concurrently execute different code sequences, relieving us of a lot of low-level programming. In fact, scheduling is so useful that it is a part of every *operating system*! - -The first job of the scheduler is to allow multiple *subprograms* to be queued up for later execution . For our purposes, a subprogram is just a statement or sequence of statements in the context of a larger program. Consider the Touch Develop program below for counting button presses. - -``` -export function countButtonPresses() { - let count = 0 - input.onButtonPressed(Button.A, () => { - count = count + 1 - }) - basic.forever(() => { - basic.showNumber(count, 150) - }) -} -``` - -The program above contains three statements that execute in order from top to bottom. The first statement - -``` -let count1 = 0 -``` - -initializesthe variable `count`. The second statement - -``` -input.onButtonPressed(Button.A, () => { - count1 = count1 + 1 -}) -``` - -informs the scheduler that on each and every event of the A button being pressed, a subprogram (called the event handler) should be queued for execution. The event handler is demarcated by the do/end keywords; it increments the variable `count` by one. The second statement - -``` -basic.forever(() => { - basic.showNumber(count1, 150) -}) -``` - -queues a `forever` loop for later execution by the scheduler; the body of this loop (between the do/end keywords) displays the current value of variable `count` on the LED screen. - -The function ends after the execution of these three statements, but this is not the end of program execution! That’s because the function queued the `forever` loop for execution by the scheduler. - -The second job of the scheduler is to periodically interrupt execution to read (poll) the various inputs to the @boardname@ (the buttons, pins, etc.) and fire off events (such as “button A pressed”). Recall that the firing of an event causes the event handler subprogram associated with that event to be queued for later execution. The scheduler uses a timer built into the @boardname@ hardware to interrupt execution every 6 milliseconds and poll the inputs, which is more than fast enough to catch the quickest press of a button. - -### Cooperative passing of control - -How does the forever loop get to start execution? Furthermore, once the forever loop is running, how does any other subprogram (like the event handler that increments the count) ever get a chance to execute? - -The answer is “cooperation” and “passing”. Think of a football team doing a drill – there is one ball and each footballer gets to dribble the ball for a certain number of touches, after which they pass to another footballer. A footballer who never passes prevents all other footballers from dribbling. A cooperative footballer always passes to some other footballer after taking a few touches. - -If you hadn’t guessed already, a footballer represents subprogram and dribbling the ball corresponds to that subprogram executing. Only one subprogram gets to execute at a time, as there is only one ball (processor). Footballer Alice passing the ball to footballer Bob corresponds to stopping execution of Alice’s subprogram (and remembering where it stopped) and starting/resuming execution of Bob’s subprogram. - -We will call this “passing control of execution” rather than “passing the ball”. However, in the world of the @boardname@, the concurrently executing subprograms are not aware of each other, so they don’t actually pass control directly to one another. Rather they pass control of execution back to the scheduler and the scheduler determines the subprogram to pass control to next. The programmer inserts a call to the `pause` function to indicate a point in the subprogram where control of execution passes to the scheduler. Also, when a subprogram ends execution, control passes to the scheduler. - -Let’s take a look at the implementation of the `forever` statement to see an example of cooperative scheduling: - -![](/static/mb/device/reactive-2.png) - -The `forever` loop actually is a function that takes a subprogram (an *Action* in Touch Develop) as a parameter. The function uses the `control -> in background` function of the @boardname@ runtime to queue a `while true` loop for execution by the scheduler. The while loop has two statements. The first statement runs the subprogram represented by the `body` parameter. The second statement passes control to the scheduler (requesting to “sleep” for 20 milliseconds). - -Though the `while true` loop will repeatedly execute the body subprogram, between each execution of the body it will permit the scheduler to execute other subprograms. If the while loop did not contain the call to `pause`, then once control passed into the while loop, it would never pass back to the scheduler and no other subprogram would be able to execute (unless the body subprogram contained a call to `pause` itself). - -### Round-robin scheduling - -Now, we come to the third and final job of the scheduler, which is to determine which subprogram to pass control to next. The scheduler uses two queues to perform this task, the sleep queue and the run queue. The sleep queue contains the subprograms that have called the pause function and still have time left to sleep. The run queue contains all the non-sleeping subprograms, such as the event handlers queued by the firing of an event. - -The scheduler moves the subprogram that has just paused into the sleep queue and then removes the subprogram at the head of the run queue and resumes its execution. Once a subprogram’s sleep period is over, the scheduler moves it from the sleep queue to the back of the run queue. - -The property of such round-robin scheduling is that under the assumption that every subprogram periodically enters the sleep queue, then every subprogram will periodically get a chance to execute. - -### Putting it all together - -Let’s go back to the `count button presses` function and revisit its execution based on what we have learned about the @boardname@ scheduler. As detailed before, the function executes three steps to: (1) initialize the variable `count` to zero; (2) set up the event handler for each press of button A; (3) queue the forever loop to the run queue. - -The function then ends execution and control passes back to the scheduler. Let’s assume the user has not pressed any buttons . The scheduler finds the `forever` loop in the run queue and passes control to it. The loop first calls `basic -> show number(0,150)`. In the diagram below, we use “Show 0” to refer to the execution of this function: - -![](/static/mb/device/reactive-3.png) - -While "Show 0" (the blue sequence) is running, periodic interrupts by the scheduler (every 6 milliseconds) poll for button presses and queue an event handler for each press of button A. Let’s say that one button press takes place during this time, as shown above. This will cause an event handler (labelled “inc”) to be queued for later execution by the scheduler. Once the "Show 0" has completed, the loop then calls `basic -> pause(20)` to put the forever loop to sleep for 20 milliseconds and give the scheduler an opportunity to run any newly queued event handler. Control passes to the “inc” event handler which will increment the variable `count` from 0 to 1 and then complete, returning control to the scheduler. At some point, the `forever` loop moves from the sleep queue to the run queue; the `forever` loop then will resume and call `basic -> show number(1,150)`. - -### Final thoughts - -Through this example, we have seen that the @boardname@ scheduler enables you to create a program that is composed of concurrent subprograms. In essence, the programmer needs to only think about the concurrent subprograms cooperatively passing control back to the scheduler, making sure no subprogram hogs control (or “dribbles the ball without passing”) for too long. While a subprogram runs, the scheduler polls the buttons and other IO peripherals at a high frequency in order to fire off events and queue event handlers for later execution, but this is invisible to the programmer. - -As a result, you can easily add a new capability to the @boardname@ by just adding a new subprogram. For example, if you want to add a reset feature to the counter program, all you need to do is add a new event handler for a press of button B that sets the global variable "count" to zero, as shown below: - -``` -export function countButtonPressesWithReset() { - let count = 0 - input.onButtonPressed(Button.A, () => { - count = count + 1 - }) - basic.forever(() => { - basic.showNumber(count, 150) - }) - input.onButtonPressed(Button.B, () => { - count = 0 - }) -} -``` - diff --git a/olddocs/js/return.md b/olddocs/js/return.md deleted file mode 100644 index 57f45c22..00000000 --- a/olddocs/js/return.md +++ /dev/null @@ -1,49 +0,0 @@ -# Return - -Exit a function. - -### @parent js/statement - - -The return statement exits a [function](/js/function) and returns a value to the code that called the function. - -### Touch Develop syntax - -return *expression* - -### Square function - -``` -/** - * // return the value x * x - * @param x TODO - */ -export function square(x: number) : number { - let result: number - return x * x - return result -} -``` - -### The type of *expression* - -The type of *expression* should match the declared return type of the function; in the above example, the return type is Number and we see that the return expression `x * x` is a Number since the input parameter `x` is a Number. - -### Storing the returned value - -The following code calls the `square` function with the number 42 and stores the output parameter in the `result` variable: - -``` -let result1 = square(42) -``` - -`result` is the default variable name for the function output, as specified in the function - -### Lessons - -[transformers](/lessons/transformers) - -### See also - -[function](/js/function), [calling functions](/js/call), [function parameters](/js/functionparameters) - diff --git a/olddocs/js/scriptid.md b/olddocs/js/scriptid.md deleted file mode 100644 index fdbe476d..00000000 --- a/olddocs/js/scriptid.md +++ /dev/null @@ -1,31 +0,0 @@ -# script id - -What is the script id? #docs - -### @parent js/contents - - -the *script id* is a unique identifier that is given to each [published](/js/publishing) script. This way you can share your scripts with other people. - -### where can I find the script id? - -when your looking at your list of scripts (**My Scripts** area), the *script id* is displayed under the author name (it begins with a forward slash: /). - -TODO Diagram - -the script id in the example above is `/tuxi`. - -### search by script id - -you can type the script id directly into the search in the hub to find it. - -### sharing your scripts - -when you [publish a script](/js/publishing), you can copy the url (which includes the script id) and send it to people. - -if you forget to copy the url when you publish, there's also a `share` button in [script options](/js/editor). - -### see also - -[publish a script](/js/publishing) - diff --git a/olddocs/js/senses.md b/olddocs/js/senses.md deleted file mode 100644 index b716ef95..00000000 --- a/olddocs/js/senses.md +++ /dev/null @@ -1,46 +0,0 @@ -# @boardname@ senses - -A #microbit library that exposes orientation and movement events. - -A library that exposes orientation and movement events. - -* detect that the screen is facing up and the board is horizontal - -``` -onScreenUp(() => { - micro_bit.showString("screen up", 100) -}) -``` - -* detect that the screen is facing down and the board is horizontal - -``` -onScreenDown(() => { - micro_bit.showString("screen down", 100) -}) -``` - -* detect when the logo is up and the board is vertical - -``` -onLogoUp(() => { - micro_bit.showString("logo up", 100) -}) -``` - -* detect when the logo is down and the board is vertical - -``` -onLogoDown(() => { - micro_bit.showString("r", 100) -}) -``` - -* detect that the device is shaken - -``` -onShake(() => { - micro_bit.showString("shake", 100) -}) -``` - diff --git a/olddocs/js/serial-library.md b/olddocs/js/serial-library.md deleted file mode 100644 index 9b2789e0..00000000 --- a/olddocs/js/serial-library.md +++ /dev/null @@ -1,128 +0,0 @@ -# Serial Library - -The serial library #docs - -The **serial library** supports [serial communication](https://en.wikipedia.org/wiki/Serial_port) between the @boardname@ and another computer. Basically, this allows you to send data from the @boardname@ to your own computer. This is very useful for debugging purposes: you can add `write line` statements in your code and see them display on your computer as the program executes. - -The code below shows a simple script that sends a line when the @boardname@ starts and another line each time the button ``A`` is pressed. - -``` -serial.writeLine("started...") -input.onButtonPressed(Button.A, () => { - serial.writeLine("A pressed") -}) -``` - -## How to read the @boardname@'s serial output from your computer - -Unfortunately, using the serial library requires quite a bit of a setup. - -### Windows - -You must install a device driver (for the computer to recognize the serial interface of the @boardname@); then, you must also install a terminal emulator (which is going to connect to the @boardname@ and read its output). Here's how to do it: - -* Follow instructions at https://developer.mbed.org/handbook/Windows-serial-configuration in order to install the device driver -* Install a terminal emulator; we recommend [Tera Term](https://ttssh2.osdn.jp/index.html.en). At the time of this writing, the latest version is 4.88 and can be downloaded [from here](http://en.osdn.jp/frs/redir.php?m=jaist&f=%2Fttssh2%2F63767%2Fteraterm-4.88.exe). Follow the instructions from the installer. - -Once both the driver and the terminal emulator are installed, plug in the @boardname@ and wait until the device is fully setup. Then, open TeraTerm. - -* Hit `File` > `New Connection` -* Check "Serial"; in the dropdown menu, pick the COM port that says "mbed Serial Port". Hit `Ok`. -* In the menus, hit `Setup` > `Serial Port` and set the baud rate to `115200`. - -You should be good. Feel free to hit `Setup` > `Save Setup` in the menus to erase the default configuration file with a new one so that you don't have to type in the settings again. - -Please note that Windows will assign you a different COM port if you plug in another @boardname@. If you're juggling between @boardname@s, you'll have to change the COM port every time. - -### Alternative Windows setup with Putty - -If you prefer another terminal emulator (such as [PuTTY](http://www.putty.org/)), here are some instructions. - -* Open Windows's [Device Manager](https://windows.microsoft.com/en-us/windows/open-device-manager); expand the section called "Ports (COM & LPT)"; write down the com number for "mbed Serial Port" (e.g. COM14) -* Open PuTTY; on the main screen, use the following settings: Serial / COM14 / 115200. Replace COM14 with the COM port number you wrote down previously. Feel free to type in a name and hit "Save" to remember this configuration. - -![](/static/mb/serial-library-0.png) - -* (optional): in the "Terminal" section, check "implicit cr in every lf" - -![](/static/mb/serial-library-1.png) - -### Linux - -(Untested). - -* Plug in the @boardname@ -* Open a terminal -* `dmesg | tail` will show you which `/dev/` node the @boardname@ was assigned (e.g. `/dev/ttyUSB0`) -* Then, do: `screen /dev/ttyUSB0 115200` (install the `screen` program if you don't have it). To exit, run `Ctrl-A` `Ctrl-D`. - -Alternative programs include minicom, etc. - -### Mac OS - -* Plug in the @boardname@ -* Open a terminal -* `ls /dev/cu.*` will return to you a list of serial devices; one of them will look like `/dev/cu.usbmodem1422` (the exact number depends on your computer) -* `screen /dev/cu.usbmodem1422 115200` will open up the @boardname@'s serial output. To exit, hit `Ctrl-A` `Ctrl-D`. - -## Using the serial library in your programs - -If the ``serial`` button is not available, you will need first to add the ``@boardname@ serial`` library to your script: - -* tap on `add new` -* tap on `library` -* select `@boardname@ serial` - -### Writing data - -This is basically what you will use the serial library for: debugging purposes. - -* write a number - -``` -serial.writeNumber(42) -``` - -* write a string - -``` -serial.writeString("hello") -``` - -* write a line of text - -``` -serial.writeLine("this is a line") -``` - -Theoretically, you can dump more sophisticated data and then read it back in the event that two @boardname@s should be connected to each other over serial. We have not tested this scenario yet as we have yet to expose functionality that allows re-routing the serial ports to the edge connector. - -* write an image - -``` -let img = images.createImage(` -. . . . . -. # . # . -. . . . . -. . . . . -# # # # # -`) -serial.writeImage(img) -``` - -* write the current screen LED status - -``` -serial.writeScreen() -``` - -### Reading data - -This is useful if you have something connected at the other end. As explained above, this is not yet a scenario. - -* reads a line of text - -``` -let msg = serial.readString() -``` - diff --git a/olddocs/js/showcase.md b/olddocs/js/showcase.md deleted file mode 100644 index 18a26319..00000000 --- a/olddocs/js/showcase.md +++ /dev/null @@ -1,16 +0,0 @@ -# Showcase Scripts - -#docs - -## Get Started with These Hex Files! - -If you have a @boardname@ and would like to explore a few scripts, we've created the following hex files for you to copy to your @boardname@ - -### Flashing Heart - -This script introduces you to the LED display: - -* {hex:xzlzgl:hex file} -MACRO: hex* [Block Editor script](/jxislh) -* [Touch Develop script](/xzlzgl) - diff --git a/olddocs/js/simulator.md b/olddocs/js/simulator.md deleted file mode 100644 index 995e063c..00000000 --- a/olddocs/js/simulator.md +++ /dev/null @@ -1,44 +0,0 @@ -# Run Code in your Browser - -Run scripts in a web browser. - -While you're writing and testing your scripts, you'll mostly be running scripts in your browser by clicking the `run` button. Both the [Microsoft Block editor](/blocks/editor) and the [Touch Develop editor](/js/editor) have a `run` button above the coding area. - -*Note*: in the Touch Develop editor, the button actually is named `run main`, reflecting the fact that execution of a Touch Develop script always beings in the `main` function - -When you click `run main` in the Touch Develop editor, your code executes and the results are simulated on-screen, using an image of the @boardname@ device, like this: - - -In the picture above, [plot image](/reference/led/plot-image) create a heart image that appears on the @boardname@ simulator. - -The @boardname@ simulator let's you... - -* write and test code, even if you don't have a @boardname@ device -* test your code throughly before downloading and running your script on the @boardname@ - -### What does the simulator support? - -The @boardname@ simulator supports the Touch Develop [functions](/js/contents) and Microsoft [blocks](/blocks/contents), including those related to the LED screen, input buttons, the compass, accelerometer, and the digital I/O pins. - -* **LED screen**: the [LED screen](/device/screen) that appears on-screen shows you what you'll see on the @boardname@ device -* **input buttons**: when running code with [button is pressed](/reference/input/button-is-pressed) or [on button pressed](/reference/input/on-button-pressed) functions, click the on-screen A or B button -* **compass**: when running code that includes [compass heading](/reference/input/compass-heading), click and drag the on-screen compass needle to change the heading -* **accelerometer**: move your mouse over the on-screen @boardname@ device to simulate [acceleration](/reference/input/acceleration). The x and y axis values are shown on-screen. -* **digital pins**: you can click the on-screen digital pins (0 , 1, or 2) to turn them on or off (see [digital write pin](/reference/pins/digital-write-pin) and [digital read pin](/reference/pins/digital-read-pin) for more info). - -**Can't see the red LEDs on the simulator?** - -If you click on the white THEME button in the top right corner of the simulator, it will switch to an accessible version of the simulator, where the LEDs are displayed in blue on a white background. - -### All done? - -Once you're done writing and testing your code on the simulator, compile and run your script on your @boardname@ device. To find out how to do this, see [run scripts on the @boardname@](/device/usb). - -### Simulator vs @boardname@ - -Running your scripts in a web browser is a *simulation* of how your code will run on the @boardname@ device. When you run your script on your @boardname@ device, the results may differ slightly. For example, the timing may be subtly different when your script runs on the @boardname@ device (you may need to adjust your [pause](/reference/basic/pause) functions). For this reason, be sure to test your scripts on the @boardname@ device. - -### See also - -[run scripts on the @boardname@](/device/usb), [Microsoft Block editor](/blocks/editor), [Touch Develop editor](/js/editor) - diff --git a/olddocs/js/statements.md b/olddocs/js/statements.md deleted file mode 100644 index 0c7019c5..00000000 --- a/olddocs/js/statements.md +++ /dev/null @@ -1,41 +0,0 @@ -# statements, operators, and libaries - -Statements, operators, and libraries. - -### @parent js/language - - -TouchDevelop functions include statements and operators. - -### Statements - -TouchDevelop statements include: - -* [break](/js/break), to exit a loop before it has completed, usually used in conjunction with an [if](/reference/logic/if) statement -* [if](/reference/logic/if) conditional statement -* [for](/reference/loops/for) and [while](/js/while) loops -* [function](/js/function) -* [return](/js/return) -* [var](/reference/variables/var) (local variable declaration) - -### Operators - -TouchDevelop operators include: - -* [assignment operator](/reference/variables/assign) `:=` (to update variables) -* arithmetic operators (`+`, `-`, `*`, `/`, mod) operate on [Numbers](/reference/types/number) -* comparison operators (such as `>`, `=`) operate on [Numbers](/reference/types/number) -* boolean operators (`not`, `or`, `and`) operate on [Booleans](/reference/types/boolean) -* concat operator combines [Strings](/reference/types/string) - -### Libraries - -Libraries provide additional functions: - -* the [@boardname@ library](/js/contents) -* the [math](/js/math) and [bits](/js/bits) libraries - -### see also - -[TouchDevelop Documentation](/js/contents), [comments](/js/comment) - diff --git a/olddocs/js/string-functions.md b/olddocs/js/string-functions.md deleted file mode 100644 index 73ba8f39..00000000 --- a/olddocs/js/string-functions.md +++ /dev/null @@ -1,178 +0,0 @@ -# String Functions - -string-related functions. - -### @parent js/language - -The following string related functions are available in Touch Develop for the @boardname@: - -* **equals** - find out if two strings are the same -* **at** - get a character within a string -* **concat** - combine two strings -* **count** - get the number of characters in a string -* **substring** - get a portion of a string -* **to character code** - converts a character into a character code -* **to number** - converts a string into a number - -Select a string variable in the [Touch Develop editor](/js/editor) to see the following string functions: - -``` -/* placeholder */ -``` - -### ~hide - -``` -let str = "hi" -``` - -### ~ - -### equals - -find out if two strings are the same - -#### Syntax - -[String](/reference/types/string) `->` **equals** (other : [String](/reference/types/string)) *returns* [Boolean](/reference/types/boolean) - -#### Parameters - -* other - [String](/reference/types/string); a string - -#### Example - -the following code does something if `str` = "Hi": - -``` -if (str == "Hi") { - // add code to do something here -} -``` - -### at - -get a character within a string, using the specified index - -#### Syntax - -[String](/reference/types/string) `->` **at** (index: [Number](/reference/types/number)) *returns* [String](/reference/types/string) - -#### Parameters - -* index- [Number](/reference/types/number); the character number within a string (0 returns the first character) - -#### Example - -The following code gets the first character from the `str` string and stores it in the `first char` variable: - -``` -let firstChar = str[0] -``` - -### The `||` operator - -To combine two strings you can use the string concatenation operation `||` as shown below: - -``` -let s = "abc" + "def" -let evaluatesToTrue = s == "abcdef" -``` - -NOTE: position the cursor outside of the string quotes, right after the string, for the || operator to appear in the keyboard. - -### concat - -combine two strings; like the concat operator (`||`) - -#### Syntax - -[String](/reference/types/string) `->` **concat** (other : [String](/reference/types/string)) *returns* [String](/reference/types/string) - -#### Parameters - -* other- [String](/reference/types/string); a string - -#### Example - -The following code combines two strings and displays the string on screen: - -``` -str = "Hi " -str = str.concat("there") -basic.showString(str, 100) -``` - -### count - -get the number of characters in a string - -#### Syntax - -[String](/reference/types/string) `->` **count** *returns* [Number](/reference/types/number) - -#### Example - -The following example gets the length of the `str` variable and stores it in the `x` variable: - -``` -let x = str.length -``` - -### Substring - -get a portion of a string, using a starting point and length - -#### Syntax - -[String](/reference/types/string) `->` **substring** (start : [Number](/reference/types/number), length : [Number](/reference/types/number)) *returns* [String](/reference/types/string) - -#### Parameters - -* start - [Number](/reference/types/number); the starting character number (0 is the first character number in a string) -* length - [Number](/reference/types/number); the string length - -#### Example - -The following code gets characters 6, 7, and 8 from the `str` string: - -``` -let asubstring = str.substr(5, 3) -``` - -### to character code - -converts the first character of a string into a character code number (unicode) - -#### Syntax - -[String](/reference/types/string) `->` **to character code** *returns* [Number](/reference/types/number) - -#### Example - -The following code converts the first character of `str` into a character code and stores the code in `x`: - -``` -x = str.toCharacterCode() -``` - -### to number - -converts a string into a number - -#### Syntax - -[String](/reference/types/string) `->` **to number** *returns* [Number](/reference/types/number) - -#### Example - -The following code converts `str` into a number and stores it in `x`: - -``` -x = parseFloat(str) -``` - -### See also - -[string](/reference/types/string), [number](/reference/types/number), [show string](/reference/basic/show-string) - diff --git a/olddocs/js/string.md b/olddocs/js/string.md deleted file mode 100644 index 109c077a..00000000 --- a/olddocs/js/string.md +++ /dev/null @@ -1,60 +0,0 @@ -# String - -a piece of text. - -### @parent js/language - -A *String* is a sequence of characters. For the @boardname@, ASCII character codes 32 to 126 are supported; letters, digits, punctuation marks, and a few symbols. All other character codes appear as a ? on the [LED screen](/device/screen). - -### Declare a string - -Use the [var statement](/reference/variables/var) and the [assignment operator](/reference/variables/assign) `:=` to declare a new *local* string variable. Like this: - -``` -let str = "this is a string" -``` - -To declare a string using the [Touch Develop editor](/js/editor): - -1. Click `var` (on the Code Keyboard). - -2. Type a name for your new string variable. - -2. Click on the right side of the `:=` operator. - -3. Type `"` (or click `"abc"`) and then type a string like `hello`. - -4. Click the check mark. - -Your code should look something like this: - -``` -let salutation = "Hello" -``` - -### The function `show string` - -Use [show string](/reference/basic/show-string) to display a string on the [LED screen](/device/screen). If the string is multiple characters, the string scrolls right to left. The following example displays `Hello world!` on the @boardname@ screen: - -``` -basic.showString("Hello world!", 100) -``` - -The first parameter of `show string` specifies the string, and the second parameter specifies the number of milliseconds between scrolling by one LED column - the larger the value, the slower the scroll will be. - -### More string functions - -Want to compare or concatenate strings? Check out the [string functions](/reference/types/string-functions). - -### Global string variables - -Unlike [local variables](/reference/variables/var), global variables are accessible across functions and in nested code blocks. To find out how to declare a global string variable, see [global variables](/js/data). - -### Lessons - -[letter up](/lessons/letter-up) - -### See also - -[local variables](/reference/variables/var), [global variables](/js/data), [string functions](/reference/types/string-functions), [Number](/reference/types/number), [show string](/reference/basic/show-string) - diff --git a/olddocs/js/types.md b/olddocs/js/types.md deleted file mode 100644 index 29adebda..00000000 --- a/olddocs/js/types.md +++ /dev/null @@ -1,19 +0,0 @@ -# types - -Touch Develop types. - -### @parent language - - -A *type* refers to a class of data and the operations permitted on that data. The following types are supported by Touch Develop for the @boardname@: - -* **[String](/reference/types/string)**: a sequence of characters -* **[Number](/reference/types/number)**: an integer number (32-bit signed) -* **[Boolean](/reference/types/boolean)**: true or false -* **[Image](/reference/image/image)**: a collection of [@boardname@ LED states](/device/screen) (on/off) -* *more types coming!!!* - -### see also - -[local variables](/reference/variables/var), [global variables](/js/data), [assignment operator](/reference/variables/assign) - diff --git a/olddocs/js/var.md b/olddocs/js/var.md deleted file mode 100644 index 4fe22280..00000000 --- a/olddocs/js/var.md +++ /dev/null @@ -1,108 +0,0 @@ -# Local Variables - -How to define and use local variables. - -### @parent language - - -A variable is a place where you can store and retrieve data. Variables have a name, a [type](/js/types), and value: - -* *name* is how you'll refer to the variable -* *type* refers to the kind of data a variable can store -* *value* refers to what's stored in the variable - -### `var` and `let` statement - -The ``var`` keyword declares a global variables that is defined within the entire scope of the function. -The ``let`` keyword defined a block-scoped variable, similarly to other languages like Java, C# or C. - -For example, this code stores the number `2` in the `num1` variable: - -* number variable -```blocks -let num1 = 2 -``` - -* string variable -```blocks -let name = "Mike" -``` - -* boolean variable - -```blocks -let bool = true -``` - -* image variable -```blocks -let img = images.createImage(` -. . # . . -. # # # . -# # # # # -. # # # . -. . # . . -`) -``` - -See [Image](/reference/image/image) for info on creating and using image variables. -### Using variables - -Once you've defined a variable, just use the variable's name whenever you need what's stored in the variable. For example, the following code shows the value stored in `counter` on the LED screen: - -``` -let counter = 5; -basic.showNumber(counter, 100) -``` - -To change the contents of a variable use the assignment operator `:=`. The following code sets `counter` to 1 and then increments `counter` by 10: - -``` -let counter = 0; -counter = 1 -counter = counter + 10 -``` - -### Why use variables? - -Variables help simplify your code. For example, instead of turning on LEDs one by one like this: - -``` -led.plot(0, 0) -led.plot(1, 1) -led.plot(2, 2) -led.plot(3, 3) -led.plot(4, 4) -``` - -You can use a variable (`i`) and a [for loop](/reference/loops/for) to plot the same series of points (`i` is incremented by 1, each time the loop repeats): - -``` -for (let i = 0; i < 5; i++) { - led.plot(i, i) -} -``` - -### Local vs global variables - -Local variables exist only within the function or block of code where they're defined. Local variables don't exist outside of where they're defined. For example: - -``` -if (led.brightness() > 127) { - let y = 1 - // `y` variable exists here -} else { - // `y` variable does not exist here -} -``` - -Use **global variables** when you need to access a variable in nested code blocks or across multiple functions. - -### Lessons - -[guess the number](/lessons/guess-the-number), [digi yoyo](/lessons/digi-yoyo), [rock paper scissors](/lessons/rock-paper-scissors), [love meter](/lessons/love-meter) - -### See also - -[types](/reference/types), [assignment operator](/reference/variables/assign) - diff --git a/olddocs/js/while.md b/olddocs/js/while.md deleted file mode 100644 index c50dd1b3..00000000 --- a/olddocs/js/while.md +++ /dev/null @@ -1,73 +0,0 @@ -# While - -Repeat code in a loop while a condition is true. - -### @parent js/language - - -Repeat code while a [Boolean](/reference/types/boolean) `condition` is true. - -### ~hide - -``` -let condition = false -``` - -### ~ - -### Block Editor - - -### Touch Develop - -``` -while (condition) { - // This code runs if `condition` is `true` -} -``` - -The while loop has a *condition* that evaluates to a [Boolean](/reference/types/boolean) value. After the `do` keyword, add the code that you want to run while the `condition` is `true`. The while loop concludes with `end while`. - -The condition is tested before any code runs. Which means that if the condition is false, the code inside the loop doesn't execute. Use the [break statement](/js/break) to exit a while loop before it's complete. - -### Example: diagonal line - -The following example uses a while loop to make a diagonal line on the LED screen (points `0, 0`, `1, 1`, `2, 2`, `3, 3`, `4, 4`). - -// index is set to 4 - -``` -let index = 4 -while (index >= 0) { - led.plot(index, index) - // // subtract 1 from `index` each time through loop - index = index - 1 -} -``` - -### Example: count until A button pressed - -The following example shows numbers on the screen(0, 1, 2, 3...), until the "A" button is pressed. - -``` -let x = 0 -while (true) { - basic.showNumber(x, 100) - let pressed = input.buttonIsPressed("A") - if (pressed) { - break - } else { - x = x + 1 - } - basic.pause(1000) -} -``` - -### Lessons - -[rotation animation](/lessons/rotation-animation), [digi yoyo](/lessons/digi-yoyo) - -### See also - -[on button pressed](/reference/input/on-button-pressed), [for](/reference/loops/for), [if](/reference/logic/if), [break](/js/break), [forever](/reference/basic/forever), [in background](/reference/control/in-background) - diff --git a/package-lock.json b/package-lock.json index 7bae4844..b99330ef 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,18 +1,150 @@ { "name": "pxt-calliope", - "version": "2.0.2", + "version": "2.1.25", "lockfileVersion": 1, "requires": true, "dependencies": { - "ajv": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.1.tgz", - "integrity": "sha1-s4u4h22ehr7plJVqBOch6IskjrI=", + "@jacdac/jacdac-ts": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/@jacdac/jacdac-ts/-/jacdac-ts-0.0.9.tgz", + "integrity": "sha512-eMps8XvVwHXTQFkQu8SZAKaBczufk4ubp3uoU4+q5fipDgPXRfO3ykHxTgj5gtk5ZjVq/zNMfSlB3is7ohQtIw==", "requires": { - "co": "4.6.0", - "fast-deep-equal": "1.0.0", - "fast-json-stable-stringify": "2.0.0", - "json-schema-traverse": "0.3.1" + "@types/w3c-web-usb": "^1.0.3", + "webusb": "^1.1.1" + } + }, + "@types/bluebird": { + "version": "2.0.33", + "resolved": "https://registry.npmjs.org/@types/bluebird/-/bluebird-2.0.33.tgz", + "integrity": "sha512-iq7ss0qO31YCYeLEPrBoVMDLw1dBotOS7394a+Dj2CSvQNjQfJvryVo9es5ghvQZmIqO7Q0tlCe9YpwTZKOoXg==", + "dev": true + }, + "@types/jquery": { + "version": "3.2.16", + "resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.2.16.tgz", + "integrity": "sha512-q2WC02YxQoX2nY1HRKlYGHpGP1saPmD7GN0pwCDlTz35a4eOtJG+aHRlXyjCuXokUukSrR2aXyBhSW3j+jPc0A==", + "dev": true + }, + "@types/marked": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@types/marked/-/marked-0.3.0.tgz", + "integrity": "sha512-CSf9YWJdX1DkTNu9zcNtdCcn6hkRtB5ILjbhRId4ZOQqx30fXmdecuaXhugQL6eyrhuXtaHJ7PHI+Vm7k9ZJjg==", + "dev": true + }, + "@types/node": { + "version": "8.0.53", + "resolved": "https://registry.npmjs.org/@types/node/-/node-8.0.53.tgz", + "integrity": "sha512-54Dm6NwYeiSQmRB1BLXKr5GELi0wFapR1npi8bnZhEcu84d/yQKqnwwXQ56hZ0RUbTG6L5nqDZaN3dgByQXQRQ==", + "dev": true + }, + "@types/react": { + "version": "16.0.25", + "resolved": "https://registry.npmjs.org/@types/react/-/react-16.0.25.tgz", + "integrity": "sha512-K79zMwWRzQ2db+nPoKpi3gA/KmLo6ZQgT4iO2QPEUdBO7as0PcgrmU9KHYzIO3V6lbD7gRjOM0/nUch6xBfOvQ==", + "dev": true + }, + "@types/react-dom": { + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-16.0.3.tgz", + "integrity": "sha512-xAvZiGhQlEhjStoKktoai8CelXVFBaSN6JX4vy1UQioRba3c2vum1TGzR0thHoEauZtIwzWg8mos0AHu2ne4jw==", + "dev": true, + "requires": { + "@types/node": "*", + "@types/react": "*" + } + }, + "@types/usb": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@types/usb/-/usb-1.5.1.tgz", + "integrity": "sha512-1qhcYMLJ0I2HcRG3G/nBcRZ0KrrTdGdUNcCkEVgcga4KMlDXWh6LZJjVA6MiWEDa+BOaQTEfGJfuNaQ71IQOpg==", + "requires": { + "@types/node": "*" + }, + "dependencies": { + "@types/node": { + "version": "12.12.8", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.8.tgz", + "integrity": "sha512-XLla8N+iyfjvsa0KKV+BP/iGSoTmwxsu5Ci5sM33z9TjohF72DEz95iNvD6pPmemvbQgxAv/909G73gUn8QR7w==" + } + } + }, + "@types/w3c-web-usb": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@types/w3c-web-usb/-/w3c-web-usb-1.0.3.tgz", + "integrity": "sha512-XilIvno46lLRyOj/1G5z88M6iimYs3dr3LNdSN9UxSWifytKsBMmRtAi53X3j0ThrrqyVotqrSeaYv9a0I131w==" + }, + "@types/web-bluetooth": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.4.tgz", + "integrity": "sha512-C+BgVBBGY9c6ixcc5PsKAmGaCy3bswZ5zx/AWIAik9dgFuBkFsXBA3ze69jJi05xdZQ99QkfBSVIX6zl+6Tmww==", + "dev": true + }, + "JSONStream": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", + "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", + "requires": { + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" + } + }, + "accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "requires": { + "mime-types": "~2.1.24", + "negotiator": "0.6.2" + } + }, + "acorn": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.1.0.tgz", + "integrity": "sha512-kL5CuoXA/dgxlBbVrflsflzQ3PAas7RYZB52NOm/6839iVYJgKMJ3cQJD+t2i5+qFa8h3MDpEOJiS64E8JLnSQ==" + }, + "acorn-node": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.8.2.tgz", + "integrity": "sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==", + "requires": { + "acorn": "^7.0.0", + "acorn-walk": "^7.0.0", + "xtend": "^4.0.2" + } + }, + "acorn-walk": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.0.0.tgz", + "integrity": "sha512-7Bv1We7ZGuU79zZbb6rRqcpxo3OY+zrdtloZWoyD8fmGX+FeXRjE+iuGkZjSXLVovLzrsvMGMy0EkwA0E0umxg==" + }, + "addressparser": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/addressparser/-/addressparser-1.0.1.tgz", + "integrity": "sha1-R6++GiqSYhkdtoOOT9HTm0CCF0Y=", + "optional": true + }, + "after": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", + "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=" + }, + "agent-base": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", + "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", + "requires": { + "es6-promisify": "^5.0.0" + } + }, + "ajv": { + "version": "6.10.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz", + "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==", + "requires": { + "fast-deep-equal": "^2.0.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" } }, "alphanum-sort": { @@ -20,206 +152,50 @@ "resolved": "https://registry.npmjs.org/alphanum-sort/-/alphanum-sort-1.0.2.tgz", "integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=" }, - "ansi-bgblack": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ansi-bgblack/-/ansi-bgblack-0.1.1.tgz", - "integrity": "sha1-poulAHiHcBtqr74/oNrf36juPKI=", + "amqplib": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/amqplib/-/amqplib-0.5.5.tgz", + "integrity": "sha512-sWx1hbfHbyKMw6bXOK2k6+lHL8TESWxjAx5hG8fBtT7wcxoXNIsFxZMnFyBjxt3yL14vn7WqBDe5U6BGOadtLg==", + "optional": true, "requires": { - "ansi-wrap": "0.1.0" - } - }, - "ansi-bgblue": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ansi-bgblue/-/ansi-bgblue-0.1.1.tgz", - "integrity": "sha1-Z73ATtybm1J4lp2hlt6j11yMNhM=", - "requires": { - "ansi-wrap": "0.1.0" - } - }, - "ansi-bgcyan": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ansi-bgcyan/-/ansi-bgcyan-0.1.1.tgz", - "integrity": "sha1-WEiUJWAL3p9VBwaN2Wnr/bUP52g=", - "requires": { - "ansi-wrap": "0.1.0" - } - }, - "ansi-bggreen": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ansi-bggreen/-/ansi-bggreen-0.1.1.tgz", - "integrity": "sha1-TjGRJIUplD9DIelr8THRwTgWr0k=", - "requires": { - "ansi-wrap": "0.1.0" - } - }, - "ansi-bgmagenta": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ansi-bgmagenta/-/ansi-bgmagenta-0.1.1.tgz", - "integrity": "sha1-myhDLAduqpmUGGcqPvvhk5HCx6E=", - "requires": { - "ansi-wrap": "0.1.0" - } - }, - "ansi-bgred": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ansi-bgred/-/ansi-bgred-0.1.1.tgz", - "integrity": "sha1-p2+Sg4OCukMpCmwXeEJPmE1vEEE=", - "requires": { - "ansi-wrap": "0.1.0" - } - }, - "ansi-bgwhite": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ansi-bgwhite/-/ansi-bgwhite-0.1.1.tgz", - "integrity": "sha1-ZQRlE3elim7OzQMxmU5IAljhG6g=", - "requires": { - "ansi-wrap": "0.1.0" - } - }, - "ansi-bgyellow": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ansi-bgyellow/-/ansi-bgyellow-0.1.1.tgz", - "integrity": "sha1-w/4usIzUdmSAKeaHTRWgs49h1E8=", - "requires": { - "ansi-wrap": "0.1.0" - } - }, - "ansi-black": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ansi-black/-/ansi-black-0.1.1.tgz", - "integrity": "sha1-9hheiJNgslRaHsUMC/Bj/EMDJFM=", - "requires": { - "ansi-wrap": "0.1.0" - } - }, - "ansi-blue": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ansi-blue/-/ansi-blue-0.1.1.tgz", - "integrity": "sha1-FbgEmQ6S/JyoxUds6PaZd3wh7b8=", - "requires": { - "ansi-wrap": "0.1.0" - } - }, - "ansi-bold": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ansi-bold/-/ansi-bold-0.1.1.tgz", - "integrity": "sha1-PmOVCvWswq4uZw5vZ96xFdGl9QU=", - "requires": { - "ansi-wrap": "0.1.0" - } - }, - "ansi-colors": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-0.2.0.tgz", - "integrity": "sha1-csMd4qDZoszQysMMyYI+6y9kNLU=", - "requires": { - "ansi-bgblack": "0.1.1", - "ansi-bgblue": "0.1.1", - "ansi-bgcyan": "0.1.1", - "ansi-bggreen": "0.1.1", - "ansi-bgmagenta": "0.1.1", - "ansi-bgred": "0.1.1", - "ansi-bgwhite": "0.1.1", - "ansi-bgyellow": "0.1.1", - "ansi-black": "0.1.1", - "ansi-blue": "0.1.1", - "ansi-bold": "0.1.1", - "ansi-cyan": "0.1.1", - "ansi-dim": "0.1.1", - "ansi-gray": "0.1.1", - "ansi-green": "0.1.1", - "ansi-grey": "0.1.1", - "ansi-hidden": "0.1.1", - "ansi-inverse": "0.1.1", - "ansi-italic": "0.1.1", - "ansi-magenta": "0.1.1", - "ansi-red": "0.1.1", - "ansi-reset": "0.1.1", - "ansi-strikethrough": "0.1.1", - "ansi-underline": "0.1.1", - "ansi-white": "0.1.1", - "ansi-yellow": "0.1.1", - "lazy-cache": "2.0.2" - } - }, - "ansi-cyan": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ansi-cyan/-/ansi-cyan-0.1.1.tgz", - "integrity": "sha1-U4rlKK+JgvKK4w2G8vF0VtJgmHM=", - "requires": { - "ansi-wrap": "0.1.0" - } - }, - "ansi-dim": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ansi-dim/-/ansi-dim-0.1.1.tgz", - "integrity": "sha1-QN5MYDqoCG2Oeoa4/5mNXDbu/Ww=", - "requires": { - "ansi-wrap": "0.1.0" - } - }, - "ansi-gray": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ansi-gray/-/ansi-gray-0.1.1.tgz", - "integrity": "sha1-KWLPVOyXksSFEKPetSRDaGHvclE=", - "requires": { - "ansi-wrap": "0.1.0" - } - }, - "ansi-green": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ansi-green/-/ansi-green-0.1.1.tgz", - "integrity": "sha1-il2al55FjVfEDjNYCzc5C44Q0Pc=", - "requires": { - "ansi-wrap": "0.1.0" - } - }, - "ansi-grey": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ansi-grey/-/ansi-grey-0.1.1.tgz", - "integrity": "sha1-WdmLasK6GfilF5jphT+6eDOaM8E=", - "requires": { - "ansi-wrap": "0.1.0" - } - }, - "ansi-hidden": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ansi-hidden/-/ansi-hidden-0.1.1.tgz", - "integrity": "sha1-7WpMSY0rt8uyidvyqNHcyFZ/rg8=", - "requires": { - "ansi-wrap": "0.1.0" - } - }, - "ansi-inverse": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ansi-inverse/-/ansi-inverse-0.1.1.tgz", - "integrity": "sha1-tq9Fgm/oJr+1KKbHmIV5Q1XM0mk=", - "requires": { - "ansi-wrap": "0.1.0" - } - }, - "ansi-italic": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ansi-italic/-/ansi-italic-0.1.1.tgz", - "integrity": "sha1-EEdDRj9iXBQqA2c5z4XtpoiYbyM=", - "requires": { - "ansi-wrap": "0.1.0" - } - }, - "ansi-magenta": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ansi-magenta/-/ansi-magenta-0.1.1.tgz", - "integrity": "sha1-BjtboW+z8j4c/aKwfAqJ3hHkMK4=", - "requires": { - "ansi-wrap": "0.1.0" - } - }, - "ansi-red": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ansi-red/-/ansi-red-0.1.1.tgz", - "integrity": "sha1-jGOPnRCAgAo1PJwoyKgcpHBdlGw=", - "requires": { - "ansi-wrap": "0.1.0" + "bitsyntax": "~0.1.0", + "bluebird": "^3.5.2", + "buffer-more-ints": "~1.0.0", + "readable-stream": "1.x >=1.1.9", + "safe-buffer": "~5.1.2", + "url-parse": "~1.4.3" + }, + "dependencies": { + "bluebird": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.1.tgz", + "integrity": "sha512-DdmyoGCleJnkbp3nkbxTLJ18rjDsE4yCggEwKNXkeV123sPNfOCYeDoeuOY+F2FrSjO1YXcTU+dsy96KMy+gcg==", + "optional": true + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "optional": true + }, + "readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "optional": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "optional": true + } } }, "ansi-regex": { @@ -227,78 +203,53 @@ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" }, - "ansi-reset": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ansi-reset/-/ansi-reset-0.1.1.tgz", - "integrity": "sha1-5+cSksPH3c1NYu9KbHwFmAkRw7c=", - "requires": { - "ansi-wrap": "0.1.0" - } - }, - "ansi-strikethrough": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ansi-strikethrough/-/ansi-strikethrough-0.1.1.tgz", - "integrity": "sha1-2Eh3FAss/wfRyT685pkE9oiF5Wg=", - "requires": { - "ansi-wrap": "0.1.0" - } - }, "ansi-styles": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" }, - "ansi-underline": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ansi-underline/-/ansi-underline-0.1.1.tgz", - "integrity": "sha1-38kg9Ml7WXfqFi34/7mIMIqqcaQ=", + "anymatch": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz", + "integrity": "sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==", "requires": { - "ansi-wrap": "0.1.0" + "micromatch": "^2.1.5", + "normalize-path": "^2.0.0" } }, - "ansi-white": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ansi-white/-/ansi-white-0.1.1.tgz", - "integrity": "sha1-nHe3wZPF7pkuYBHTbsTJIbRXiUQ=", - "requires": { - "ansi-wrap": "0.1.0" - } - }, - "ansi-wrap": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz", - "integrity": "sha1-qCJQ3bABXponyoLoLqYDu/pF768=" - }, - "ansi-yellow": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ansi-yellow/-/ansi-yellow-0.1.1.tgz", - "integrity": "sha1-y5NW8vRscy8OMZnmEClVp32oPB0=", - "requires": { - "ansi-wrap": "0.1.0" - } + "applicationinsights-js": { + "version": "1.0.20", + "resolved": "https://registry.npmjs.org/applicationinsights-js/-/applicationinsights-js-1.0.20.tgz", + "integrity": "sha512-vN6fEv2fNPZtw76/mv5OJ44cTP/VzSDahdXVIGnRB5Apnf2/9PIl4IyWpwS9biG53I1sWvkw83RjdrAnsIKoRQ==" }, "aproba": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha1-aALmJk79GMeQobDVF/DyYnvyyUo=", - "optional": true + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" }, "are-we-there-yet": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz", - "integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=", - "optional": true, + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", + "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", "requires": { - "delegates": "1.0.0", - "readable-stream": "2.3.3" + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" } }, "argparse": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz", - "integrity": "sha1-c9g7wmP4bpf4zE9rrhsOkKfSLIY=", + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "requires": { - "sprintf-js": "1.0.3" + "sprintf-js": "~1.0.2" + } + }, + "arr-diff": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", + "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", + "requires": { + "arr-flatten": "^1.0.1" } }, "arr-flatten": { @@ -306,65 +257,146 @@ "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==" }, - "arr-swap": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arr-swap/-/arr-swap-1.0.1.tgz", - "integrity": "sha1-FHWQ7WX8gVvAf+8Jl8Llgj1kNTQ=", - "optional": true, - "requires": { - "is-number": "3.0.0" - } + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=" + }, + "array-slice": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-0.2.3.tgz", + "integrity": "sha1-3Tz7gO15c6dRF82sabC5nshhhvU=" + }, + "array-unique": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", + "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=" + }, + "arraybuffer.slice": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz", + "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==" }, "asap": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=", - "dev": true, "optional": true }, "asn1": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", - "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=" + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "asn1.js": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", + "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", + "requires": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "assert": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz", + "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==", + "requires": { + "object-assign": "^4.1.1", + "util": "0.10.3" + }, + "dependencies": { + "inherits": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", + "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=" + }, + "util": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", + "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", + "requires": { + "inherits": "2.0.1" + } + } + } }, "assert-plus": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" }, + "assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==" + }, "assign-symbols": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=" + }, + "ast-types": { + "version": "0.13.2", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.2.tgz", + "integrity": "sha512-uWMHxJxtfj/1oZClOxDEV1sQ1HCDkA4MG8Gr69KKeBjEVH0R84WlejZ0y2DcwyBlpAEMltmVYkVgqfLFb2oyiA==", "optional": true }, + "async": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", + "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", + "optional": true, + "requires": { + "lodash": "^4.17.14" + } + }, + "async-each": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", + "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==" + }, + "async-limiter": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==" + }, "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" }, + "atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==" + }, "autoprefixer": { "version": "6.7.7", "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-6.7.7.tgz", "integrity": "sha1-Hb0cg1ZY41zj+ZhAmdsAWFx4IBQ=", "requires": { - "browserslist": "1.7.7", - "caniuse-db": "1.0.30000782", - "normalize-range": "0.1.2", - "num2fraction": "1.2.2", - "postcss": "5.2.18", - "postcss-value-parser": "3.3.0" + "browserslist": "^1.7.6", + "caniuse-db": "^1.0.30000634", + "normalize-range": "^0.1.2", + "num2fraction": "^1.2.2", + "postcss": "^5.2.16", + "postcss-value-parser": "^3.2.3" }, "dependencies": { "postcss": { "version": "5.2.18", "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha1-ut+hSX1GJE9jkPWLMZgw2RB4U8U=", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", "requires": { - "chalk": "1.1.3", - "js-base64": "2.4.0", - "source-map": "0.5.7", - "supports-color": "3.2.3" + "chalk": "^1.1.3", + "js-base64": "^2.1.9", + "source-map": "^0.5.6", + "supports-color": "^3.2.3" } } } @@ -375,108 +407,550 @@ "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" }, "aws4": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz", - "integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=" + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", + "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==" + }, + "axios": { + "version": "0.15.3", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.15.3.tgz", + "integrity": "sha1-LJ1jiy4ZGgjqHWzJiOrda6W9wFM=", + "optional": true, + "requires": { + "follow-redirects": "1.0.0" + }, + "dependencies": { + "follow-redirects": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.0.0.tgz", + "integrity": "sha1-jjQpjL0uF28lTv/sdaHHjMhJ/Tc=", + "optional": true, + "requires": { + "debug": "^2.2.0" + } + } + } + }, + "backo2": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", + "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=" }, "balanced-match": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz", - "integrity": "sha1-yz8+PHMtwPAe5wtAPzAuYddwmDg=" + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "requires": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" + } + } + }, + "base64-arraybuffer": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz", + "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg=" + }, + "base64-js": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", + "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==" + }, + "base64id": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-1.0.0.tgz", + "integrity": "sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY=" }, "bcrypt-pbkdf": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", - "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", - "optional": true, + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", "requires": { - "tweetnacl": "0.14.5" + "tweetnacl": "^0.14.3" } }, + "better-assert": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz", + "integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=", + "requires": { + "callsite": "1.0.0" + } + }, + "binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==" + }, "bindings": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.3.0.tgz", - "integrity": "sha1-s0b27PapX1qBXFg5/HzbIlAvHtc=", - "optional": true + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "requires": { + "file-uri-to-path": "1.0.0" + } }, - "bl": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.1.tgz", - "integrity": "sha1-ysMo977kVzDUBLaSID/LWQ4XLV4=", + "bitsyntax": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/bitsyntax/-/bitsyntax-0.1.0.tgz", + "integrity": "sha512-ikAdCnrloKmFOugAfxWws89/fPc+nw0OOG1IzIE72uSOg/A3cYptKCjSUhDTuj7fhsJtzkzlv7l3b8PzRHLN0Q==", "optional": true, "requires": { - "readable-stream": "2.3.3" + "buffer-more-ints": "~1.0.0", + "debug": "~2.6.9", + "safe-buffer": "~5.1.2" } }, + "bl": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-3.0.0.tgz", + "integrity": "sha512-EUAyP5UHU5hxF8BPT0LKW8gjYLhq1DQIcneOX/pL/m2Alo+OYDQAJlHq+yseMP50Os2nHXOSic6Ss3vSQeyf4A==", + "requires": { + "readable-stream": "^3.0.1" + }, + "dependencies": { + "readable-stream": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz", + "integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, + "blob": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz", + "integrity": "sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig==" + }, "bluebird": { "version": "3.5.1", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz", - "integrity": "sha1-2VUfnemPH82h5oPRfukaBgLuLrk=" + "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==" + }, + "bn.js": { + "version": "4.11.8", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", + "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==" + }, + "body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "requires": { + "bytes": "3.1.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "qs": "6.7.0", + "raw-body": "2.4.0", + "type-is": "~1.6.17" + } }, "boom": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz", - "integrity": "sha1-T4owBctKfjiJ90kDD9JbluAdLjE=", + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", + "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", "requires": { - "hoek": "4.2.0" + "hoek": "2.x.x" } }, "brace-expansion": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", - "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "requires": { - "balanced-match": "1.0.0", + "balanced-match": "^1.0.0", "concat-map": "0.0.1" + } + }, + "braces": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", + "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", + "requires": { + "expand-range": "^1.8.1", + "preserve": "^0.2.0", + "repeat-element": "^1.1.2" + } + }, + "brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" + }, + "browser-pack": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/browser-pack/-/browser-pack-6.1.0.tgz", + "integrity": "sha512-erYug8XoqzU3IfcU8fUgyHqyOXqIE4tUTTQ+7mqUjQlvnXkOO6OlT9c/ZoJVHYoAaqGxr09CN53G7XIsO4KtWA==", + "requires": { + "JSONStream": "^1.0.3", + "combine-source-map": "~0.8.0", + "defined": "^1.0.0", + "safe-buffer": "^5.1.1", + "through2": "^2.0.0", + "umd": "^3.0.0" + } + }, + "browser-resolve": { + "version": "1.11.3", + "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.3.tgz", + "integrity": "sha512-exDi1BYWB/6raKHmDTCicQfTkqwN5fioMFV4j8BsfMU4R2DK/QfZfK7kOVkmWCNANf0snkBzqGqAJBao9gZMdQ==", + "requires": { + "resolve": "1.1.7" }, "dependencies": { - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + "resolve": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=" } } }, + "browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==" + }, + "browserify": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/browserify/-/browserify-16.2.0.tgz", + "integrity": "sha512-yotdAkp/ZbgDesHQBYU37zjc29JDH4iXT8hjzM1fdUVWogjARX0S1cKeX24Ci6zZ+jG+ADmCTRt6xvtmJnI+BQ==", + "requires": { + "JSONStream": "^1.0.3", + "assert": "^1.4.0", + "browser-pack": "^6.0.1", + "browser-resolve": "^1.11.0", + "browserify-zlib": "~0.2.0", + "buffer": "^5.0.2", + "cached-path-relative": "^1.0.0", + "concat-stream": "^1.6.0", + "console-browserify": "^1.1.0", + "constants-browserify": "~1.0.0", + "crypto-browserify": "^3.0.0", + "defined": "^1.0.0", + "deps-sort": "^2.0.0", + "domain-browser": "^1.2.0", + "duplexer2": "~0.1.2", + "events": "^2.0.0", + "glob": "^7.1.0", + "has": "^1.0.0", + "htmlescape": "^1.1.0", + "https-browserify": "^1.0.0", + "inherits": "~2.0.1", + "insert-module-globals": "^7.0.0", + "labeled-stream-splicer": "^2.0.0", + "mkdirp": "^0.5.0", + "module-deps": "^6.0.0", + "os-browserify": "~0.3.0", + "parents": "^1.0.1", + "path-browserify": "~0.0.0", + "process": "~0.11.0", + "punycode": "^1.3.2", + "querystring-es3": "~0.2.0", + "read-only-stream": "^2.0.0", + "readable-stream": "^2.0.2", + "resolve": "^1.1.4", + "shasum": "^1.0.0", + "shell-quote": "^1.6.1", + "stream-browserify": "^2.0.0", + "stream-http": "^2.0.0", + "string_decoder": "^1.1.1", + "subarg": "^1.0.0", + "syntax-error": "^1.1.1", + "through2": "^2.0.0", + "timers-browserify": "^1.0.1", + "tty-browserify": "0.0.1", + "url": "~0.11.0", + "util": "~0.10.1", + "vm-browserify": "^1.0.0", + "xtend": "^4.0.0" + } + }, + "browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "requires": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "browserify-cipher": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", + "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", + "requires": { + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" + } + }, + "browserify-des": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", + "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", + "requires": { + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "browserify-rsa": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", + "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", + "requires": { + "bn.js": "^4.1.0", + "randombytes": "^2.0.1" + } + }, + "browserify-sign": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.0.4.tgz", + "integrity": "sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=", + "requires": { + "bn.js": "^4.1.1", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.2", + "elliptic": "^6.0.0", + "inherits": "^2.0.1", + "parse-asn1": "^5.0.0" + } + }, + "browserify-zlib": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", + "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", + "requires": { + "pako": "~1.0.5" + } + }, "browserslist": { "version": "1.7.7", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-1.7.7.tgz", "integrity": "sha1-C9dnBCWL6CmyOYu1Dkti0aFmsLk=", "requires": { - "caniuse-db": "1.0.30000782", - "electron-to-chromium": "1.3.28" + "caniuse-db": "^1.0.30000639", + "electron-to-chromium": "^1.2.7" } }, + "buffer": { + "version": "5.4.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.4.3.tgz", + "integrity": "sha512-zvj65TkFeIt3i6aj5bIvJDzjjQQGs4o/sNoezg1F1kYap9Nu2jcUdpwzRSJTHMMzG0H7bZkn4rNQpImhuxWX2A==", + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4" + } + }, + "buffer-alloc": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", + "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", + "requires": { + "buffer-alloc-unsafe": "^1.1.0", + "buffer-fill": "^1.0.0" + } + }, + "buffer-alloc-unsafe": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", + "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==" + }, + "buffer-fill": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", + "integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw=" + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" + }, + "buffer-more-ints": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-more-ints/-/buffer-more-ints-1.0.0.tgz", + "integrity": "sha512-EMetuGFz5SLsT0QTnXzINh4Ksr+oo4i+UGTXEshiGCQWnsgSs7ZhJ8fzlwQ+OzEMs0MpDAMr1hxnblp5a4vcHg==" + }, + "buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=" + }, + "buildmail": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/buildmail/-/buildmail-4.0.1.tgz", + "integrity": "sha1-h393OLeHKYccmhBeO4N9K+EaenI=", + "optional": true, + "requires": { + "addressparser": "1.0.1", + "libbase64": "0.1.0", + "libmime": "3.0.0", + "libqp": "1.1.0", + "nodemailer-fetch": "1.6.0", + "nodemailer-shared": "1.1.0", + "punycode": "1.4.1" + } + }, + "builtin-status-codes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", + "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=" + }, + "bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" + }, + "cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "requires": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" + } + } + }, + "cached-path-relative": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cached-path-relative/-/cached-path-relative-1.0.2.tgz", + "integrity": "sha512-5r2GqsoEb4qMTTN9J+WzXfjov+hjxT+j3u5K+kIVNIwAd99DLCJE9pBIMP1qVeybV6JiijL385Oz0DcYxfbOIg==" + }, + "callsite": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", + "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=" + }, "caniuse-api": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-1.6.1.tgz", "integrity": "sha1-tTTnxzTE+B7F++isoq0kNUuWLGw=", "requires": { - "browserslist": "1.7.7", - "caniuse-db": "1.0.30000782", - "lodash.memoize": "4.1.2", - "lodash.uniq": "4.5.0" + "browserslist": "^1.3.6", + "caniuse-db": "^1.0.30000529", + "lodash.memoize": "^4.1.2", + "lodash.uniq": "^4.5.0" + }, + "dependencies": { + "lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=" + } } }, "caniuse-db": { - "version": "1.0.30000782", - "resolved": "https://registry.npmjs.org/caniuse-db/-/caniuse-db-1.0.30000782.tgz", - "integrity": "sha1-2IFbzhV4w1Cs7REyUHMBIF4Pq1M=" + "version": "1.0.30001010", + "resolved": "https://registry.npmjs.org/caniuse-db/-/caniuse-db-1.0.30001010.tgz", + "integrity": "sha512-frpo0HYuu8tOQqTq/B4LVBDUHFwAeEHLHmSMzG90Ymgq4ll4EArwpqFzNANfQaQwD/q3IIZqQYxftbprZnt8pA==" }, "caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" }, + "chai": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-3.5.0.tgz", + "integrity": "sha1-TQJjewZ/6Vi9v906QOxW/vc3Mkc=", + "requires": { + "assertion-error": "^1.0.1", + "deep-eql": "^0.1.3", + "type-detect": "^1.0.0" + } + }, "chalk": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "requires": { - "ansi-styles": "2.2.1", - "escape-string-regexp": "1.0.5", - "has-ansi": "2.0.0", - "strip-ansi": "3.0.1", - "supports-color": "2.0.0" + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" }, "dependencies": { "supports-color": { @@ -486,65 +960,92 @@ } } }, - "choices-separator": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/choices-separator/-/choices-separator-2.0.0.tgz", - "integrity": "sha1-kv0XYxgteQM/XFxR0Lo1LlVnxpY=", - "optional": true, + "chokidar": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz", + "integrity": "sha1-eY5ol3gVHIB2tLNg5e3SjNortGg=", "requires": { - "ansi-dim": "0.1.1", - "debug": "2.6.9", - "strip-color": "0.1.0" + "anymatch": "^1.3.0", + "async-each": "^1.0.0", + "fsevents": "^1.0.0", + "glob-parent": "^2.0.0", + "inherits": "^2.0.1", + "is-binary-path": "^1.0.0", + "is-glob": "^2.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.0.0" } }, "chownr": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.0.1.tgz", - "integrity": "sha1-4qdQQqlVGQi+vSW4Uj1fl2nXkYE=", - "optional": true + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.3.tgz", + "integrity": "sha512-i70fVHhmV3DtTl6nqvZOnIjbY0Pe4kAUjwHj8z0zAdgBtYrJyYwLKCCuRBQ5ppkyL0AkN7HKRnETdmdp1zqNXw==" + }, + "cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "circular-json": { + "version": "0.5.9", + "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.5.9.tgz", + "integrity": "sha512-4ivwqHpIFJZBuhN3g/pEcdbnGUywkBblloGbkglyloVjjR3uT6tieI89MVOfbP2tHX5sgb01FuLgAOzebNlJNQ==" }, "clap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/clap/-/clap-1.2.3.tgz", - "integrity": "sha1-TzZ0WzIAhJJVf0ZBLWbVDLmbzlE=", + "integrity": "sha512-4CoL/A3hf90V3VIEjeuhSvlGFEHKzOz+Wfc2IVZc+FaUgU0ZQafJTP49fvnULipOPcAfqhyI2duwQyns6xqjYA==", "requires": { - "chalk": "1.1.3" + "chalk": "^1.1.3" + } + }, + "class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "requires": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" + } } }, "clone": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.3.tgz", - "integrity": "sha1-KY1+IjFmD0DAA8LtMUDezz9TCF8=" - }, - "clone-deep": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-1.0.0.tgz", - "integrity": "sha512-hmJRX8x1QOJVV+GUjOBzi6iauhPqc9hIF6xitWRBbiPZOBb6vGo/mDRIK9P74RTKSQK7AE8B0DDWY/vpRrPmQw==", - "requires": { - "for-own": "1.0.0", - "is-plain-object": "2.0.4", - "kind-of": "5.1.0", - "shallow-clone": "1.0.0" - }, - "dependencies": { - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" - } - } + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=" }, "co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "optional": true }, "coa": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/coa/-/coa-1.0.4.tgz", "integrity": "sha1-qe8VNmDWqGqL3sAomlxoTSF0Mv0=", "requires": { - "q": "1.5.1" + "q": "^1.1.2" } }, "code-point-at": { @@ -556,10 +1057,9 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", - "optional": true, "requires": { - "map-visit": "1.0.0", - "object-visit": "1.0.1" + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" } }, "color": { @@ -567,15 +1067,15 @@ "resolved": "https://registry.npmjs.org/color/-/color-0.11.4.tgz", "integrity": "sha1-bXtcdPtl6EHNSHkq0e1eB7kE12Q=", "requires": { - "clone": "1.0.3", - "color-convert": "1.9.1", - "color-string": "0.3.0" + "clone": "^1.0.2", + "color-convert": "^1.3.0", + "color-string": "^0.3.0" } }, "color-convert": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz", - "integrity": "sha1-wSYRB66y8pTr/+ye2eytUppgl+0=", + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", "requires": { "color-name": "1.1.3" } @@ -590,7 +1090,7 @@ "resolved": "https://registry.npmjs.org/color-string/-/color-string-0.3.0.tgz", "integrity": "sha1-J9RvtnAlxcL6JZk7+/V55HhBuZE=", "requires": { - "color-name": "1.1.3" + "color-name": "^1.0.0" } }, "colormin": { @@ -598,9 +1098,9 @@ "resolved": "https://registry.npmjs.org/colormin/-/colormin-1.1.2.tgz", "integrity": "sha1-6i90IKcrlogaOKrlnsEkpvcpgTM=", "requires": { - "color": "0.11.4", + "color": "^0.11.0", "css-color-names": "0.0.4", - "has": "1.0.1" + "has": "^1.0.1" } }, "colors": { @@ -608,61 +1108,185 @@ "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz", "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=" }, - "combined-stream": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz", - "integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=", + "combine-lists": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/combine-lists/-/combine-lists-1.0.1.tgz", + "integrity": "sha1-RYwH4J4NkA/Ci3Cj/sLazR0st/Y=", "requires": { - "delayed-stream": "1.0.0" + "lodash": "^4.5.0" + } + }, + "combine-source-map": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/combine-source-map/-/combine-source-map-0.8.0.tgz", + "integrity": "sha1-pY0N8ELBhvz4IqjoAV9UUNLXmos=", + "requires": { + "convert-source-map": "~1.1.0", + "inline-source-map": "~0.6.0", + "lodash.memoize": "~3.0.3", + "source-map": "~0.5.3" + } + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "requires": { + "delayed-stream": "~1.0.0" } }, "commander": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.1.0.tgz", - "integrity": "sha1-0SG7roYNmZKj1Re6lvVliOR8Z4E=" + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "optional": true + }, + "component-bind": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", + "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=" }, "component-emitter": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", - "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=" + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" + }, + "component-inherit": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz", + "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=" }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "connect": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", + "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", + "requires": { + "debug": "2.6.9", + "finalhandler": "1.1.2", + "parseurl": "~1.3.3", + "utils-merge": "1.0.1" + } + }, + "console-browserify": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", + "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==" + }, "console-control-strings": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" }, + "constants-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", + "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=" + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + }, + "convert-source-map": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.1.3.tgz", + "integrity": "sha1-SCnId+n+SbMWHzvzZziI4gRpmGA=" + }, + "cookie": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", + "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" + }, "copy-descriptor": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", - "optional": true + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=" + }, + "core-js": { + "version": "2.6.10", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.10.tgz", + "integrity": "sha512-I39t74+4t+zau64EN1fE5v2W31Adtc/REhzWN+gWRRXg6WH5qAsZm62DHpQ1+Yhe4047T55jvzz7MUqF/dBBlA==" }, "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, - "cryptiles": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz", - "integrity": "sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4=", + "create-ecdh": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.3.tgz", + "integrity": "sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw==", "requires": { - "boom": "5.2.0" - }, - "dependencies": { - "boom": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", - "integrity": "sha1-XdnabuOl8wIHdDYpDLcX0/SlTgI=", - "requires": { - "hoek": "4.2.0" - } - } + "bn.js": "^4.1.0", + "elliptic": "^6.0.0" + } + }, + "create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "requires": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "requires": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "cryptiles": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", + "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=", + "optional": true, + "requires": { + "boom": "2.x.x" + } + }, + "crypto-browserify": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", + "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", + "requires": { + "browserify-cipher": "^1.0.0", + "browserify-sign": "^4.0.0", + "create-ecdh": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.0", + "diffie-hellman": "^5.0.0", + "inherits": "^2.0.1", + "pbkdf2": "^3.0.3", + "public-encrypt": "^4.0.0", + "randombytes": "^2.0.0", + "randomfill": "^1.0.3" } }, "css-color-names": { @@ -675,49 +1299,49 @@ "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-3.10.0.tgz", "integrity": "sha1-Tzj2zqK5sX+gFJDyPx3GjqZcHDg=", "requires": { - "autoprefixer": "6.7.7", - "decamelize": "1.2.0", - "defined": "1.0.0", - "has": "1.0.1", - "object-assign": "4.1.1", - "postcss": "5.2.18", - "postcss-calc": "5.3.1", - "postcss-colormin": "2.2.2", - "postcss-convert-values": "2.6.1", - "postcss-discard-comments": "2.0.4", - "postcss-discard-duplicates": "2.1.0", - "postcss-discard-empty": "2.1.0", - "postcss-discard-overridden": "0.1.1", - "postcss-discard-unused": "2.2.3", - "postcss-filter-plugins": "2.0.2", - "postcss-merge-idents": "2.1.7", - "postcss-merge-longhand": "2.0.2", - "postcss-merge-rules": "2.1.2", - "postcss-minify-font-values": "1.0.5", - "postcss-minify-gradients": "1.0.5", - "postcss-minify-params": "1.2.2", - "postcss-minify-selectors": "2.1.1", - "postcss-normalize-charset": "1.1.1", - "postcss-normalize-url": "3.0.8", - "postcss-ordered-values": "2.2.3", - "postcss-reduce-idents": "2.4.0", - "postcss-reduce-initial": "1.0.1", - "postcss-reduce-transforms": "1.0.4", - "postcss-svgo": "2.1.6", - "postcss-unique-selectors": "2.0.2", - "postcss-value-parser": "3.3.0", - "postcss-zindex": "2.2.0" + "autoprefixer": "^6.3.1", + "decamelize": "^1.1.2", + "defined": "^1.0.0", + "has": "^1.0.1", + "object-assign": "^4.0.1", + "postcss": "^5.0.14", + "postcss-calc": "^5.2.0", + "postcss-colormin": "^2.1.8", + "postcss-convert-values": "^2.3.4", + "postcss-discard-comments": "^2.0.4", + "postcss-discard-duplicates": "^2.0.1", + "postcss-discard-empty": "^2.0.1", + "postcss-discard-overridden": "^0.1.1", + "postcss-discard-unused": "^2.2.1", + "postcss-filter-plugins": "^2.0.0", + "postcss-merge-idents": "^2.1.5", + "postcss-merge-longhand": "^2.0.1", + "postcss-merge-rules": "^2.0.3", + "postcss-minify-font-values": "^1.0.2", + "postcss-minify-gradients": "^1.0.1", + "postcss-minify-params": "^1.0.4", + "postcss-minify-selectors": "^2.0.4", + "postcss-normalize-charset": "^1.1.0", + "postcss-normalize-url": "^3.0.7", + "postcss-ordered-values": "^2.1.0", + "postcss-reduce-idents": "^2.2.2", + "postcss-reduce-initial": "^1.0.0", + "postcss-reduce-transforms": "^1.0.3", + "postcss-svgo": "^2.1.1", + "postcss-unique-selectors": "^2.0.2", + "postcss-value-parser": "^3.2.3", + "postcss-zindex": "^2.0.1" }, "dependencies": { "postcss": { "version": "5.2.18", "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha1-ut+hSX1GJE9jkPWLMZgw2RB4U8U=", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", "requires": { - "chalk": "1.1.3", - "js-base64": "2.4.0", - "source-map": "0.5.7", - "supports-color": "3.2.3" + "chalk": "^1.1.3", + "js-base64": "^2.1.9", + "source-map": "^0.5.6", + "supports-color": "^3.2.3" } } } @@ -727,22 +1351,43 @@ "resolved": "https://registry.npmjs.org/csso/-/csso-2.3.2.tgz", "integrity": "sha1-3dUsWHAz9J6Utx/FVWnyUuj/X4U=", "requires": { - "clap": "1.2.3", - "source-map": "0.5.7" + "clap": "^1.0.9", + "source-map": "^0.5.3" } }, + "custom-event": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", + "integrity": "sha1-XQKkaFCt8bSjF5RqOSj8y1v9BCU=" + }, + "dash-ast": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dash-ast/-/dash-ast-1.0.0.tgz", + "integrity": "sha512-Vy4dx7gquTeMcQR/hDkYLGUnwVil6vk4FOOct+djUnHOUWt+zJPJAaRIXaAFkPXtJjvlY7o3rfRu0/3hpnwoUA==" + }, "dashdash": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", "requires": { - "assert-plus": "1.0.0" + "assert-plus": "^1.0.0" } }, + "data-uri-to-buffer": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-1.2.0.tgz", + "integrity": "sha512-vKQ9DTQPN1FLYiiEEOQ6IBGFqvjCa5rSK3cWMy/Nespm5d/x3dGFT9UBZnkLxCwua/IXBi2TYnwTEpsOvhC4UQ==", + "optional": true + }, + "date-format": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/date-format/-/date-format-1.2.0.tgz", + "integrity": "sha1-YV6CjiM90aubua4JUODOzPpuytg=" + }, "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "requires": { "ms": "2.0.0" } @@ -752,18 +1397,90 @@ "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" }, + "decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=" + }, + "decompress-response": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz", + "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==", + "requires": { + "mimic-response": "^2.0.0" + } + }, + "deep-eql": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-0.1.3.tgz", + "integrity": "sha1-71WKyrjeJSBs1xOQbXTlaTDrafI=", + "requires": { + "type-detect": "0.1.1" + }, + "dependencies": { + "type-detect": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-0.1.1.tgz", + "integrity": "sha1-C6XsKohWQORw6k6FBZcZANrFiCI=" + } + } + }, "deep-extend": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.4.2.tgz", - "integrity": "sha1-SLaZwn4zS/ifEIkr5DL25MfTSn8=", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" + }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", "optional": true }, "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", "requires": { - "is-descriptor": "1.0.2" + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "dependencies": { + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" + } } }, "defined": { @@ -771,6 +1488,25 @@ "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=" }, + "degenerator": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-1.0.4.tgz", + "integrity": "sha1-/PSQo37OJmRk2cxDGrmMWBnO0JU=", + "optional": true, + "requires": { + "ast-types": "0.x.x", + "escodegen": "1.x.x", + "esprima": "3.x.x" + }, + "dependencies": { + "esprima": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", + "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=", + "optional": true + } + } + }, "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -779,73 +1515,403 @@ "delegates": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + }, + "deps-sort": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/deps-sort/-/deps-sort-2.0.1.tgz", + "integrity": "sha512-1orqXQr5po+3KI6kQb9A4jnXT1PBwggGl2d7Sq2xsnOeI9GPcE/tGcF9UiSZtZBM7MukY4cAh7MemS6tZYipfw==", + "requires": { + "JSONStream": "^1.0.3", + "shasum-object": "^1.0.0", + "subarg": "^1.0.0", + "through2": "^2.0.0" + } + }, + "des.js": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz", + "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==", + "requires": { + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=" + }, + "detective": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/detective/-/detective-5.2.0.tgz", + "integrity": "sha512-6SsIx+nUUbuK0EthKjv0zrdnajCCXVYGmbYYiYjFVpzcjwEs/JMDZ8tPRG29J/HhN56t3GJp2cGSWDRjjot8Pg==", + "requires": { + "acorn-node": "^1.6.1", + "defined": "^1.0.0", + "minimist": "^1.1.1" + } + }, + "di": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz", + "integrity": "sha1-gGZJMmzqp8qjMG112YXqJ0i6kTw=" + }, + "diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==" + }, + "diffie-hellman": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", + "requires": { + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" + } + }, + "dom-serialize": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz", + "integrity": "sha1-ViromZ9Evl6jB29UGdzVnrQ6yVs=", + "requires": { + "custom-event": "~1.0.0", + "ent": "~2.2.0", + "extend": "^3.0.0", + "void-elements": "^2.0.0" + } + }, + "domain-browser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", + "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==" + }, + "double-ended-queue": { + "version": "2.1.0-0", + "resolved": "https://registry.npmjs.org/double-ended-queue/-/double-ended-queue-2.1.0-0.tgz", + "integrity": "sha1-ED01J/0xUo9AGIEwyEHv3XgmTlw=", "optional": true }, - "ecc-jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", - "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", - "optional": true, + "duplexer2": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", + "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=", "requires": { - "jsbn": "0.1.1" + "readable-stream": "^2.0.2" } }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, "electron-to-chromium": { - "version": "1.3.28", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.28.tgz", - "integrity": "sha1-jdTmRYCGZE6fnwoc8y4qH53/2e4=" + "version": "1.3.306", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.306.tgz", + "integrity": "sha512-frDqXvrIROoYvikSKTIKbHbzO6M3/qC6kCIt/1FOa9kALe++c4VAJnwjSFvf1tYLEUsP2n9XZ4XSCyqc3l7A/A==" + }, + "elliptic": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.1.tgz", + "integrity": "sha512-xvJINNLbTeWQjrl6X+7eQCrIy/YPv5XCpKW6kB5mKvtnGILoLDcySuwomfdzt0BMdLNVnuRNTuzKNHj0bva1Cg==", + "requires": { + "bn.js": "^4.4.0", + "brorand": "^1.0.1", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.0" + } + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" }, "end-of-stream": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.0.tgz", - "integrity": "sha1-epDYM+/abPpurA9JSduw+tOmMgY=", + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", "requires": { - "once": "1.4.0" + "once": "^1.4.0" } }, + "engine.io": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.1.5.tgz", + "integrity": "sha512-D06ivJkYxyRrcEe0bTpNnBQNgP9d3xog+qZlLbui8EsMr/DouQpf5o9FzJnWYHEYE0YsFHllUv2R1dkgYZXHcA==", + "requires": { + "accepts": "~1.3.4", + "base64id": "1.0.0", + "cookie": "0.3.1", + "debug": "~3.1.0", + "engine.io-parser": "~2.1.0", + "uws": "~9.14.0", + "ws": "~3.3.1" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + } + } + }, + "engine.io-client": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.1.6.tgz", + "integrity": "sha512-hnuHsFluXnsKOndS4Hv6SvUrgdYx1pk2NqfaDMW+GWdgfU3+/V25Cj7I8a0x92idSpa5PIhJRKxPvp9mnoLsfg==", + "requires": { + "component-emitter": "1.2.1", + "component-inherit": "0.0.3", + "debug": "~3.1.0", + "engine.io-parser": "~2.1.1", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "ws": "~3.3.1", + "xmlhttprequest-ssl": "~1.5.4", + "yeast": "0.1.2" + }, + "dependencies": { + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=" + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + } + } + }, + "engine.io-parser": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.1.3.tgz", + "integrity": "sha512-6HXPre2O4Houl7c4g7Ic/XzPnHBvaEmN90vtRO9uLmwtRqQmTOw0QMevL1TOfL2Cpu1VzsaTmMotQgMdkzGkVA==", + "requires": { + "after": "0.8.2", + "arraybuffer.slice": "~0.0.7", + "base64-arraybuffer": "0.1.5", + "blob": "0.0.5", + "has-binary2": "~1.0.2" + } + }, + "ent": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", + "integrity": "sha1-6WQhkyWiHQX0RGai9obtbOX13R0=" + }, "errno": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.6.tgz", - "integrity": "sha512-IsORQDpaaSwcDP4ZZnHxgE85werpo34VYn1Ud3mq+eUsF593faR8oCZNXrROVkpFu2TsbrNhHin0aUrTsQ9vNw==", - "dev": true, + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", + "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", "optional": true, "requires": { - "prr": "1.0.1" + "prr": "~1.0.1" } }, - "error-symbol": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/error-symbol/-/error-symbol-0.1.0.tgz", - "integrity": "sha1-Ck2uN9YA0VopukU9jvkg8YRDM/Y=" + "es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==" + }, + "es6-promisify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", + "requires": { + "es6-promise": "^4.0.3" + } + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" }, + "escodegen": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.12.0.tgz", + "integrity": "sha512-TuA+EhsanGcme5T3R0L80u4t8CpbXQjegRmf7+FPTJrtCTErXFeelblRgHQa1FofEzqYYJmJ/OqjTwREp9qgmg==", + "optional": true, + "requires": { + "esprima": "^3.1.3", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.6.1" + }, + "dependencies": { + "esprima": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", + "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=", + "optional": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "optional": true + } + } + }, "esprima": { "version": "2.7.3", "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=" }, - "expand-template": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-1.1.0.tgz", - "integrity": "sha1-4J77qXe/mPnuDtJavQxpLgKuw/w=", + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", "optional": true }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "optional": true + }, + "eventemitter3": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.0.tgz", + "integrity": "sha512-qerSRB0p+UDEssxTtm6EDKcE7W4OaoisfIMl4CngyEhjpYglocpNg6UEqCvemdGhosAsg4sO2dXJOdyBifPGCg==" + }, + "events": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/events/-/events-2.1.0.tgz", + "integrity": "sha512-3Zmiobend8P9DjmKAty0Era4jV8oJ0yGYe2nJJAxgymF9+N8F2m0hhZiMoWtcfepExzNKZumFU3ksdQbInGWCg==" + }, + "evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "requires": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "expand-braces": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/expand-braces/-/expand-braces-0.1.2.tgz", + "integrity": "sha1-SIsdHSRRyz06axks/AMPRMWFX+o=", + "requires": { + "array-slice": "^0.2.3", + "array-unique": "^0.2.1", + "braces": "^0.1.2" + }, + "dependencies": { + "braces": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/braces/-/braces-0.1.5.tgz", + "integrity": "sha1-wIVxEIUpHYt1/ddOqw+FlygHEeY=", + "requires": { + "expand-range": "^0.1.0" + } + }, + "expand-range": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-0.1.1.tgz", + "integrity": "sha1-TLjtoJk8pW+k9B/ELzy7TMrf8EQ=", + "requires": { + "is-number": "^0.1.1", + "repeat-string": "^0.2.2" + } + }, + "is-number": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-0.1.1.tgz", + "integrity": "sha1-aaevEWlj1HIG7JvZtIoUIW8eOAY=" + }, + "repeat-string": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-0.2.2.tgz", + "integrity": "sha1-x6jTI2BoNiBZp+RlH8aITosftK4=" + } + } + }, + "expand-brackets": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", + "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", + "requires": { + "is-posix-bracket": "^0.1.0" + } + }, + "expand-range": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", + "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", + "requires": { + "fill-range": "^2.1.0" + } + }, + "expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==" + }, "extend": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", - "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=" + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" }, "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", "requires": { - "is-extendable": "0.1.1" + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "extglob": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", + "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", + "requires": { + "is-extglob": "^1.0.0" } }, "extsprintf": { @@ -854,21 +1920,68 @@ "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" }, "fast-deep-equal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz", - "integrity": "sha1-liVqO8l1WV6zbYLpkp0GDYk0Of8=" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", + "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=" }, "fast-json-stable-stringify": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "optional": true + }, + "fast-safe-stringify": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz", + "integrity": "sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA==" + }, "faye-websocket": { "version": "0.11.1", "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.1.tgz", "integrity": "sha1-8O/hjE9W5PQK/H4Gxxn9XuYYjzg=", "requires": { - "websocket-driver": "0.7.0" + "websocket-driver": ">=0.5.1" + } + }, + "file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==" + }, + "filename-regex": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", + "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=" + }, + "fill-range": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz", + "integrity": "sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==", + "requires": { + "is-number": "^2.1.0", + "isobject": "^2.0.0", + "randomatic": "^3.0.0", + "repeat-element": "^1.1.2", + "repeat-string": "^1.5.2" + } + }, + "finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" } }, "findup": { @@ -876,21 +1989,49 @@ "resolved": "https://registry.npmjs.org/findup/-/findup-0.1.5.tgz", "integrity": "sha1-itkpozk7rGJ5V6fl3kYjsGsOLOs=", "requires": { - "colors": "0.6.2", - "commander": "2.1.0" + "colors": "~0.6.0-1", + "commander": "~2.1.0" }, "dependencies": { "colors": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/colors/-/colors-0.6.2.tgz", "integrity": "sha1-JCP+ZnisDF2uiFLl0OW+CMmXq8w=" + }, + "commander": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.1.0.tgz", + "integrity": "sha1-0SG7roYNmZKj1Re6lvVliOR8Z4E=" } } }, "flatten": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/flatten/-/flatten-1.0.2.tgz", - "integrity": "sha1-2uRqnXj74lKSJYzB54CkHZXAN4I=" + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/flatten/-/flatten-1.0.3.tgz", + "integrity": "sha512-dVsPA/UwQ8+2uoFe5GHtiBMu48dWLTdsuEd7CKGlZlD78r1TTWBvDuFaFGKCo/ZfEr95Uk56vZoX86OsHkUeIg==" + }, + "follow-redirects": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.9.0.tgz", + "integrity": "sha512-CRcPzsSIbXyVDl0QI01muNDu69S8trU4jArW9LpOt2WtC6LyUJetcIrmfHsRBx7/Jb6GHJUiuqyYxPooFfNt6A==", + "requires": { + "debug": "^3.0.0" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } }, "for-in": { "version": "1.0.2", @@ -898,11 +2039,11 @@ "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=" }, "for-own": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", - "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", + "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", "requires": { - "for-in": "1.0.2" + "for-in": "^1.0.1" } }, "forever-agent": { @@ -911,79 +2052,653 @@ "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" }, "form-data": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.1.tgz", - "integrity": "sha1-b7lPvXGIUwbXPRXMSX/kzE7NRL8=", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", "requires": { - "asynckit": "0.4.0", - "combined-stream": "1.0.5", - "mime-types": "2.1.17" + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" } }, + "fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "requires": { + "map-cache": "^0.2.2" + } + }, + "fs-access": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/fs-access/-/fs-access-1.0.1.tgz", + "integrity": "sha1-1qh/JiJxzv6+wwxVNAf7mV2od3o=", + "requires": { + "null-check": "^1.0.0" + } + }, + "fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" + }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, + "fsevents": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz", + "integrity": "sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==", + "optional": true, + "requires": { + "nan": "^2.12.1", + "node-pre-gyp": "^0.12.0" + }, + "dependencies": { + "abbrev": { + "version": "1.1.1", + "bundled": true, + "optional": true + }, + "ansi-regex": { + "version": "2.1.1", + "bundled": true + }, + "aproba": { + "version": "1.2.0", + "bundled": true, + "optional": true + }, + "are-we-there-yet": { + "version": "1.1.5", + "bundled": true, + "optional": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "balanced-match": { + "version": "1.0.0", + "bundled": true + }, + "brace-expansion": { + "version": "1.1.11", + "bundled": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "chownr": { + "version": "1.1.1", + "bundled": true, + "optional": true + }, + "code-point-at": { + "version": "1.1.0", + "bundled": true + }, + "concat-map": { + "version": "0.0.1", + "bundled": true + }, + "console-control-strings": { + "version": "1.1.0", + "bundled": true + }, + "core-util-is": { + "version": "1.0.2", + "bundled": true, + "optional": true + }, + "debug": { + "version": "4.1.1", + "bundled": true, + "optional": true, + "requires": { + "ms": "^2.1.1" + } + }, + "deep-extend": { + "version": "0.6.0", + "bundled": true, + "optional": true + }, + "delegates": { + "version": "1.0.0", + "bundled": true, + "optional": true + }, + "detect-libc": { + "version": "1.0.3", + "bundled": true, + "optional": true + }, + "fs-minipass": { + "version": "1.2.5", + "bundled": true, + "optional": true, + "requires": { + "minipass": "^2.2.1" + } + }, + "fs.realpath": { + "version": "1.0.0", + "bundled": true, + "optional": true + }, + "gauge": { + "version": "2.7.4", + "bundled": true, + "optional": true, + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, + "glob": { + "version": "7.1.3", + "bundled": true, + "optional": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "has-unicode": { + "version": "2.0.1", + "bundled": true, + "optional": true + }, + "iconv-lite": { + "version": "0.4.24", + "bundled": true, + "optional": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ignore-walk": { + "version": "3.0.1", + "bundled": true, + "optional": true, + "requires": { + "minimatch": "^3.0.4" + } + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "optional": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "bundled": true + }, + "ini": { + "version": "1.3.5", + "bundled": true, + "optional": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "isarray": { + "version": "1.0.0", + "bundled": true, + "optional": true + }, + "minimatch": { + "version": "3.0.4", + "bundled": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "bundled": true + }, + "minipass": { + "version": "2.3.5", + "bundled": true, + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "minizlib": { + "version": "1.2.1", + "bundled": true, + "optional": true, + "requires": { + "minipass": "^2.2.1" + } + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.1.1", + "bundled": true, + "optional": true + }, + "needle": { + "version": "2.3.0", + "bundled": true, + "optional": true, + "requires": { + "debug": "^4.1.0", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + } + }, + "node-pre-gyp": { + "version": "0.12.0", + "bundled": true, + "optional": true, + "requires": { + "detect-libc": "^1.0.2", + "mkdirp": "^0.5.1", + "needle": "^2.2.1", + "nopt": "^4.0.1", + "npm-packlist": "^1.1.6", + "npmlog": "^4.0.2", + "rc": "^1.2.7", + "rimraf": "^2.6.1", + "semver": "^5.3.0", + "tar": "^4" + } + }, + "nopt": { + "version": "4.0.1", + "bundled": true, + "optional": true, + "requires": { + "abbrev": "1", + "osenv": "^0.1.4" + } + }, + "npm-bundled": { + "version": "1.0.6", + "bundled": true, + "optional": true + }, + "npm-packlist": { + "version": "1.4.1", + "bundled": true, + "optional": true, + "requires": { + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1" + } + }, + "npmlog": { + "version": "4.1.2", + "bundled": true, + "optional": true, + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "bundled": true + }, + "object-assign": { + "version": "4.1.1", + "bundled": true, + "optional": true + }, + "once": { + "version": "1.4.0", + "bundled": true, + "requires": { + "wrappy": "1" + } + }, + "os-homedir": { + "version": "1.0.2", + "bundled": true, + "optional": true + }, + "os-tmpdir": { + "version": "1.0.2", + "bundled": true, + "optional": true + }, + "osenv": { + "version": "0.1.5", + "bundled": true, + "optional": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true, + "optional": true + }, + "process-nextick-args": { + "version": "2.0.0", + "bundled": true, + "optional": true + }, + "rc": { + "version": "1.2.8", + "bundled": true, + "optional": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "bundled": true, + "optional": true + } + } + }, + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "optional": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "rimraf": { + "version": "2.6.3", + "bundled": true, + "optional": true, + "requires": { + "glob": "^7.1.3" + } + }, + "safe-buffer": { + "version": "5.1.2", + "bundled": true + }, + "safer-buffer": { + "version": "2.1.2", + "bundled": true, + "optional": true + }, + "sax": { + "version": "1.2.4", + "bundled": true, + "optional": true + }, + "semver": { + "version": "5.7.0", + "bundled": true, + "optional": true + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true, + "optional": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true, + "optional": true + }, + "string-width": { + "version": "1.0.2", + "bundled": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "string_decoder": { + "version": "1.1.1", + "bundled": true, + "optional": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "bundled": true, + "optional": true + }, + "tar": { + "version": "4.4.8", + "bundled": true, + "optional": true, + "requires": { + "chownr": "^1.1.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.3.4", + "minizlib": "^1.1.1", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.2" + } + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true, + "optional": true + }, + "wide-align": { + "version": "1.1.3", + "bundled": true, + "optional": true, + "requires": { + "string-width": "^1.0.2 || 2" + } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true + }, + "yallist": { + "version": "3.0.3", + "bundled": true + } + } + }, + "ftp": { + "version": "0.3.10", + "resolved": "https://registry.npmjs.org/ftp/-/ftp-0.3.10.tgz", + "integrity": "sha1-kZfYYa2BQvPmPVqDv+TFn3MwiF0=", + "optional": true, + "requires": { + "readable-stream": "1.1.x", + "xregexp": "2.0.0" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "optional": true + }, + "readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "optional": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "optional": true + } + } + }, "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha1-pWiZ0+o8m6uHS7l3O3xe3pL0iV0=" - }, - "fuse.js": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-2.6.1.tgz", - "integrity": "sha1-0RjgD5qFn3s1TtT3dAIUJJ4ypXo=" + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, "gauge": { "version": "2.7.4", "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, + "generate-function": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", + "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==", "optional": true, "requires": { - "aproba": "1.2.0", - "console-control-strings": "1.1.0", - "has-unicode": "2.0.1", - "object-assign": "4.1.1", - "signal-exit": "3.0.2", - "string-width": "1.0.2", - "strip-ansi": "3.0.1", - "wide-align": "1.1.2" + "is-property": "^1.0.2" } }, + "generate-object-property": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz", + "integrity": "sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA=", + "optional": true, + "requires": { + "is-property": "^1.0.0" + } + }, + "get-assigned-identifiers": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/get-assigned-identifiers/-/get-assigned-identifiers-1.2.0.tgz", + "integrity": "sha512-mBBwmeGTrxEMO4pMaaf/uUEFHnYtwr8FTe8Y/mer4rcV/bye0qGm6pw1bGZFGStxC5O76c5ZAVBGnqHmOaJpdQ==" + }, + "get-uri": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-2.0.4.tgz", + "integrity": "sha512-v7LT/s8kVjs+Tx0ykk1I+H/rbpzkHvuIq87LmeXptcf5sNWm9uQiwjNAt94SJPA1zOlCntmnOlJvVWKmzsxG8Q==", + "optional": true, + "requires": { + "data-uri-to-buffer": "1", + "debug": "2", + "extend": "~3.0.2", + "file-uri-to-path": "1", + "ftp": "~0.3.10", + "readable-stream": "2" + } + }, + "get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=" + }, "getpass": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", "requires": { - "assert-plus": "1.0.0" + "assert-plus": "^1.0.0" } }, "github-from-package": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", - "integrity": "sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4=", - "optional": true + "integrity": "sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4=" }, "glob": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha1-wZyd+aAocC1nhhI4SmVSQExjbRU=", + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-base": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", + "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", + "requires": { + "glob-parent": "^2.0.0", + "is-glob": "^2.0.0" + } + }, + "glob-parent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", + "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", + "requires": { + "is-glob": "^2.0.0" } }, "graceful-fs": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", - "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", - "dev": true, - "optional": true + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", + "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==" + }, + "growl": { + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.3.tgz", + "integrity": "sha512-hKlsbA5Vu3xsh1Cg3J7jSmX/WaW6A5oBeqzM88oNbCRQFz+zUaXm6yxS4RVytp1scBoJzSYl4YAEOQIt6O8V1Q==" }, "har-schema": { "version": "2.0.0", @@ -991,20 +2706,20 @@ "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" }, "har-validator": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz", - "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=", + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", + "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", "requires": { - "ajv": "5.5.1", - "har-schema": "2.0.0" + "ajv": "^6.5.5", + "har-schema": "^2.0.0" } }, "has": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.1.tgz", - "integrity": "sha1-hGFzP1OLCDfJNh45qauelwTcLyg=", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", "requires": { - "function-bind": "1.1.1" + "function-bind": "^1.1.1" } }, "has-ansi": { @@ -1012,9 +2727,29 @@ "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", "requires": { - "ansi-regex": "2.1.1" + "ansi-regex": "^2.0.0" } }, + "has-binary2": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz", + "integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==", + "requires": { + "isarray": "2.0.1" + }, + "dependencies": { + "isarray": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", + "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=" + } + } + }, + "has-cors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", + "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=" + }, "has-flag": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", @@ -1023,55 +2758,258 @@ "has-unicode": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", - "optional": true + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" }, - "hawk": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/hawk/-/hawk-6.0.2.tgz", - "integrity": "sha1-r02RTrBl+bXOTZ0RwcshJu7MMDg=", + "has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", "requires": { - "boom": "4.3.1", - "cryptiles": "3.1.2", - "hoek": "4.2.0", - "sntp": "2.1.0" + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" + } } }, - "highlight.js": { - "version": "9.12.0", - "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.12.0.tgz", - "integrity": "sha1-5tnb5Xy+/mB1HwKvM2GVhwyQwB4=" + "has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "requires": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "dependencies": { + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "hash-base": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", + "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "hawk": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", + "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=", + "optional": true, + "requires": { + "boom": "2.x.x", + "cryptiles": "2.x.x", + "hoek": "2.x.x", + "sntp": "1.x.x" + } + }, + "he": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", + "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=" + }, + "hipchat-notifier": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/hipchat-notifier/-/hipchat-notifier-1.1.0.tgz", + "integrity": "sha1-ttJJdVQ3wZEII2d5nTupoPI7Ix4=", + "optional": true, + "requires": { + "lodash": "^4.0.0", + "request": "^2.0.0" + } + }, + "hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "requires": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } }, "hoek": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.0.tgz", - "integrity": "sha1-ctnQdU9/4lyi0BrY+PmpRJqJUm0=" + "version": "2.16.3", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", + "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=" }, "html-comment-regex": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/html-comment-regex/-/html-comment-regex-1.1.2.tgz", + "integrity": "sha512-P+M65QY2JQ5Y0G9KKdlDpo0zK+/OHptU5AaBwUfAIDJZk1MYf32Frm84EcOytfJE0t5JvkAnKlmjsXDnWzCJmQ==" + }, + "htmlescape": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/html-comment-regex/-/html-comment-regex-1.1.1.tgz", - "integrity": "sha1-ZouTd26q5V696POtRkswekljYl4=" + "resolved": "https://registry.npmjs.org/htmlescape/-/htmlescape-1.1.1.tgz", + "integrity": "sha1-OgPtwiFLyjtmQko+eVk0lQnLA1E=" + }, + "http-errors": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + }, + "dependencies": { + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + } + } }, "http-parser-js": { - "version": "0.4.9", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.4.9.tgz", - "integrity": "sha1-6hoE+2St/wJC6ZdPKX3Uw8rSceE=" + "version": "0.4.10", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.4.10.tgz", + "integrity": "sha1-ksnBN0w1CF912zWexWzCV8u5P6Q=" + }, + "http-proxy": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.0.tgz", + "integrity": "sha512-84I2iJM/n1d4Hdgc6y2+qY5mDaz2PUVjlg9znE9byl+q0uC3DeByqBGReQu5tpLK0TAqTIXScRUV+dg7+bUPpQ==", + "requires": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + } + }, + "http-proxy-agent": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz", + "integrity": "sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==", + "requires": { + "agent-base": "4", + "debug": "3.1.0" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + } + } }, "http-signature": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", "requires": { - "assert-plus": "1.0.0", - "jsprim": "1.4.1", - "sshpk": "1.13.1" + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" } }, + "httpntlm": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/httpntlm/-/httpntlm-1.6.1.tgz", + "integrity": "sha1-rQFScUOi6Hc8+uapb1hla7UqNLI=", + "requires": { + "httpreq": ">=0.4.22", + "underscore": "~1.7.0" + } + }, + "httpreq": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/httpreq/-/httpreq-0.4.24.tgz", + "integrity": "sha1-QzX/2CzZaWaKOUZckprGHWOTYn8=" + }, + "https-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", + "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=" + }, + "https-proxy-agent": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", + "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", + "optional": true, + "requires": { + "agent-base": "^4.3.0", + "debug": "^3.1.0" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "optional": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "optional": true + } + } + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ieee754": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" + }, "image-size": { "version": "0.5.5", "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", "integrity": "sha1-Cd/Uq50g4p6xw+gLiZA3jfnjy5w=", - "dev": true, "optional": true }, "indexes-of": { @@ -1079,30 +3017,65 @@ "resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz", "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=" }, + "indexof": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", + "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=" + }, + "inflection": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/inflection/-/inflection-1.12.0.tgz", + "integrity": "sha1-ogCTVlbW9fa8TcdQLhrstwMihBY=", + "optional": true + }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" + "once": "^1.3.0", + "wrappy": "1" } }, - "info-symbol": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/info-symbol/-/info-symbol-0.1.0.tgz", - "integrity": "sha1-J4QdcoZ920JCzWEtecEGM4gcang=" - }, "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "ini": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", - "integrity": "sha1-7uJfVtscnsYIXgwid4CD9Zar+Sc=", - "optional": true + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" + }, + "inline-source-map": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/inline-source-map/-/inline-source-map-0.6.2.tgz", + "integrity": "sha1-+Tk0ccGKedFyT4Y/o4tYY3Ct4qU=", + "requires": { + "source-map": "~0.5.3" + } + }, + "insert-module-globals": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/insert-module-globals/-/insert-module-globals-7.2.0.tgz", + "integrity": "sha512-VE6NlW+WGn2/AeOMd496AHFYmE7eLKkUY6Ty31k4og5vmA3Fjuwe9v6ifH6Xx/Hz27QvdoMoviw1/pqWRB09Sw==", + "requires": { + "JSONStream": "^1.0.3", + "acorn-node": "^1.5.2", + "combine-source-map": "^0.8.0", + "concat-stream": "^1.6.1", + "is-buffer": "^1.1.0", + "path-is-absolute": "^1.0.1", + "process": "~0.11.0", + "through2": "^2.0.0", + "undeclared-identifiers": "^1.1.2", + "xtend": "^4.0.0" + } + }, + "ip": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", + "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=" }, "is-absolute-url": { "version": "2.1.0", @@ -1110,18 +3083,19 @@ "integrity": "sha1-UFMN+4T8yap9vnhS6Do3uTufKqY=" }, "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", "requires": { - "kind-of": "6.0.2" - }, - "dependencies": { - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" - } + "kind-of": "^3.0.2" + } + }, + "is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "requires": { + "binary-extensions": "^1.0.0" } }, "is-buffer": { @@ -1130,56 +3104,94 @@ "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" }, "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", "requires": { - "kind-of": "6.0.2" - }, - "dependencies": { - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" - } + "kind-of": "^3.0.2" } }, "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", "requires": { - "is-accessor-descriptor": "1.0.0", - "is-data-descriptor": "1.0.0", - "kind-of": "6.0.2" + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" }, "dependencies": { "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" } } }, + "is-dotfile": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz", + "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=" + }, + "is-equal-shallow": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz", + "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=", + "requires": { + "is-primitive": "^2.0.0" + } + }, "is-extendable": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=" }, + "is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=" + }, "is-fullwidth-code-point": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "requires": { - "number-is-nan": "1.0.1" + "number-is-nan": "^1.0.0" + } + }, + "is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "requires": { + "is-extglob": "^1.0.0" + } + }, + "is-my-ip-valid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-my-ip-valid/-/is-my-ip-valid-1.0.0.tgz", + "integrity": "sha512-gmh/eWXROncUzRnIa1Ubrt5b8ep/MGSnfAUI3aRp+sqTCs1tv1Isl8d8F6JmkN3dXKc3ehZMrtiPN9eL03NuaQ==", + "optional": true + }, + "is-my-json-valid": { + "version": "2.20.0", + "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.20.0.tgz", + "integrity": "sha512-XTHBZSIIxNsIsZXg7XB5l8z/OBFosl1Wao4tXLpeC7eKU4Vm/kdop2azkPqULwnfGQjmeDIyey9g7afMMtdWAA==", + "optional": true, + "requires": { + "generate-function": "^2.0.0", + "generate-object-property": "^1.1.0", + "is-my-ip-valid": "^1.0.0", + "jsonpointer": "^4.0.0", + "xtend": "^4.0.0" } }, "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", + "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.0.2" } }, "is-plain-obj": { @@ -1192,15 +3204,43 @@ "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", "requires": { - "isobject": "3.0.1" + "isobject": "^3.0.1" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" + } } }, + "is-posix-bracket": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz", + "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=" + }, + "is-primitive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz", + "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=" + }, + "is-property": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", + "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=" + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "optional": true + }, "is-svg": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-svg/-/is-svg-2.1.0.tgz", "integrity": "sha1-z2EJDaDZ77yrhyLeum8DIgjbsOk=", "requires": { - "html-comment-regex": "1.1.1" + "html-comment-regex": "^1.1.0" } }, "is-typedarray": { @@ -1218,10 +3258,26 @@ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" }, + "isbinaryfile": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-3.0.3.tgz", + "integrity": "sha512-8cJBL5tTd2OS0dM4jz07wQd5g0dCCqIhUxPIGtZfa5L6hWlvV5MHTITy/DBAsF+Oe2LS1X3krBUhNwaGUWpWxw==", + "requires": { + "buffer-alloc": "^1.2.0" + } + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + }, "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "requires": { + "isarray": "1.0.0" + } }, "isstream": { "version": "0.1.2", @@ -1229,30 +3285,34 @@ "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" }, "jquery": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.3.1.tgz", - "integrity": "sha512-Ubldcmxp5np52/ENotGxlLe6aGMvmF4R8S6tZjsP6Knsaxd/xp3Zrh50cG93lR6nPXyUFwzN3ZSOQI0wRJNdGg==", - "dev": true + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.4.1.tgz", + "integrity": "sha512-36+AdBzCL+y6qjw5Tx7HgzeGCzC81MDDgaUP8ld2zhx58HdqXGoBd+tHdrBMiyjGQs0Hxs/MLZTu/eHNJJuWPw==" }, "js-base64": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.4.0.tgz", - "integrity": "sha1-nlZv7mJHUaHXIMlmzWIm0p1AJao=" + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.5.1.tgz", + "integrity": "sha512-M7kLczedRMYX4L8Mdh4MzyAMM9O5osx+4FcOQuTvr3A9F2D9S5JXheN0ewNbrvK2UatkTRhL5ejGmGSjNMiZuw==" + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true }, "js-yaml": { "version": "3.7.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.7.0.tgz", "integrity": "sha1-XJZ93YN6m/3KXy3oQlOr6KHAO4A=", "requires": { - "argparse": "1.0.9", - "esprima": "2.7.3" + "argparse": "^1.0.7", + "esprima": "^2.6.0" } }, "jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", - "optional": true + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" }, "json-schema": { "version": "0.2.3", @@ -1260,18 +3320,16 @@ "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" }, "json-schema-traverse": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", - "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=" + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" }, "json-stable-stringify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", - "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", - "dev": true, - "optional": true, + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-0.0.1.tgz", + "integrity": "sha1-YRwj6BTbN1Un34URk9tZ3Sryf0U=", "requires": { - "jsonify": "0.0.0" + "jsonify": "~0.0.0" } }, "json-stringify-safe": { @@ -1282,8 +3340,17 @@ "jsonify": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", - "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", - "dev": true, + "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=" + }, + "jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=" + }, + "jsonpointer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz", + "integrity": "sha1-T9kss04OnbPInIYi7PUfm5eMbLk=", "optional": true }, "jsprim": { @@ -1297,13 +3364,227 @@ "verror": "1.10.0" } }, - "keytar": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/keytar/-/keytar-3.0.2.tgz", - "integrity": "sha1-TcFd01I/4wYx+dOIV4pAFRpgWG8=", - "optional": true, + "karma": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/karma/-/karma-2.0.0.tgz", + "integrity": "sha512-K9Kjp8CldLyL9ANSUctDyxC7zH3hpqXj/K09qVf06K3T/kXaHtFZ5tQciK7OzQu68FLvI89Na510kqQ2LCbpIw==", "requires": { - "nan": "2.3.2" + "bluebird": "^3.3.0", + "body-parser": "^1.16.1", + "browserify": "^14.5.0", + "chokidar": "^1.4.1", + "colors": "^1.1.0", + "combine-lists": "^1.0.0", + "connect": "^3.6.0", + "core-js": "^2.2.0", + "di": "^0.0.1", + "dom-serialize": "^2.2.0", + "expand-braces": "^0.1.1", + "glob": "^7.1.1", + "graceful-fs": "^4.1.2", + "http-proxy": "^1.13.0", + "isbinaryfile": "^3.0.0", + "lodash": "^4.17.4", + "log4js": "^2.3.9", + "mime": "^1.3.4", + "minimatch": "^3.0.2", + "optimist": "^0.6.1", + "qjobs": "^1.1.4", + "range-parser": "^1.2.0", + "rimraf": "^2.6.0", + "safe-buffer": "^5.0.1", + "socket.io": "2.0.4", + "source-map": "^0.6.1", + "tmp": "0.0.33", + "useragent": "^2.1.12" + }, + "dependencies": { + "acorn": { + "version": "5.7.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz", + "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==" + }, + "browserify": { + "version": "14.5.0", + "resolved": "https://registry.npmjs.org/browserify/-/browserify-14.5.0.tgz", + "integrity": "sha512-gKfOsNQv/toWz+60nSPfYzuwSEdzvV2WdxrVPUbPD/qui44rAkB3t3muNtmmGYHqrG56FGwX9SUEQmzNLAeS7g==", + "requires": { + "JSONStream": "^1.0.3", + "assert": "^1.4.0", + "browser-pack": "^6.0.1", + "browser-resolve": "^1.11.0", + "browserify-zlib": "~0.2.0", + "buffer": "^5.0.2", + "cached-path-relative": "^1.0.0", + "concat-stream": "~1.5.1", + "console-browserify": "^1.1.0", + "constants-browserify": "~1.0.0", + "crypto-browserify": "^3.0.0", + "defined": "^1.0.0", + "deps-sort": "^2.0.0", + "domain-browser": "~1.1.0", + "duplexer2": "~0.1.2", + "events": "~1.1.0", + "glob": "^7.1.0", + "has": "^1.0.0", + "htmlescape": "^1.1.0", + "https-browserify": "^1.0.0", + "inherits": "~2.0.1", + "insert-module-globals": "^7.0.0", + "labeled-stream-splicer": "^2.0.0", + "module-deps": "^4.0.8", + "os-browserify": "~0.3.0", + "parents": "^1.0.1", + "path-browserify": "~0.0.0", + "process": "~0.11.0", + "punycode": "^1.3.2", + "querystring-es3": "~0.2.0", + "read-only-stream": "^2.0.0", + "readable-stream": "^2.0.2", + "resolve": "^1.1.4", + "shasum": "^1.0.0", + "shell-quote": "^1.6.1", + "stream-browserify": "^2.0.0", + "stream-http": "^2.0.0", + "string_decoder": "~1.0.0", + "subarg": "^1.0.0", + "syntax-error": "^1.1.1", + "through2": "^2.0.0", + "timers-browserify": "^1.0.1", + "tty-browserify": "~0.0.0", + "url": "~0.11.0", + "util": "~0.10.1", + "vm-browserify": "~0.0.1", + "xtend": "^4.0.0" + } + }, + "concat-stream": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.5.2.tgz", + "integrity": "sha1-cIl4Yk2FavQaWnQd790mHadSwmY=", + "requires": { + "inherits": "~2.0.1", + "readable-stream": "~2.0.0", + "typedarray": "~0.0.5" + }, + "dependencies": { + "readable-stream": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz", + "integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "~1.0.0", + "process-nextick-args": "~1.0.6", + "string_decoder": "~0.10.x", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + } + } + }, + "detective": { + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/detective/-/detective-4.7.1.tgz", + "integrity": "sha512-H6PmeeUcZloWtdt4DAkFyzFL94arpHr3NOwwmVILFiy+9Qd4JTxxXrzfyGk/lmct2qVGBwTSwSXagqu2BxmWig==", + "requires": { + "acorn": "^5.2.1", + "defined": "^1.0.0" + } + }, + "domain-browser": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.1.7.tgz", + "integrity": "sha1-hnqksJP6oF8d4IwG9NeyH9+GmLw=" + }, + "events": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", + "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=" + }, + "module-deps": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/module-deps/-/module-deps-4.1.1.tgz", + "integrity": "sha1-IyFYM/HaE/1gbMuAh7RIUty4If0=", + "requires": { + "JSONStream": "^1.0.3", + "browser-resolve": "^1.7.0", + "cached-path-relative": "^1.0.0", + "concat-stream": "~1.5.0", + "defined": "^1.0.0", + "detective": "^4.0.0", + "duplexer2": "^0.1.2", + "inherits": "^2.0.1", + "parents": "^1.0.0", + "readable-stream": "^2.0.2", + "resolve": "^1.1.3", + "stream-combiner2": "^1.1.1", + "subarg": "^1.0.0", + "through2": "^2.0.0", + "xtend": "^4.0.0" + } + }, + "process-nextick-args": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", + "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=" + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "requires": { + "glob": "^7.1.3" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "string_decoder": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "vm-browserify": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-0.0.4.tgz", + "integrity": "sha1-XX6kW7755Kb/ZflUOOCofDV9WnM=", + "requires": { + "indexof": "0.0.1" + } + } + } + }, + "karma-chai": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/karma-chai/-/karma-chai-0.1.0.tgz", + "integrity": "sha1-vuWtQEAFF4Ea40u5RfdikJEIt5o=" + }, + "karma-chrome-launcher": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-2.2.0.tgz", + "integrity": "sha512-uf/ZVpAabDBPvdPdveyk1EPgbnloPvFFGgmRhYLTDH7gEB4nZdSBk8yTU47w1g/drLSx5uMOkjKk7IWKfWg/+w==", + "requires": { + "fs-access": "^1.0.0", + "which": "^1.2.1" + } + }, + "karma-mocha": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/karma-mocha/-/karma-mocha-1.3.0.tgz", + "integrity": "sha1-7qrH/8DiAetjxGdEDStpx883eL8=", + "requires": { + "minimist": "1.2.0" } }, "kind-of": { @@ -1311,231 +3592,426 @@ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } }, - "koalas": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/koalas/-/koalas-1.0.2.tgz", - "integrity": "sha1-MYQz8HQjXbePrlZhoCqMpT7ilc0=" - }, - "lazy-cache": { + "labeled-stream-splicer": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-2.0.2.tgz", - "integrity": "sha1-uRkKT5EzVGlIQIWfio9whNiCImQ=", + "resolved": "https://registry.npmjs.org/labeled-stream-splicer/-/labeled-stream-splicer-2.0.2.tgz", + "integrity": "sha512-Ca4LSXFFZUjPScRaqOcFxneA0VpKZr4MMYCljyQr4LIewTLb3Y0IUTIsnBBsVubIeEfxeSZpSjSsRM8APEQaAw==", "requires": { - "set-getter": "0.1.0" + "inherits": "^2.0.1", + "stream-splicer": "^2.0.0" } }, "less": { "version": "2.7.3", "resolved": "https://registry.npmjs.org/less/-/less-2.7.3.tgz", - "integrity": "sha1-zBJg9RyQCp7A2R+2mYE54CUHtjs=", - "dev": true, + "integrity": "sha512-KPdIJKWcEAb02TuJtaLrhue0krtRLoRoo7x6BNJIBelO00t/CCdJQUnHW5V34OnHMWzIktSalJxRO+FvytQlCQ==", "requires": { - "errno": "0.1.6", - "graceful-fs": "4.1.11", - "image-size": "0.5.5", - "mime": "1.6.0", - "mkdirp": "0.5.1", - "promise": "7.3.1", + "errno": "^0.1.1", + "graceful-fs": "^4.1.2", + "image-size": "~0.5.0", + "mime": "^1.2.11", + "mkdirp": "^0.5.0", + "promise": "^7.1.1", "request": "2.81.0", - "source-map": "0.5.7" + "source-map": "^0.5.3" }, "dependencies": { "ajv": { "version": "4.11.8", "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=", - "dev": true, "optional": true, "requires": { - "co": "4.6.0", - "json-stable-stringify": "1.0.1" + "co": "^4.6.0", + "json-stable-stringify": "^1.0.1" } }, "assert-plus": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz", "integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ=", - "dev": true, "optional": true }, "aws-sign2": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz", "integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8=", - "dev": true, "optional": true }, - "boom": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", - "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", - "dev": true, - "requires": { - "hoek": "2.16.3" - } - }, - "cryptiles": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", - "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=", - "dev": true, - "optional": true, - "requires": { - "boom": "2.10.1" - } - }, "form-data": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz", "integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=", - "dev": true, "optional": true, "requires": { - "asynckit": "0.4.0", - "combined-stream": "1.0.5", - "mime-types": "2.1.17" + "asynckit": "^0.4.0", + "combined-stream": "^1.0.5", + "mime-types": "^2.1.12" } }, "har-schema": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-1.0.5.tgz", "integrity": "sha1-0mMTX0MwfALGAq/I/pWXDAFRNp4=", - "dev": true, "optional": true }, "har-validator": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-4.2.1.tgz", "integrity": "sha1-M0gdDxu/9gDdID11gSpqX7oALio=", - "dev": true, "optional": true, "requires": { - "ajv": "4.11.8", - "har-schema": "1.0.5" + "ajv": "^4.9.1", + "har-schema": "^1.0.5" } }, - "hawk": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", - "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=", - "dev": true, - "optional": true, - "requires": { - "boom": "2.10.1", - "cryptiles": "2.0.5", - "hoek": "2.16.3", - "sntp": "1.0.9" - } - }, - "hoek": { - "version": "2.16.3", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", - "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=", - "dev": true - }, "http-signature": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=", - "dev": true, "optional": true, "requires": { - "assert-plus": "0.2.0", - "jsprim": "1.4.1", - "sshpk": "1.13.1" + "assert-plus": "^0.2.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" } }, + "json-stable-stringify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", + "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", + "optional": true, + "requires": { + "jsonify": "~0.0.0" + } + }, + "oauth-sign": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", + "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=", + "optional": true + }, "performance-now": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-0.2.0.tgz", "integrity": "sha1-M+8wxcd9TqIcWlOGnZG1bY8lVeU=", - "dev": true, "optional": true }, "qs": { "version": "6.4.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz", "integrity": "sha1-E+JtKK1rD/qpExLNO/cI7TUecjM=", - "dev": true, "optional": true }, "request": { "version": "2.81.0", "resolved": "https://registry.npmjs.org/request/-/request-2.81.0.tgz", "integrity": "sha1-xpKJRqDgbF+Nb4qTM0af/aRimKA=", - "dev": true, "optional": true, "requires": { - "aws-sign2": "0.6.0", - "aws4": "1.6.0", - "caseless": "0.12.0", - "combined-stream": "1.0.5", - "extend": "3.0.1", - "forever-agent": "0.6.1", - "form-data": "2.1.4", - "har-validator": "4.2.1", - "hawk": "3.1.3", - "http-signature": "1.1.1", - "is-typedarray": "1.0.0", - "isstream": "0.1.2", - "json-stringify-safe": "5.0.1", - "mime-types": "2.1.17", - "oauth-sign": "0.8.2", - "performance-now": "0.2.0", - "qs": "6.4.0", - "safe-buffer": "5.1.1", - "stringstream": "0.0.5", - "tough-cookie": "2.3.3", - "tunnel-agent": "0.6.0", - "uuid": "3.1.0" + "aws-sign2": "~0.6.0", + "aws4": "^1.2.1", + "caseless": "~0.12.0", + "combined-stream": "~1.0.5", + "extend": "~3.0.0", + "forever-agent": "~0.6.1", + "form-data": "~2.1.1", + "har-validator": "~4.2.1", + "hawk": "~3.1.3", + "http-signature": "~1.1.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.7", + "oauth-sign": "~0.8.1", + "performance-now": "^0.2.0", + "qs": "~6.4.0", + "safe-buffer": "^5.0.1", + "stringstream": "~0.0.4", + "tough-cookie": "~2.3.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.0.0" } }, - "sntp": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", - "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=", - "dev": true, + "tough-cookie": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz", + "integrity": "sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==", "optional": true, "requires": { - "hoek": "2.16.3" + "punycode": "^1.4.1" } } } }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "optional": true, + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, + "libbase64": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/libbase64/-/libbase64-0.1.0.tgz", + "integrity": "sha1-YjUag5VjrF/1vSbxL2Dpgwu3UeY=" + }, + "libmime": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/libmime/-/libmime-3.0.0.tgz", + "integrity": "sha1-UaGp50SOy9Ms2lRCFnW7IbwJPaY=", + "requires": { + "iconv-lite": "0.4.15", + "libbase64": "0.1.0", + "libqp": "1.1.0" + }, + "dependencies": { + "iconv-lite": { + "version": "0.4.15", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.15.tgz", + "integrity": "sha1-/iZaIYrGpXz+hUkn6dBMGYJe3es=" + } + } + }, + "libqp": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/libqp/-/libqp-1.1.0.tgz", + "integrity": "sha1-9ebgatdLeU+1tbZpiL9yjvHe2+g=" + }, + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" + }, "lodash.memoize": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=" + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-3.0.4.tgz", + "integrity": "sha1-LcvSwofLwKVcxCMovQxzYVDVPj8=" }, "lodash.uniq": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=" }, - "log-ok": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/log-ok/-/log-ok-0.1.1.tgz", - "integrity": "sha1-vqPdNqzQuKckDXhza1uXxlREozQ=", + "log4js": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/log4js/-/log4js-2.11.0.tgz", + "integrity": "sha512-z1XdwyGFg8/WGkOyF6DPJjivCWNLKrklGdViywdYnSKOvgtEBo2UyEMZS5sD2mZrQlU3TvO8wDWLc8mzE1ncBQ==", "requires": { - "ansi-green": "0.1.1", - "success-symbol": "0.1.0" + "amqplib": "^0.5.2", + "axios": "^0.15.3", + "circular-json": "^0.5.4", + "date-format": "^1.2.0", + "debug": "^3.1.0", + "hipchat-notifier": "^1.1.0", + "loggly": "^1.1.0", + "mailgun-js": "^0.18.0", + "nodemailer": "^2.5.0", + "redis": "^2.7.1", + "semver": "^5.5.0", + "slack-node": "~0.2.0", + "streamroller": "0.7.0" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } } }, - "log-utils": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/log-utils/-/log-utils-0.2.1.tgz", - "integrity": "sha1-pMIXoN2aUFFdm5ICBgkas9TgMc8=", + "loggly": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/loggly/-/loggly-1.1.1.tgz", + "integrity": "sha1-Cg/B0/o6XsRP3HuJe+uipGlc6+4=", + "optional": true, "requires": { - "ansi-colors": "0.2.0", - "error-symbol": "0.1.0", - "info-symbol": "0.1.0", - "log-ok": "0.1.1", - "success-symbol": "0.1.0", - "time-stamp": "1.1.0", - "warning-symbol": "0.1.0" + "json-stringify-safe": "5.0.x", + "request": "2.75.x", + "timespan": "2.3.x" + }, + "dependencies": { + "assert-plus": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz", + "integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ=", + "optional": true + }, + "aws-sign2": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz", + "integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8=", + "optional": true + }, + "bl": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/bl/-/bl-1.1.2.tgz", + "integrity": "sha1-/cqHGplxOqANGeO7ukHER4emU5g=", + "optional": true, + "requires": { + "readable-stream": "~2.0.5" + } + }, + "caseless": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz", + "integrity": "sha1-cVuW6phBWTzDMGeSP17GDr2k99c=", + "optional": true + }, + "form-data": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.0.0.tgz", + "integrity": "sha1-bwrrrcxdoWwT4ezBETfYX5uIOyU=", + "optional": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.5", + "mime-types": "^2.1.11" + } + }, + "har-validator": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz", + "integrity": "sha1-zcvAgYgmWtEZtqWnyKtw7s+10n0=", + "optional": true, + "requires": { + "chalk": "^1.1.1", + "commander": "^2.9.0", + "is-my-json-valid": "^2.12.4", + "pinkie-promise": "^2.0.0" + } + }, + "http-signature": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", + "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=", + "optional": true, + "requires": { + "assert-plus": "^0.2.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "node-uuid": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.8.tgz", + "integrity": "sha1-sEDrCSOWivq/jTL7HxfxFn/auQc=", + "optional": true + }, + "oauth-sign": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", + "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=", + "optional": true + }, + "process-nextick-args": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", + "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", + "optional": true + }, + "qs": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.2.3.tgz", + "integrity": "sha1-HPyyXBCpsrSDBT/zn138kjOQjP4=", + "optional": true + }, + "readable-stream": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz", + "integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=", + "optional": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "~1.0.0", + "process-nextick-args": "~1.0.6", + "string_decoder": "~0.10.x", + "util-deprecate": "~1.0.1" + } + }, + "request": { + "version": "2.75.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.75.0.tgz", + "integrity": "sha1-0rgmiihtoT6qXQGt9dGMyQ9lfZM=", + "optional": true, + "requires": { + "aws-sign2": "~0.6.0", + "aws4": "^1.2.1", + "bl": "~1.1.2", + "caseless": "~0.11.0", + "combined-stream": "~1.0.5", + "extend": "~3.0.0", + "forever-agent": "~0.6.1", + "form-data": "~2.0.0", + "har-validator": "~2.0.6", + "hawk": "~3.1.3", + "http-signature": "~1.1.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.7", + "node-uuid": "~1.4.7", + "oauth-sign": "~0.8.1", + "qs": "~6.2.0", + "stringstream": "~0.0.4", + "tough-cookie": "~2.3.0", + "tunnel-agent": "~0.4.1" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "optional": true + }, + "tough-cookie": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz", + "integrity": "sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==", + "optional": true, + "requires": { + "punycode": "^1.4.1" + } + }, + "tunnel-agent": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz", + "integrity": "sha1-Y3PbdpCf5XDgjXNYM2Xtgop07us=", + "optional": true + } + } + }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, + "lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" } }, "lzma": { @@ -1543,76 +4019,178 @@ "resolved": "https://registry.npmjs.org/lzma/-/lzma-2.3.2.tgz", "integrity": "sha1-N4OySFi5wOdHoN88vx+1/KqSxEE=" }, - "macaddress": { - "version": "0.2.8", - "resolved": "https://registry.npmjs.org/macaddress/-/macaddress-0.2.8.tgz", - "integrity": "sha1-WQTcU3w57G2+/q6QIycTX6hRHxI=" + "mailcomposer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/mailcomposer/-/mailcomposer-4.0.1.tgz", + "integrity": "sha1-DhxEsqB890DuF9wUm6AJ8Zyt/rQ=", + "optional": true, + "requires": { + "buildmail": "4.0.1", + "libmime": "3.0.0" + } + }, + "mailgun-js": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/mailgun-js/-/mailgun-js-0.18.1.tgz", + "integrity": "sha512-lvuMP14u24HS2uBsJEnzSyPMxzU2b99tQsIx1o6QNjqxjk8b3WvR+vq5oG1mjqz/IBYo+5gF+uSoDS0RkMVHmg==", + "optional": true, + "requires": { + "async": "~2.6.0", + "debug": "~3.1.0", + "form-data": "~2.3.0", + "inflection": "~1.12.0", + "is-stream": "^1.1.0", + "path-proxy": "~1.0.0", + "promisify-call": "^2.0.2", + "proxy-agent": "~3.0.0", + "tsscmp": "~1.0.0" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "optional": true, + "requires": { + "ms": "2.0.0" + } + } + } + }, + "map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=" }, "map-visit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", - "optional": true, "requires": { - "object-visit": "1.0.1" + "object-visit": "^1.0.0" } }, "marked": { - "version": "0.3.7", - "resolved": "https://registry.npmjs.org/marked/-/marked-0.3.7.tgz", - "integrity": "sha1-gO87vxvQDRyc/r5CuhuMhdoljQ0=" + "version": "0.3.19", + "resolved": "https://registry.npmjs.org/marked/-/marked-0.3.19.tgz", + "integrity": "sha512-ea2eGWOqNxPcXv8dyERdSr/6FmzvWwzjMxpfGB/sbMccXoct+xY+YukPD+QTUZwyvK7BZwcr4m21WBOW41pAkg==" }, "math-expression-evaluator": { "version": "1.2.17", "resolved": "https://registry.npmjs.org/math-expression-evaluator/-/math-expression-evaluator-1.2.17.tgz", "integrity": "sha1-3oGf282E3M2PrlnGrreWFbnSZqw=" }, + "math-random": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.4.tgz", + "integrity": "sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A==" + }, + "md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + }, + "micromatch": { + "version": "2.3.11", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", + "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", + "requires": { + "arr-diff": "^2.0.0", + "array-unique": "^0.2.1", + "braces": "^1.8.2", + "expand-brackets": "^0.1.4", + "extglob": "^0.3.1", + "filename-regex": "^2.0.0", + "is-extglob": "^1.0.0", + "is-glob": "^2.0.1", + "kind-of": "^3.0.2", + "normalize-path": "^2.0.1", + "object.omit": "^2.0.0", + "parse-glob": "^3.0.4", + "regex-cache": "^0.4.2" + } + }, + "miller-rabin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", + "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", + "requires": { + "bn.js": "^4.0.0", + "brorand": "^1.0.1" + } + }, "mime": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha1-Ms2eXGRVO9WNGaVor0Uqz/BJgbE=", - "dev": true, - "optional": true + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" }, "mime-db": { - "version": "1.30.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz", - "integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE=" + "version": "1.42.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.42.0.tgz", + "integrity": "sha512-UbfJCR4UAVRNgMpfImz05smAXK7+c+ZntjaA26ANtkXLlOe947Aag5zdIcKQULAiF9Cq4WxBi9jUs5zkA84bYQ==" }, "mime-types": { - "version": "2.1.17", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz", - "integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=", + "version": "2.1.25", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.25.tgz", + "integrity": "sha512-5KhStqB5xpTAeGqKBAMgwaYMnQik7teQN4IAzC7npDv6kzeU6prfkR67bc87J1kWMPGkoaZSq1npmexMgkmEVg==", "requires": { - "mime-db": "1.30.0" + "mime-db": "1.42.0" } }, + "mimic-response": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.0.0.tgz", + "integrity": "sha512-8ilDoEapqA4uQ3TwS0jakGONKXVJqpy+RpM+3b7pLdOjghCrEiGp9SRkFbUHAmZW9vdnrENWHjaweIoTIJExSQ==" + }, + "minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + }, + "minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" + }, "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "requires": { - "brace-expansion": "1.1.8" + "brace-expansion": "^1.1.7" } }, "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" }, - "mixin-object": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/mixin-object/-/mixin-object-2.0.1.tgz", - "integrity": "sha1-T7lJRB2rGCVA8f4DW6YOGUel5X4=", + "mixin-deep": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", "requires": { - "for-in": "0.1.8", - "is-extendable": "0.1.1" + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" }, "dependencies": { - "for-in": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-0.1.8.tgz", - "integrity": "sha1-2Hc5COMSVhCZUrH9ubP6hn0ndeE=" + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "requires": { + "is-plain-object": "^2.0.4" + } } } }, @@ -1622,6 +4200,94 @@ "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "requires": { "minimist": "0.0.8" + }, + "dependencies": { + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + } + } + }, + "mocha": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-5.1.0.tgz", + "integrity": "sha512-d6RWgYPILd+AoWVOxiD0UwUqRicnE1inTxMr40CXOgqYve1MvnKntoLAtLIcxjEeVjEoYYTe5QAq3mUc6/ySjQ==", + "requires": { + "browser-stdout": "1.3.1", + "commander": "2.11.0", + "debug": "3.1.0", + "diff": "3.5.0", + "escape-string-regexp": "1.0.5", + "glob": "7.1.2", + "growl": "1.10.3", + "he": "1.1.1", + "minimatch": "3.0.4", + "mkdirp": "0.5.1", + "supports-color": "4.4.0" + }, + "dependencies": { + "commander": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz", + "integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==" + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=" + }, + "supports-color": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", + "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", + "requires": { + "has-flag": "^2.0.0" + } + } + } + }, + "module-deps": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/module-deps/-/module-deps-6.2.1.tgz", + "integrity": "sha512-UnEn6Ah36Tu4jFiBbJVUtt0h+iXqxpLqDvPS8nllbw5RZFmNJ1+Mz5BjYnM9ieH80zyxHkARGLnMIHlPK5bu6A==", + "requires": { + "JSONStream": "^1.0.3", + "browser-resolve": "^1.7.0", + "cached-path-relative": "^1.0.2", + "concat-stream": "~1.6.0", + "defined": "^1.0.0", + "detective": "^5.0.2", + "duplexer2": "^0.1.2", + "inherits": "^2.0.1", + "parents": "^1.0.0", + "readable-stream": "^2.0.2", + "resolve": "^1.4.0", + "stream-combiner2": "^1.1.1", + "subarg": "^1.0.0", + "through2": "^2.0.0", + "xtend": "^4.0.0" } }, "ms": { @@ -1629,50 +4295,165 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, - "mute-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", - "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=" - }, "nan": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.3.2.tgz", - "integrity": "sha1-TU7PF+HaTpie+08nPY0AIBytCH4=", + "version": "2.13.2", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.13.2.tgz", + "integrity": "sha512-TghvYc72wlMGMVMluVo9WRJc0mB8KxxF/gZ4YYFy7V2ZQX9l7rgbPg7vjS9mt6U5HXODVFVI2bOduCzwOMv/lw==" + }, + "nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=" + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=" + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" + } + } + }, + "napi-build-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.1.tgz", + "integrity": "sha512-boQj1WFgQH3v4clhu3mTNfP+vOBxorDlE8EKiMjUlLG3C4qAESnn9AxIOkFgTR2c9LtzNjPrjS60cT27ZKBhaA==" + }, + "negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" + }, + "netmask": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/netmask/-/netmask-1.0.6.tgz", + "integrity": "sha1-ICl+idhvb2QA8lDZ9Pa0wZRfzTU=", "optional": true }, "node-abi": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.1.2.tgz", - "integrity": "sha1-TabKzrZoX80x590ZlO9rt9CpwLI=", - "optional": true, + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.12.0.tgz", + "integrity": "sha512-VhPBXCIcvmo/5K8HPmnWJyyhvgKxnHTUMXR/XwGHV68+wrgkzST4UmQrY/XszSWA5dtnXpNp528zkcyJ/pzVcw==", "requires": { - "semver": "5.4.1" + "semver": "^5.4.1" } }, - "node-hid": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/node-hid/-/node-hid-0.5.7.tgz", - "integrity": "sha1-XIfDPkvLnbZN7PIbo8e50BTqwSM=", + "nodemailer": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-2.7.2.tgz", + "integrity": "sha1-8kLmSa7q45tsftdA73sGHEBNMPk=", "optional": true, "requires": { - "bindings": "1.3.0", - "nan": "2.8.0", - "prebuild-install": "2.4.1" + "libmime": "3.0.0", + "mailcomposer": "4.0.1", + "nodemailer-direct-transport": "3.3.2", + "nodemailer-shared": "1.1.0", + "nodemailer-smtp-pool": "2.8.2", + "nodemailer-smtp-transport": "2.7.2", + "socks": "1.1.9" }, "dependencies": { - "nan": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.8.0.tgz", - "integrity": "sha1-7XFfP+neArV6XmJS2QqWZ14fCFo=", + "smart-buffer": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-1.1.15.tgz", + "integrity": "sha1-fxFLW2X6s+KjWqd1uxLw0cZJvxY=", "optional": true + }, + "socks": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/socks/-/socks-1.1.9.tgz", + "integrity": "sha1-Yo1+TQSRJDVEWsC25Fk3bLPm1pE=", + "optional": true, + "requires": { + "ip": "^1.1.2", + "smart-buffer": "^1.0.4" + } } } }, + "nodemailer-direct-transport": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/nodemailer-direct-transport/-/nodemailer-direct-transport-3.3.2.tgz", + "integrity": "sha1-6W+vuQNYVglH5WkBfZfmBzilCoY=", + "optional": true, + "requires": { + "nodemailer-shared": "1.1.0", + "smtp-connection": "2.12.0" + } + }, + "nodemailer-fetch": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/nodemailer-fetch/-/nodemailer-fetch-1.6.0.tgz", + "integrity": "sha1-ecSQihwPXzdbc/6IjamCj23JY6Q=" + }, + "nodemailer-shared": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/nodemailer-shared/-/nodemailer-shared-1.1.0.tgz", + "integrity": "sha1-z1mU4v0mjQD1zw+nZ6CBae2wfsA=", + "requires": { + "nodemailer-fetch": "1.6.0" + } + }, + "nodemailer-smtp-pool": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/nodemailer-smtp-pool/-/nodemailer-smtp-pool-2.8.2.tgz", + "integrity": "sha1-LrlNbPhXgLG0clzoU7nL1ejajHI=", + "optional": true, + "requires": { + "nodemailer-shared": "1.1.0", + "nodemailer-wellknown": "0.1.10", + "smtp-connection": "2.12.0" + } + }, + "nodemailer-smtp-transport": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/nodemailer-smtp-transport/-/nodemailer-smtp-transport-2.7.2.tgz", + "integrity": "sha1-A9ccdjFPFKx9vHvwM6am0W1n+3c=", + "optional": true, + "requires": { + "nodemailer-shared": "1.1.0", + "nodemailer-wellknown": "0.1.10", + "smtp-connection": "2.12.0" + } + }, + "nodemailer-wellknown": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/nodemailer-wellknown/-/nodemailer-wellknown-0.1.10.tgz", + "integrity": "sha1-WG24EB2zDLRDjrVGc3pBqtDPE9U=" + }, "noop-logger": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/noop-logger/-/noop-logger-0.1.1.tgz", - "integrity": "sha1-lKKxYzxPExdVMAfYlm/Q6EG2pMI=", - "optional": true + "integrity": "sha1-lKKxYzxPExdVMAfYlm/Q6EG2pMI=" + }, + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "requires": { + "remove-trailing-separator": "^1.0.1" + } }, "normalize-range": { "version": "0.1.2", @@ -1684,24 +4465,28 @@ "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-1.9.1.tgz", "integrity": "sha1-LMDWazHqIwNkWENuNiDYWVTGbDw=", "requires": { - "object-assign": "4.1.1", - "prepend-http": "1.0.4", - "query-string": "4.3.4", - "sort-keys": "1.1.2" + "object-assign": "^4.0.1", + "prepend-http": "^1.0.0", + "query-string": "^4.1.0", + "sort-keys": "^1.0.0" } }, "npmlog": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", - "integrity": "sha1-CKfyqL9zRgR3mp76StXMcXq7lUs=", - "optional": true, + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", "requires": { - "are-we-there-yet": "1.1.4", - "console-control-strings": "1.1.0", - "gauge": "2.7.4", - "set-blocking": "2.0.0" + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" } }, + "null-check": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/null-check/-/null-check-1.0.0.tgz", + "integrity": "sha1-l33/1xdgErnsMNKjnbXPcqBDnt0=" + }, "num2fraction": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz", @@ -1713,70 +4498,36 @@ "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" }, "oauth-sign": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", - "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=" + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" }, "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" }, + "object-component": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz", + "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=" + }, "object-copy": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", - "optional": true, "requires": { - "copy-descriptor": "0.1.1", - "define-property": "0.2.5", - "kind-of": "3.2.2" + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" }, "dependencies": { "define-property": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "optional": true, "requires": { - "is-descriptor": "0.1.6" - } - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "optional": true, - "requires": { - "kind-of": "3.2.2" - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "optional": true, - "requires": { - "kind-of": "3.2.2" - } - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "optional": true, - "requires": { - "is-accessor-descriptor": "0.1.6", - "is-data-descriptor": "0.1.4", - "kind-of": "5.1.0" - }, - "dependencies": { - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "optional": true - } + "is-descriptor": "^0.1.0" } } } @@ -1786,7 +4537,46 @@ "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", "requires": { - "isobject": "3.0.1" + "isobject": "^3.0.0" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" + } + } + }, + "object.omit": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", + "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=", + "requires": { + "for-own": "^0.1.4", + "is-extendable": "^0.1.1" + } + }, + "object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "requires": { + "isobject": "^3.0.1" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" + } + } + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "requires": { + "ee-first": "1.1.1" } }, "once": { @@ -1794,75 +4584,301 @@ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "requires": { - "wrappy": "1.0.2" + "wrappy": "1" } }, - "os-homedir": { + "optimist": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", + "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", + "requires": { + "minimist": "~0.0.1", + "wordwrap": "~0.0.2" + }, + "dependencies": { + "minimist": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", + "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=" + } + } + }, + "optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "optional": true, + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + } + }, + "os-browserify": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", + "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=" + }, + "os-tmpdir": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", - "optional": true + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" + }, + "pac-proxy-agent": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-3.0.1.tgz", + "integrity": "sha512-44DUg21G/liUZ48dJpUSjZnFfZro/0K5JTyFYLBcmh9+T6Ooi4/i4efwUiEy0+4oQusCBqWdhv16XohIj1GqnQ==", + "optional": true, + "requires": { + "agent-base": "^4.2.0", + "debug": "^4.1.1", + "get-uri": "^2.0.0", + "http-proxy-agent": "^2.1.0", + "https-proxy-agent": "^3.0.0", + "pac-resolver": "^3.0.0", + "raw-body": "^2.2.0", + "socks-proxy-agent": "^4.0.1" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "optional": true, + "requires": { + "ms": "^2.1.1" + } + }, + "https-proxy-agent": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-3.0.1.tgz", + "integrity": "sha512-+ML2Rbh6DAuee7d07tYGEKOEi2voWPUGan+ExdPbPW6Z3svq+JCqr0v8WmKPOkz1vOVykPCBSuobe7G8GJUtVg==", + "optional": true, + "requires": { + "agent-base": "^4.3.0", + "debug": "^3.1.0" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "optional": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, + "pac-resolver": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-3.0.0.tgz", + "integrity": "sha512-tcc38bsjuE3XZ5+4vP96OfhOugrX+JcnpUbhfuc4LuXBLQhoTthOstZeoQJBDnQUDYzYmdImKsbz0xSl1/9qeA==", + "optional": true, + "requires": { + "co": "^4.6.0", + "degenerator": "^1.0.4", + "ip": "^1.1.5", + "netmask": "^1.0.6", + "thunkify": "^2.1.2" + } + }, + "pako": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.10.tgz", + "integrity": "sha512-0DTvPVU3ed8+HNXOu5Bs+o//Mbdj9VNQMUOe9oKCwh8l0GNwpTDMKCWbRjgtD291AWnkAgkqA/LOnQS8AmS1tw==" + }, + "parents": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parents/-/parents-1.0.1.tgz", + "integrity": "sha1-/t1NK/GTp3dF/nHjcdc8MwfZx1E=", + "requires": { + "path-platform": "~0.11.15" + } + }, + "parse-asn1": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.5.tgz", + "integrity": "sha512-jkMYn1dcJqF6d5CpU689bq7w/b5ALS9ROVSpQDPrZsqqesUJii9qutvoT5ltGedNXMO2e16YUWIghG9KxaViTQ==", + "requires": { + "asn1.js": "^4.0.0", + "browserify-aes": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.0", + "pbkdf2": "^3.0.3", + "safe-buffer": "^5.1.1" + } + }, + "parse-glob": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", + "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=", + "requires": { + "glob-base": "^0.3.0", + "is-dotfile": "^1.0.0", + "is-extglob": "^1.0.0", + "is-glob": "^2.0.0" + } + }, + "parseqs": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz", + "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=", + "requires": { + "better-assert": "~1.0.0" + } + }, + "parseuri": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz", + "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=", + "requires": { + "better-assert": "~1.0.0" + } + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" + }, + "pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=" + }, + "path-browserify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz", + "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==" }, "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" + }, + "path-platform": { + "version": "0.11.15", + "resolved": "https://registry.npmjs.org/path-platform/-/path-platform-0.11.15.tgz", + "integrity": "sha1-6GQhf3TDaFDwhSt43Hv31KVyG/I=" + }, + "path-proxy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/path-proxy/-/path-proxy-1.0.0.tgz", + "integrity": "sha1-GOijaFn8nS8aU7SN7hOFQ8Ag3l4=", + "optional": true, + "requires": { + "inflection": "~1.3.0" + }, + "dependencies": { + "inflection": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/inflection/-/inflection-1.3.8.tgz", + "integrity": "sha1-y9Fg2p91sUw8xjV41POWeEvzAU4=", + "optional": true + } + } + }, + "pbkdf2": { + "version": "3.0.17", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.17.tgz", + "integrity": "sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA==", + "requires": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, "performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" }, - "pointer-symbol": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/pointer-symbol/-/pointer-symbol-1.0.0.tgz", - "integrity": "sha1-YPkRAgTqepKbYmRKITFVQ8uz1Ec=", + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", "optional": true }, - "postcss": { - "version": "6.0.14", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.14.tgz", - "integrity": "sha1-VTTHIRRznnXQr88BfbhTCZ9WKIU=", + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "optional": true, "requires": { - "chalk": "2.3.0", - "source-map": "0.6.1", - "supports-color": "4.5.0" + "pinkie": "^2.0.0" + } + }, + "pngjs": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-3.4.0.tgz", + "integrity": "sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==" + }, + "posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=" + }, + "postcss": { + "version": "6.0.21", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.21.tgz", + "integrity": "sha512-y/bKfbQz2Nn/QBC08bwvYUxEFOVGfPIUOTsJ2CK5inzlXW9SdYR1x4pEsG9blRAF/PX+wRNdOah+gx/hv4q7dw==", + "requires": { + "chalk": "^2.3.2", + "source-map": "^0.6.1", + "supports-color": "^5.3.0" }, "dependencies": { "ansi-styles": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", - "integrity": "sha1-wVm41b4PnlpvNG2rlPFs4CIWG4g=", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "requires": { - "color-convert": "1.9.1" + "color-convert": "^1.9.0" } }, "chalk": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.0.tgz", - "integrity": "sha1-tepI78nBeT3MybR2fJORTT8tUro=", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { - "ansi-styles": "3.2.0", - "escape-string-regexp": "1.0.5", - "supports-color": "4.5.0" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" } }, "has-flag": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", - "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=" + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=" + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" }, "supports-color": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", - "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "has-flag": "2.0.0" + "has-flag": "^3.0.0" } } } @@ -1872,20 +4888,20 @@ "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-5.3.1.tgz", "integrity": "sha1-d7rnypKK2FcW4v2kLyYb98HWW14=", "requires": { - "postcss": "5.2.18", - "postcss-message-helpers": "2.0.0", - "reduce-css-calc": "1.3.0" + "postcss": "^5.0.2", + "postcss-message-helpers": "^2.0.0", + "reduce-css-calc": "^1.2.6" }, "dependencies": { "postcss": { "version": "5.2.18", "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha1-ut+hSX1GJE9jkPWLMZgw2RB4U8U=", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", "requires": { - "chalk": "1.1.3", - "js-base64": "2.4.0", - "source-map": "0.5.7", - "supports-color": "3.2.3" + "chalk": "^1.1.3", + "js-base64": "^2.1.9", + "source-map": "^0.5.6", + "supports-color": "^3.2.3" } } } @@ -1895,20 +4911,20 @@ "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-2.2.2.tgz", "integrity": "sha1-ZjFBfV8OkJo9fsJrJMio0eT5bks=", "requires": { - "colormin": "1.1.2", - "postcss": "5.2.18", - "postcss-value-parser": "3.3.0" + "colormin": "^1.0.5", + "postcss": "^5.0.13", + "postcss-value-parser": "^3.2.3" }, "dependencies": { "postcss": { "version": "5.2.18", "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha1-ut+hSX1GJE9jkPWLMZgw2RB4U8U=", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", "requires": { - "chalk": "1.1.3", - "js-base64": "2.4.0", - "source-map": "0.5.7", - "supports-color": "3.2.3" + "chalk": "^1.1.3", + "js-base64": "^2.1.9", + "source-map": "^0.5.6", + "supports-color": "^3.2.3" } } } @@ -1918,19 +4934,19 @@ "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-2.6.1.tgz", "integrity": "sha1-u9hZPFwf0uPRwyK7kl3K6Nrk1i0=", "requires": { - "postcss": "5.2.18", - "postcss-value-parser": "3.3.0" + "postcss": "^5.0.11", + "postcss-value-parser": "^3.1.2" }, "dependencies": { "postcss": { "version": "5.2.18", "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha1-ut+hSX1GJE9jkPWLMZgw2RB4U8U=", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", "requires": { - "chalk": "1.1.3", - "js-base64": "2.4.0", - "source-map": "0.5.7", - "supports-color": "3.2.3" + "chalk": "^1.1.3", + "js-base64": "^2.1.9", + "source-map": "^0.5.6", + "supports-color": "^3.2.3" } } } @@ -1940,18 +4956,18 @@ "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-2.0.4.tgz", "integrity": "sha1-vv6J+v1bPazlzM5Rt2uBUUvgDj0=", "requires": { - "postcss": "5.2.18" + "postcss": "^5.0.14" }, "dependencies": { "postcss": { "version": "5.2.18", "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha1-ut+hSX1GJE9jkPWLMZgw2RB4U8U=", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", "requires": { - "chalk": "1.1.3", - "js-base64": "2.4.0", - "source-map": "0.5.7", - "supports-color": "3.2.3" + "chalk": "^1.1.3", + "js-base64": "^2.1.9", + "source-map": "^0.5.6", + "supports-color": "^3.2.3" } } } @@ -1961,18 +4977,18 @@ "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-2.1.0.tgz", "integrity": "sha1-uavye4isGIFYpesSq8riAmO5GTI=", "requires": { - "postcss": "5.2.18" + "postcss": "^5.0.4" }, "dependencies": { "postcss": { "version": "5.2.18", "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha1-ut+hSX1GJE9jkPWLMZgw2RB4U8U=", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", "requires": { - "chalk": "1.1.3", - "js-base64": "2.4.0", - "source-map": "0.5.7", - "supports-color": "3.2.3" + "chalk": "^1.1.3", + "js-base64": "^2.1.9", + "source-map": "^0.5.6", + "supports-color": "^3.2.3" } } } @@ -1982,18 +4998,18 @@ "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-2.1.0.tgz", "integrity": "sha1-0rS9nVztXr2Nyt52QMfXzX9PkrU=", "requires": { - "postcss": "5.2.18" + "postcss": "^5.0.14" }, "dependencies": { "postcss": { "version": "5.2.18", "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha1-ut+hSX1GJE9jkPWLMZgw2RB4U8U=", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", "requires": { - "chalk": "1.1.3", - "js-base64": "2.4.0", - "source-map": "0.5.7", - "supports-color": "3.2.3" + "chalk": "^1.1.3", + "js-base64": "^2.1.9", + "source-map": "^0.5.6", + "supports-color": "^3.2.3" } } } @@ -2003,18 +5019,18 @@ "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-0.1.1.tgz", "integrity": "sha1-ix6vVU9ob7KIzYdMVWZ7CqNmjVg=", "requires": { - "postcss": "5.2.18" + "postcss": "^5.0.16" }, "dependencies": { "postcss": { "version": "5.2.18", "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha1-ut+hSX1GJE9jkPWLMZgw2RB4U8U=", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", "requires": { - "chalk": "1.1.3", - "js-base64": "2.4.0", - "source-map": "0.5.7", - "supports-color": "3.2.3" + "chalk": "^1.1.3", + "js-base64": "^2.1.9", + "source-map": "^0.5.6", + "supports-color": "^3.2.3" } } } @@ -2024,41 +5040,40 @@ "resolved": "https://registry.npmjs.org/postcss-discard-unused/-/postcss-discard-unused-2.2.3.tgz", "integrity": "sha1-vOMLLMWR/8Y0Mitfs0ZLbZNPRDM=", "requires": { - "postcss": "5.2.18", - "uniqs": "2.0.0" + "postcss": "^5.0.14", + "uniqs": "^2.0.0" }, "dependencies": { "postcss": { "version": "5.2.18", "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha1-ut+hSX1GJE9jkPWLMZgw2RB4U8U=", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", "requires": { - "chalk": "1.1.3", - "js-base64": "2.4.0", - "source-map": "0.5.7", - "supports-color": "3.2.3" + "chalk": "^1.1.3", + "js-base64": "^2.1.9", + "source-map": "^0.5.6", + "supports-color": "^3.2.3" } } } }, "postcss-filter-plugins": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/postcss-filter-plugins/-/postcss-filter-plugins-2.0.2.tgz", - "integrity": "sha1-bYWGJTTXNaxCDkqFgG4fXUKG2Ew=", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/postcss-filter-plugins/-/postcss-filter-plugins-2.0.3.tgz", + "integrity": "sha512-T53GVFsdinJhgwm7rg1BzbeBRomOg9y5MBVhGcsV0CxurUdVj1UlPdKtn7aqYA/c/QVkzKMjq2bSV5dKG5+AwQ==", "requires": { - "postcss": "5.2.18", - "uniqid": "4.1.1" + "postcss": "^5.0.4" }, "dependencies": { "postcss": { "version": "5.2.18", "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha1-ut+hSX1GJE9jkPWLMZgw2RB4U8U=", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", "requires": { - "chalk": "1.1.3", - "js-base64": "2.4.0", - "source-map": "0.5.7", - "supports-color": "3.2.3" + "chalk": "^1.1.3", + "js-base64": "^2.1.9", + "source-map": "^0.5.6", + "supports-color": "^3.2.3" } } } @@ -2068,20 +5083,20 @@ "resolved": "https://registry.npmjs.org/postcss-merge-idents/-/postcss-merge-idents-2.1.7.tgz", "integrity": "sha1-TFUwMTwI4dWzu/PSu8dH4njuonA=", "requires": { - "has": "1.0.1", - "postcss": "5.2.18", - "postcss-value-parser": "3.3.0" + "has": "^1.0.1", + "postcss": "^5.0.10", + "postcss-value-parser": "^3.1.1" }, "dependencies": { "postcss": { "version": "5.2.18", "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha1-ut+hSX1GJE9jkPWLMZgw2RB4U8U=", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", "requires": { - "chalk": "1.1.3", - "js-base64": "2.4.0", - "source-map": "0.5.7", - "supports-color": "3.2.3" + "chalk": "^1.1.3", + "js-base64": "^2.1.9", + "source-map": "^0.5.6", + "supports-color": "^3.2.3" } } } @@ -2091,18 +5106,18 @@ "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-2.0.2.tgz", "integrity": "sha1-I9kM0Sewp3mUkVMyc5A0oaTz1lg=", "requires": { - "postcss": "5.2.18" + "postcss": "^5.0.4" }, "dependencies": { "postcss": { "version": "5.2.18", "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha1-ut+hSX1GJE9jkPWLMZgw2RB4U8U=", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", "requires": { - "chalk": "1.1.3", - "js-base64": "2.4.0", - "source-map": "0.5.7", - "supports-color": "3.2.3" + "chalk": "^1.1.3", + "js-base64": "^2.1.9", + "source-map": "^0.5.6", + "supports-color": "^3.2.3" } } } @@ -2112,22 +5127,22 @@ "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-2.1.2.tgz", "integrity": "sha1-0d9d+qexrMO+VT8OnhDofGG19yE=", "requires": { - "browserslist": "1.7.7", - "caniuse-api": "1.6.1", - "postcss": "5.2.18", - "postcss-selector-parser": "2.2.3", - "vendors": "1.0.1" + "browserslist": "^1.5.2", + "caniuse-api": "^1.5.2", + "postcss": "^5.0.4", + "postcss-selector-parser": "^2.2.2", + "vendors": "^1.0.0" }, "dependencies": { "postcss": { "version": "5.2.18", "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha1-ut+hSX1GJE9jkPWLMZgw2RB4U8U=", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", "requires": { - "chalk": "1.1.3", - "js-base64": "2.4.0", - "source-map": "0.5.7", - "supports-color": "3.2.3" + "chalk": "^1.1.3", + "js-base64": "^2.1.9", + "source-map": "^0.5.6", + "supports-color": "^3.2.3" } } } @@ -2142,20 +5157,20 @@ "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-1.0.5.tgz", "integrity": "sha1-S1jttWZB66fIR0qzUmyv17vey2k=", "requires": { - "object-assign": "4.1.1", - "postcss": "5.2.18", - "postcss-value-parser": "3.3.0" + "object-assign": "^4.0.1", + "postcss": "^5.0.4", + "postcss-value-parser": "^3.0.2" }, "dependencies": { "postcss": { "version": "5.2.18", "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha1-ut+hSX1GJE9jkPWLMZgw2RB4U8U=", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", "requires": { - "chalk": "1.1.3", - "js-base64": "2.4.0", - "source-map": "0.5.7", - "supports-color": "3.2.3" + "chalk": "^1.1.3", + "js-base64": "^2.1.9", + "source-map": "^0.5.6", + "supports-color": "^3.2.3" } } } @@ -2165,19 +5180,19 @@ "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-1.0.5.tgz", "integrity": "sha1-Xb2hE3NwP4PPtKPqOIHY11/15uE=", "requires": { - "postcss": "5.2.18", - "postcss-value-parser": "3.3.0" + "postcss": "^5.0.12", + "postcss-value-parser": "^3.3.0" }, "dependencies": { "postcss": { "version": "5.2.18", "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha1-ut+hSX1GJE9jkPWLMZgw2RB4U8U=", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", "requires": { - "chalk": "1.1.3", - "js-base64": "2.4.0", - "source-map": "0.5.7", - "supports-color": "3.2.3" + "chalk": "^1.1.3", + "js-base64": "^2.1.9", + "source-map": "^0.5.6", + "supports-color": "^3.2.3" } } } @@ -2187,21 +5202,21 @@ "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-1.2.2.tgz", "integrity": "sha1-rSzgcTc7lDs9kwo/pZo1jCjW8fM=", "requires": { - "alphanum-sort": "1.0.2", - "postcss": "5.2.18", - "postcss-value-parser": "3.3.0", - "uniqs": "2.0.0" + "alphanum-sort": "^1.0.1", + "postcss": "^5.0.2", + "postcss-value-parser": "^3.0.2", + "uniqs": "^2.0.0" }, "dependencies": { "postcss": { "version": "5.2.18", "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha1-ut+hSX1GJE9jkPWLMZgw2RB4U8U=", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", "requires": { - "chalk": "1.1.3", - "js-base64": "2.4.0", - "source-map": "0.5.7", - "supports-color": "3.2.3" + "chalk": "^1.1.3", + "js-base64": "^2.1.9", + "source-map": "^0.5.6", + "supports-color": "^3.2.3" } } } @@ -2211,21 +5226,21 @@ "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-2.1.1.tgz", "integrity": "sha1-ssapjAByz5G5MtGkllCBFDEXNb8=", "requires": { - "alphanum-sort": "1.0.2", - "has": "1.0.1", - "postcss": "5.2.18", - "postcss-selector-parser": "2.2.3" + "alphanum-sort": "^1.0.2", + "has": "^1.0.1", + "postcss": "^5.0.14", + "postcss-selector-parser": "^2.0.0" }, "dependencies": { "postcss": { "version": "5.2.18", "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha1-ut+hSX1GJE9jkPWLMZgw2RB4U8U=", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", "requires": { - "chalk": "1.1.3", - "js-base64": "2.4.0", - "source-map": "0.5.7", - "supports-color": "3.2.3" + "chalk": "^1.1.3", + "js-base64": "^2.1.9", + "source-map": "^0.5.6", + "supports-color": "^3.2.3" } } } @@ -2235,18 +5250,18 @@ "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-1.1.1.tgz", "integrity": "sha1-757nEhLX/nWceO0WL2HtYrXLk/E=", "requires": { - "postcss": "5.2.18" + "postcss": "^5.0.5" }, "dependencies": { "postcss": { "version": "5.2.18", "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha1-ut+hSX1GJE9jkPWLMZgw2RB4U8U=", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", "requires": { - "chalk": "1.1.3", - "js-base64": "2.4.0", - "source-map": "0.5.7", - "supports-color": "3.2.3" + "chalk": "^1.1.3", + "js-base64": "^2.1.9", + "source-map": "^0.5.6", + "supports-color": "^3.2.3" } } } @@ -2256,21 +5271,21 @@ "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-3.0.8.tgz", "integrity": "sha1-EI90s/L82viRov+j6kWSJ5/HgiI=", "requires": { - "is-absolute-url": "2.1.0", - "normalize-url": "1.9.1", - "postcss": "5.2.18", - "postcss-value-parser": "3.3.0" + "is-absolute-url": "^2.0.0", + "normalize-url": "^1.4.0", + "postcss": "^5.0.14", + "postcss-value-parser": "^3.2.3" }, "dependencies": { "postcss": { "version": "5.2.18", "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha1-ut+hSX1GJE9jkPWLMZgw2RB4U8U=", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", "requires": { - "chalk": "1.1.3", - "js-base64": "2.4.0", - "source-map": "0.5.7", - "supports-color": "3.2.3" + "chalk": "^1.1.3", + "js-base64": "^2.1.9", + "source-map": "^0.5.6", + "supports-color": "^3.2.3" } } } @@ -2280,19 +5295,19 @@ "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-2.2.3.tgz", "integrity": "sha1-7sbCpntsQSqNsgQud/6NpD+VwR0=", "requires": { - "postcss": "5.2.18", - "postcss-value-parser": "3.3.0" + "postcss": "^5.0.4", + "postcss-value-parser": "^3.0.1" }, "dependencies": { "postcss": { "version": "5.2.18", "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha1-ut+hSX1GJE9jkPWLMZgw2RB4U8U=", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", "requires": { - "chalk": "1.1.3", - "js-base64": "2.4.0", - "source-map": "0.5.7", - "supports-color": "3.2.3" + "chalk": "^1.1.3", + "js-base64": "^2.1.9", + "source-map": "^0.5.6", + "supports-color": "^3.2.3" } } } @@ -2302,19 +5317,19 @@ "resolved": "https://registry.npmjs.org/postcss-reduce-idents/-/postcss-reduce-idents-2.4.0.tgz", "integrity": "sha1-wsbSDMlYKE9qv75j92Cb9AkFmtM=", "requires": { - "postcss": "5.2.18", - "postcss-value-parser": "3.3.0" + "postcss": "^5.0.4", + "postcss-value-parser": "^3.0.2" }, "dependencies": { "postcss": { "version": "5.2.18", "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha1-ut+hSX1GJE9jkPWLMZgw2RB4U8U=", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", "requires": { - "chalk": "1.1.3", - "js-base64": "2.4.0", - "source-map": "0.5.7", - "supports-color": "3.2.3" + "chalk": "^1.1.3", + "js-base64": "^2.1.9", + "source-map": "^0.5.6", + "supports-color": "^3.2.3" } } } @@ -2324,18 +5339,18 @@ "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-1.0.1.tgz", "integrity": "sha1-aPgGlfBF0IJjqHmtJA343WT2ROo=", "requires": { - "postcss": "5.2.18" + "postcss": "^5.0.4" }, "dependencies": { "postcss": { "version": "5.2.18", "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha1-ut+hSX1GJE9jkPWLMZgw2RB4U8U=", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", "requires": { - "chalk": "1.1.3", - "js-base64": "2.4.0", - "source-map": "0.5.7", - "supports-color": "3.2.3" + "chalk": "^1.1.3", + "js-base64": "^2.1.9", + "source-map": "^0.5.6", + "supports-color": "^3.2.3" } } } @@ -2345,20 +5360,20 @@ "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-1.0.4.tgz", "integrity": "sha1-/3b02CEkN7McKYpC0uFEQCV3GuE=", "requires": { - "has": "1.0.1", - "postcss": "5.2.18", - "postcss-value-parser": "3.3.0" + "has": "^1.0.1", + "postcss": "^5.0.8", + "postcss-value-parser": "^3.0.1" }, "dependencies": { "postcss": { "version": "5.2.18", "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha1-ut+hSX1GJE9jkPWLMZgw2RB4U8U=", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", "requires": { - "chalk": "1.1.3", - "js-base64": "2.4.0", - "source-map": "0.5.7", - "supports-color": "3.2.3" + "chalk": "^1.1.3", + "js-base64": "^2.1.9", + "source-map": "^0.5.6", + "supports-color": "^3.2.3" } } } @@ -2368,9 +5383,9 @@ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-2.2.3.tgz", "integrity": "sha1-+UN3iGBsPJrO4W/+jYsWKX8nu5A=", "requires": { - "flatten": "1.0.2", - "indexes-of": "1.0.1", - "uniq": "1.0.1" + "flatten": "^1.0.2", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" } }, "postcss-svgo": { @@ -2378,21 +5393,21 @@ "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-2.1.6.tgz", "integrity": "sha1-tt8YqmE7Zm4TPwittSGcJoSsEI0=", "requires": { - "is-svg": "2.1.0", - "postcss": "5.2.18", - "postcss-value-parser": "3.3.0", - "svgo": "0.7.2" + "is-svg": "^2.0.0", + "postcss": "^5.0.14", + "postcss-value-parser": "^3.2.3", + "svgo": "^0.7.0" }, "dependencies": { "postcss": { "version": "5.2.18", "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha1-ut+hSX1GJE9jkPWLMZgw2RB4U8U=", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", "requires": { - "chalk": "1.1.3", - "js-base64": "2.4.0", - "source-map": "0.5.7", - "supports-color": "3.2.3" + "chalk": "^1.1.3", + "js-base64": "^2.1.9", + "source-map": "^0.5.6", + "supports-color": "^3.2.3" } } } @@ -2402,279 +5417,203 @@ "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-2.0.2.tgz", "integrity": "sha1-mB1X0p3csz57Hf4f1DuGSfkzyh0=", "requires": { - "alphanum-sort": "1.0.2", - "postcss": "5.2.18", - "uniqs": "2.0.0" + "alphanum-sort": "^1.0.1", + "postcss": "^5.0.4", + "uniqs": "^2.0.0" }, "dependencies": { "postcss": { "version": "5.2.18", "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha1-ut+hSX1GJE9jkPWLMZgw2RB4U8U=", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", "requires": { - "chalk": "1.1.3", - "js-base64": "2.4.0", - "source-map": "0.5.7", - "supports-color": "3.2.3" + "chalk": "^1.1.3", + "js-base64": "^2.1.9", + "source-map": "^0.5.6", + "supports-color": "^3.2.3" } } } }, "postcss-value-parser": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.0.tgz", - "integrity": "sha1-h/OPnxj3dKSrTIojL1xc6IcqnRU=" + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" }, "postcss-zindex": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/postcss-zindex/-/postcss-zindex-2.2.0.tgz", "integrity": "sha1-0hCd3AVbka9n/EyzsCWUZjnSryI=", "requires": { - "has": "1.0.1", - "postcss": "5.2.18", - "uniqs": "2.0.0" + "has": "^1.0.1", + "postcss": "^5.0.4", + "uniqs": "^2.0.0" }, "dependencies": { "postcss": { "version": "5.2.18", "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha1-ut+hSX1GJE9jkPWLMZgw2RB4U8U=", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", "requires": { - "chalk": "1.1.3", - "js-base64": "2.4.0", - "source-map": "0.5.7", - "supports-color": "3.2.3" + "chalk": "^1.1.3", + "js-base64": "^2.1.9", + "source-map": "^0.5.6", + "supports-color": "^3.2.3" } } } }, "prebuild-install": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-2.4.1.tgz", - "integrity": "sha512-99TyEFYTTkBWANT+mwSptmLb9ZCLQ6qKIUE36fXSIOtShB0JNprL2hzBD8F1yIuT9btjFrFEwbRHXhqDi1HmRA==", - "optional": true, + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-5.3.3.tgz", + "integrity": "sha512-GV+nsUXuPW2p8Zy7SarF/2W/oiK8bFQgJcncoJ0d7kRpekEA0ftChjfEaF9/Y+QJEc/wFR7RAEa8lYByuUIe2g==", "requires": { - "expand-template": "1.1.0", + "detect-libc": "^1.0.3", + "expand-template": "^2.0.3", "github-from-package": "0.0.0", - "minimist": "1.2.0", - "mkdirp": "0.5.1", - "node-abi": "2.1.2", - "noop-logger": "0.1.1", - "npmlog": "4.1.2", - "os-homedir": "1.0.2", - "pump": "1.0.3", - "rc": "1.2.2", - "simple-get": "1.4.3", - "tar-fs": "1.16.0", - "tunnel-agent": "0.6.0", - "xtend": "4.0.1" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "optional": true - } + "minimist": "^1.2.0", + "mkdirp": "^0.5.1", + "napi-build-utils": "^1.0.1", + "node-abi": "^2.7.0", + "noop-logger": "^0.1.1", + "npmlog": "^4.0.1", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^3.0.3", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0", + "which-pm-runs": "^1.0.0" } }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=" + }, "prepend-http": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=" }, - "process-nextick-args": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", - "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=" + "preserve": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", + "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=" }, - "promirepl": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/promirepl/-/promirepl-1.0.1.tgz", - "integrity": "sha1-KVGq66K/P+InT/Y6FtlMBMpghy4=", - "optional": true + "process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=" + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" }, "promise": { "version": "7.3.1", "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", - "integrity": "sha1-BktyYCsY+Q8pGSuLG8QY/9Hr078=", + "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", + "optional": true, + "requires": { + "asap": "~2.0.3" + } + }, + "promisify-call": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/promisify-call/-/promisify-call-2.0.4.tgz", + "integrity": "sha1-1IwtRWUszM1SgB3ey9UzptS9X7o=", + "optional": true, + "requires": { + "with-callback": "^1.0.2" + } + }, + "prop-types": { + "version": "15.7.2", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", + "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", "dev": true, - "optional": true, "requires": { - "asap": "2.0.6" + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.8.1" } }, - "prompt-actions": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/prompt-actions/-/prompt-actions-3.0.2.tgz", - "integrity": "sha512-dhz2Fl7vK+LPpmnQ/S/eSut4BnH4NZDLyddHKi5uTU/2PDn3grEMGkgsll16V5RpVUh/yxdiam0xsM0RD4xvtg==", + "proxy-agent": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-3.0.3.tgz", + "integrity": "sha512-PXVVVuH9tiQuxQltFJVSnXWuDtNr+8aNBP6XVDDCDiUuDN8eRCm+ii4/mFWmXWEA0w8jjJSlePa4LXlM4jIzNA==", "optional": true, "requires": { - "debug": "2.6.9" - } - }, - "prompt-base": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/prompt-base/-/prompt-base-4.1.0.tgz", - "integrity": "sha512-svGzgLUKZoqomz9SGMkf1hBG8Wl3K7JGuRCXc/Pv7xw8239hhaTBXrmjt7EXA9P/QZzdyT8uNWt9F/iJTXq75g==", - "optional": true, - "requires": { - "component-emitter": "1.2.1", - "debug": "3.1.0", - "koalas": "1.0.2", - "log-utils": "0.2.1", - "prompt-actions": "3.0.2", - "prompt-question": "5.0.2", - "readline-ui": "2.2.3", - "readline-utils": "2.2.3", - "static-extend": "0.1.2" + "agent-base": "^4.2.0", + "debug": "^3.1.0", + "http-proxy-agent": "^2.1.0", + "https-proxy-agent": "^2.2.1", + "lru-cache": "^4.1.2", + "pac-proxy-agent": "^3.0.0", + "proxy-from-env": "^1.0.0", + "socks-proxy-agent": "^4.0.1" }, "dependencies": { "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", "optional": true, "requires": { - "ms": "2.0.0" - } - } - } - }, - "prompt-checkbox": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/prompt-checkbox/-/prompt-checkbox-2.2.0.tgz", - "integrity": "sha512-T/QWgkdUmKjRSr0FQlV8O+LfgmBk8PwDbWhzllm7mwWNAjs3qOVuru5Y1gV4/14L73zCncqcuwGwvnDyVcVgvA==", - "optional": true, - "requires": { - "ansi-cyan": "0.1.1", - "debug": "2.6.9", - "prompt-base": "4.1.0" - } - }, - "prompt-choices": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/prompt-choices/-/prompt-choices-4.0.6.tgz", - "integrity": "sha512-JfXujJo79TKG6KUHE+1S4tYLUEMRLM/mW9Bz49qrGKxVpnBGsQSv9lPiLKZgHtGEzXH7nG2kfMvWBEaKQs+JkQ==", - "optional": true, - "requires": { - "arr-flatten": "1.1.0", - "arr-swap": "1.0.1", - "choices-separator": "2.0.0", - "clone-deep": "1.0.0", - "collection-visit": "1.0.0", - "debug": "3.1.0", - "define-property": "1.0.0", - "extend-shallow": "2.0.1", - "is-number": "3.0.0", - "kind-of": "5.1.0", - "koalas": "1.0.2", - "lazy-cache": "2.0.2", - "log-utils": "0.2.1", - "pointer-symbol": "1.0.0", - "radio-symbol": "2.0.0", - "set-value": "2.0.0", - "strip-color": "0.1.0", - "terminal-paginator": "2.0.2", - "toggle-array": "1.0.1" - }, - "dependencies": { - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "optional": true, - "requires": { - "ms": "2.0.0" + "ms": "^2.1.1" } }, - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "optional": true } } }, - "prompt-list": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/prompt-list/-/prompt-list-3.1.2.tgz", - "integrity": "sha512-5ezD3usudKMQVpMFLV5R0RTpUF0T+VRvQvmQyDz8Rpz274lKwabZO4ozTR8tq2X4HuovqZb3kGqFZmJeXjAyDw==", - "optional": true, - "requires": { - "ansi-cyan": "0.1.1", - "ansi-dim": "0.1.1", - "debug": "3.1.0", - "prompt-radio": "1.2.1" - }, - "dependencies": { - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "optional": true, - "requires": { - "ms": "2.0.0" - } - } - } - }, - "prompt-question": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/prompt-question/-/prompt-question-5.0.2.tgz", - "integrity": "sha512-wreaLbbu8f5+7zXds199uiT11Ojp59Z4iBi6hONlSLtsKGTvL2UY8VglcxQ3t/X4qWIxsNCg6aT4O8keO65v6Q==", - "optional": true, - "requires": { - "clone-deep": "1.0.0", - "debug": "3.1.0", - "define-property": "1.0.0", - "isobject": "3.0.1", - "kind-of": "5.1.0", - "koalas": "1.0.2", - "prompt-choices": "4.0.6" - }, - "dependencies": { - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "optional": true, - "requires": { - "ms": "2.0.0" - } - }, - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "optional": true - } - } - }, - "prompt-radio": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prompt-radio/-/prompt-radio-1.2.1.tgz", - "integrity": "sha512-vH1iAkgbWyvZBC1BTajydiHmwJP4F1b684gq0fm2wOjPVW1zaDo01OXWr/Dske0XdoHhtZFNMOXNj/ZUSRBywg==", - "optional": true, - "requires": { - "debug": "2.6.9", - "prompt-checkbox": "2.2.0" - } + "proxy-from-env": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.0.0.tgz", + "integrity": "sha1-M8UDmPcOp+uW0h97gXYwpVeRx+4=", + "optional": true }, "prr": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", - "dev": true, "optional": true }, - "pump": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/pump/-/pump-1.0.3.tgz", - "integrity": "sha1-Xf6DEcM7v2/BgmH580cCxHwIqVQ=", + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" + }, + "psl": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.4.0.tgz", + "integrity": "sha512-HZzqCGPecFLyoRj5HLfuDSKYTJkAfB5thKBIkRHtGjWwY7p1dAyveIbXIq4tO0KYfDF2tHqPUgY9SDnGm00uFw==" + }, + "public-encrypt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", + "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", "requires": { - "end-of-stream": "1.4.0", - "once": "1.4.0" + "bn.js": "^4.1.0", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "parse-asn1": "^5.0.0", + "randombytes": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" } }, "punycode": { @@ -2682,64 +5621,41 @@ "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" }, - "pxt-core": { - "version": "0.18.1", - "resolved": "https://registry.npmjs.org/pxt-core/-/pxt-core-0.18.1.tgz", - "integrity": "sha512-r8Sou8lu3MuPAIF31bLFtRSoQ2IsFjVIpzm4tdYp9ewhG1esbrznXbQdT+XCiuNFALlZTt8p9dfljYrJh85kAg==", + "pxt-common-packages": { + "version": "6.16.23", + "resolved": "https://registry.npmjs.org/pxt-common-packages/-/pxt-common-packages-6.16.23.tgz", + "integrity": "sha512-/a6Pb9obdmLur46YhimrjkbyItTlUhRdCWS5h2BuRlqu3dIMr2jP8kKV+08ZrM2iE8PmafgXqVFXfCNg8iZkyw==", "requires": { + "@jacdac/jacdac-ts": "^0.0.9", + "pxt-core": "^5.24.8" + } + }, + "pxt-core": { + "version": "5.28.18", + "resolved": "https://registry.npmjs.org/pxt-core/-/pxt-core-5.28.18.tgz", + "integrity": "sha512-nnXRlM1jE3ZI0DFnhlZd8aFHyssGj2QONl470Z5luNadF5WK2rtjK1OdpzphrARe9YAg8hS7RYCy7GCvMivSjg==", + "requires": { + "applicationinsights-js": "^1.0.20", "bluebird": "3.5.1", + "browserify": "16.2.0", + "chai": "^3.5.0", "cssnano": "3.10.0", "faye-websocket": "0.11.1", - "fuse.js": "2.6.1", - "highlight.js": "9.12.0", - "keytar": "3.0.2", + "karma": "2.0.0", + "karma-chai": "0.1.0", + "karma-chrome-launcher": "2.2.0", + "karma-mocha": "1.3.0", + "less": "2.7.3", "lzma": "2.3.2", - "marked": "0.3.7", - "node-hid": "0.5.7", - "postcss": "6.0.14", - "request": "2.83.0", + "marked": "0.3.19", + "mocha": "5.1.0", + "pngjs": "3.4.0", + "postcss": "6.0.21", + "request": "2.88.0", "rimraf": "2.5.4", "rtlcss": "2.2.1", - "serialport": "6.1.1" - }, - "dependencies": { - "commander": { - "version": "2.15.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", - "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", - "optional": true - }, - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "optional": true, - "requires": { - "ms": "2.0.0" - } - }, - "nan": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.10.0.tgz", - "integrity": "sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA==", - "optional": true - }, - "serialport": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/serialport/-/serialport-6.1.1.tgz", - "integrity": "sha512-l7S8QgjVEb1n+saBSlZpcVKzkhCS4n0HmLdjbgCc+mA3IeHtVvMH/aPcx7auqGOHljMRgwfJdl0x5Kn9ImD1rA==", - "optional": true, - "requires": { - "bindings": "1.3.0", - "commander": "2.15.1", - "debug": "3.1.0", - "nan": "2.10.0", - "prebuild-install": "2.4.1", - "promirepl": "1.0.1", - "prompt-list": "3.1.2", - "safe-buffer": "5.1.1" - } - } + "semantic-ui-less": "2.2.14", + "uglify-js": "3.3.21" } }, "q": { @@ -2747,317 +5663,976 @@ "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=" }, + "qjobs": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz", + "integrity": "sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==" + }, "qs": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", - "integrity": "sha1-NJzfbu+J7EXBLX1es/wMhwNDptg=" + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" }, "query-string": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz", "integrity": "sha1-u7aTucqRXCMlFbIosaArYJBD2+s=", "requires": { - "object-assign": "4.1.1", - "strict-uri-encode": "1.1.0" + "object-assign": "^4.1.0", + "strict-uri-encode": "^1.0.0" } }, - "radio-symbol": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/radio-symbol/-/radio-symbol-2.0.0.tgz", - "integrity": "sha1-eqm/xQSFY21S3XbWqOYxspB5muE=", - "optional": true, + "querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=" + }, + "querystring-es3": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", + "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=" + }, + "querystringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.1.1.tgz", + "integrity": "sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA==", + "optional": true + }, + "randomatic": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.1.1.tgz", + "integrity": "sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw==", "requires": { - "ansi-gray": "0.1.1", - "ansi-green": "0.1.1", - "is-windows": "1.0.2" + "is-number": "^4.0.0", + "kind-of": "^6.0.0", + "math-random": "^1.0.1" + }, + "dependencies": { + "is-number": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", + "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==" + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" + } + } + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "randomfill": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", + "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", + "requires": { + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" + } + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" + }, + "raw-body": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", + "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "requires": { + "bytes": "3.1.0", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" } }, "rc": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.2.tgz", - "integrity": "sha1-2M6ctX6NZNnHut2YdsfDTL48cHc=", - "optional": true, + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", "requires": { - "deep-extend": "0.4.2", - "ini": "1.3.5", - "minimist": "1.2.0", - "strip-json-comments": "2.0.1" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "optional": true - } + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + } + }, + "react": { + "version": "16.8.3", + "resolved": "https://registry.npmjs.org/react/-/react-16.8.3.tgz", + "integrity": "sha512-3UoSIsEq8yTJuSu0luO1QQWYbgGEILm+eJl2QN/VLDi7hL+EN18M3q3oVZwmVzzBJ3DkM7RMdRwBmZZ+b4IzSA==", + "dev": true, + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "prop-types": "^15.6.2", + "scheduler": "^0.13.3" + } + }, + "react-is": { + "version": "16.12.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.12.0.tgz", + "integrity": "sha512-rPCkf/mWBtKc97aLL9/txD8DZdemK0vkA3JMLShjlJB3Pj3s+lpf1KaBzMfQrAmhMQB0n1cU/SUGgKKBCe837Q==", + "dev": true + }, + "read-only-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-only-stream/-/read-only-stream-2.0.0.tgz", + "integrity": "sha1-JyT9aoET1zdkrCiNQ4YnDB2/F/A=", + "requires": { + "readable-stream": "^2.0.2" } }, "readable-stream": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", - "integrity": "sha1-No8lEtefnUb9/HE0mueHi7weuVw=", + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "1.0.7", - "safe-buffer": "5.1.1", - "string_decoder": "1.0.3", - "util-deprecate": "1.0.2" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, - "readline-ui": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/readline-ui/-/readline-ui-2.2.3.tgz", - "integrity": "sha512-ix7jz0PxqQqcIuq3yQTHv1TOhlD2IHO74aNO+lSuXsRYm1d+pdyup1yF3zKyLK1wWZrVNGjkzw5tUegO2IDy+A==", - "optional": true, + "readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", "requires": { - "component-emitter": "1.2.1", - "debug": "2.6.9", - "readline-utils": "2.2.3", - "string-width": "2.1.1" + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" }, "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "optional": true + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=" }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "optional": true + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=" }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "optional": true, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", "requires": { - "is-fullwidth-code-point": "2.0.0", - "strip-ansi": "4.0.0" + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } } }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "optional": true, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", "requires": { - "ansi-regex": "3.0.0" + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + } + }, + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" + } + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" } } } }, - "readline-utils": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/readline-utils/-/readline-utils-2.2.3.tgz", - "integrity": "sha1-b4R9a48ZFcORtYHDZ81HhzhiNRo=", + "redis": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/redis/-/redis-2.8.0.tgz", + "integrity": "sha512-M1OkonEQwtRmZv4tEWF2VgpG0JWJ8Fv1PhlgT5+B+uNq2cA3Rt1Yt/ryoR+vQNOQcIEgdCdfH0jr3bDpihAw1A==", + "optional": true, "requires": { - "arr-flatten": "1.1.0", - "extend-shallow": "2.0.1", - "is-buffer": "1.1.6", - "is-number": "3.0.0", - "is-windows": "1.0.2", - "koalas": "1.0.2", - "mute-stream": "0.0.7", - "strip-color": "0.1.0", - "window-size": "1.1.0" + "double-ended-queue": "^2.1.0-0", + "redis-commands": "^1.2.0", + "redis-parser": "^2.6.0" } }, + "redis-commands": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/redis-commands/-/redis-commands-1.5.0.tgz", + "integrity": "sha512-6KxamqpZ468MeQC3bkWmCB1fp56XL64D4Kf0zJSwDZbVLLm7KFkoIcHrgRvQ+sk8dnhySs7+yBg94yIkAK7aJg==", + "optional": true + }, + "redis-parser": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-2.6.0.tgz", + "integrity": "sha1-Uu0J2srBCPGmMcB+m2mUHnoZUEs=", + "optional": true + }, "reduce-css-calc": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/reduce-css-calc/-/reduce-css-calc-1.3.0.tgz", "integrity": "sha1-dHyRTgSWFKTJz7umKYca0dKSdxY=", "requires": { - "balanced-match": "0.4.2", - "math-expression-evaluator": "1.2.17", - "reduce-function-call": "1.0.2" + "balanced-match": "^0.4.2", + "math-expression-evaluator": "^1.2.14", + "reduce-function-call": "^1.0.1" + }, + "dependencies": { + "balanced-match": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz", + "integrity": "sha1-yz8+PHMtwPAe5wtAPzAuYddwmDg=" + } } }, "reduce-function-call": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/reduce-function-call/-/reduce-function-call-1.0.2.tgz", - "integrity": "sha1-WiAL+S4ON3UXUv5FsKszD9S2vpk=", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/reduce-function-call/-/reduce-function-call-1.0.3.tgz", + "integrity": "sha512-Hl/tuV2VDgWgCSEeWMLwxLZqX7OK59eU1guxXsRKTAyeYimivsKdtcV4fu3r710tpG5GmDKDhQ0HSZLExnNmyQ==", "requires": { - "balanced-match": "0.4.2" + "balanced-match": "^1.0.0" } }, - "request": { - "version": "2.83.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.83.0.tgz", - "integrity": "sha1-ygtl2gLtYpNYh4COb1EDgQNOM1Y=", + "regex-cache": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz", + "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==", "requires": { - "aws-sign2": "0.7.0", - "aws4": "1.6.0", - "caseless": "0.12.0", - "combined-stream": "1.0.5", - "extend": "3.0.1", - "forever-agent": "0.6.1", - "form-data": "2.3.1", - "har-validator": "5.0.3", - "hawk": "6.0.2", - "http-signature": "1.2.0", - "is-typedarray": "1.0.0", - "isstream": "0.1.2", - "json-stringify-safe": "5.0.1", - "mime-types": "2.1.17", - "oauth-sign": "0.8.2", - "performance-now": "2.1.0", - "qs": "6.5.1", - "safe-buffer": "5.1.1", - "stringstream": "0.0.5", - "tough-cookie": "2.3.3", - "tunnel-agent": "0.6.0", - "uuid": "3.1.0" + "is-equal-shallow": "^0.1.3" } }, + "regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "requires": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + } + }, + "remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=" + }, + "repeat-element": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", + "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==" + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=" + }, + "request": { + "version": "2.88.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", + "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.0", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.4.3", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "dependencies": { + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" + } + } + }, + "requestretry": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/requestretry/-/requestretry-1.13.0.tgz", + "integrity": "sha512-Lmh9qMvnQXADGAQxsXHP4rbgO6pffCfuR8XUBdP9aitJcLQJxhp7YZK4xAVYXnPJ5E52mwrfiKQtKonPL8xsmg==", + "optional": true, + "requires": { + "extend": "^3.0.0", + "lodash": "^4.15.0", + "request": "^2.74.0", + "when": "^3.7.7" + } + }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" + }, + "resolve": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz", + "integrity": "sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==", + "requires": { + "path-parse": "^1.0.6" + } + }, + "resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=" + }, + "ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==" + }, "rimraf": { "version": "2.5.4", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.5.4.tgz", "integrity": "sha1-loAAk8vxoMhr2VtGJUZ1NcKd+gQ=", "requires": { - "glob": "7.1.2" + "glob": "^7.0.5" + } + }, + "ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" } }, "rtlcss": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/rtlcss/-/rtlcss-2.2.1.tgz", - "integrity": "sha1-+FN+QVUggWawXhiYAhMZNvzv0p4=", + "integrity": "sha512-JjQ5DlrmwiItAjlmhoxrJq5ihgZcE0wMFxt7S17bIrt4Lw0WwKKFk+viRhvodB/0falyG/5fiO043ZDh6/aqTw==", "requires": { - "chalk": "2.3.0", - "findup": "0.1.5", - "mkdirp": "0.5.1", - "postcss": "6.0.14", - "strip-json-comments": "2.0.1" + "chalk": "^2.3.0", + "findup": "^0.1.5", + "mkdirp": "^0.5.1", + "postcss": "^6.0.14", + "strip-json-comments": "^2.0.0" }, "dependencies": { "ansi-styles": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", - "integrity": "sha1-wVm41b4PnlpvNG2rlPFs4CIWG4g=", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "requires": { - "color-convert": "1.9.1" + "color-convert": "^1.9.0" } }, "chalk": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.0.tgz", - "integrity": "sha1-tepI78nBeT3MybR2fJORTT8tUro=", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { - "ansi-styles": "3.2.0", - "escape-string-regexp": "1.0.5", - "supports-color": "4.5.0" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" } }, "has-flag": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", - "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=" + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" }, "supports-color": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", - "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "has-flag": "2.0.0" + "has-flag": "^3.0.0" } } } }, "safe-buffer": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", - "integrity": "sha1-iTMSr2myEj3vcfV4iQAWce6yyFM=" + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "requires": { + "ret": "~0.1.10" + } + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "sax": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha1-KBYjTiN4vdxOU1T6tcqold9xANk=" + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + }, + "scheduler": { + "version": "0.13.6", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.13.6.tgz", + "integrity": "sha512-IWnObHt413ucAYKsD9J1QShUKkbKLQQHdxRyw73sw4FN26iWr3DY/H34xGPe4nmL1DwXyWmSWmMrA9TfQbE/XQ==", + "dev": true, + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + } }, "semantic-ui-less": { "version": "2.2.14", "resolved": "https://registry.npmjs.org/semantic-ui-less/-/semantic-ui-less-2.2.14.tgz", "integrity": "sha512-JLkTqjOtct+OwM/JRv0SH76gCC0eE98xp5G4D29e9VbJ66QjWD3nB3waB7drpaMUFXo/YbKcyNOJBgMamcJI0Q==", - "dev": true, "requires": { - "jquery": "3.3.1" + "jquery": "x.*" } }, "semver": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz", - "integrity": "sha1-4FnAnYVx8FQII3M0M1BdOi8AsY4=", - "optional": true + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" }, "set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", - "optional": true - }, - "set-getter": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/set-getter/-/set-getter-0.1.0.tgz", - "integrity": "sha1-12nBgsnVpR9AkUXy+6guXoboA3Y=", - "requires": { - "to-object-path": "0.3.0" - } + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" }, "set-value": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz", - "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==", - "optional": true, + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", "requires": { - "extend-shallow": "2.0.1", - "is-extendable": "0.1.1", - "is-plain-object": "2.0.4", - "split-string": "3.1.0" - } - }, - "shallow-clone": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-1.0.0.tgz", - "integrity": "sha512-oeXreoKR/SyNJtRJMAKPDSvd28OqEwG4eR/xc856cRGBII7gX9lvAqDxusPm0846z/w/hWYjI1NpKwJ00NHzRA==", - "requires": { - "is-extendable": "0.1.1", - "kind-of": "5.1.0", - "mixin-object": "2.0.1" + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" }, "dependencies": { - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } } } }, + "setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + }, + "sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "shasum": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/shasum/-/shasum-1.0.2.tgz", + "integrity": "sha1-5wEjENj0F/TetXEhUOVni4euVl8=", + "requires": { + "json-stable-stringify": "~0.0.0", + "sha.js": "~2.4.4" + } + }, + "shasum-object": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shasum-object/-/shasum-object-1.0.0.tgz", + "integrity": "sha512-Iqo5rp/3xVi6M4YheapzZhhGPVs0yZwHj7wvwQ1B9z8H6zk+FEnI7y3Teq7qwnekfEhu8WmG2z0z4iWZaxLWVg==", + "requires": { + "fast-safe-stringify": "^2.0.7" + } + }, + "shell-quote": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.2.tgz", + "integrity": "sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg==" + }, "signal-exit": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", - "optional": true + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" + }, + "simple-concat": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.0.tgz", + "integrity": "sha1-c0TLuLbib7J9ZrL8hvn21Zl1IcY=" }, "simple-get": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-1.4.3.tgz", - "integrity": "sha1-6XVe2kB+ltpAxeUVjJ6jezO+y+s=", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.0.tgz", + "integrity": "sha512-bCR6cP+aTdScaQCnQKbPKtJOKDp/hj9EDLJo3Nw4y1QksqaovlW/bnptB6/c1e+qmNIDHRK+oXFDdEqBT8WzUA==", + "requires": { + "decompress-response": "^4.2.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "slack-node": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/slack-node/-/slack-node-0.2.0.tgz", + "integrity": "sha1-3kuN3aqLeT9h29KTgQT9q/N9+jA=", "optional": true, "requires": { - "once": "1.4.0", - "unzip-response": "1.0.2", - "xtend": "4.0.1" + "requestretry": "^1.2.2" + } + }, + "smart-buffer": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.1.0.tgz", + "integrity": "sha512-iVICrxOzCynf/SNaBQCw34eM9jROU/s5rzIhpOvzhzuYHfJR/DhZfDkXiZSgKXfgv26HT3Yni3AV/DGw0cGnnw==" + }, + "smtp-connection": { + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/smtp-connection/-/smtp-connection-2.12.0.tgz", + "integrity": "sha1-1275EnyyPCJZ7bHoNJwujV4tdME=", + "requires": { + "httpntlm": "1.6.1", + "nodemailer-shared": "1.1.0" + } + }, + "snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "requires": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "requires": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" + } + } + }, + "snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "requires": { + "kind-of": "^3.2.0" } }, "sntp": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/sntp/-/sntp-2.1.0.tgz", - "integrity": "sha1-LGzsFP7cIiJznK+bXD2F0cxaLMg=", + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", + "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=", + "optional": true, "requires": { - "hoek": "4.2.0" + "hoek": "2.x.x" + } + }, + "socket.io": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.0.4.tgz", + "integrity": "sha1-waRZDO/4fs8TxyZS8Eb3FrKeYBQ=", + "requires": { + "debug": "~2.6.6", + "engine.io": "~3.1.0", + "socket.io-adapter": "~1.1.0", + "socket.io-client": "2.0.4", + "socket.io-parser": "~3.1.1" + } + }, + "socket.io-adapter": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.1.tgz", + "integrity": "sha1-KoBeihTWNyEk3ZFZrUUC+MsH8Gs=" + }, + "socket.io-client": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.0.4.tgz", + "integrity": "sha1-CRilUkBtxeVAs4Dc2Xr8SmQzL44=", + "requires": { + "backo2": "1.0.2", + "base64-arraybuffer": "0.1.5", + "component-bind": "1.0.0", + "component-emitter": "1.2.1", + "debug": "~2.6.4", + "engine.io-client": "~3.1.0", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "object-component": "0.0.3", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "socket.io-parser": "~3.1.1", + "to-array": "0.1.4" + }, + "dependencies": { + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=" + } + } + }, + "socket.io-parser": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.1.3.tgz", + "integrity": "sha512-g0a2HPqLguqAczs3dMECuA1RgoGFPyvDqcbaDEdCWY9g59kdUAz3YRmaJBNKXflrHNwB7Q12Gkf/0CZXfdHR7g==", + "requires": { + "component-emitter": "1.2.1", + "debug": "~3.1.0", + "has-binary2": "~1.0.2", + "isarray": "2.0.1" + }, + "dependencies": { + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=" + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, + "isarray": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", + "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=" + } + } + }, + "socks": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.3.3.tgz", + "integrity": "sha512-o5t52PCNtVdiOvzMry7wU4aOqYWL0PeCXRWBEiJow4/i/wr+wpsJQ9awEu1EonLIqsfGd5qSgDdxEOvCdmBEpA==", + "requires": { + "ip": "1.1.5", + "smart-buffer": "^4.1.0" + } + }, + "socks-proxy-agent": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-4.0.2.tgz", + "integrity": "sha512-NT6syHhI9LmuEMSK6Kd2V7gNv5KFZoLE7V5udWmn0de+3Mkj3UMA/AJPLyeNUVmElCurSHtUdM3ETpR3z770Wg==", + "requires": { + "agent-base": "~4.2.1", + "socks": "~2.3.2" + }, + "dependencies": { + "agent-base": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.2.1.tgz", + "integrity": "sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg==", + "requires": { + "es6-promisify": "^5.0.0" + } + } } }, "sort-keys": { @@ -3065,7 +6640,7 @@ "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz", "integrity": "sha1-RBttTTRnmPG05J6JIK37oOVD+a0=", "requires": { - "is-plain-obj": "1.1.0" + "is-plain-obj": "^1.0.0" } }, "source-map": { @@ -3073,34 +6648,29 @@ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" }, + "source-map-resolve": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz", + "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", + "requires": { + "atob": "^2.1.1", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "source-map-url": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", + "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=" + }, "split-string": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", - "optional": true, "requires": { - "extend-shallow": "3.0.2" - }, - "dependencies": { - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "optional": true, - "requires": { - "assign-symbols": "1.0.0", - "is-extendable": "1.0.1" - } - }, - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "optional": true, - "requires": { - "is-plain-object": "2.0.4" - } - } + "extend-shallow": "^3.0.0" } }, "sprintf-js": { @@ -3109,95 +6679,107 @@ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" }, "sshpk": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz", - "integrity": "sha1-US322mKHFEMW3EwY/hzx2UBzm+M=", + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", "requires": { - "asn1": "0.2.3", - "assert-plus": "1.0.0", - "bcrypt-pbkdf": "1.0.1", - "dashdash": "1.14.1", - "ecc-jsbn": "0.1.1", - "getpass": "0.1.7", - "jsbn": "0.1.1", - "tweetnacl": "0.14.5" + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" } }, "static-extend": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", - "optional": true, "requires": { - "define-property": "0.2.5", - "object-copy": "0.1.0" + "define-property": "^0.2.5", + "object-copy": "^0.1.0" }, "dependencies": { "define-property": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "optional": true, "requires": { - "is-descriptor": "0.1.6" + "is-descriptor": "^0.1.0" + } + } + } + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" + }, + "stream-browserify": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz", + "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==", + "requires": { + "inherits": "~2.0.1", + "readable-stream": "^2.0.2" + } + }, + "stream-combiner2": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stream-combiner2/-/stream-combiner2-1.1.1.tgz", + "integrity": "sha1-+02KFCDqNidk4hrUeAOXvry0HL4=", + "requires": { + "duplexer2": "~0.1.0", + "readable-stream": "^2.0.2" + } + }, + "stream-http": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz", + "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==", + "requires": { + "builtin-status-codes": "^3.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.3.6", + "to-arraybuffer": "^1.0.0", + "xtend": "^4.0.0" + } + }, + "stream-splicer": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/stream-splicer/-/stream-splicer-2.0.1.tgz", + "integrity": "sha512-Xizh4/NPuYSyAXyT7g8IvdJ9HJpxIGL9PjyhtywCZvvP0OPIdqyrr4dMikeuvY8xahpdKEBlBTySe583totajg==", + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.2" + } + }, + "streamroller": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-0.7.0.tgz", + "integrity": "sha512-WREzfy0r0zUqp3lGO096wRuUp7ho1X6uo/7DJfTlEi0Iv/4gT7YHqXDjKC2ioVGBZtE8QzsQD9nx1nIuoZ57jQ==", + "requires": { + "date-format": "^1.2.0", + "debug": "^3.1.0", + "mkdirp": "^0.5.1", + "readable-stream": "^2.3.0" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "requires": { + "ms": "^2.1.1" } }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "optional": true, - "requires": { - "kind-of": "3.2.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "optional": true, - "requires": { - "is-buffer": "1.1.6" - } - } - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "optional": true, - "requires": { - "kind-of": "3.2.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "optional": true, - "requires": { - "is-buffer": "1.1.6" - } - } - } - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "optional": true, - "requires": { - "is-accessor-descriptor": "0.1.6", - "is-data-descriptor": "0.1.4", - "kind-of": "5.1.0" - } - }, - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "optional": true + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" } } }, @@ -3211,53 +6793,52 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "requires": { - "code-point-at": "1.1.0", - "is-fullwidth-code-point": "1.0.0", - "strip-ansi": "3.0.1" + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" } }, "string_decoder": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", - "integrity": "sha1-D8Z9fBQYJd6UKC3VNr7GubzoYKs=", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { - "safe-buffer": "5.1.1" + "safe-buffer": "~5.1.0" } }, "stringstream": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", - "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=" + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.6.tgz", + "integrity": "sha512-87GEBAkegbBcweToUrdzf3eLhWNg06FJTebl4BVJz/JgWy8CvEr9dRtX5qWphiynMSQlxxi+QqN0z5T32SLlhA==", + "optional": true }, "strip-ansi": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "requires": { - "ansi-regex": "2.1.1" + "ansi-regex": "^2.0.0" } }, - "strip-color": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/strip-color/-/strip-color-0.1.0.tgz", - "integrity": "sha1-EG9l09PmotlAHKwOsM6LinArT3s=" - }, "strip-json-comments": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" }, - "success-symbol": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/success-symbol/-/success-symbol-0.1.0.tgz", - "integrity": "sha1-JAIuSG878c3KCUKDt2nEctO3KJc=" + "subarg": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/subarg/-/subarg-1.0.0.tgz", + "integrity": "sha1-9izxdYHplrSPyWVpn1TAauJouNI=", + "requires": { + "minimist": "^1.1.0" + } }, "supports-color": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", "requires": { - "has-flag": "1.0.0" + "has-flag": "^1.0.0" } }, "svgo": { @@ -3265,200 +6846,586 @@ "resolved": "https://registry.npmjs.org/svgo/-/svgo-0.7.2.tgz", "integrity": "sha1-n1dyQTlSE1xv779Ar+ak+qiLS7U=", "requires": { - "coa": "1.0.4", - "colors": "1.1.2", - "csso": "2.3.2", - "js-yaml": "3.7.0", - "mkdirp": "0.5.1", - "sax": "1.2.4", - "whet.extend": "0.9.9" + "coa": "~1.0.1", + "colors": "~1.1.2", + "csso": "~2.3.1", + "js-yaml": "~3.7.0", + "mkdirp": "~0.5.1", + "sax": "~1.2.1", + "whet.extend": "~0.9.9" + } + }, + "syntax-error": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/syntax-error/-/syntax-error-1.4.0.tgz", + "integrity": "sha512-YPPlu67mdnHGTup2A8ff7BC2Pjq0e0Yp/IyTFN03zWO0RcK07uLcbi7C2KpGR2FvWbaB0+bfE27a+sBKebSo7w==", + "requires": { + "acorn-node": "^1.2.0" } }, "tar-fs": { - "version": "1.16.0", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-1.16.0.tgz", - "integrity": "sha1-6HeiWsvMUdjHkNocV8nPQ5gXuJY=", - "optional": true, + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.0.0.tgz", + "integrity": "sha512-vaY0obB6Om/fso8a8vakQBzwholQ7v5+uy+tF3Ozvxv1KNezmVQAiWtcNmMHFSFPqL3dJA8ha6gdtFbfX9mcxA==", "requires": { - "chownr": "1.0.1", - "mkdirp": "0.5.1", - "pump": "1.0.3", - "tar-stream": "1.5.5" + "chownr": "^1.1.1", + "mkdirp": "^0.5.1", + "pump": "^3.0.0", + "tar-stream": "^2.0.0" } }, "tar-stream": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.5.5.tgz", - "integrity": "sha1-XK2Ed59FyDsfJQjZawnYjHIYr1U=", - "optional": true, + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.1.0.tgz", + "integrity": "sha512-+DAn4Nb4+gz6WZigRzKEZl1QuJVOLtAwwF+WUxy1fJ6X63CaGaUAxJRD2KEn1OMfcbCjySTYpNC6WmfQoIEOdw==", "requires": { - "bl": "1.2.1", - "end-of-stream": "1.4.0", - "readable-stream": "2.3.3", - "xtend": "4.0.1" + "bl": "^3.0.0", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "dependencies": { + "readable-stream": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz", + "integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } } }, - "terminal-paginator": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/terminal-paginator/-/terminal-paginator-2.0.2.tgz", - "integrity": "sha512-IZMT5ECF9p4s+sNCV8uvZSW9E1+9zy9Ji9xz2oee8Jfo7hUFpauyjxkhfRcIH6Lu3Wdepv5D1kVRc8Hx74/LfQ==", - "optional": true, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" + }, + "through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", "requires": { - "debug": "2.6.9", - "extend-shallow": "2.0.1", - "log-utils": "0.2.1" + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" } }, - "time-stamp": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.1.0.tgz", - "integrity": "sha1-dkpaEa9QVhkhsTPztE5hhofg9cM=" + "thunkify": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/thunkify/-/thunkify-2.1.2.tgz", + "integrity": "sha1-+qDp0jDFGsyVyhOjYawFyn4EVT0=", + "optional": true + }, + "timers-browserify": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-1.4.2.tgz", + "integrity": "sha1-ycWLV1voQHN1y14kYtrO50NZ9B0=", + "requires": { + "process": "~0.11.0" + } + }, + "timespan": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/timespan/-/timespan-2.3.0.tgz", + "integrity": "sha1-SQLOBAvRPYRcj1myfp1ZutbzmSk=", + "optional": true + }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "requires": { + "os-tmpdir": "~1.0.2" + } + }, + "to-array": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz", + "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=" + }, + "to-arraybuffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", + "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=" }, "to-object-path": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.0.2" } }, - "toggle-array": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toggle-array/-/toggle-array-1.0.1.tgz", - "integrity": "sha1-y/WEB5K9UJfzMReugkyTKv/ofVg=", - "optional": true, + "to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", "requires": { - "isobject": "3.0.1" + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" } }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + }, + "dependencies": { + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "requires": { + "kind-of": "^3.0.2" + } + } + } + }, + "toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" + }, "tough-cookie": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.3.tgz", - "integrity": "sha1-C2GKVWW23qkL80JdBNVe3EdadWE=", + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", + "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", "requires": { - "punycode": "1.4.1" + "psl": "^1.1.24", + "punycode": "^1.4.1" } }, + "tsscmp": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/tsscmp/-/tsscmp-1.0.6.tgz", + "integrity": "sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA==", + "optional": true + }, + "tty-browserify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.1.tgz", + "integrity": "sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw==" + }, "tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", "requires": { - "safe-buffer": "5.1.1" + "safe-buffer": "^5.0.1" } }, "tweetnacl": { "version": "0.14.5", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", - "optional": true + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "requires": { + "prelude-ls": "~1.1.2" + } + }, + "type-detect": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-1.0.0.tgz", + "integrity": "sha1-diIXzAbbJY7EiQihKY6LlRIejqI=" + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" }, "typescript": { - "version": "1.8.10", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-1.8.10.tgz", - "integrity": "sha1-tHXW4N/wv1DyluXKbvn7tccyDx4=", + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.6.1.tgz", + "integrity": "sha1-7znN6ierrAtQAkLWcmq5DgyEZjE=", "dev": true }, + "uglify-js": { + "version": "3.3.21", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.3.21.tgz", + "integrity": "sha512-uy82472lH8tshK3jS3c5IFb5MmNKd/5qyBd0ih8sM42L3jWvxnE339U9gZU1zufnLVs98Stib9twq8dLm2XYCA==", + "requires": { + "commander": "~2.15.0", + "source-map": "~0.6.1" + }, + "dependencies": { + "commander": { + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", + "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==" + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "ultron": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", + "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==" + }, + "umd": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/umd/-/umd-3.0.3.tgz", + "integrity": "sha512-4IcGSufhFshvLNcMCV80UnQVlZ5pMOC8mvNPForqwA4+lzYQuetTESLDQkeLmihq8bRcnpbQa48Wb8Lh16/xow==" + }, + "undeclared-identifiers": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/undeclared-identifiers/-/undeclared-identifiers-1.1.3.tgz", + "integrity": "sha512-pJOW4nxjlmfwKApE4zvxLScM/njmwj/DiUBv7EabwE4O8kRUy+HIwxQtZLBPll/jx1LJyBcqNfB3/cpv9EZwOw==", + "requires": { + "acorn-node": "^1.3.0", + "dash-ast": "^1.0.0", + "get-assigned-identifiers": "^1.2.0", + "simple-concat": "^1.0.0", + "xtend": "^4.0.1" + } + }, + "underscore": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.7.0.tgz", + "integrity": "sha1-a7rwh3UA02vjTsqlhODbn+8DUgk=" + }, + "union-value": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "requires": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + } + }, "uniq": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz", "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=" }, - "uniqid": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/uniqid/-/uniqid-4.1.1.tgz", - "integrity": "sha1-iSIN32t1GuUrX3JISGNShZa7hME=", - "requires": { - "macaddress": "0.2.8" - } - }, "uniqs": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/uniqs/-/uniqs-2.0.0.tgz", "integrity": "sha1-/+3ks2slKQaW5uFl1KWe25mOawI=" }, - "unzip-response": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/unzip-response/-/unzip-response-1.0.2.tgz", - "integrity": "sha1-uYTwh3/AqJwsdzzB73tbIytbBv4=", - "optional": true + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, + "unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "requires": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "dependencies": { + "has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "requires": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "dependencies": { + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "requires": { + "isarray": "1.0.0" + } + } + } + }, + "has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=" + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" + } + } + }, + "uri-js": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "requires": { + "punycode": "^2.1.0" + }, + "dependencies": { + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + } + } + }, + "urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=" + }, + "url": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", + "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", + "requires": { + "punycode": "1.3.2", + "querystring": "0.2.0" + }, + "dependencies": { + "punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" + } + } + }, + "url-parse": { + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.4.7.tgz", + "integrity": "sha512-d3uaVyzDB9tQoSXFvuSUNFibTd9zxd2bkVrDRvF5TmvWWQwqE4lgYJ5m+x1DbecWkw+LK4RNl2CU1hHuOKPVlg==", + "optional": true, + "requires": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, + "usb": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/usb/-/usb-1.6.1.tgz", + "integrity": "sha512-iZRGRsdbCvhBpeufY+cpy7LS9OMrh1hobvHaxa6/HNr1mgqrfeNpfbzoRCBofkG9MpLsujKieBFzqdPWcMugYQ==", + "requires": { + "bindings": "^1.4.0", + "nan": "2.13.2", + "prebuild-install": "^5.3.3" + } + }, + "use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==" + }, + "useragent": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/useragent/-/useragent-2.3.0.tgz", + "integrity": "sha512-4AoH4pxuSvHCjqLO04sU6U/uE65BYza8l/KKBS0b0hnUPWi+cQ2BpeTEwejCSx9SPV5/U03nniDTrWx5NrmKdw==", + "requires": { + "lru-cache": "4.1.x", + "tmp": "0.0.x" + } + }, + "util": { + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz", + "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==", + "requires": { + "inherits": "2.0.3" + }, + "dependencies": { + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + } + } }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" + }, "uuid": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz", - "integrity": "sha1-PdPT55Crwk17DToDT/q6vijrvAQ=" + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz", + "integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==" + }, + "uws": { + "version": "9.14.0", + "resolved": "https://registry.npmjs.org/uws/-/uws-9.14.0.tgz", + "integrity": "sha512-HNMztPP5A1sKuVFmdZ6BPVpBQd5bUjNC8EFMFiICK+oho/OQsAJy5hnIx4btMHiOk8j04f/DbIlqnEZ9d72dqg==", + "optional": true }, "vendors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/vendors/-/vendors-1.0.1.tgz", - "integrity": "sha1-N61zyO5Bf7PVgOeFMSMH0nSEfyI=" + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/vendors/-/vendors-1.0.3.tgz", + "integrity": "sha512-fOi47nsJP5Wqefa43kyWSg80qF+Q3XA6MUkgi7Hp1HQaKDQW4cQrK2D0P7mmbFtsV1N89am55Yru/nyEwRubcw==" }, "verror": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", "requires": { - "assert-plus": "1.0.0", + "assert-plus": "^1.0.0", "core-util-is": "1.0.2", - "extsprintf": "1.3.0" + "extsprintf": "^1.2.0" } }, - "warning-symbol": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/warning-symbol/-/warning-symbol-0.1.0.tgz", - "integrity": "sha1-uzHdEbeg+dZ6su2V9Fe2WCW7rSE=" + "vm-browserify": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", + "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==" + }, + "void-elements": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", + "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=" }, "websocket-driver": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.0.tgz", - "integrity": "sha1-DK+dLXVdk67gSdS90NP+LMoqJOs=", + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.3.tgz", + "integrity": "sha512-bpxWlvbbB459Mlipc5GBzzZwhoZgGEZLuqPaR0INBGnPAY1vdBX6hPnoFXiw+3yWxDuHyQjO2oXTMyS8A5haFg==", "requires": { - "http-parser-js": "0.4.9", - "websocket-extensions": "0.1.3" + "http-parser-js": ">=0.4.0 <0.4.11", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" } }, "websocket-extensions": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.3.tgz", - "integrity": "sha1-XS/yKXcAPsaHpLhwc9+7rBRszyk=" + "integrity": "sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg==" + }, + "webusb": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/webusb/-/webusb-1.3.1.tgz", + "integrity": "sha512-Z7JLoko7LHavfeuLteaT2B4+79EKME6EbTGw+Kg2iXCHNlQ2e57A5GZM6wd0uLeLuW+CnvCSV3ZP1u3l9Yxmgw==", + "requires": { + "@types/node": "^8.0.54", + "@types/usb": "^1.5.1", + "usb": "^1.6.0" + }, + "dependencies": { + "@types/node": { + "version": "8.10.59", + "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.59.tgz", + "integrity": "sha512-8RkBivJrDCyPpBXhVZcjh7cQxVBSmRk9QM7hOketZzp6Tg79c0N8kkpAIito9bnJ3HCVCHVYz+KHTEbfQNfeVQ==" + } + } + }, + "when": { + "version": "3.7.8", + "resolved": "https://registry.npmjs.org/when/-/when-3.7.8.tgz", + "integrity": "sha1-xxMLan6gRpPoQs3J56Hyqjmjn4I=", + "optional": true }, "whet.extend": { "version": "0.9.9", "resolved": "https://registry.npmjs.org/whet.extend/-/whet.extend-0.9.9.tgz", "integrity": "sha1-+HfVv2SMl+WqVC+twW1qJZucEaE=" }, - "wide-align": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.2.tgz", - "integrity": "sha1-Vx4PGwYEY268DfwhsDObvjE0FxA=", - "optional": true, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", "requires": { - "string-width": "1.0.2" + "isexe": "^2.0.0" } }, - "window-size": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/window-size/-/window-size-1.1.0.tgz", - "integrity": "sha1-O0AtMkTzVWHbLJdhrZ0eUoawei0=", + "which-pm-runs": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.0.0.tgz", + "integrity": "sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs=" + }, + "wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", "requires": { - "define-property": "1.0.0", - "is-number": "3.0.0" + "string-width": "^1.0.2 || 2" } }, + "with-callback": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/with-callback/-/with-callback-1.0.2.tgz", + "integrity": "sha1-oJYpuakgAo1yFAT7Q1vc/1yRvCE=", + "optional": true + }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "optional": true + }, + "wordwrap": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=" + }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, + "ws": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", + "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", + "requires": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0", + "ultron": "~1.1.0" + } + }, + "xmlhttprequest-ssl": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz", + "integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=" + }, + "xregexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-2.0.0.tgz", + "integrity": "sha1-UqY+VsoLhKfzpfPWGHLxJq16WUM=", + "optional": true + }, "xtend": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", - "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=" + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" + }, + "yeast": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", + "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=" } } } diff --git a/package.json b/package.json index 4c72b69e..6a058158 100644 --- a/package.json +++ b/package.json @@ -1,42 +1,52 @@ { "name": "pxt-calliope", - "version": "2.0.2", - "description": "Calliope Mini editor for PXT", + "version": "2.1.28", + "description": "micro:bit target for Microsoft MakeCode (PXT)", "keywords": [ "JavaScript", "education", - "microbit" + "calliope", + "mini" ], "repository": { "type": "git", - "url": "git+https://github.com/Microsoft/pxt-calliope.git" + "url": "git+https://github.com/Microsoft/pxt-microbit.git" }, "author": "", "license": "MIT", - "homepage": "https://github.com/Microsoft/pxt-calliope#readme", + "homepage": "https://github.com/Microsoft/pxt-microbit#readme", "files": [ "README.md", "pxtarget.json", + "targetconfig.json", "built/*.js", "built/*.json", "built/*.d.ts", "built/hexcache", + "built/web", "sim/public", "docs/*.md", "docs/*/*.md", - "docs/*/*/*.md" + "docs/*/*/*.md", + "docs/static/*.svg", + "docs/static/*.png", + "docs/static/icons/favicon.ico" ], "devDependencies": { - "typescript": "^1.8.7", - "rtlcss": "^2.1.2", - "autoprefixer": "^6.7.6", + "@types/bluebird": "2.0.33", + "@types/jquery": "3.2.16", + "@types/marked": "0.3.0", + "@types/node": "8.0.53", + "@types/react": "16.0.25", + "@types/react-dom": "16.0.3", + "@types/web-bluetooth": "0.0.4", "less": "2.7.3", - "semantic-ui-less": "2.2.14" + "react": "16.8.3", + "semantic-ui-less": "2.2.14", + "typescript": "2.6.1" }, "dependencies": { - "pxt-core": "0.19.20" - }, - "scripts": { - "test": "node node_modules/pxt-core/built/pxt.js travis" + "pxt-common-packages": "6.16.24", + "pxt-core": "5.28.24" } } diff --git a/pxtarget.json b/pxtarget.json index 05d68d9a..93821dfa 100644 --- a/pxtarget.json +++ b/pxtarget.json @@ -1,24 +1,27 @@ { "id": "calliopemini", - "aliases": [ - "calliope" - ], - "name": " calliope mini", "nickname": "mini", - "title": "Calliope mini - Blocks / Javascript editor", - "description": "A Blocks / JavaScript code editor for the calliope mini.", + "name": "makecode.calliope.cc", + "title": "Microsoft MakeCode for Calliope mini", + "description": "A Blocks / JavaScript code editor for the Calliope mini powered by Microsoft MakeCode.", "corepkg": "core", "bundleddirs": [ "libs/core", "libs/radio", "libs/devices", - "libs/bluetooth" + "libs/bluetooth", + "libs/radio-broadcast" ], "cloud": { "workspace": false, "packages": true, "sharing": true, - "publishing": false, + "thumbnails": true, + "publishing": true, + "importing": true, + "preferredPackages": [ + "Microsoft/pxt-neopixel" + ], "githubPackages": true }, "compile": { @@ -31,29 +34,79 @@ "flashUsableEnd": 245760, "flashEnd": 245760, "flashCodeAlign": 1024, - "upgrades": [ - { - "type": "package", - "map": { - "microbit": "core", - "microbit-bluetooth": "bluetooth", - "microbit-radio": "radio", - "microbit-devices": "devices", - "microbit-led": "", - "microbit-music": "", - "microbit-game": "", - "microbit-pins": "", - "microbit-serial": "" + "floatingPoint": true, + "taggedInts": true, + "utf8": false, + "gc": true, + "imageRefTag": 9, + "patches": { + "0.0.0 - 1.0.0": [ + { + "type": "package", + "map": { + "microbit": "core", + "microbit-bluetooth": "bluetooth", + "microbit-radio": "radio", + "microbit-devices": "devices", + "microbit-led": "", + "microbit-music": "", + "microbit-game": "", + "microbit-pins": "", + "microbit-serial": "" + } + }, + { + "type": "missingPackage", + "map": { + "radio\\s*\\.": "radio", + "bluetooth\\s*\\.": "bluetooth", + "devices\\s*\\.": "devices" + } + }, + { + "type": "api", + "map": { + "bluetooth\\s*\\.\\s*uartRead\\s*\\((.*?)\\)": "bluetooth.uartReadUntil($1)", + "bluetooth\\s*\\.\\s*uartWrite\\s*\\((.*?)\\)": "bluetooth.uartWriteUntil($1)", + "input\\s*\\.\\s*calibrate\\s*\\(": "input.calibrateCompass(", + "radio\\s*\\.\\s*onDataPacketReceived\\(\\s*\\(\\{\\s*receivedNumber\\s*\\}\\)\\s*=>\\s*\\{": "radio.onReceivedNumber(function (receivedNumber) {", + "radio\\s*\\.\\s*onDataPacketReceived\\(\\s*\\(\\{\\s*receivedString: name, receivedNumber: value\\s*\\}\\)\\s*=>\\s*\\{": "radio.onReceivedValue(function (name, value) {", + "radio\\s*\\.\\s*onDataPacketReceived\\(\\s*\\(\\{\\s*receivedString\\s*\\}\\)\\s*=>\\s*\\{": "radio.onReceivedString(function (receivedString) {", + "Math\\s*\\.\\s*random\\s*\\(": "Math.randomRange(0, " + } + }, + { + "type": "blockId", + "map": { + "device_get_acceleration": "device_acceleration" + } + }, + { + "type": "blockValue", + "map": { + "device_print_message.message": "text" + } } - }, - { - "type": "api", - "map": { - "bluetooth\\.uartRead\\((.*?)\\)": "bluetooth.uartReadUntil($1)", - "bluetooth\\.uartWrite\\((.*?)\\)": "bluetooth.uartWriteUntil($1)" + ], + "0.0.0 - 1.4.12": [ + { + "type": "api", + "map": { + "DisplayMode\\s*\\.\\s*BackAndWhite": "DisplayMode.BlackAndWhite" + } } + ] + }, + "hidSelectors": [ + { + "usagePage": "0xFF00", + "usageId": "0x0001", + "vid": "0x0d28", + "pid": "0x0204" } - ] + ], + "webUSB": true, + "useNewFunctions": true }, "runtime": { "mathBlocks": true, @@ -63,6 +116,17 @@ "textBlocks": true, "listsBlocks": true, "functionBlocks": true, + "functionsOptions": { + "useNewFunctions": true, + "extraFunctionEditorTypes": [ + { + "typeName": "game.LedSprite", + "label": "LedSprite", + "icon": "send", + "defaultName": "sprite" + } + ] + }, "onStartColor": "#54C9C9", "onStartNamespace": "basic", "onStartWeight": 54 @@ -125,9 +189,9 @@ "C15": "C_P15", "C19": "C_P19", "C20": "C_P20", - "EXT_PWR": "EXT_PWR", - "SPKR": "SPKR", - "BTN_A": "BTN_A", + "EXT_PWR":"EXT_PWR", + "SPKR":"SPKR", + "BTN_A": "BTN_A", "BTN_B": "BTN_B", "MOTOR1": "M_OUT1", "MOTOR2": "M_OUT2" @@ -180,13 +244,27 @@ "yottaTarget": "calliope-mini-classic-gcc", "yottaCorePackage": "microbit", "githubCorePackage": "calliope-mini/microbit", - "gittag": "v2.0.0-rc8-calliope-1.0.3", + "gittag": "pxtgc-0", "serviceId": "calliope" }, "serial": { - "manufacturerFilter": "^mbed$", - "nameFilter": "^mbed Serial Port", - "log": true + "nameFilter": "^(mbed Serial Port|DAPLink CMSIS-DAP)", + "log": true, + "useEditor": true, + "editorTheme": { + "graphBackground": "#d9d9d9", + "lineColors": [ + "#6633cc", + "#3891A6", + "#3454D1", + "#EF767A", + "#F46197", + "#107C10" + ] + }, + "vendorId": "0x0d28", + "productId": "0x0204", + "rawHID": true }, "appTheme": { "accentColor": "#249899", @@ -198,26 +276,74 @@ "footerLogo": "./static/Calliopeminieditor.svg", "cardLogo": "./static/icons/apple-touch-icon.png", "appLogo": "./static/icons/apple-touch-icon.png", - "homeUrl": "https://makecode.calliope.cc/", - "embedUrl": "https://makecode.calliope.cc/", - "privacyUrl": "https://go.microsoft.com/fwlink/?LinkId=521839", - "termsOfUseUrl": "https://go.microsoft.com/fwlink/?LinkID=206977", - "githubUrl": "https://github.com/Microsoft/pxt-calliope", - "crowdinProject": "kindscript", "organization": "Microsoft MakeCode", "organizationUrl": "https://makecode.com/", "organizationLogo": "./static/Microsoft-logo_rgb_c-gray-square.png", "organizationWideLogo": "./static/Microsoft-logo_rgb_c-white.png", + "homeScreenHero": "./static/hero.png", + "homeUrl": "https://makecode.calliope.cc/", + "embedUrl": "https://makecode.calliope.cc/", + "shareUrl": "https://makecode.calliope.cc/", + "privacyUrl": "https://go.microsoft.com/fwlink/?LinkId=521839", + "termsOfUseUrl": "https://go.microsoft.com/fwlink/?LinkID=206977", + "githubUrl": "https://github.com/Microsoft/pxt-calliope", "boardName": "Calliope mini", "driveDisplayName": "MINI", - "hideSideDocs": true, + "appStoreID": "1309545545", + "mobileSafariDownloadProtocol": "microbithex://?data", + "crowdinProject": "kindscript", + "extendEditor": true, + "extendFieldEditors": true, + "enableTrace": true, + "ignoreDocsErrors": true, + "experiments": [ + "allowPackageExtensions", + "instructions", + "debugger", + "debugExtensionCode", + "bluetoothUartConsole", + "bluetoothPartialFlashing", + "simScreenshot", + "simGif", + "qrCode", + "githubBlocksDiff" + ], + "bluetoothUartFilters": [ + { + "namePrefix": "Calliope mini" + } + ], + "docMenu": [ + { + "name": "Support", + "path": "https://calliope.cc/faq" + }, + { + "name": "Reference", + "path": "/reference" + }, + { + "name": "Blocks", + "path": "/blocks" + }, + { + "name": "JavaScript", + "path": "/javascript" + }, + { + "name": "Hardware", + "path": "/device" + }, + { + "name": "Buy", + "path": "https://shop.calliope.cc/" + } + ], + "hasReferenceDocs": false, "invertedMenu": true, - "invertedToolbox": true, + "coloredToolbox": true, "monacoToolbox": true, "hasAudio": true, - "highContrast": true, - "simAnimationEnter": "rotate in", - "simAnimationExit": "rotate out", "blocklyOptions": { "grid": { "spacing": 45, @@ -226,29 +352,77 @@ "snap": false } }, - "docMenu": [], - "hasReferenceDocs": false, + "blockColors": { + "basic": "#54C9C9", + "input": "#C94600", + "music": "#DF4600", + "led": "#8169E6", + "radio": "#E3008C", + "motors": "#008272", + "logic": "#006970", + "loops": "#107C10", + "math": "#712672", + "variables": "#A80000", + "text": "#996600", + "advanced": "#DDDDDD", + "functions": "#005A9E", + "arrays": "#E65722" + }, + "highContrast": true, + "greenScreen": true, + "print": true, "selectLanguage": true, "availableLocales": [ "en", + "ar", + "cs", + "da", "de", "el", + "es-ES", + "fi", "fr", + "hu", + "is", "it", + "ja", "ko", "nl", "no", + "pl", + "pt-BR", + "pt-PT", + "ru", + "si-LK", + "sk", "sv-SE", "tr", - "zh-TW", - "zh-CN" + "uk", + "zh-CN", + "zh-TW" ], + "monacoColors": { + "editor.background": "#ecf0f1" + }, "browserDbPrefixes": { + "1": "v1", "2": "v2" }, "editorVersionPaths": { - "1": "v1" - } + "0": "v0" + }, + "showProjectSettings": true, + "scriptManager": true, + "simGifTransparent": "rgba(0,0,0,0)", + "simGifMaxFrames": 44, + "simScreenshotMaxUriLength": 300000, + "importExtensionFiles": true }, - "ignoreDocsErrors": true + "queryVariants": { + "hidemenu": { + "appTheme": { + "hideMenuBar": true + } + } + } } \ No newline at end of file diff --git a/pxtwapp/pxtwapp/images/SmallTile.scale-200.png b/pxtwapp/pxtwapp/images/SmallTile.scale-200.png deleted file mode 100644 index 898bd8b2..00000000 Binary files a/pxtwapp/pxtwapp/images/SmallTile.scale-200.png and /dev/null differ diff --git a/pxtwapp/pxtwapp/images/SplashScreen.scale-200.png b/pxtwapp/pxtwapp/images/SplashScreen.scale-200.png deleted file mode 100644 index 6e3cddb4..00000000 Binary files a/pxtwapp/pxtwapp/images/SplashScreen.scale-200.png and /dev/null differ diff --git a/pxtwapp/pxtwapp/images/Square150x150Logo.scale-200.png b/pxtwapp/pxtwapp/images/Square150x150Logo.scale-200.png deleted file mode 100644 index 550dd4e0..00000000 Binary files a/pxtwapp/pxtwapp/images/Square150x150Logo.scale-200.png and /dev/null differ diff --git a/pxtwapp/pxtwapp/images/Square44x44Logo.altform-unplated_targetsize-48.png b/pxtwapp/pxtwapp/images/Square44x44Logo.altform-unplated_targetsize-48.png deleted file mode 100644 index 64a270a5..00000000 Binary files a/pxtwapp/pxtwapp/images/Square44x44Logo.altform-unplated_targetsize-48.png and /dev/null differ diff --git a/pxtwapp/pxtwapp/images/Square44x44Logo.scale-200.png b/pxtwapp/pxtwapp/images/Square44x44Logo.scale-200.png deleted file mode 100644 index ea8816b3..00000000 Binary files a/pxtwapp/pxtwapp/images/Square44x44Logo.scale-200.png and /dev/null differ diff --git a/pxtwapp/pxtwapp/images/Square44x44Logo.targetsize-48.png b/pxtwapp/pxtwapp/images/Square44x44Logo.targetsize-48.png deleted file mode 100644 index 64a270a5..00000000 Binary files a/pxtwapp/pxtwapp/images/Square44x44Logo.targetsize-48.png and /dev/null differ diff --git a/pxtwapp/pxtwapp/images/Wide310x150Logo.scale-200.png b/pxtwapp/pxtwapp/images/Wide310x150Logo.scale-200.png deleted file mode 100644 index 380fb999..00000000 Binary files a/pxtwapp/pxtwapp/images/Wide310x150Logo.scale-200.png and /dev/null differ diff --git a/pxtwapp/pxtwapp/images/logo.png b/pxtwapp/pxtwapp/images/logo.png deleted file mode 100644 index f0aa99f2..00000000 Binary files a/pxtwapp/pxtwapp/images/logo.png and /dev/null differ diff --git a/pxtwapp/pxtwapp/images/storelogo.scale-200.png b/pxtwapp/pxtwapp/images/storelogo.scale-200.png deleted file mode 100644 index 23d0522d..00000000 Binary files a/pxtwapp/pxtwapp/images/storelogo.scale-200.png and /dev/null differ diff --git a/pxtwapp/pxtwapp/package.appxmanifest b/pxtwapp/pxtwapp/package.appxmanifest index 2978d804..7402c62d 100644 --- a/pxtwapp/pxtwapp/package.appxmanifest +++ b/pxtwapp/pxtwapp/package.appxmanifest @@ -1,59 +1,59 @@ - - - - - - Microsoft MakeCode for Calliope Mini - Calliope.cc - images\storelogo.png - - - - - - - - - - - - - - - - - - - - - - - - Microsoft MakeCode binary file - - .hex - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + MakeCode for micro:bit + Micro:bit Educational Foundation + images\storelogo.png + + + + + + + + + + + + + + + + + + + + + + + + Microsoft MakeCode binary file + + .hex + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/pxtwapp/pxtwapp/pxtwapp.jsproj b/pxtwapp/pxtwapp/pxtwapp.jsproj index b43b3d02..3de8b68a 100644 --- a/pxtwapp/pxtwapp/pxtwapp.jsproj +++ b/pxtwapp/pxtwapp/pxtwapp.jsproj @@ -52,11 +52,11 @@ 10.0.10240.0 $(VersionNumberMajor).$(VersionNumberMinor) en-US - pxtwapp_TemporaryKey.pfx + pxtwapp_StoreKey.pfx true Always x86|x64|arm - BA3D3E800661F789BAE7216F8D6F76608D1C4D62 + 0F8807625041D61E0F9B573FC89308FB2C535CE2 @@ -74,6 +74,8 @@ + + diff --git a/resources/generateleds/generateandupdate.sh b/resources/generateleds/generateandupdate.sh new file mode 100644 index 00000000..27813977 --- /dev/null +++ b/resources/generateleds/generateandupdate.sh @@ -0,0 +1,12 @@ +# Run the generate script +node generateleds.js + +# Copy the generated led png files into the right directory +cp -R out/*.png ../../libs/core/jres/icons/ + +# Rebuilt the jres with those new files +cd ../../libs/core +pxt jres + +# Return back to generateleds directory +cd ../../resources/generateleds diff --git a/resources/generateleds/generateleds.js b/resources/generateleds/generateleds.js new file mode 100644 index 00000000..a043b5c4 --- /dev/null +++ b/resources/generateleds/generateleds.js @@ -0,0 +1,287 @@ +var fs = require('fs'); +var path = require('path'); + +// You need to npm install svg2png for this to work +var svg2png = require('svg2png'); + +var svgdir = "svg"; +var outputdir = "out"; + +const svgNS = "http://www.w3.org/2000/svg"; + +const icons = { + heart: ` + . # . # . + # # # # # + # # # # # + . # # # . + . . # . .`, + smallheart: ` + . . . . . + . # . # . + . # # # . + . . # . . + . . . . .`, + happy: ` + . . . . . + . # . # . + . . . . . + # . . . # + . # # # .`, + sad: ` + . . . . . + . # . # . + . . . . . + . # # # . + # . . . #`, + confused: ` + . . . . . + . # . # . + . . . . . + . # . # . + # . # . #`, + angry: ` + # . . . # + . # . # . + . . . . . + # # # # # + # . # . #`, + asleep: ` + . . . . . + # # . # # + . . . . . + . # # # . + . . . . .`, + surprised: ` + . # . # . + . . . . . + . . # . . + . # . # . + . . # . .`, + silly: ` + # . . . # + . . . . . + # # # # # + . . . # # + . . . # #`, + fabulous: ` + # # # # # + # # . # # + . . . . . + . # . # . + . # # # .`, + meh: ` + # # . # # + . . . . . + . . . # . + . . # . . + . # . . .`, + yes: ` + . . . . . + . . . . # + . . . # . + # . # . . + . # . . .`, + no: ` + # . . . # + . # . # . + . . # . . + . # . # . + # . . . #`, + triangle: ` + . . . . . + . . # . . + . # . # . + # # # # # + . . . . .`, + lefttriangle: ` + # . . . . + # # . . . + # . # . . + # . . # . + # # # # #`, + chessboard: ` + . # . # . + # . # . # + . # . # . + # . # . # + . # . # .`, + diamond: ` + . . # . . + . # . # . + # . . . # + . # . # . + . . # . .`, + smalldiamond: ` + . . . . . + . . # . . + . # . # . + . . # . . + . . . . .`, + square: ` + # # # # # + # . . . # + # . . . # + # . . . # + # # # # #`, + smallsquare: ` + . . . . . + . # # # . + . # . # . + . # # # . + . . . . .`, + scissors: ` + # # . . # + # # . # . + . . # . . + # # . # . + # # . . #`, + tshirt: ` + # # . # # + # # # # # + . # # # . + . # # # . + . # # # .`, + rollerskate: ` + . . . # # + . . . # # + # # # # # + # # # # # + . # . # .`, + duck: ` + . # # . . + # # # . . + . # # # # + . # # # . + . . . . .`, + house: ` + . . # . . + . # # # . + # # # # # + . # # # . + . # . # .`, + tortoise: ` + . . . . . + . # # # . + # # # # # + . # . # . + . . . . .`, + butterfly: ` + # # . # # + # # # # # + . . # . . + # # # # # + # # . # #`, + stickfigure: ` + . . # . . + # # # # # + . . # . . + . # . # . + # . . . #`, + ghost: ` + . # # # . + # . # . # + # # # # # + # # # # # + # . # . #`, + sword: ` + . . # . . + . . # . . + . . # . . + . # # # . + . . # . .` + , + giraffe: ` + # # . . . + . # . . . + . # . . . + . # # # . + . # . # .`, + skull: ` + . # # # . + # . # . # + # # # # # + . # # # . + . # # # .`, + umbrella: ` + . # # # . + # # # # # + . . # . . + # . # . . + # # # . .`, + snake: ` + # # . . . + # # . # # + . # . # . + . # # # . + . . . . .`, + rabbit: ` + # . # . . + # . # . . + # # # # . + # # . # . + # # # # .`, + cow: ` + # . . . # + # . . . # + # # # # # + . # # # . + . . # . .`, + quarternote: ` + . . # . . + . . # . . + . . # . . + # # # . . + # # # . .`, + eigthnote: ` + . . # . . + . . # # . + . . # . # + # # # . . + # # # . .`, + pitchfork: ` + # . # . # + # . # . # + # # # # # + . . # . . + . . # . .`, + target: ` + . . # . . + . # # # . + # # . # # + . # # # . + . . # . .` +} + +Object.keys(icons).forEach(icon => { + const data = icons[icon]; + const hexLiteral = data + .replace(/[ \n`\(\)]/gi, ''); + + var svg = ``; + const width = 200; + const height = 200; + //svg += ''; + for (var i = 0; i < 5; i++) { + for (j = 0; j < 5; j++) { + const hexItemVal = hexLiteral[(i * 5) + j] ? hexLiteral[(i * 5) + j] == '#' : false; + const x = j * (width / 5); + const y = i * (height / 5); + svg += `\n`; //#006CC2 + } + } + svg += ``; + const svgPath = path.join(svgdir, icon + ".svg"); + fs.writeFile(svgPath, svg, { encoding: 'utf8', flag: 'w' }, function(err, result) { + if (err) console.log("error writing to file"); + }); + + const sourceBuffer = Buffer.from(svg, 'utf8'); + svg2png(sourceBuffer, { width: 200, height: 200 }) + .then(buffer => fs.writeFile(path.join(outputdir, icon + "-icon.png"), buffer, { encoding: 'utf8', flag: 'w' }, function (err, result) { + if (err) console.log("error writing to file"); + })) + .catch(e => console.error(e)); +}); \ No newline at end of file diff --git a/resources/generateleds/out/angry-icon.png b/resources/generateleds/out/angry-icon.png new file mode 100644 index 00000000..4c55747e Binary files /dev/null and b/resources/generateleds/out/angry-icon.png differ diff --git a/resources/generateleds/out/asleep-icon.png b/resources/generateleds/out/asleep-icon.png new file mode 100644 index 00000000..7b4d65c8 Binary files /dev/null and b/resources/generateleds/out/asleep-icon.png differ diff --git a/resources/generateleds/out/butterfly-icon.png b/resources/generateleds/out/butterfly-icon.png new file mode 100644 index 00000000..fcd60187 Binary files /dev/null and b/resources/generateleds/out/butterfly-icon.png differ diff --git a/resources/generateleds/out/chessboard-icon.png b/resources/generateleds/out/chessboard-icon.png new file mode 100644 index 00000000..dd7a597e Binary files /dev/null and b/resources/generateleds/out/chessboard-icon.png differ diff --git a/resources/generateleds/out/confused-icon.png b/resources/generateleds/out/confused-icon.png new file mode 100644 index 00000000..873453f9 Binary files /dev/null and b/resources/generateleds/out/confused-icon.png differ diff --git a/resources/generateleds/out/cow-icon.png b/resources/generateleds/out/cow-icon.png new file mode 100644 index 00000000..bd558775 Binary files /dev/null and b/resources/generateleds/out/cow-icon.png differ diff --git a/resources/generateleds/out/diamond-icon.png b/resources/generateleds/out/diamond-icon.png new file mode 100644 index 00000000..e75b01a1 Binary files /dev/null and b/resources/generateleds/out/diamond-icon.png differ diff --git a/resources/generateleds/out/duck-icon.png b/resources/generateleds/out/duck-icon.png new file mode 100644 index 00000000..5504f1ab Binary files /dev/null and b/resources/generateleds/out/duck-icon.png differ diff --git a/resources/generateleds/out/eigthnote-icon.png b/resources/generateleds/out/eigthnote-icon.png new file mode 100644 index 00000000..559c73aa Binary files /dev/null and b/resources/generateleds/out/eigthnote-icon.png differ diff --git a/resources/generateleds/out/fabulous-icon.png b/resources/generateleds/out/fabulous-icon.png new file mode 100644 index 00000000..280beaf7 Binary files /dev/null and b/resources/generateleds/out/fabulous-icon.png differ diff --git a/resources/generateleds/out/ghost-icon.png b/resources/generateleds/out/ghost-icon.png new file mode 100644 index 00000000..565e9bfb Binary files /dev/null and b/resources/generateleds/out/ghost-icon.png differ diff --git a/resources/generateleds/out/giraffe-icon.png b/resources/generateleds/out/giraffe-icon.png new file mode 100644 index 00000000..7d3e041d Binary files /dev/null and b/resources/generateleds/out/giraffe-icon.png differ diff --git a/resources/generateleds/out/happy-icon.png b/resources/generateleds/out/happy-icon.png new file mode 100644 index 00000000..90c3dfba Binary files /dev/null and b/resources/generateleds/out/happy-icon.png differ diff --git a/resources/generateleds/out/heart-icon.png b/resources/generateleds/out/heart-icon.png new file mode 100644 index 00000000..dd2c61e8 Binary files /dev/null and b/resources/generateleds/out/heart-icon.png differ diff --git a/resources/generateleds/out/house-icon.png b/resources/generateleds/out/house-icon.png new file mode 100644 index 00000000..22fb9f1a Binary files /dev/null and b/resources/generateleds/out/house-icon.png differ diff --git a/resources/generateleds/out/lefttriangle-icon.png b/resources/generateleds/out/lefttriangle-icon.png new file mode 100644 index 00000000..b349b683 Binary files /dev/null and b/resources/generateleds/out/lefttriangle-icon.png differ diff --git a/resources/generateleds/out/meh-icon.png b/resources/generateleds/out/meh-icon.png new file mode 100644 index 00000000..72a66b70 Binary files /dev/null and b/resources/generateleds/out/meh-icon.png differ diff --git a/resources/generateleds/out/no-icon.png b/resources/generateleds/out/no-icon.png new file mode 100644 index 00000000..01a1d549 Binary files /dev/null and b/resources/generateleds/out/no-icon.png differ diff --git a/resources/generateleds/out/pitchfork-icon.png b/resources/generateleds/out/pitchfork-icon.png new file mode 100644 index 00000000..2a22985d Binary files /dev/null and b/resources/generateleds/out/pitchfork-icon.png differ diff --git a/resources/generateleds/out/quarternote-icon.png b/resources/generateleds/out/quarternote-icon.png new file mode 100644 index 00000000..dbe27f24 Binary files /dev/null and b/resources/generateleds/out/quarternote-icon.png differ diff --git a/resources/generateleds/out/rabbit-icon.png b/resources/generateleds/out/rabbit-icon.png new file mode 100644 index 00000000..a4da265d Binary files /dev/null and b/resources/generateleds/out/rabbit-icon.png differ diff --git a/resources/generateleds/out/rollerskate-icon.png b/resources/generateleds/out/rollerskate-icon.png new file mode 100644 index 00000000..9d1b72f7 Binary files /dev/null and b/resources/generateleds/out/rollerskate-icon.png differ diff --git a/resources/generateleds/out/sad-icon.png b/resources/generateleds/out/sad-icon.png new file mode 100644 index 00000000..07e4f9f5 Binary files /dev/null and b/resources/generateleds/out/sad-icon.png differ diff --git a/resources/generateleds/out/scissors-icon.png b/resources/generateleds/out/scissors-icon.png new file mode 100644 index 00000000..1472667b Binary files /dev/null and b/resources/generateleds/out/scissors-icon.png differ diff --git a/resources/generateleds/out/silly-icon.png b/resources/generateleds/out/silly-icon.png new file mode 100644 index 00000000..42b5d987 Binary files /dev/null and b/resources/generateleds/out/silly-icon.png differ diff --git a/resources/generateleds/out/skull-icon.png b/resources/generateleds/out/skull-icon.png new file mode 100644 index 00000000..990911d2 Binary files /dev/null and b/resources/generateleds/out/skull-icon.png differ diff --git a/resources/generateleds/out/smalldiamond-icon.png b/resources/generateleds/out/smalldiamond-icon.png new file mode 100644 index 00000000..0313b3a3 Binary files /dev/null and b/resources/generateleds/out/smalldiamond-icon.png differ diff --git a/resources/generateleds/out/smallheart-icon.png b/resources/generateleds/out/smallheart-icon.png new file mode 100644 index 00000000..73566f22 Binary files /dev/null and b/resources/generateleds/out/smallheart-icon.png differ diff --git a/resources/generateleds/out/smallsquare-icon.png b/resources/generateleds/out/smallsquare-icon.png new file mode 100644 index 00000000..592bd304 Binary files /dev/null and b/resources/generateleds/out/smallsquare-icon.png differ diff --git a/resources/generateleds/out/snake-icon.png b/resources/generateleds/out/snake-icon.png new file mode 100644 index 00000000..4fe28a02 Binary files /dev/null and b/resources/generateleds/out/snake-icon.png differ diff --git a/resources/generateleds/out/square-icon.png b/resources/generateleds/out/square-icon.png new file mode 100644 index 00000000..c14b8557 Binary files /dev/null and b/resources/generateleds/out/square-icon.png differ diff --git a/resources/generateleds/out/stickfigure-icon.png b/resources/generateleds/out/stickfigure-icon.png new file mode 100644 index 00000000..bec156af Binary files /dev/null and b/resources/generateleds/out/stickfigure-icon.png differ diff --git a/resources/generateleds/out/surprised-icon.png b/resources/generateleds/out/surprised-icon.png new file mode 100644 index 00000000..c21d3626 Binary files /dev/null and b/resources/generateleds/out/surprised-icon.png differ diff --git a/resources/generateleds/out/sword-icon.png b/resources/generateleds/out/sword-icon.png new file mode 100644 index 00000000..140341c4 Binary files /dev/null and b/resources/generateleds/out/sword-icon.png differ diff --git a/resources/generateleds/out/target-icon.png b/resources/generateleds/out/target-icon.png new file mode 100644 index 00000000..a36a0307 Binary files /dev/null and b/resources/generateleds/out/target-icon.png differ diff --git a/resources/generateleds/out/tortoise-icon.png b/resources/generateleds/out/tortoise-icon.png new file mode 100644 index 00000000..026b8315 Binary files /dev/null and b/resources/generateleds/out/tortoise-icon.png differ diff --git a/resources/generateleds/out/triangle-icon.png b/resources/generateleds/out/triangle-icon.png new file mode 100644 index 00000000..e32cc6af Binary files /dev/null and b/resources/generateleds/out/triangle-icon.png differ diff --git a/resources/generateleds/out/tshirt-icon.png b/resources/generateleds/out/tshirt-icon.png new file mode 100644 index 00000000..55d1bee7 Binary files /dev/null and b/resources/generateleds/out/tshirt-icon.png differ diff --git a/resources/generateleds/out/umbrella-icon.png b/resources/generateleds/out/umbrella-icon.png new file mode 100644 index 00000000..e911179f Binary files /dev/null and b/resources/generateleds/out/umbrella-icon.png differ diff --git a/resources/generateleds/out/yes-icon.png b/resources/generateleds/out/yes-icon.png new file mode 100644 index 00000000..e0fd2749 Binary files /dev/null and b/resources/generateleds/out/yes-icon.png differ diff --git a/resources/generateleds/svg/angry.svg b/resources/generateleds/svg/angry.svg new file mode 100644 index 00000000..ca9b3678 --- /dev/null +++ b/resources/generateleds/svg/angry.svg @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/resources/generateleds/svg/asleep.svg b/resources/generateleds/svg/asleep.svg new file mode 100644 index 00000000..0e00935d --- /dev/null +++ b/resources/generateleds/svg/asleep.svg @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/resources/generateleds/svg/butterfly.svg b/resources/generateleds/svg/butterfly.svg new file mode 100644 index 00000000..cd8ddd0d --- /dev/null +++ b/resources/generateleds/svg/butterfly.svg @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/resources/generateleds/svg/chessboard.svg b/resources/generateleds/svg/chessboard.svg new file mode 100644 index 00000000..7841e7fe --- /dev/null +++ b/resources/generateleds/svg/chessboard.svg @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/resources/generateleds/svg/confused.svg b/resources/generateleds/svg/confused.svg new file mode 100644 index 00000000..b5e45b00 --- /dev/null +++ b/resources/generateleds/svg/confused.svg @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/resources/generateleds/svg/cow.svg b/resources/generateleds/svg/cow.svg new file mode 100644 index 00000000..8d0e1962 --- /dev/null +++ b/resources/generateleds/svg/cow.svg @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/resources/generateleds/svg/diamond.svg b/resources/generateleds/svg/diamond.svg new file mode 100644 index 00000000..9b02d607 --- /dev/null +++ b/resources/generateleds/svg/diamond.svg @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/resources/generateleds/svg/duck.svg b/resources/generateleds/svg/duck.svg new file mode 100644 index 00000000..454ba76e --- /dev/null +++ b/resources/generateleds/svg/duck.svg @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/resources/generateleds/svg/eigthnote.svg b/resources/generateleds/svg/eigthnote.svg new file mode 100644 index 00000000..f769a202 --- /dev/null +++ b/resources/generateleds/svg/eigthnote.svg @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/resources/generateleds/svg/fabulous.svg b/resources/generateleds/svg/fabulous.svg new file mode 100644 index 00000000..a87ccbb2 --- /dev/null +++ b/resources/generateleds/svg/fabulous.svg @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/resources/generateleds/svg/ghost.svg b/resources/generateleds/svg/ghost.svg new file mode 100644 index 00000000..b680c9c7 --- /dev/null +++ b/resources/generateleds/svg/ghost.svg @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/resources/generateleds/svg/giraffe.svg b/resources/generateleds/svg/giraffe.svg new file mode 100644 index 00000000..bebb9aae --- /dev/null +++ b/resources/generateleds/svg/giraffe.svg @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/resources/generateleds/svg/happy.svg b/resources/generateleds/svg/happy.svg new file mode 100644 index 00000000..41edd23e --- /dev/null +++ b/resources/generateleds/svg/happy.svg @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/resources/generateleds/svg/heart.svg b/resources/generateleds/svg/heart.svg new file mode 100644 index 00000000..c9081685 --- /dev/null +++ b/resources/generateleds/svg/heart.svg @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/resources/generateleds/svg/house.svg b/resources/generateleds/svg/house.svg new file mode 100644 index 00000000..2e80fcc8 --- /dev/null +++ b/resources/generateleds/svg/house.svg @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/resources/generateleds/svg/lefttriangle.svg b/resources/generateleds/svg/lefttriangle.svg new file mode 100644 index 00000000..911f4e63 --- /dev/null +++ b/resources/generateleds/svg/lefttriangle.svg @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/resources/generateleds/svg/meh.svg b/resources/generateleds/svg/meh.svg new file mode 100644 index 00000000..51fd6802 --- /dev/null +++ b/resources/generateleds/svg/meh.svg @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/resources/generateleds/svg/no.svg b/resources/generateleds/svg/no.svg new file mode 100644 index 00000000..498bcbfd --- /dev/null +++ b/resources/generateleds/svg/no.svg @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/resources/generateleds/svg/pitchfork.svg b/resources/generateleds/svg/pitchfork.svg new file mode 100644 index 00000000..55e2a197 --- /dev/null +++ b/resources/generateleds/svg/pitchfork.svg @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/resources/generateleds/svg/quarternote.svg b/resources/generateleds/svg/quarternote.svg new file mode 100644 index 00000000..d7e8f974 --- /dev/null +++ b/resources/generateleds/svg/quarternote.svg @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/resources/generateleds/svg/rabbit.svg b/resources/generateleds/svg/rabbit.svg new file mode 100644 index 00000000..25b898e2 --- /dev/null +++ b/resources/generateleds/svg/rabbit.svg @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/resources/generateleds/svg/rollerskate.svg b/resources/generateleds/svg/rollerskate.svg new file mode 100644 index 00000000..8b377248 --- /dev/null +++ b/resources/generateleds/svg/rollerskate.svg @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/resources/generateleds/svg/sad.svg b/resources/generateleds/svg/sad.svg new file mode 100644 index 00000000..aeb702c6 --- /dev/null +++ b/resources/generateleds/svg/sad.svg @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/resources/generateleds/svg/scissors.svg b/resources/generateleds/svg/scissors.svg new file mode 100644 index 00000000..23f4fbbf --- /dev/null +++ b/resources/generateleds/svg/scissors.svg @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/resources/generateleds/svg/silly.svg b/resources/generateleds/svg/silly.svg new file mode 100644 index 00000000..067082e7 --- /dev/null +++ b/resources/generateleds/svg/silly.svg @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/resources/generateleds/svg/skull.svg b/resources/generateleds/svg/skull.svg new file mode 100644 index 00000000..bb26d47c --- /dev/null +++ b/resources/generateleds/svg/skull.svg @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/resources/generateleds/svg/smalldiamond.svg b/resources/generateleds/svg/smalldiamond.svg new file mode 100644 index 00000000..8fb75133 --- /dev/null +++ b/resources/generateleds/svg/smalldiamond.svg @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/resources/generateleds/svg/smallheart.svg b/resources/generateleds/svg/smallheart.svg new file mode 100644 index 00000000..ba080772 --- /dev/null +++ b/resources/generateleds/svg/smallheart.svg @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/resources/generateleds/svg/smallsquare.svg b/resources/generateleds/svg/smallsquare.svg new file mode 100644 index 00000000..417c2b1d --- /dev/null +++ b/resources/generateleds/svg/smallsquare.svg @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/resources/generateleds/svg/snake.svg b/resources/generateleds/svg/snake.svg new file mode 100644 index 00000000..fac08a8d --- /dev/null +++ b/resources/generateleds/svg/snake.svg @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/resources/generateleds/svg/square.svg b/resources/generateleds/svg/square.svg new file mode 100644 index 00000000..584509d0 --- /dev/null +++ b/resources/generateleds/svg/square.svg @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/resources/generateleds/svg/stickfigure.svg b/resources/generateleds/svg/stickfigure.svg new file mode 100644 index 00000000..a450bb7a --- /dev/null +++ b/resources/generateleds/svg/stickfigure.svg @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/resources/generateleds/svg/surprised.svg b/resources/generateleds/svg/surprised.svg new file mode 100644 index 00000000..9fb21769 --- /dev/null +++ b/resources/generateleds/svg/surprised.svg @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/resources/generateleds/svg/sword.svg b/resources/generateleds/svg/sword.svg new file mode 100644 index 00000000..8ef410c2 --- /dev/null +++ b/resources/generateleds/svg/sword.svg @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/resources/generateleds/svg/target.svg b/resources/generateleds/svg/target.svg new file mode 100644 index 00000000..6a08b477 --- /dev/null +++ b/resources/generateleds/svg/target.svg @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/resources/generateleds/svg/tortoise.svg b/resources/generateleds/svg/tortoise.svg new file mode 100644 index 00000000..b41d6ac0 --- /dev/null +++ b/resources/generateleds/svg/tortoise.svg @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/resources/generateleds/svg/triangle.svg b/resources/generateleds/svg/triangle.svg new file mode 100644 index 00000000..bb2a716d --- /dev/null +++ b/resources/generateleds/svg/triangle.svg @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/resources/generateleds/svg/tshirt.svg b/resources/generateleds/svg/tshirt.svg new file mode 100644 index 00000000..ad585ea9 --- /dev/null +++ b/resources/generateleds/svg/tshirt.svg @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/resources/generateleds/svg/umbrella.svg b/resources/generateleds/svg/umbrella.svg new file mode 100644 index 00000000..47be238a --- /dev/null +++ b/resources/generateleds/svg/umbrella.svg @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/resources/generateleds/svg/yes.svg b/resources/generateleds/svg/yes.svg new file mode 100644 index 00000000..96e61294 --- /dev/null +++ b/resources/generateleds/svg/yes.svg @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/resources/gestures/BackSideUp.svg b/resources/gestures/BackSideUp.svg new file mode 100644 index 00000000..69323d1b --- /dev/null +++ b/resources/gestures/BackSideUp.svg @@ -0,0 +1 @@ +BackSideUp \ No newline at end of file diff --git a/resources/gestures/FreeFall.svg b/resources/gestures/FreeFall.svg new file mode 100644 index 00000000..eee781ab --- /dev/null +++ b/resources/gestures/FreeFall.svg @@ -0,0 +1 @@ +FreeFall \ No newline at end of file diff --git a/resources/gestures/FrontSideUp.svg b/resources/gestures/FrontSideUp.svg new file mode 100644 index 00000000..07d2d1c6 --- /dev/null +++ b/resources/gestures/FrontSideUp.svg @@ -0,0 +1 @@ +FrontSideUp \ No newline at end of file diff --git a/resources/gestures/Impact3G.svg b/resources/gestures/Impact3G.svg new file mode 100644 index 00000000..3d1d6b0c --- /dev/null +++ b/resources/gestures/Impact3G.svg @@ -0,0 +1 @@ +Impact3G \ No newline at end of file diff --git a/resources/gestures/Impact6G.svg b/resources/gestures/Impact6G.svg new file mode 100644 index 00000000..456d2f6f --- /dev/null +++ b/resources/gestures/Impact6G.svg @@ -0,0 +1 @@ +Impact6G \ No newline at end of file diff --git a/resources/gestures/Impact8G.svg b/resources/gestures/Impact8G.svg new file mode 100644 index 00000000..f4696728 --- /dev/null +++ b/resources/gestures/Impact8G.svg @@ -0,0 +1 @@ +Impact8G \ No newline at end of file diff --git a/resources/gestures/Shake.svg b/resources/gestures/Shake.svg new file mode 100644 index 00000000..0a09f218 --- /dev/null +++ b/resources/gestures/Shake.svg @@ -0,0 +1,72 @@ + + + + + + image/svg+xml + + Shake + + + + + + Shake + + + + + diff --git a/resources/gestures/TiltBackward.svg b/resources/gestures/TiltBackward.svg new file mode 100644 index 00000000..b79e4442 --- /dev/null +++ b/resources/gestures/TiltBackward.svg @@ -0,0 +1 @@ +TiltBackward \ No newline at end of file diff --git a/resources/gestures/TiltForward.svg b/resources/gestures/TiltForward.svg new file mode 100644 index 00000000..1d67aea5 --- /dev/null +++ b/resources/gestures/TiltForward.svg @@ -0,0 +1 @@ +TiltForward \ No newline at end of file diff --git a/resources/gestures/TiltLeft.svg b/resources/gestures/TiltLeft.svg new file mode 100644 index 00000000..159acb0b --- /dev/null +++ b/resources/gestures/TiltLeft.svg @@ -0,0 +1 @@ +TiltLeft \ No newline at end of file diff --git a/resources/gestures/TiltRight.svg b/resources/gestures/TiltRight.svg new file mode 100644 index 00000000..8a7368b9 --- /dev/null +++ b/resources/gestures/TiltRight.svg @@ -0,0 +1 @@ +TiltRight \ No newline at end of file diff --git a/resources/herobanner/Microbit_Hero_Illustration_06.ai b/resources/herobanner/Microbit_Hero_Illustration_06.ai new file mode 100644 index 00000000..671bd244 --- /dev/null +++ b/resources/herobanner/Microbit_Hero_Illustration_06.ai @@ -0,0 +1,6868 @@ +%PDF-1.5 % +1 0 obj <>/OCGs[7 0 R 8 0 R 9 0 R 10 0 R 11 0 R 12 0 R 99 0 R 100 0 R 101 0 R 102 0 R 103 0 R 104 0 R 192 0 R 193 0 R 194 0 R 195 0 R 190 0 R 191 0 R 277 0 R 278 0 R 279 0 R 280 0 R 281 0 R 282 0 R 365 0 R 364 0 R 366 0 R 367 0 R 368 0 R 369 0 R 451 0 R 452 0 R 453 0 R 454 0 R 455 0 R 456 0 R 538 0 R 539 0 R 540 0 R 541 0 R 542 0 R 543 0 R 625 0 R 626 0 R 627 0 R 628 0 R 629 0 R 630 0 R 712 0 R 713 0 R 714 0 R 715 0 R 716 0 R 717 0 R]>>/Pages 3 0 R/Type/Catalog>> endobj 2 0 obj <>stream + + + + + application/pdf + + + Web + + + Adobe Illustrator CC 22.0 (Macintosh) + 2018-10-25T11:19:39-07:00 + 2018-10-25T12:36:57-07:00 + 2018-10-25T12:36:57-07:00 + + + + 256 + 108 + JPEG + /9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgAbAEAAwER AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE 1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp 0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo +DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A9U4q7FXYq7FUHcf3zfR+ rFV+mkm13Nf3kv4SNiqJxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2Kux V2KuxV2KsJ8+ee77y5qFra21vFKs8RkLS8qghiKDiR4ZbCAIsuk7U7Unp5iMQDY6sYH5zayaf6Fa 7/8AGT/mrJ+EHWf6Isv82P2/rd/yubWdv9CtdzT/AHZ/zVj4QX/RFl/mx+39bh+c2skD/QrXc0/3 Z/zVj4QX/RFl/mx+1mOh+aodQ0mwvr4pb3GoO8cUSBipZJTGAOvgOuYWoz48UhGRoyNB6jsw5NVg 8UDlZPlRP6mN63+Zup6Lq11pkFtbyRQSkK8nPl8f7zehA/azLhjBDo9f2zPDmMAAQK+60Cfzm1n/ AJYrXrx/3Z/zVkvCDh/6Isn82P2rk/OPXHYIljbM7NwVQJCSSaAUDd8fCike0OU7cMftVb382fM1 hd/Vb7S4LebircH5hgGFRyHLb6cAxxLPL27nxy4ZwAPxQ3/K6dZ9Qq1jbAdAf3n/ADVh8INf+iPJ f0x+13/K6daEhVrG2A8f3n/NWPhBf9EeS/pj9rv+V060JCrWNtTsf3n/ADVj4QX/AER5L+mP2uP5 060JCpsbbj4/vP8AmrHwgv8AojyX9I+1x/OnWhIVNjbcfH95/wA1Y+EF/wBEeS/pDm/OnWlk4mxt uPj+8/5qx8IJPtHO/pDm/OnWlk4mxtuPj+87/wCyx8IL/ojnf0hzfnTrSycTY2vHx/ef81Y+EFPt HO/pDm/OnWlk4mxtePj+8/5qx8IKfaOd/SHN+dOtrJT6jalfEep/zVj4QU+0c7+gL3/OTWwhYWVq dqj+8/5qx8IMj7RTr6Qti/OfWnFPqVsG8P3n/NWPhBEfaOZ/gHzak/OjXEkCmxtadz+8r/xLHwgp 9o5g/QPmqH849b4FhZWp2qP7z/mrHwgy/wBEU6+kfNZF+c+tvsbK1Df89P8AmrHwgxj7RzP8A+bU v5z64jgfUbUilT/eV/4lj4QWXtHMH6B81T/lcet8OQsrUilR/ef81Y+EGX+iKVfQPmpxfnRrb7Gy tQ3/AD0/5qx8IIj7RyP8A+bpfzn12NgPqNqQev8Aef8ANWPhBZe0ch/APmqD849bZeQs7Uj/AJ6f 81YPCDIe0Uv5g+anF+dGuOaNZWoPb+8/5qw+EGMfaSR/gHzbm/ObXY+NLG1Nev8Aef8ANWPhBZe0 ch/APmyvyD55vvMlxdR3MEUSwIrqYuVakkEHkWyucAHbdmdpHU8W1cNfaxf85TTXNP3pW3Ox7/Gc sxfS6b2h/vY/1f0vPFP2fiHUjp+Byx58FsN9n4h1I6fhituDbD4h1puPwOKgvVvKWqaBZ+WfL8Op sn1m7mmi07nE0hMv1lgApCtwNSu5pmJlwRnKyAeH7H0b2dw5p6O8d8MRLi3ra5ee/Vg3no/87ZqP xAfvR2/yF2OZGPk8b2yf8Kl8P9yGL6nf/U7YyD4mLlENKqHIPEPuNicytNg8WYjdOvhHiKK0D8yr TQdHluLW29TzROWRZp1BgtYvGMCpZ299vxrsp9lRlPugPmT91O40eSGCJMRxZD16AeSTaf5tudRv nN9KbqeZi0txSrcm8Qvb6MdVocQhxQNEdPx1cHUwkSZy5lOo3JmMdOVTRabnNJOQiLJoOHjjKUuE CyeTHm8zaq2vyaZbaZ6kMEypPdmQcRGaEsuwWtDWnLKseYTFx5O5z9lwwQvLMCdfT593VkAmCysr fZrsfDL3ScW7vWCylW+z2PhivFu71QsrK32ex8MV4qKHuZIzeRwzXZsrdg7NOEMlCsdUXiu/xNRf atc2HZ+GMzK48VV972/sV2dh1WTL4uMZeGMaBNczut01NJuL65ivfMTWFrHMEt7hraWUyxUc+pwR qp9lBx/yvY5s8mliADHECa5X7vx8H0DN7N6OMQY6aEjW44qo7bb/AB+SFv5IIFraa0t1SFZCPSlj PqGQqYhyruqUcnYdhvkoaTGeeOt+/wC3n8GyHs1oD9WniN+++nPn8G9JvZmmdZXLqRXfehrmD2np oYxExFPF+3XZGl0mPFLDAQMpEGr7gmTxLJIaNTptmofNzGy36TJGwLfCfbpinhoNLbHZlf5HFAgm dh5X13VjysrSSVQKepTjGT/rsVX8ciZAOVi0GbN9ESfu+aaD8tfNkaENDGFYU3ljG5/2WQOaI5lz Y9harkB9oWP+WfmmOjPFGgrQEyxjf6WyXiBA7A1R5D7Qidd/LTVdK0KbWr67hWK2iWSaJBI7jkQO NFU1NW7YBkDZm7Cyxhxkx2HL8bMCXXtIiU+pdiKMjdpkeJP+CkCr+OT4g60aTJ0F+7dGwxJLGssM qvG4DI67gg9wRhtoOMhUkjLsqsw5U8OuKkW3HCyV+Ko7jFRGli2/IBlfb5YsRBdJGW4Kzb70NOvT FkQ9G/JaIx6jqW9awx/8SOVZeT0vs3GjP/N/Ss/OUka5p+4Fbc7Hv8Zw4vpavaH+9j/V/S89Vj8P xDqR/Zljz4LgT8PxDqR/ZituBNB8Q60/sOK29O8t675a07y75Zt9XCtd39zLBpZaIykTm5KijUPD 4mXfK/ClLiI6c3v+wpzGkHCSAeK/9MWHeeif8WahuB+9H/EF2OHHyeU7Z/xqXw/3IY9PGs0LxORx clDUeNcsjIg2HWCVG/N5hqnk3zFPchI4vUEQMbSFgFJDMQQT4g5k6398YyEhy6+8vUaHtPBigeLv /QybyH5Z1TRJrmXUVRIZk4IQ1fjBqAPHNbmzxxxGOMhKZnHYX9PI91c7+DZqJQ1cJT4ZCEIS9R2H FzHvuuGvNl3qBVKnpIxWtP2QBUV9+QynNDxcogfpiOI+Z/h+4l1OjzDT4JZR/eSlwR8hVyI89wPK 1olCyFG+zXY+GZtOo4993CUCVlbpXY4V4t3eqFlZW+z2PhivFu3G00l39XiiaZ2+wkY5MfkB1zM0 +hllgZggcPe2Y4GRoLRoOs6xfxW1nZSTSIS5h4mpVSA/LagFRTfNrp9GMEJSnOMeIV7npewO0cuj GaMIylPLDhBG3Cd/V8D7kNdaQbK7K3NoIZCquIZKkBXUMpA6bg1zLx6Oc4V4pI7wO7zXP7S9peGM MsshVb8peVyG/wCN2kjtfUHO3h4tttGNtsxNdo5YcfGMkyb73XS7a1o38fL/AMrJfrRCLbwTH040 RWpUqoH6s0M8kpfUSfe4Op7Qz5iBlnPIBy4pGVfNqZqS1U+FCMg4cjuqGUPC3ZgNxiy4rDOPI/k3 lpr67qVu1zAql7OwHWWn7bf5PgO/66M2Shs9B2T2ZcPFyCx0j3+bOr7WdLh0SCbUZf0YJFDCA7OK fshR28M1+o051GPhsxvueqx62GCInOojzY9q3n3yXqdr9Una6eKMh+caBSSoI/aPv4ZPVdnDPjEJ 3QcXT+0+DBMygbPuP7EJ5j86+RfMFpDaX4vRFBMtwnpIinmisorUttRzmdGMgui9rMOmkZQ5kVuE 48y+e/KWpeV7q0MrSG4hFIQVRyaggVPOhBHhkPDvYhxtT2rh8EmM/VW1Hd5Nf2Udt6b2kzPDPF60 HPbklWQqy1biysjLsffpicRjvDn3dP2fB0R1kMhEc9ShIbTEQJx6Xt9VHmJXY5EXbHjp72xN7o3G 3uG+KW1PwwTnuJFGyOf9+KK+PIbZbAiQsOFllLFkOLN6hHa/uMT1ieYHIjlSY2+oQ31tFcwgpWqv G2zo6ni6MB+0rChyYLiZ4GEqRkU3McW+1+vCxjK1CKUofEHqMWEZUqXLBgjKdt/4Yspl6P8AkpKX 1DUgeohj3/2RyrLyem9m5Xx/5v6Vv5y/8dzT+m9udj3+M4cX0tXtD/ex/q/peeKfsbg1J+nLHnw2 D9ncdT/tYq4HYbjrT+zFXp/lvX9A0zy75ZttUj9S51G5lg05vSEnGY3JUGp+xuy75GOGc+Ix5RG7 2nZeojj0+MH+Ikf7IsN89f8AKWahuP70df8AUXY4MfJ5/tn/ABqXw/3ISIn3X7VOnz2OTdWuDcE5 AKWZyqlhVVp1qO/XbMLOZzn4cTwirkevkB8i7bRRw4sRz5Rxni4YR6EjcmXkLG3W1L1QJHMtZHFa Md2+Qr0/VluHTQxD0j9bRqe0s2pkBkl6eg5Rj8B/axLzP+Y+naFc29lcsDNKzSSiMcmijoSK1rUs QAB9O2YcMs5SMx1AHyv9b6lqvZPszSRx4c08k5AmRoxHMC9uG/4Rwi/eWHQ/mN50124k/Qzw2VvE UUmaMSuXkJCiiRyGlP8AJoKVJy85pR5uqx+zGl1Mv3MeGIoeqUjZPuB+6mMXf5nefxM8Mmq0aNmV vTjt6VBoaMiUYeBrk/EJcE9i6aBI4BY8yf0s6/J/zjrWrXV/Zatc/WljRZYZJAOakniRUUqvTLcc iXR9t6PFiEZQFXs9IfUrrTbo3lrK8E8Q/dyxMUcchxNGFCNmzpexhGWOcZCxY2dLp5yEvSaLKtL0 TVte8m33mifWZD9WSYG0ctIzBGErKXLjjzf4qUO+ZM9ZjxZo4o4/qrf7O528dJPJilkM/pvb7e9A /l35e07zS9+NRvTYNaqjRCq1cGvI/HTZKDp45Zr9fkwiJjG7LDRaGGUkSlVBjsMd/HOJLm2eO0LM sVwUYRvSo+Fz8LfRg7TycWGY7q+8Ovy4+GFosyKspUgcTSh8M5Nw+Ki5pFWUggFTT6MVMqKY6Ppw 1HVLSyGwuJURmHZSfiP/AAORJoOTpsPiZIw7y9jvLq/0k3d1L6S6La24+rQqPjDKAAvbInwzAVfi Xu9zKU8RlI14UY7fB4xrOtXeo6k91eNzZ+gPRR4DJRjQeG1mslmycUv7EHcT20MXOR0jDbIWIWpI 2ArhaREnkGreeGZKqVb3FCDixHmjLKxa5uGLFYbOFQ91cuPhjWpH0s3RVG5OJLZjx8R7ojme78dB 1X6ndwXLILZClrbx+lbK1C3AEsSxH7TMzMfniAyzZBL6fpAoJbZshaVCBUNyAp2YAn8a5TiFGQ87 +f7bczWS48eKZ5mHCffAkD/YcCXx0s/MVzEoHoXsKXPDb+9jPpSt9K+nlo5uLkN4wf5pr4HcfpTg cCtQBTscLRspQyK/wsBy/XhYxlbczBGXYUNaj7sVkaej/kyVN/qJXoYU/wCJHKsvJ6f2d/j/AM39 Kl+cv/Hc0/pvbnY/65w4vpaPaH+9j/V/S89Un4d1Na/T/bljz4cK/Dup3P0+2KuBNBuvWn9mKvW/ Jmo2Fr5W0OK5QvJcyzR25ChuL/WGHU9OoyMcMp8RH8I3ez7Mzxhp8Yl/ESB/piwHz1X/ABZqG6/3 o6/6i7HBj5Og7Z/xqXw/3ISKp8V+1T9exybq2w8grR1pyI4kAj8QfwzGy6YTPFconyLn6btA4ocB jCcbupDketEUd6CSaF510zWdSvtPt29K6sXKurRojHixViobk1AaAmm1RlA0nFsZzPxdpn1BwCM/ BxVLkaJ/TTw3zB5T1r9HTeZru7hninmbmvKRpq+s8O5KCPZoyKB+mWAVs9ZLPLKeORuUtyUPbWds tqsXJouZjf1S9ujfvbRnoW5MePqLsD260bKyXaQxR4asjkecRzhfO+Vj5c6khdXFvJAbgSq8zNBU CSMni1shPwRqo+FhQ+B2O9Thi0aoRI4r9Xp6j+aOgH9nI7vWPI9l5f03zTBBpl9BeRyafMjmI27N +6mhKNIYC3xOHb7e+2XYRu8x7SZOLBCwBwkDYeR3PeXq3lSS2PnTSbeaGO59WYqttJx+MUFdm2PG vLN3op1iyi+E8P3PNdmi8w2sWHr13pwjtfMSQaRaITH6kdSoLEwAdFjPQqab9cx8eW5YrnLn/vve 9VPFQyVCP4HuTWl8mu2/GG1iElnJurszVSSOoFET4fjzG9JxHeR9Q+4+bk+oZBtEek/ePJhPn5bl vIFh9ZmtiLe6RfTjDDeMvF8BLmtB1HHM2HD4mShLeH6jvs6ftIH8qLMdj+sd7zEyIspUgcTShp0z BeTsW08POQ8SBSm2KmNlkX5fxunmzTwSCvN/+TbZDJydn2OCNTD4/cWWeYrPzda+UdY/TuoxXrS3 EZsTEip6cJkHwNxSOp+/JZJYiY8Arveh7RjljpsnHK+Ve6w8xkiZ36gMBuMLxZjZeK/nQmpT66FR ZZLDTraL12UM0UUk7uQW2opcAD3plOSJO/QPYdgQjHDv9UpH7KYFpEdq+o2/12d7WzL0nuIhydE/ aIA37+B+R6ZXACxewd5kvhNCyymbzRP5Y1OH/D+pSXtoQrXVpdE3EIdH3jDPHDyqoFSqLStOuZJy DHL0Gx57/oDiflhljWSNfZ8er0j8uvzStPMEl7pWqRx2l87zTaWwoFaNizLASONWjBov8w9xvm4d TjyRkJAA7kfqdL2j2ZHFDiiNq3/WzCKBjM5Vhtx3zWw+uXwdRnh/g2L3zP2j9SEdWufMdKj/AEO0 4k9uVzJUj5gQAn5jLerRKP7r+tL/AHI/48mccUiV3BU9RhceMSFNbdiAysPY4sRBfJGz8FZhy3+n piykLei/ktE0eo6nU1Bhj/4kcqy8npfZuNGf+b+lb+cv/Hc0/p/vOdj/AK5w4vpavaH+9j/V/S89 X9n7JrX6f7csefDh+z9k1J+n+3FXDoPsmp+/2xV6z5L1mys/J2mmdGk/fywAxqG4u0rOK1Ipscw8 +TgPve07KzRjpoX3kfaWD/mBBJF5tvuYAEjo6EjqDGMyMfJ0HbUSNTLzr7gx4/7H7VP17HLHVO8f s/ap/YcVYTq+i67o2v3eu+V7O1u5L8Bb+xmARiymvqRPVKFv2hXc77nKyCDYdtg1WLLAYs5I4fpP 6D+h5vrPlj8wLvTInk0mRLWS8uP3MHqOwkllbZ0DOBGrxuEIFOp71OulqsYmQZbj8fpe7xerDCMR sBzo2QeVnl02rl15o3T/AMuvOWm62tncQmGwiZbm71DZbdRBDIxJkZOS0R2G4+fY5QdfilGwd+73 +5y9NOeM3R4bs9+wPf7z5KI/KzzdciZdQaO2mQC301JpU/0uWFXVIYastKrH8PKnb3o/yji6b9Tz 2/Ftc8c5fVd8hy6fHyrr06bgz8ueRPM+g3lteaVfWT+YI0rqOjyyRv6cMnxKHKM5+IcfDqN8u02t 8SdRBo8jR3p1XauHGMB8X6RXLnuzvSR5wGtfpvVWgsLizheDT4bRixRpGSR5WkO9awrSmdV2LDiy SEv5h+8PIyzYYDgw8V8QkSduXID5vSvJf5iaVbaVqy+abi5v7y++CGQl5SUCEcDyYcaF9vnmdqtF MygcXDERPu7vJ2Gm1cQJjJxSMh+vzZ35h8xaR5ZtdF1q80asElu0AEfpF1eRY3UdSCKId+WazDhn mOSAnvxX183Y5cscXBMw24a6eTxG+v7W98zXN7Apht7qd5oreg4xo7cwm23wr4DOgyQIwmJNng/3 rzeciXEQKBJ+9MS6LKVYDjtQ06ZyDrbFqczFZqrtSlMWMjRZX+XKNc+arMoP7kSSSewEbD9ZAyGT k7fsUcWoj5X9zIPMNl5k0zypqw8waouo/WbyM2HFAnpxcgeBoq74ylCRHCKen7bnEaaXw+8PNZ2I lDKewocm8DM7vHfOnmnQE1fzNZ3tk019cgQ283poyrxtkWOrFlZeE1X2BzGmdy972RCtNC/M/awC 3EUFo/qFXe7gAhA9Nyh+sAHny3Q8YjTvv4HKuZd5GoQN7mcduRr1de7l7/gWrhFlsIpYkXjAnG4c KqkSSyyFRUNVvgUb09vfEc2MxcAR/Dz95Jr37fqegeUPLnloaj5Wu7GaSXUJ2MtwCxMf7q2eSWgM SUMcwVdmP6suhE2C6XtbIBp599fe9Y+vRWUNzdTmlvEGkkPUhUUVp92Sx85Hz/QA8rqQaw4xz8P7 ZTlL7iFLTLeaK1FxOCt5esbq5FalXcACOv8AxWgVPoy2IcPVTBkBH6Y7D9fx5ppFMHWh+1+vC1xl ahFKUPip6jFrjKl9ywIRlPjQ/diymXo/5Kyl7/UgeohT/iRyrLyem9m5Xx/5v6Vv5yiuuaf0P+jn Y/656YcX0tXtD/ex/q/peeKPsbIak/T+HXLHnw2B9nZNyfp/DrirgNhshqfv/Drir0D8qtdjhmn0 idlAnYzWh6VkAo6/MqBT5ZTlHV6T2f1QBOI9dx7+qc+cvKlx5itVvbaEQ6lbEoIpKATRg/Z5HoR2 PTMLQaqeSJM4mG7t+3OyRlAOMgzA+fl+p5Xd2V3aTNBdQ+jMH3SRSp79iPxzZAvD5MUoGpCj5qVO uy/a/wAwdsLBpXj9RldR12NMVBFtpMVnYghJCET1Aq8iImZkBYitFMjUHTc+Oa3L2VhnIyIO/ntv zd3p/aLU4oDGCKjsNt67mH67rHmO18/6Hptle+hpd96rXNskcSgmPk8pLBOQ5hvHrkD2Vp7Hp+0/ rdppu3M8tNklKXqidjQ6/Bb5O1TXJ/OfmOC+1CaezsZhHZo7U482ZqVFC3FaCpyzH2fgBPoDV2h2 tn8DGRIiUhvWzMS8frvzUEn9ojf6czMeCEPpiB7g85m1mXJtklKQ8yT96jcqHJjovXqdtqUptmz7 P1UcOTilZFU1RmAUE9kiURbcNQ1oWHU+5JzentXTjlv8HP08sc5EZMnB/mk/cj9S1vzHqFtDY30j 3FtbUEMMsgZFoKDb2GUw7Q0sCZRjRPPZ3AjoZADJqp7dPCP/ABX6EtkivRVPQRSRxqCNgR88tPa+ Ej9jkYMfY8JxlLPklRB/u+f3q2m281vM4uB8LAAVIbf8c0+vz4sgHAPspt9re1+z9VHGNNGpRJs8 HDtsnFlY3V7eC2tLZriRqUWNeRHuadB7nNYTTxuLFLJLhiLL07y55LWz0jULWK9W2166iEcs8FGe 2VtwooQanua/LpXMX8xCUjEEEx5h77sPs78kY5ckOK/lQ6frY/551CSKzsPL0t2b+5skD31y+5eU jv8AL7/HLoCzbrPajXQyZOCAEQTxV3dw/S8b8wedtQ0PzZbwtpYu9BgWF7791KZXMjMCsTIQKAD4 tvEVqRjKZBp1mh7OxZMRnI+qzQsAbd/VC3fkryf50ifVkWezuLu4e8nnMbpLylJL27IUWNEjqqrw LUC9RU5osubVRySIgTHevd0/Hn7nr8GbTwxxjPJAERHUc+vw7vdtW6E07yF5Ml1L9J6TryHRozby 3GmQtA5idVPEyzPO4UKxLN9NK5SdXn4aMDffv/xLsseaOKQ4ZxBNGjW5HlY5WhE/JrS7mG8S416N 5PQppE8aIIVMThVSZo6ks3PqBuAx60yyHaRIsjhr7fd+O5P5aeWXDH1GvkB+PP5oOHRE8hzaZqz3 N1eW9pM9tq8DQTpFG9xGwE1t6saI6jhRmRmrt05AZm6PXHJKq9PPp9u/6uvc6TtXRceIwBAmeXnX 48+jI4vO/lvWdbs/L8cjhjP60zGNgkrIfUjhUgV+3QtyAFFp3zNwTBj7yT9tuk7S7Py4jLIQPTCE PdUIxJ+z7WbyMiOoKjiR4ZlPLyIBVAsdKqo9iBgZUFOFo3FCo5fIb4WMSC3KUQr8IKmtRQe2KyoP R/yZCfpDUSgFDCm4/wBY5Vl5PT+zlXP/ADf0qX5y/wDHc0/p/vOev+uemHF9LR7Q/wB7H+r+l56o +xsnf6fw65Y8+HAfZ2Xqfp/DrirgNhspqfv/AA64quikkikSWNgkiPyR12IZTUEEdCMDKMiCCOdv RdK/MG31PTDpusXLWF0/wLqEQ+FqH9sDdSe9NvlmDrNIcuMxiTG+oez7I9oYRkPGAsfI/qP2Ml1W a9n8vRpoUtpqV8vpqr3LK6MF+2x367ZLBDgiIyJNDn3vR6eWmzZeLL/dG/p39yl5js9ZXQFbQLPT 31usfNLhE9Hp+88Po3y/EYcXrvhcQ4MPEfSOH3O8z2erro8beXrPT31bmnqrconp8OJ506b8qUye nOPi/eE8Pk4mowen93GPF5hH6rYgQRnTbW0ab1B6nqolPToa06b1pkcBhZ4yarp3rnwbDgjG76jo x7zz+WHk/wAzXFld3mj2t7dWzBA8kkkXCInkeIieMcq98xchl0bZQMR6APNcn5U+QbPzInmOw0eB dZaVpJ7xpZmY+oCrkq0hQ1BOxXKdSc1x8OufqvucrHjxEESG3RP9QsQJ7T6la2jQmQfXC6JUR1H2 felcGoln4o+HXDfqvu8vtTg0+m4ZcY3r00Bz80Pq9lejUdNGl2li1iZG/SjSonMR1Xj6fTenLM0E Vuz0+n0vBPxB669NAc9+f2IbXLPWhrWlDR7PT30hnP6XaZE9UJyWnpdN+PLLMZhwniJ4ujijBire I+S7VbPVxr+mrptnp7aIa/pN5UT1hvt6fTt7ZLGcfAeInj6OLkwHjHDGPB12R81iP0pAIrW0OncT 9YYonqBqHjx+mmRiYeGbvj6dyZYP3gqMeDrtu57H/cqgW1s/0bw+Niiepzoent0zFufF/RZHAOP6 Y8PuV2uILKYs01vb2KrulVQ8vkMorP412PCrl1tzf3UMfdL7GFeYfO2jafNdyaFGsmoXW015vwX/ AFfmd9suw6HHHIcgFSlzdP2l7R1jGOB4+Hl3D9bD/K+hXOv+Yo4riUlHLTXcoNWKDc/8ESBmbI0H lNFppanP6jz3JTb8z3tW1e10yyREh06AIVWgIZ9+Ne9FC4MfK3L7dMfFjjhVQj+P0MQVJVRlanGh +jLHTAEB5ZB5J83eV9HmsbdrbUtM1KUQ6gkcMjTpDMPTeReLA0VfnTr45TwkB6Setw6nIJm4TgLj uKsb0j/LHkrzfoFl9Wub+1fTo2aWS0gQszcgfi9RkRtiBt4Zg9o4pHAfLd3/ALOdraaXaeOVESkD Gye8bCt+Z2ZzpM0stkeVCq1Q19h/blnZmc5MIvmNnUe2fZkdJr5CG0Mg4wO6yb+FgvPvNWhny1qF v5y03So75Qoe+jJYek1P79aHYty3PEgUr3y3CKhE/wBEfcy1GY6jPm085mP7yXD5+o+n4e/yZD5R /MHSPNZ9GIG01GMVa0lYVYdSY2H2wO+wPtmRGYLotf2XkwbnePf+vuZZEkqVBoVybroghSW3k2ZS PY1xYiBXypI4QGnLf6emKZAl6N+SsbpqOphjsYY6f8Ecqy8npvZsEGf+b+lb+corrmn7A/6Odj/r nphxfS1e0P8Aex/q/peeKPs7L1P0/wBuWPPhsD7Oy9T9P9uKuA2Gymp+/wDtxVqnTZTVvv8A7cVd Tpspq33/ANuKrgWWvGgq1OtK9djgSCRyb9SXf4v2vE/ccaZccu9pZyZGVia12NTjSBkN1blnJkZG JrXY1ONKMhurbE59RkYmtdjU40viG6toTn1GRieuxqcaXxDdW3659UoxPsanGl8Q3VteufVKMT7G pxpfEN1bjORKVYmm1DU+GNL4hvm4zkSlWJptQ1PhjS+Ib5uM5EpViabUNTjS+Ib5uM5EpViabUNT jS+Ib5qc0riavImnQE1wsJzNr2kV4WI603GKSbCe+VfM0Wg2F9NHR9SueMFtUH90m7M52od6UHiM hKNl2Og1sdPjlIf3kth5DvSG8mle5MzuXkf4mcmpJJqST75MOuySJlZ5rhKHibsQDUfRinisKUM3 H4W+z2PhiwjKnXJ/eAj+X+uCrZGRjIEbEKNrEYI5UgUFXqwq32SRTpTpmFh05w2ICwTfPk9Nr+2I dpcGTUyMZ448J4Y/UASdjfM9b2HMc+FfAVSIQuOcXHiQdxSlNxmXCHDER7g89n1Ry5pZDsZyMvdZ tiupflh5WbUIL+wWXS7qN1lV7J+AqGrsrBlX/YgYDjDsMfbOWI4Z1kie/wDX/azea4tZppDbI0UR 3SNzyIFPHau+TDr8k4SkeAUO5BwzFDQ7qeowuPGVKly32GU+ND92LKZejfkrLzv9SB+0IUr/AMEc qy8npvZuV8f+b+l6JrPlTy/rU0c2p2guJYl4RsXkWi1rT4GXvlUZkcnfajQYcxBnGyPM/oS7/lWn kj/q2Dx/vZ/+a8l4snG/kbS/zPtl+tv/AJVp5I/6tg8f72f/AJrx8WSf5G0v8z7Zfra/5Vp5I/6t g8f72fr/AMHj4sl/kbS/zPtl+t3/ACrTyR/1bB4/3s/X/g8fFkv8jaX+Z9p/W7/lWfkj/q2Dx/vZ /wDmvHxZL/I2l/mfaf1u/wCVaeSP+rYNzU/vZ+v/AAePiyX+R9L/ADPtP63f8qz8kb/7jBvuf3s/ /NePiyX+R9L/ADPtP63H8s/I5NTpgr/xln/5rx8WS/yNpf5n2n9bj+WXkcmp0wV/4yz/APNePiyX +R9L/M+0/rcfyz8jk1OmCv8Axln/AOa8fFkv8j6X+Z9p/W4/ll5HJqdMFf8AjLP/AM14+LJf5H0v 8z7T+tx/LLyOdzpg/wCR0/8AzXj4sl/kfS/zPtP63H8svI5NTpg/5HT/APNePiyT/I+l/mfaf1uP 5ZeRz10wf8jp/wDmvHxZL/I+l/mfaf1tH8svI566YP8AkdP/ANVMfFkv8j6X+Z9p/W4/ll5HPXTB /wAjp/8Aqpj4sl/kjTfzPtP63H8svI566YP+R0//AFUx8WS/yRpv5n3/AK3H8svI566YP+R0/wD1 Ux8WS/yRpv5n3/rcPyy8jj/pWD/kdP8A9VMfFkv8kab+YPt/W7/lWPkb/q2D/kdP/wBVMfFkv8ka X+YPt/W4/ll5HPXTBt/xdP8A9VMfFkv8kab+YPt/W4fll5HHTTB/yOn/AOqmPiyX+SNN/MH2u/5V j5G/6tg/5HT/APVTHxZL/JGm/mD7XH8sfI566YNun76f/qpj4sk/yTpv5g+1w/LHyOOmmD/kdP8A 9VMfFkv8k6b+YPtd/wAqw8jf9Wwf8jp/+qmPiyX+SdN/MH2u/wCVY+Run6MG3T99P/1Ux8WS/wAk 6b+YPtcPyx8jA1GmCv8Axmn/AOqmPiyX+SdN/MH2tf8AKsPI3/VsH/I6f/qpj4sl/knTfzB9rf8A yrHyNSn6MFB/xdP/ANVMfFkv8k6b+YEy0Tyn5f0OSWTS7QW7zALKecj1ANR9tmyMpk83I0+kxYb4 I8NptkXJdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdir sVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirs VdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsV dirsVdirsVdirsVdir//2Q== + + + + proof:pdf + uuid:65E6390686CF11DBA6E2D887CEACB407 + xmp.did:5768d99c-a9ed-41a4-9aad-da4127e60438 + uuid:686ada3e-9582-9946-a49f-cd5a2673ab5b + + uuid:357b99bf-0568-7a44-864e-9fa618945959 + xmp.did:4dedc7d7-33be-4ed2-a141-c9be17d90f85 + uuid:65E6390686CF11DBA6E2D887CEACB407 + proof:pdf + + + + + saved + xmp.iid:5dee8c19-d41e-4561-a65a-4970cb2dbe92 + 2018-03-21T13:16:38-07:00 + Adobe Illustrator CC 22.0 (Macintosh) + / + + + saved + xmp.iid:5768d99c-a9ed-41a4-9aad-da4127e60438 + 2018-10-25T11:19:39-07:00 + Adobe Illustrator CC 22.0 (Macintosh) + / + + + + Web + Document + Adobe PDF library 15.00 + 21.0.0 + 1 + True + False + + 2828.000000 + 777.000000 + Pixels + + + + + MonacoBSemi-Bold + MonacoBSemi + Bold + Open Type + 7.0d1e1 + False + Monaco-Bold.otf + + + SegoeUI + Segoe UI + Regular + Open Type + Version 1.00 + False + Segoe UI.ttf + + + + + + Cyan + Magenta + Yellow + Black + + + + + + Default Swatch Group + 0 + + + + White + RGB + PROCESS + 255 + 255 + 255 + + + Black + RGB + PROCESS + 0 + 0 + 0 + + + RGB Red + RGB + PROCESS + 255 + 0 + 0 + + + RGB Yellow + RGB + PROCESS + 255 + 255 + 0 + + + RGB Green + RGB + PROCESS + 0 + 255 + 0 + + + RGB Cyan + RGB + PROCESS + 0 + 255 + 255 + + + RGB Blue + RGB + PROCESS + 0 + 0 + 255 + + + RGB Magenta + RGB + PROCESS + 255 + 0 + 255 + + + R=193 G=39 B=45 + RGB + PROCESS + 193 + 39 + 45 + + + R=237 G=28 B=36 + RGB + PROCESS + 237 + 28 + 36 + + + R=241 G=90 B=36 + RGB + PROCESS + 241 + 90 + 36 + + + R=247 G=147 B=30 + RGB + PROCESS + 247 + 147 + 30 + + + R=251 G=176 B=59 + RGB + PROCESS + 251 + 176 + 59 + + + R=252 G=238 B=33 + RGB + PROCESS + 252 + 238 + 33 + + + R=217 G=224 B=33 + RGB + PROCESS + 217 + 224 + 33 + + + R=140 G=198 B=63 + RGB + PROCESS + 140 + 198 + 63 + + + R=57 G=181 B=74 + RGB + PROCESS + 57 + 181 + 74 + + + R=0 G=146 B=69 + RGB + PROCESS + 0 + 146 + 69 + + + R=0 G=104 B=55 + RGB + PROCESS + 0 + 104 + 55 + + + R=34 G=181 B=115 + RGB + PROCESS + 34 + 181 + 115 + + + R=0 G=169 B=157 + RGB + PROCESS + 0 + 169 + 157 + + + R=41 G=171 B=226 + RGB + PROCESS + 41 + 171 + 226 + + + R=0 G=113 B=188 + RGB + PROCESS + 0 + 113 + 188 + + + R=46 G=49 B=146 + RGB + PROCESS + 46 + 49 + 146 + + + R=27 G=20 B=100 + RGB + PROCESS + 27 + 20 + 100 + + + R=102 G=45 B=145 + RGB + PROCESS + 102 + 45 + 145 + + + R=147 G=39 B=143 + RGB + PROCESS + 147 + 39 + 143 + + + R=158 G=0 B=93 + RGB + PROCESS + 158 + 0 + 93 + + + R=212 G=20 B=90 + RGB + PROCESS + 212 + 20 + 90 + + + R=237 G=30 B=121 + RGB + PROCESS + 237 + 30 + 121 + + + R=199 G=178 B=153 + RGB + PROCESS + 199 + 178 + 153 + + + R=153 G=134 B=117 + RGB + PROCESS + 153 + 134 + 117 + + + R=115 G=99 B=87 + RGB + PROCESS + 115 + 99 + 87 + + + R=83 G=71 B=65 + RGB + PROCESS + 83 + 71 + 65 + + + R=198 G=156 B=109 + RGB + PROCESS + 198 + 156 + 109 + + + R=166 G=124 B=82 + RGB + PROCESS + 166 + 124 + 82 + + + R=140 G=98 B=57 + RGB + PROCESS + 140 + 98 + 57 + + + R=117 G=76 B=36 + RGB + PROCESS + 117 + 76 + 36 + + + R=96 G=56 B=19 + RGB + PROCESS + 96 + 56 + 19 + + + R=66 G=33 B=11 + RGB + PROCESS + 66 + 33 + 11 + + + Illus Gray 1 243-243-243 + PROCESS + 100.000000 + RGB + 243 + 243 + 243 + + + Illus Gray 2 230-230-230 + PROCESS + 100.000000 + RGB + 230 + 230 + 230 + + + Illus Gray 3 210-210-210 + PROCESS + 100.000000 + RGB + 210 + 210 + 210 + + + Illus Gray 4 194-194-194 + PROCESS + 100.000000 + RGB + 194 + 194 + 194 + + + Illus Gray 5 178-178-178 + PROCESS + 100.000000 + RGB + 178 + 178 + 178 + + + Illus Gray 6 147-147-147 + PROCESS + 100.000000 + RGB + 147 + 147 + 147 + + + Illus Gray 7 115-115-115 + PROCESS + 100.000000 + RGB + 115 + 115 + 115 + + + Illus Gray 8 80-80-80 + PROCESS + 100.000000 + RGB + 80 + 80 + 80 + + + Illus Gray 9 40-40-40 + PROCESS + 100.000000 + RGB + 40 + 40 + 40 + + + Orange 216-59-1 + PROCESS + 100.000000 + RGB + 216 + 59 + 1 + + + Orange-HL 226-108-65 + PROCESS + 100.000000 + RGB + 226 + 108 + 65 + + + Skintone7 142-86-46 + PROCESS + 100.000000 + RGB + 142 + 86 + 46 + + + Skin7 MT 112-67-34 + PROCESS + 100.000000 + RGB + 112 + 67 + 34 + + + Skin7 HL 180-143-117 + PROCESS + 100.000000 + RGB + 180 + 143 + 117 + + + Skin7 SD 84-50-23 + PROCESS + 100.000000 + RGB + 84 + 50 + 23 + + + Skin9 SD 48-29-25 + PROCESS + 100.000000 + RGB + 48 + 29 + 25 + + + Dk Red-MT 128-24-24 + PROCESS + 100.000000 + RGB + 135 + 25 + 25 + + + Yellow-HL 255-203-64 + PROCESS + 100.000000 + RGB + 255 + 203 + 64 + + + Blue-HL 64-154-225 + PROCESS + 100.000000 + RGB + 64 + 154 + 225 + + + Lt Teal 0-178-148 + PROCESS + 100.000000 + RGB + 0 + 178 + 148 + + + Lt Green 186-216-10 + PROCESS + 100.000000 + RGB + 186 + 216 + 10 + + + Skin5 HL 216-176-127 + PROCESS + 100.000000 + RGB + 216 + 176 + 127 + + + Skintone4 216-176-148 + PROCESS + 100.000000 + RGB + 216 + 176 + 148 + + + Skin4 MT 184-151-124 + PROCESS + 100.000000 + RGB + 184 + 151 + 124 + + + Skintone5 206-156-95 + PROCESS + 100.000000 + RGB + 206 + 156 + 95 + + + Skin5 MT 186-140-87 + PROCESS + 100.000000 + RGB + 186 + 140 + 87 + + + Yellow-SD 199-142-0 + PROCESS + 100.000000 + RGB + 196 + 140 + 0 + + + Yellow-MT 240-174-0 + PROCESS + 100.000000 + RGB + 229 + 166 + 0 + + + Lt Blue 0-188-242 + PROCESS + 100.000000 + RGB + 0 + 188 + 242 + + + Purple-HL 165-121-214 + PROCESS + 100.000000 + RGB + 164 + 121 + 214 + + + Lt Magenta-HL 234-64-169 + PROCESS + 100.000000 + RGB + 234 + 64 + 169 + + + Red-HL 238-77-90 + PROCESS + 100.000000 + RGB + 238 + 77 + 90 + + + Lt Blue-HL 64-205-245 + PROCESS + 100.000000 + RGB + 64 + 205 + 245 + + + Green-MT 56-161-56 + PROCESS + 100.000000 + RGB + 56 + 161 + 56 + + + Green-HL 120-197-120 + PROCESS + 100.000000 + RGB + 120 + 196 + 120 + + + Lt Green-HL 215-240-75 + PROCESS + 100.000000 + RGB + 215 + 239 + 75 + + + Magenta-HL 199-64-182 + PROCESS + 100.000000 + RGB + 199 + 64 + 182 + + + Lt Orange 255-140-0 + PROCESS + 100.000000 + RGB + 255 + 140 + 0 + + + Teal 0-130-114 + PROCESS + 100.000000 + RGB + 0 + 130 + 114 + + + Green 16-124-16 + PROCESS + 100.000000 + RGB + 16 + 124 + 16 + + + Dk Green-HL 34-153-78 + PROCESS + 100.000000 + RGB + 33 + 153 + 78 + + + Magenta-MT 158-0-139 + PROCESS + 100.000000 + RGB + 158 + 0 + 138 + + + White + PROCESS + 100.000000 + RGB + 255 + 255 + 255 + + + Lt Orange-HL 255-169-64 + PROCESS + 100.000000 + RGB + 255 + 169 + 64 + + + Lt Yellow-HL 255-248-128 + PROCESS + 100.000000 + RGB + 255 + 248 + 128 + + + Lt Teal-HL 64-197-175 + PROCESS + 100.000000 + RGB + 64 + 197 + 175 + + + Lt Orange-MT 240-132-0 + PROCESS + 100.000000 + RGB + 240 + 132 + 0 + + + Yellow 255-185-0 + PROCESS + 100.000000 + RGB + 255 + 185 + 0 + + + Lt Teal-MT 0-140-116 + PROCESS + 100.000000 + RGB + 0 + 140 + 116 + + + Teal-MT 0-82-72 + PROCESS + 100.000000 + RGB + 0 + 81 + 71 + + + Lt Teal-SD 0-110-91 + PROCESS + 100.000000 + RGB + 0 + 110 + 90 + + + Red 232-17-35 + PROCESS + 100.000000 + RGB + 232 + 17 + 35 + + + Red-MT 217-16-33 + PROCESS + 100.000000 + RGB + 186 + 13 + 28 + + + Teal-HL 64-161-149 + PROCESS + 100.000000 + RGB + 64 + 161 + 149 + + + Blue 0-120-215 + PROCESS + 100.000000 + RGB + 0 + 120 + 215 + + + Lt Yellow 255-241-0 + PROCESS + 100.000000 + RGB + 255 + 241 + 0 + + + Blue-MT 0-100-181 + PROCESS + 100.000000 + RGB + 0 + 100 + 181 + + + Mid Blue-MT 33-57-181 + PROCESS + 100.000000 + RGB + 32 + 56 + 181 + + + Mid Blue-HL 47-96-224 + PROCESS + 100.000000 + RGB + 47 + 95 + 224 + + + Dk Blue-HL 57-99-163 + PROCESS + 100.000000 + RGB + 57 + 99 + 163 + + + Dk Teal-MT 35-107-112 + PROCESS + 100.000000 + RGB + 34 + 107 + 112 + + + Purple 92-45-145 + PROCESS + 100.000000 + RGB + 92 + 45 + 145 + + + Dk Blue-MT 45-61-135 + PROCESS + 100.000000 + RGB + 44 + 61 + 135 + + + Blue-SD 0-72-128 + PROCESS + 100.000000 + RGB + 0 + 71 + 127 + + + Orange-MT 189-54-4 + PROCESS + 100.000000 + RGB + 188 + 53 + 3 + + + + + + Grays + 1 + + + + R=0 G=0 B=0 + RGB + PROCESS + 0 + 0 + 0 + + + R=26 G=26 B=26 + RGB + PROCESS + 26 + 26 + 26 + + + R=51 G=51 B=51 + RGB + PROCESS + 51 + 51 + 51 + + + R=77 G=77 B=77 + RGB + PROCESS + 77 + 77 + 77 + + + R=102 G=102 B=102 + RGB + PROCESS + 102 + 102 + 102 + + + R=128 G=128 B=128 + RGB + PROCESS + 128 + 128 + 128 + + + R=153 G=153 B=153 + RGB + PROCESS + 153 + 153 + 153 + + + R=179 G=179 B=179 + RGB + PROCESS + 179 + 179 + 179 + + + R=204 G=204 B=204 + RGB + PROCESS + 204 + 204 + 204 + + + R=230 G=230 B=230 + RGB + PROCESS + 230 + 230 + 230 + + + R=242 G=242 B=242 + RGB + PROCESS + 242 + 242 + 242 + + + + + + Web Color Group + 1 + + + + R=63 G=169 B=245 + RGB + PROCESS + 63 + 169 + 245 + + + R=122 G=201 B=67 + RGB + PROCESS + 122 + 201 + 67 + + + R=255 G=147 B=30 + RGB + PROCESS + 255 + 147 + 30 + + + R=255 G=29 B=37 + RGB + PROCESS + 255 + 29 + 37 + + + R=255 G=123 B=172 + RGB + PROCESS + 255 + 123 + 172 + + + R=189 G=204 B=212 + RGB + PROCESS + 189 + 204 + 212 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + endstream endobj 3 0 obj <> endobj 14 0 obj <>/Resources<>/ExtGState<>/Font<>/Pattern<>/ProcSet[/PDF/Text]/Properties<>/Shading<>/XObject<>>>/Thumb 744 0 R/TrimBox[9.0 9.0 2837.0 786.0]/Type/Page>> endobj 719 0 obj <>stream +H͒$]?WE Ffpop5ϣ*ga=]ٕ>w};vλsumww??X)fBme0-//~pO?{gWa:Wwzx{,ݹ__A~7np +Y~n JӠ'`vꯙ>CqicӂU'}Χեha~9*s]bisc-l'oBa;pb;p|9ߖJ^RJqE{h:-9ysKȍ#TNޖɬoe/`3~ӪR.^n%/_m 1Hiso2r8`k_Zu!'բ0W@?e7̉d8/i\2:gq&)ˎ \.!¯ a- |9Bo3gbƏi(QhZsl+(;wņBYF?&IuI$|,#!k&st-cӚ.M$q1R_),R{>g='z" xFUN'z5amk*Ik8 qݨBFm45>9㔖}acuuX:og0?Ϋͅ]u9ͅkyn=ۿg$ՠ77/ޫv7whTclp p<&['q8#f <*x$">dI hR|^Eȷc#n=b^KRnrm7sF̏pqh144^FOb5a~2j$9MUL-3)gM˯s.U0TLCDTTzYî{\ y&[jbto+ECYո%\pTg"E%SGrP4ZDԓg_P-@TM@?r|y_D+saǩ"ye}e,[H؃CdaeEUÑnrYk>bv guDW>W|8x{oOMPUoB6{bƳ@&?ݾ۾Ps*է(K~g{U2 =Ͻ=w[op[b4Fu3w2LA"+jU+pcV՗+7?鹙LM!M: !$EIJQyqDU>-ށ<\]%'&̗^p&;8EF /vFJUb] QcTP/<;R9aͱW4>=#z:^`Zm"DfEIznjnr)NL/fH[Š1ՙN5MO׳JUsc<5A4vm {Px.=[[ff''zٳcх*Lb"+I)I>`no#8; ' B'$T G'Q0ْZe*hʖ#qhF6CJHUժ|Q؉BUzQij%)Y:>EK0#ٲt@*a\&t+KkVoFUHUB?h7$ɽ3^5!ˀf:zN>w}%O]:(5o$ A)'7XwwZ+V dX>pKufܖUߓTԣ?Vnu=gȪ6< +|r-[ ~:xn(a&(HfqLU4ǭ]qǀYf8J> A!)չ6zauBJfČb[z0R( +$kix4WTH/dm$sPk-AdMզ9aOju H|, 3r,zMα4Ϡ6Z#>4(!&Qamߚ*X&Lh&Zu6q*Ӷ^3=š5lmA>[vy(cx{no(։XfyF1/O`Lyޝ]Gf Q =_3+4m^{5!=:z7EZuOO6Z?f)O~̀b9KvR9?vhu k9mO$Ӯq*VOdyAAGDS'Бh)eC@ɵ/|i k ++P-~ӛNk]W4HBE@V` +5L3h=ˊe #%ɖWSye8𗄓Br^r)<=CN!OLPW0a|=ӑf}x[yELL^{9 dh튢߿9ڴve/gS,N_Xm6vDj0,ztzB]J@;Su!ȷjl<Y7bv0 e9egΰxP>{;PEoF?~tGm ĚY1#3Zطv|R4F$F[c>|O$VK+ *w{` x@ыLJp Is.[ǨWFH4jx6:+rW5cPP6(ѫzep,;8%ns('h, Hr5Pu4Jv +r +4 +7# +qZ: N$ hHAң [$VSןp?˕!2JwLmD K.$""iHB_R杛ϖ4t,,r?[(T3WOMno퍙-  v*Lf +؞@`Jt!"z(*N-h⛯\P;i(WO\1ݥ=`w:)R蘸D$]`Gamǫj۪z6(d1@%|Ɛz`涇$b@ UΓ 1g٪ KaT B0S +j1j*ob蓎HvM?44XP4dҊ?m|84F֤Z;^>$-u~   2m~h +ԆV Bzwa}ekoL{(A⻔ݼbh=h(E#Yl!I/ZcuZv͞mcuR)E)۷Xm fNLwי %.#lh}wb=w$ἷ=rGAePx0>X:!hmpa9v뎪CY&]wP &);GɹeNa$ql}c>8=m]? ^Lٚ䠲] 8BzE֔(?:{[z.LS^tdS{')nQl#Sߺ^U'KYdwMȦ`*Em(XL5j#a줃 1Xq XI0΅ZTQP'1BX;օrz=;s֩JXᨡ+ICE+A +ٯ[+שJ<-1. =ߩ/­YIBCFrAK0C}s9R41cZ WQcUU)F|ZFT`4N+ dNIDƟZ+0hbD_AOqIc){ҕ.}GGP*jQ|WBji11^Ni28gދt ng:0ˤ ƋXUgJ0X\dnD^ͨYH4J1V/L +%.lS!rfLz$% +A੍Xh6zb]I]ya +?xS  ʞ5Ð\YN/م5e*=S|n{Y\ wٙe{I)fI 9lTSE;AM4 &NE nDTa[_ U^y\A{R=2TØV|`=_л͵)ܔgb^1< w?ZNGit@*.SaLq%[0Ҵ,1z8z}֌uO ̧o]o].=#12rhq43C!Y[u@frԣLKE<[,U +yyjxu'&ꄤRѦ<{ r1oٱpڱ):EKyOю?2-:}N,$Ch?A)&PxQ^Dq .$7 Njsc#&BF~/gBY %Lyc x1`-k |}nhʈ%,Þ.!!k f.X }aፆo۷B.c;f@V))[ptतw e8"M{۠`3nppK ŴiTL3tBݮtFàv1C& +83C,Mdf {饶^w8`d"j8\{&&km/۱N0A"eTm0VB IЯVBF%U;aFuX8\3tT6Wb_'b oŵ9+b/<0JXxpד& +VƋ'^4 [͞ 6ͼ[WmoT&u`]`:YH%z(A{ze:ɄTw)'fN"7Id5k̾;V;VWՐ׵jZK8,Hf"(.\ *uf]؅\d^,J4tdPZ~65ԘNN;K)MUbU|hB^M>E3:t*axr3ifS3hxcU"g8/LBPi`]rY㺡_CgWZN4I<+?XNrU铉78i^*7+4P*Rӗ/bR@ƞW~&?7uY)jd + +̨RFIsSu Kz(4aTG0ľ&xW艪LEC,n ot3c^;|Rd i4?5ݹiÔ)M?4d4f{ML|XϾ^ȿTN)IdR;BQnHjEVtcsl/R +NRLc,RBU1C74da#|rFsn-ɦedYJU[vm!xfRulsSNL_W2Ͱd"/q[&OYkm&y.ͤ$lK3'cmm]-> hiI4D=$LLqcWC#bP|d8ङroE^٬2mD71^&thlD,G玐vÇ%4+FjV$$vٚa1{b"CƃPݭRnɧhnעhdJox J!pȀ1!-M[vژ| hw|| =LQBwc1(8گc E-Ȁğ600~umE'3znkcGLbc !5ъ)8bB$I^Y]]vkecW5 \`8MgOa!!#;h,DtB^q].'46R箤NI|wUv%,8|}y{D{f1$'K\#-.#$ikBbGkԸV8)S*,RDBGB +G_PBJ_YiKRS8N"u +iMj[HJ -Y7&%YMʏi;V+v0EKPtfWX!.䡻LNوh]|.2fbӍk2yeVk]2{e VYcDosسQk9$`ё7fǛ@ZWVW +th@ yC0AB p8vԮgRHvp-dT,S5tPSz|/8pXbuZlbQÛ.DvbZtx4-"C, ZL&iOMWS1)A5u6v%7uk<6I5tMeQ8l]J +=$7Ix!N&FjMB2 +lI8{JT1BԘȲD2{yxX pQG*b)H PTa̩l|Y'Mz(WЋ+t $8/DZ}=[:g >ߪ\nx,Hy:Mng +tOTsӕ87W#ʱA B>znңE65 ?%+>tq}Ffk۰~K)ؼ斷cyiyi;f+O?}(w?_yQ=t6⥨LZ%K˘%}kDJQN~fU@K+tOJZ;a9J7b@R+WMA.0ّ:":JSWfAmv-üް`f=$j'֢Qv 򜘤gD.TcӞ৾ÔփFvt Ҷolσwk㜇2"; +{D׵}}ȵrFWu]"(^>+GJX+zc[@I9yBό'<39w\c-fy'x(XR_J{3ȵqBʡ֗á^}V#Wȅ*CjEy9P Qnr^#SQJ/+\NkP#0T%Cs&6g5r\fGyz%I2y77Had[ bW6j<@k}O#NU#~}7G_IuQpsIOBq"8YӞ7z_w:LLyk(|҅X/Q0< v8~ Y[G+כcty8{ɌH̡P}{s$,jP Be-޴؏AAjÀɋ}ZK8\iQ_PbPתRϮ l8B?9j0O8uNƺ8saפP}Y#ď{&Q]n甆rQ +rvްR8܈] +/)uQ-ȫ]Kbbw;'LDya֕(, +oHh[I/Afa-\p$ZHrW5}T ]2 mkEu,6sIX)ZxWnAIeE1)zgE)-EB{ A.)~N*5"ZQ^F;,|K;ՎeBVs"K+Eǒ%IL Ƥةtm̳ڈ]2LMtQIV'(*HH f/ /F Ek5ېb vK4XSR:6,!lU),YBK-2ױ0URj@\Y jD> Dzrcu{]?BO/.t/Oי2v+ѩ-#`4dQAPq#gOmHEcˑ*=oHx j, vwӧdoT|go^3ɭ^cµKS% #]$Q̴{LG9ФFT#ϮOt+.+)=^ +oG27+'T&CE;T.Aeﮨt_J(`{-hTَ%n@5k({u5o%;mT,%Z)u;s[f^WUXAA 3LPq2*njvOzeQFp/FsFV:dWШiR#gՈUŲ ZfS>F2v7Rí .FIB,桩H{mo y*cWT !134K*n=2/D1Rz23pH{[zɉB|ƫY~}e=D36It㯉ec:<06ï(NS7^Xr0'mh])L0e;͎rDAiPޭRr'Ҏԯ9 2+95{'/"[vMoрIJV$ $U$O#4ֺǕ^lSXs_zf~#wQ\c'V59lxUˀvd:5g΋z6+rP<xdy󀟺2 0krwZsXǷrD K*/O@xҥPȝ7G>"v<裬Lo]F& 3", +u?S'q.GԎ.\xٗpKG_ke\<.(My,~BG');|&.Vtj'aGx4u0Yfhw Rր+@_aԶz2.P^zR  #e64^'1ezXW⮂V +C9i^#Y zpM:~Za0&cI  4x@?R +w%̬;kvS:8X$eCSrO. ;5OAđ.Չ=H:)ɲeBD*ݩ(ecFه? Q6 L(L%0G1@Fc0|&Muӕ׬`5&v(Pe#Q{rזy˟/p47HnϿut. Rgh:-6&1_~݉)A2RnhT@LxBks"8[&FL-|[{a-* 7* +*r3/{$0B-4f:K<@;(e~sZj˦_’K@qoŨL^evWPQ}>C &`lK2pL@sݖq}D"R(um[ ;уܴ&zu(ѹkPwYq49S`hmy:U]$X^b^9"QHSPEC5% +I*%m )[ )%i\M*kd!Axo@s@A ARwz9jn*%Qw+Ȃq=$[$dQ~5ƊLDarc@np;"m D!Rk25Mot~VI[`_vJ*WRGgaeڣY7t $} ju@8I@rȤfA`ZN얼t* d*kXsdx؈7v8YpQEσ B6TTLAj )HRiۮF^b;doe[ЕQ kML)[Q:dp[ 0.+*IVqL*jM\ 'lL#4#:į3aȑlg{T[V}? ߙ쇚5R.݊|9owI}yB|ąGCQʨ9ZD6C4tҤaҩK6un D?[t\6qEN +ʖ(I/&^8L`X͡pL,kڟdU͖4]$jz+!GuAC{v>0edW{syTU-> DsZ4i~kݎW&Y.rt D.ftPDrWna,٧g4ߓ=L-G7K#\{n0)݈u#,ĤKwP }_~gosAlrz8ˌoU7\,˗ӎr*@?Jq$7BX[R}Ү(ř5zP!W21׍URdFSN%.Ӭ<6V,oǞ[_W75ot@-iw—<=G2 dk5yD\pUBfHF+J:V¢c՚ށ,k&+P5\6P mD@/ +q +1K[G0ju. zBȅ*yJa|J?Ku*W#Nq?d?`8덊͸R* S]^z]_{P,q!5ͅK8Ȑ^,Z0K/~O\OE-aݖBZ umǺyVpaEڥP,X09spIV=}k,8=YAV^[X@ms^/˒ВXQK`#`Kyx2ux:ͧUR[?قѫO[ yv)ZƽE0&1ܶ D@]d',Z+[)8YFX BJ;t:_ {+ly^N]#X=>ޢG9 >IL0v9,lK+شm};©Ju% z[-xڙVe޵P /GAGpS ,,bJT (qX.7x"e9W'vLOwoج>/~}i +9;j\h9,$ky 2ɶR/- ױN/V9@uklpN#D&1$|k^Ls{u%!ln4SpQQr֣;WNE<3-ueR'QJWwP5QX& "1v1ʒ`Qi|I5[ ̒6L1 ^pc~LsFyf*)v v cn,^v &I֊&vߴp%)e-mrEHm4ȆC&.tp¡x8!K|+GarQ/"/N-zd"EC.n +ݸ}G¥#}P-1!^ϲ@[943=e׾;8)473`*pν.(@9Jl/@ +'ܳz8bI$SKh!UDl5=U SB,Jr~G\חN9a +yQ>| +:cHfG1rhs*k;Vڂh 1Xg8Ӝ8 Ôj T[ +$/oCf'Z@RبOPRх}5խ/8 |v&фx\2lPH \m5>TʷH%+QY"AFB!Q@D,c ` %vGo D'dMԶrkk +`2U[^ vR{}z/O>P߷7](];I}/ms;96)"EQlR#Xh!:BӤE;q 6gB8- 2yA:MrȷղqT 9HfvC)#`!߮\qF!,uu=cr\HiF w[+3UfŸ`!3\X3\YNg^%k^58 <0.C_O4s SSEJ-]Yޏp&5~{櫜 +f>'LZD7M?=@!> endobj 744 0 obj <>stream +8;WR30ok!L&7t**dK_&Y#&0H(;'TpD?bsuf!=Tfa/Kd:gTPF@b%k1XtV^_mHYa0ib +Mn%JXk;rXfOJ4/B)^H>\7FDmlR5]&=CLbMp=1VWh2Y8GWYB*V\,FYg,L@KEYIFOTD +`^G5]@oRgNEG9fiLeRa(FWKSOIQ?_`;<]GZiqDYlGbb&K;8:UHb\W9oR)PY7Cj?4# +99pL/=)V!21eCUeeOml'C9%(@<8Z;cYFRXK>a*7Po_%k$igm0.Ue%jFE70Bi3^P1n +o%uT76[6Z8d.A`3(?h0S2soke'3eG58YKQ!`XWLeO4Q8_EB9)s'@/D%8?TZXL:_&G=pTW4gJCNY\mML9'.Tq(>NmHjko0DkcdW;*+^A2 +#b*gR$#4&6fdF-)XA!pQH0'kMP"-L7,=;?%Ih5hUoFq8Aj&O#5Qbf&_L_/S>ki2OV +P+TQP'f*[QcB0h;E;O^S]$L0[R!:+eJt7,B`-diGCp2L&0iNLJp/.ZUO6DqWpS5<)pG"88fci#2g=7Fnpf7rC +@6$;+[.&_5nsMoS*oV4e02brJ0o9)k:91,[H=,RA3eSE+gP&PAEjCHA(>YLb"s9rOA- ++P,/LM0l,dg90d_?c-2=l)uoSaMrZ%>q:;(iGNo=#56(]odDVIHbPQ33pBjaY1B@T +Dpi7A<7+fq'6dcfj.$\,leM64HM%4;Xea1V~> endstream endobj 746 0 obj [/Indexed/DeviceRGB 255 747 0 R] endobj 747 0 obj <>stream +8;X]O>EqN@%''O_@%e@?J;%+8(9e>X=MR6S?i^YgA3=].HDXF.R$lIL@"pJ+EP(%0 +b]6ajmNZn*!='OQZeQ^Y*,=]?C.B+\Ulg9dhD*"iC[;*=3`oP1[!S^)?1)IZ4dup` +E1r!/,*0[*9.aFIR2&b-C#soRZ7Dl%MLY\.?d>Mn +6%Q2oYfNRF$$+ON<+]RUJmC0InDZ4OTs0S!saG>GGKUlQ*Q?45:CI&4J'_2j$XKrcYp0n+Xl_nU*O( +l[$6Nn+Z_Nq0]s7hs]`XX1nZ8&94a\~> endstream endobj 730 0 obj <>/ExtGState<>>>/Subtype/Form>>stream +/CS0 cs 0.953 0.953 0.953 scn +/GS0 gs +q 1 0 0 1 2610.2649 280.5333 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2610.2649 140.4879 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2610.2649 0.4423 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2610.2649 420.5788 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2610.2649 560.6243 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2610.2649 700.6697 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2470.5969 280.5333 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2470.5969 140.4879 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2470.5969 0.4423 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2470.5969 420.5788 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2470.5969 560.6243 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2470.5969 700.6697 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2330.929 280.5333 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2330.929 140.4879 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2330.929 0.4423 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2330.929 420.5788 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2330.929 560.6243 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2330.929 700.6697 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2191.2605 280.5333 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2191.2605 140.4879 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2191.2605 0.4423 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2191.2605 420.5788 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2191.2605 560.6243 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2191.2605 700.6697 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2051.5925 280.5333 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2051.5925 140.4879 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2051.5925 0.4423 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2051.5925 420.5788 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2051.5925 560.6243 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2051.5925 700.6697 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 1911.9244 280.5333 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 1911.9244 140.4879 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 1911.9244 0.4423 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 1911.9244 420.5788 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 1911.9244 560.6243 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 1911.9244 700.6697 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 1772.2565 280.5333 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 1772.2565 140.4879 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 1772.2565 0.4423 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 1772.2565 420.5788 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 1772.2565 560.6243 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 1772.2565 700.6697 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2891.1687 280.5333 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2891.1687 140.4879 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2891.1687 0.4423 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2891.1687 420.5788 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2891.1687 560.6243 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2891.1687 700.6697 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2751.5002 280.5333 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2751.5002 140.4879 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2751.5002 0.4423 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2751.5002 420.5788 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2751.5002 560.6243 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2751.5002 700.6697 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 1632.7433 467.2005 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1632.7433 373.8532 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1632.7433 280.506 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1632.7433 560.5477 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1632.7433 653.895 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1632.7433 747.2422 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1540.1378 467.2005 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1540.1378 373.8532 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1540.1378 280.506 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1540.1378 560.5477 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1540.1378 653.895 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1540.1378 747.2422 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1447.0421 467.2005 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1447.0421 373.8532 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1447.0421 280.506 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1447.0421 560.5477 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1447.0421 653.895 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1447.0421 747.2422 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1353.9464 467.2005 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1353.9464 373.8532 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1353.9464 280.506 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1353.9464 560.5477 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1353.9464 653.895 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1353.9464 747.2422 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1260.8507 467.2005 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1260.8507 373.8532 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1260.8507 280.506 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1260.8507 560.5477 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1260.8507 653.895 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1260.8507 747.2422 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1167.2179 467.2005 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1167.2179 373.8532 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1167.2179 280.506 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1167.2179 560.5477 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1167.2179 653.895 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1167.2179 747.2422 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1074.1222 467.2005 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1074.1222 373.8532 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1074.1222 280.506 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1074.1222 560.5477 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1074.1222 653.895 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1074.1222 747.2422 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 981.0266 467.2005 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 981.0266 373.8532 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 981.0266 280.506 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 981.0266 560.5477 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 981.0266 653.895 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 981.0266 747.2422 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 887.9308 467.2005 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 887.9308 373.8532 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 887.9308 280.506 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 887.9308 560.5477 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 887.9308 653.895 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 887.9308 747.2422 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 794.8351 467.2005 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 794.8351 373.8532 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 794.8351 280.506 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 794.8351 560.5477 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 794.8351 653.895 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 794.8351 747.2422 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1632.7433 1.0757 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1632.7433 94.4229 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1632.7433 187.7701 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1540.1378 1.0757 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1540.1378 94.4229 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1540.1378 187.7701 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1447.0421 1.0757 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1447.0421 94.4229 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1447.0421 187.7701 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1353.9464 1.0757 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1353.9464 94.4229 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1353.9464 187.7701 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1260.8507 1.0757 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1260.8507 94.4229 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1260.8507 187.7701 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1167.2179 1.0757 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1167.2179 94.4229 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1167.2179 187.7701 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1074.1222 1.0757 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1074.1222 94.4229 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1074.1222 187.7701 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 981.0266 1.0757 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 981.0266 94.4229 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 981.0266 187.7701 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 887.9308 1.0757 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 887.9308 94.4229 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 887.9308 187.7701 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 794.8351 1.0757 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 794.8351 94.4229 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 794.8351 187.7701 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 701.7436 653.748 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 701.7436 607.0692 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 701.7436 560.3902 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 701.7436 700.4269 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 701.7436 747.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 701.7436 793.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 655.4355 653.748 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 655.4355 607.0692 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 655.4355 560.3902 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 655.4355 700.4269 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 655.4355 747.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 655.4355 793.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 608.8825 653.748 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 608.8825 607.0692 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 608.8825 560.3902 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 608.8825 700.4269 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 608.8825 747.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 608.8825 793.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 562.3293 653.748 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 562.3293 607.0692 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 562.3293 560.3902 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 562.3293 700.4269 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 562.3293 747.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 562.3293 793.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 515.7763 653.748 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 515.7763 607.0692 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 515.7763 560.3902 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 515.7763 700.4269 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 515.7763 747.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 515.7763 793.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 468.9545 653.748 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 468.9545 607.0692 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 468.9545 560.3902 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 468.9545 700.4269 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 468.9545 747.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 468.9545 793.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 422.4013 653.748 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 422.4013 607.0692 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 422.4013 560.3902 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 422.4013 700.4269 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 422.4013 747.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 422.4013 793.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 375.8481 653.748 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 375.8481 607.0692 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 375.8481 560.3902 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 375.8481 700.4269 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 375.8481 747.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 375.8481 793.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 329.2951 653.748 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 329.2951 607.0692 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 329.2951 560.3902 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 329.2951 700.4269 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 329.2951 747.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 329.2951 793.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 282.7419 653.748 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 282.7419 607.0692 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 282.7419 560.3902 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 282.7419 700.4269 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 282.7419 747.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 282.7419 793.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 701.7436 467.3381 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 701.7436 514.017 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 655.4355 467.3381 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 655.4355 514.017 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 608.8825 467.3381 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 608.8825 514.017 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 562.3293 467.3381 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 562.3293 514.017 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 515.7763 467.3381 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 515.7763 514.017 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 468.9545 467.3381 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 468.9545 514.017 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 422.4013 467.3381 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 422.4013 514.017 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 375.8481 467.3381 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 375.8481 514.017 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 329.2951 467.3381 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 329.2951 514.017 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 282.7419 467.3381 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 282.7419 514.017 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 701.7436 280.748 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 701.7436 234.0692 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 701.7436 187.3902 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 701.7436 327.4269 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 701.7436 374.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 701.7436 420.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 655.4355 280.748 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 655.4355 234.0692 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 655.4355 187.3902 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 655.4355 327.4269 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 655.4355 374.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 655.4355 420.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 608.8825 280.748 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 608.8825 234.0692 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 608.8825 187.3902 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 608.8825 327.4269 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 608.8825 374.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 608.8825 420.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 562.3293 280.748 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 562.3293 234.0692 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 562.3293 187.3902 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 562.3293 327.4269 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 562.3293 374.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 562.3293 420.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 515.7763 280.748 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 515.7763 234.0692 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 515.7763 187.3902 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 515.7763 327.4269 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 515.7763 374.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 515.7763 420.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 468.9545 280.748 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 468.9545 234.0692 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 468.9545 187.3902 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 468.9545 327.4269 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 468.9545 374.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 468.9545 420.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 422.4013 280.748 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 422.4013 234.0692 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 422.4013 187.3902 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 422.4013 327.4269 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 422.4013 374.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 422.4013 420.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 375.8481 280.748 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 375.8481 234.0692 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 375.8481 187.3902 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 375.8481 327.4269 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 375.8481 374.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 375.8481 420.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 329.2951 280.748 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 329.2951 234.0692 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 329.2951 187.3902 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 329.2951 327.4269 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 329.2951 374.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 329.2951 420.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 282.7419 280.748 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 282.7419 234.0692 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 282.7419 187.3902 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 282.7419 327.4269 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 282.7419 374.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 282.7419 420.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 701.7436 94.3381 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 701.7436 141.017 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 655.4355 94.3381 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 655.4355 141.017 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 608.8825 94.3381 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 608.8825 141.017 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 562.3293 94.3381 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 562.3293 141.017 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 515.7763 94.3381 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 515.7763 141.017 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 468.9545 94.3381 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 468.9545 141.017 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 422.4013 94.3381 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 422.4013 141.017 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 375.8481 94.3381 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 375.8481 141.017 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 329.2951 94.3381 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 329.2951 141.017 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 282.7419 94.3381 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 282.7419 141.017 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 701.7436 1.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 701.7436 47.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 655.4355 1.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 655.4355 47.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 608.8825 1.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 608.8825 47.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 562.3293 1.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 562.3293 47.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 515.7763 1.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 515.7763 47.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 468.9545 1.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 468.9545 47.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 422.4013 1.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 422.4013 47.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 375.8481 1.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 375.8481 47.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 329.2951 1.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 329.2951 47.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 282.7419 1.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 282.7419 47.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 235.267 653.748 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 235.267 607.0692 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 235.267 560.3902 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 235.267 700.4269 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 235.267 747.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 235.267 793.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 188.9589 653.748 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 188.9589 607.0692 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 188.9589 560.3902 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 188.9589 700.4269 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 188.9589 747.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 188.9589 793.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 142.4057 653.748 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 142.4057 607.0692 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 142.4057 560.3902 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 142.4057 700.4269 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 142.4057 747.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 142.4057 793.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 95.8527 653.748 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 95.8527 607.0692 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 95.8527 560.3902 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 95.8527 700.4269 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 95.8527 747.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 95.8527 793.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 49.2995 653.748 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 49.2995 607.0692 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 49.2995 560.3902 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 49.2995 700.4269 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 49.2995 747.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 49.2995 793.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 2.4777 653.748 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 2.4777 607.0692 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 2.4777 560.3902 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 2.4777 700.4269 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 2.4777 747.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 2.4777 793.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 235.267 467.3381 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 235.267 514.017 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 188.9589 467.3381 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 188.9589 514.017 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 142.4057 467.3381 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 142.4057 514.017 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 95.8527 467.3381 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 95.8527 514.017 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 49.2995 467.3381 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 49.2995 514.017 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 2.4777 467.3381 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 2.4777 514.017 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 235.267 280.748 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 235.267 234.0692 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 235.267 187.3902 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 235.267 327.4269 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 235.267 374.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 235.267 420.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 188.9589 280.748 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 188.9589 234.0692 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 188.9589 187.3902 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 188.9589 327.4269 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 188.9589 374.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 188.9589 420.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 142.4057 280.748 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 142.4057 234.0692 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 142.4057 187.3902 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 142.4057 327.4269 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 142.4057 374.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 142.4057 420.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 95.8527 280.748 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 95.8527 234.0692 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 95.8527 187.3902 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 95.8527 327.4269 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 95.8527 374.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 95.8527 420.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 49.2995 280.748 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 49.2995 234.0692 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 49.2995 187.3902 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 49.2995 327.4269 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 49.2995 374.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 49.2995 420.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 2.4777 280.748 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 2.4777 234.0692 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 2.4777 187.3902 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 2.4777 327.4269 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 2.4777 374.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 2.4777 420.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 235.267 94.3381 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 235.267 141.017 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 188.9589 94.3381 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 188.9589 141.017 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 142.4057 94.3381 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 142.4057 141.017 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 95.8527 94.3381 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 95.8527 141.017 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 49.2995 94.3381 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 49.2995 141.017 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 2.4777 94.3381 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 2.4777 141.017 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 235.267 1.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 235.267 47.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 188.9589 1.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 188.9589 47.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 142.4057 1.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 142.4057 47.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 95.8527 1.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 95.8527 47.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 49.2995 1.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 49.2995 47.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 2.4777 1.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 2.4777 47.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q + endstream endobj 731 0 obj <>/ExtGState<>/Font<>/ProcSet[/PDF/Text]>>/Subtype/Form>>stream +BT +/CS0 cs 1 1 1 scn +/GS0 gs +/T1_0 1 Tf +0 Tc 0 Tw 0 Ts 100 Tz 0 Tr 26 0 0 26 1310.2639 682.0497 Tm +(on)Tj +ET + endstream endobj 732 0 obj <>/ExtGState<>>>/Subtype/Form>>stream +/CS0 cs 0 0 0 scn +/GS0 gs +q 1 0 0 1 1401.5856 323.8414 cm +0 0 m +25.188 1.677 l +29.825 1.986 33.834 -1.523 34.143 -6.16 c +35.82 -31.349 l +36.129 -35.986 32.62 -39.995 27.983 -40.304 c +2.794 -41.981 l +-1.843 -42.289 -5.852 -38.781 -6.161 -34.143 c +-7.837 -8.955 l +-8.146 -4.318 -4.637 -0.309 0 0 c +f +Q + endstream endobj 733 0 obj <>/ExtGState<>>>/Subtype/Form>>stream +/CS0 cs 0 0 0 scn +/GS0 gs +q 1 0 0 1 1441.9059 528.9256 cm +0 0 m +25.188 1.677 l +29.826 1.986 33.835 -1.523 34.144 -6.16 c +35.82 -31.349 l +36.129 -35.986 32.62 -39.995 27.983 -40.304 c +2.795 -41.981 l +-1.842 -42.289 -5.852 -38.78 -6.16 -34.143 c +-7.837 -8.955 l +-8.146 -4.318 -4.637 -0.309 0 0 c +f +Q + endstream endobj 734 0 obj <>/ExtGState<>>>/Subtype/Form>>stream +/CS0 cs 0 0 0 scn +/GS0 gs +q 1 0 0 1 1451.9669 377.7953 cm +0 0 m +25.188 1.677 l +29.825 1.986 33.835 -1.523 34.144 -6.16 c +35.82 -31.349 l +36.129 -35.986 32.62 -39.995 27.983 -40.304 c +2.795 -41.981 l +-1.842 -42.289 -5.852 -38.781 -6.16 -34.143 c +-7.837 -8.955 l +-8.146 -4.318 -4.637 -0.309 0 0 c +f +Q + endstream endobj 735 0 obj <>/ExtGState<>>>/Subtype/Form>>stream +/CS0 cs 0 0 0 scn +/GS0 gs +q 1 0 0 1 1455.3204 327.4186 cm +0 0 m +25.188 1.677 l +29.826 1.985 33.835 -1.523 34.144 -6.16 c +35.82 -31.349 l +36.129 -35.986 32.62 -39.995 27.983 -40.304 c +2.795 -41.981 l +-1.842 -42.289 -5.852 -38.781 -6.16 -34.143 c +-7.837 -8.955 l +-8.146 -4.318 -4.637 -0.309 0 0 c +f +Q + endstream endobj 736 0 obj <>/ExtGState<>/Font<>/ProcSet[/PDF/Text]>>/Subtype/Form>>stream +BT +/CS0 cs 1 1 1 scn +/GS0 gs +/T1_0 1 Tf +0 Tc 0 Tw 0 Ts 100 Tz 0 Tr 26 0 0 26 1379.1553 682.0497 Tm +(shake)Tj +ET + endstream endobj 737 0 obj <>/ExtGState<>>>/Subtype/Form>>stream +/CS0 cs 0.137 0.122 0.125 scn +/GS0 gs +q 1 0 0 1 1492.5216 692.3195 cm +0 0 m +0.005 -0.954 -0.374 -1.87 -1.049 -2.543 c +-6.845 -8.338 l +-8.257 -9.738 -10.533 -9.738 -11.945 -8.338 c +-17.726 -2.543 l +-18.406 -1.871 -18.789 -0.956 -18.79 0 c +-18.787 0.957 -18.411 1.875 -17.74 2.558 c +-17.312 2.912 -16.676 3.607 -9.388 3.607 c +-2.099 3.607 -1.419 2.927 -1.049 2.558 c +-0.374 1.878 0.004 0.958 0 0 c +f +Q + endstream endobj 738 0 obj <>/ExtGState<>/Font<>/ProcSet[/PDF/Text]>>/Subtype/Form>>stream +BT +/CS0 cs 1 1 1 scn +/GS0 gs +/T1_0 1 Tf +0 Tc 0 Tw 0 Ts 100 Tz 0 Tr 25.9425 1.7269 -1.7269 25.9425 1218.8367 556.2019 Tm +(show\037leds)Tj +ET + endstream endobj 739 0 obj <>/ExtGState<>>>/Subtype/Form>>stream +/CS0 cs 0 0 0 scn +/GS0 gs +q 1 0 0 1 1226.965 514.6168 cm +0 0 m +25.188 1.677 l +29.826 1.985 33.835 -1.523 34.144 -6.16 c +35.82 -31.349 l +36.129 -35.986 32.62 -39.995 27.983 -40.304 c +2.795 -41.981 l +-1.842 -42.289 -5.852 -38.781 -6.16 -34.143 c +-7.837 -8.955 l +-8.146 -4.318 -4.637 -0.309 0 0 c +f +Q + endstream endobj 740 0 obj <>/ExtGState<>>>/Subtype/Form>>stream +/CS0 cs 0 0 0 scn +/GS0 gs +q 1 0 0 1 1237.026 363.4865 cm +0 0 m +25.188 1.677 l +29.826 1.985 33.835 -1.523 34.144 -6.16 c +35.82 -31.349 l +36.129 -35.986 32.62 -39.995 27.983 -40.304 c +2.795 -41.981 l +-1.842 -42.289 -5.852 -38.781 -6.16 -34.143 c +-7.837 -8.955 l +-8.146 -4.318 -4.637 -0.309 0 0 c +f +Q + endstream endobj 741 0 obj <>/ExtGState<>>>/Subtype/Form>>stream +/CS0 cs 0 0 0 scn +/GS0 gs +q 1 0 0 1 1240.3795 313.1097 cm +0 0 m +25.188 1.677 l +29.826 1.986 33.835 -1.523 34.144 -6.16 c +35.82 -31.349 l +36.129 -35.986 32.62 -39.995 27.983 -40.304 c +2.795 -41.981 l +-1.842 -42.289 -5.852 -38.78 -6.16 -34.143 c +-7.837 -8.955 l +-8.146 -4.318 -4.637 -0.309 0 0 c +f +Q + endstream endobj 742 0 obj <>/ExtGState<>>>/Subtype/Form>>stream +/CS0 cs 0 0 0 scn +/GS0 gs +q 1 0 0 1 1294.1149 316.687 cm +0 0 m +25.188 1.677 l +29.826 1.985 33.835 -1.523 34.144 -6.16 c +35.82 -31.349 l +36.129 -35.986 32.62 -39.995 27.983 -40.304 c +2.795 -41.981 l +-1.842 -42.289 -5.852 -38.781 -6.16 -34.143 c +-7.837 -8.955 l +-8.146 -4.318 -4.637 -0.309 0 0 c +f +Q + endstream endobj 743 0 obj <>/ExtGState<>>>/Subtype/Form>>stream +/CS0 cs 0 0 0 scn +/GS0 gs +q 1 0 0 1 1334.4357 521.7712 cm +0 0 m +25.188 1.677 l +29.825 1.986 33.834 -1.523 34.144 -6.16 c +35.82 -31.349 l +36.129 -35.986 32.62 -39.995 27.983 -40.304 c +2.794 -41.981 l +-1.842 -42.289 -5.852 -38.781 -6.161 -34.143 c +-7.837 -8.955 l +-8.146 -4.318 -4.637 -0.309 0 0 c +f +Q + endstream endobj 761 0 obj <> endobj 724 0 obj <> endobj 722 0 obj [/ICCBased 762 0 R] endobj 762 0 obj <>stream +HyTSwoɞc [5laQIBHADED2mtFOE.c}08׎8GNg9w߽'0 ֠Jb  + 2y.-;!KZ ^i"L0- @8(r;q7Ly&Qq4j|9 +V)gB0iW8#8wթ8_٥ʨQQj@&A)/g>'Kt;\ ӥ$պFZUn(4T%)뫔0C&Zi8bxEB;Pӓ̹A om?W= +x-[0}y)7ta>jT7@tܛ`q2ʀ&6ZLĄ?_yxg)˔zçLU*uSkSeO4?׸c. R ߁-25 S>ӣVd`rn~Y&+`;A4 A9=-tl`;~p Gp| [`L`< "A YA+Cb(R,*T2B- +ꇆnQt}MA0alSx k&^>0|>_',G!"F$H:R!zFQd?r 9\A&G rQ hE]a4zBgE#H *B=0HIpp0MxJ$D1D, VĭKĻYdE"EI2EBGt4MzNr!YK ?%_&#(0J:EAiQ(()ӔWT6U@P+!~mD eԴ!hӦh/']B/ҏӿ?a0nhF!X8܌kc&5S6lIa2cKMA!E#ƒdV(kel }}Cq9 +N')].uJr + wG xR^[oƜchg`>b$*~ :Eb~,m,-ݖ,Y¬*6X[ݱF=3뭷Y~dó ti zf6~`{v.Ng#{}}jc1X6fm;'_9 r:8q:˜O:ϸ8uJqnv=MmR 4 +n3ܣkGݯz=[==<=GTB(/S,]6*-W:#7*e^YDY}UjAyT`#D="b{ų+ʯ:!kJ4Gmt}uC%K7YVfFY .=b?SƕƩȺy چ k5%4m7lqlioZlG+Zz͹mzy]?uuw|"űNwW&e֥ﺱ*|j5kyݭǯg^ykEklD_p߶7Dmo꿻1ml{Mś nLl<9O[$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! +zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Km endstream endobj 760 0 obj <> endobj 759 0 obj <> endobj 758 0 obj <> endobj 757 0 obj <> endobj 756 0 obj <> endobj 710 0 obj <> endobj 763 0 obj <> endobj 764 0 obj <> endobj 765 0 obj <>stream +HyPSW_#䅼:j RQP4(qy@6qD+uUVKP, +F%e+Seu3qON=;OɥD"2?11%)"72~cސ6]PI`PCU Հopu 6on$4 qT6I$k:S.S9.*227$cx9fV4b卦TDh,zeK+_xِksYzSn㳹pf-s̬q +sM<ްQot,nz]A' mD͋v٘xX"%c)",K%;qwX* VH/KɴrL-.ee}N|UPœwo PNG'bj;b'Ez@% &`^݇ u7N'9Ksnc{SaР7 ؙQSD!J4 zκGL^n +>-)2bV,XAi5!i#, ݿ*aۮKɮgaN5p:[~'G"A//'&ge7^Ή ps~o6`76\+b>Z־RpnsovRO`@#8e +F߻<4RTÒ깯A \O@^ϳfH N>:46)|Xz=5J7j h + ٱH8D͈dj: @2q^X׾vy흦.u*sݘak'!IduTc:#tQ̇ha L[7 +zW;/90ĮdɑC:~G!ekNdB`"X$"D2MD!%3F9"w~} +`;o~qoQ +7mƥe +Nb+WJ*yL ^%,{N@G6"߃b mІr?4>" \_K?/ endstream endobj 755 0 obj <> endobj 754 0 obj <> endobj 753 0 obj <> endobj 752 0 obj <> endobj 751 0 obj <> endobj 750 0 obj <> endobj 749 0 obj <> endobj 748 0 obj <> endobj 728 0 obj <> endobj 729 0 obj <> endobj 767 0 obj <> endobj 768 0 obj <> endobj 769 0 obj <> endobj 770 0 obj <> endobj 766 0 obj <> endobj 771 0 obj <> endobj 712 0 obj <> endobj 713 0 obj <> endobj 714 0 obj <> endobj 715 0 obj <> endobj 716 0 obj <> endobj 717 0 obj <> endobj 782 0 obj [/View/Design] endobj 783 0 obj <>>> endobj 780 0 obj [/View/Design] endobj 781 0 obj <>>> endobj 778 0 obj [/View/Design] endobj 779 0 obj <>>> endobj 776 0 obj [/View/Design] endobj 777 0 obj <>>> endobj 774 0 obj [/View/Design] endobj 775 0 obj <>>> endobj 772 0 obj [/View/Design] endobj 773 0 obj <>>> endobj 727 0 obj <> endobj 711 0 obj <> endobj 784 0 obj <> endobj 785 0 obj <>stream +Hy|MwϹ~G{GhIm5PEQA&{h#A6E56^CRjƨY^Y3}9;9Ąp,Pӻw?h~d saQ  D9!ӳи0[âB Wt Co @OLz;\n4k-1OpSH- 59]&` {kع) ks2q !-97Jp500-Iѹ٪W!Tik`J+(jX'@N޺5LAgEir!o) m M*yBfb!>Wf(.d5VMR3J5_-U3ya\wPS)tTlr7i~LhCfhlmO+Үiec֠6z{ݪw }>J5~ Zn^?"bmcmkmod5[{ZY!]nn;݊.]v˵SV[[] ZKC]ᐼp/Pf*ծ$*uzE\ȋi)JrKr)ʔa*25e3?@{UӵqW -K;nh?jOg:F*9{-~z8;pzX|[8_[8M;LvwOz-z^ĩ7d5r::ɮ!ɯ\ 5XMieo)U}£&f#W̻wP4{=>oc6{=aڃA5 ͵9MzqŋJ9R pu'":bpu`ynJr93I],c{JYb_s#*~`[fÝ:mrUiԣE3%ICOa1RIK(ajcay"^"CẴ 5U5{N5zN#Ʃ4;tè [V[a,PȅJ;SX+!rap~4M¿WA1EP @)<-\1|5PaDBD ! !`.$A"$wY5B:ȦypadʷBacPEB8(ЀN8'NFOB#S= 8iqD_?` <8bcb` | _ƶ*.16Xx|;B!Np.&4/u`2`*a:f<] aw ̆#:='U +i/}I_>O 0 SJ8:I4:K<]bHD RLW*}K:}G7&ݢ2B1R\YWƺuz2w&z>/bٟg6 d*! b6 Cp6dh6FTl&l`'C01!*]a?*q_<բFlb!f +_1K</-Eia\& $Olj11u ظFw͘c܍ o.OԌ''sf~]nUwUm.el!e,e<)Os ݰǼe6wU,gYyNWA^eyEUkT#Tc6IE&*J5UT3\K`g]VѪڬhSڪiԤjnGWמKڇuJ-][jگ/AyWauD]``n&جCultL7:BG&:J7ts[薺ncK趺n;^褎c]t]uNI:YTy_ntJtЙ_=u/mY~ :I4 H DɔBFݨ; l6 l0ð1cFb¦ c4 J ʤ4FhpNi(3pyЀq8 1gp.v% +\W*܈q 7V܎;q7}xGK r<1/ewx w?n#L:fX$y'5ȕL"r#C0g N&yQ &I6SաTS QQ030c|{b/S05PHMc z4&;4&!Mh:}Bi}Fi-VRY|h>22alV A.J貜*?t9Cx6!P#fÍH죌c,k7LZjZ +L7d&ֈl)6bzwl; ݍ)́ 0BX_WX K`),V*(`A!fYlrYjyfO>L_f83Gra1pL.E<310Kp).c +UjǼ3]&|\f0xg܂ەm0GPxqT +tpt)Ym$LLCh0 A!A$ BwT|հX'z8^_Xfzq8&S2~%PPePu\XzUԇ+p .c \o4`?6* yB0 ~"5pץFpnb(qPX*?b8܃p%Y1cKx?~/j1ٙ0=g{QI@x5#s@[J੾*.UV]sfoKY?_emfs6xdcvv=oEe6"I쳋\Q+q>ebUD gu&fٲXp_Դa6ߓÙBk忧 +^p7 ym:BĮmlcƫBxr=D5B1&7IApj@`‡-i`iyf[ +xIDlr\a sݪgV֯ r3] 3MyvOpdnưlk@<6eIۖdTvQ؅_a + ˴{Es {b;! +ɍ=n~ŨB^:o{˅J?(#}ݳwf!ekvgbǦ4^qWLuXjTmSi +ԴR_kq}pMբhSQ1U13߷Ana-B@@Ss[3P["pVv m='gQu56->>0$lCv^ѹD*xJC*;<5;ZGz~|ph{ iBKzttVV(Y[6EUalb[:%Z G A\: .o$q㠛sOG=UYAv ?p=r4.!jnwЀjv8mp7ҳ_a6}VzZV]=Aq ŠO6{܉97}/ zjJBAv VW-1`KЕ߹%(.zI?=PfaݹyQL`c%g/F[nC0y0[g szdY9]Y%oza_W%ݚ dz%խ| +򳣊+Ri$#r[:G1=9uk֦hrb:,*9l/[j2O\κV\Ja [}`pa N6Hw۫_9I̤+\ĶfY<^!WέKlzTmOw]sm槻&g_1 +*z;n1&%-IW/d|:_VTIFauJ6]o:nKgm\$J>?CH:S<{9#nK;uCkIg;;8|#i(nc?%P'󦺋?4N84{L/\GH?0 VD@€0}x8~GǘΣ˿DuS|y +@|&`^ l^ cT~罷vƆ1n@e Y~Qچ-bZj7KW>X0=iuPO%Q +mT`)ab,a} ,5k6@3snRt&8(:gf)G9>6u3޳vm'tg?g7U51|`/Xt˚YG$ ÿgT8HOkC>Y| BN@;]T&pn@/1Zy:ױihƺ.b_ᆩn?Gw(39/ʂf|8y˵8؆A~Mo_96&1_kO3GkqCbz6t(CGD]fpWUzf>G8ۡFe7ЁONk09@fz}O$VtGwksgЏN;j/敖Wvһr99sa/U ]R!z?U[D.Qc_g=f3KڡshXކOW%J\Ża6isĝ7N=cԄ,bxh?n7|p>a_ ?89ڐ?/p7/[ĒS~zV#X=>XS$oXF,Ttc}7&Bbm\Tp." T OYݭCۥ|}:Qcqkkn /xg"Cw)y xvIc.b㯁B3'>6y8M͈'jJ`@ 8s=I>V???(4pޛĘp>NAq<%;8gzkDVY8s`PM$Cg {܏/]kk68Yy%K"?Yv'r־B}eu7\$4.z@37\K\FFXdn;wNϓy31VבQeZkYto>07sˬo5JڛWWz)|˛3vq ʈMO"gq[&wRH?~ +w*û +ҠZv1؍!~Qޫ4E2ݥϙV7/!AQ[@;Jq]>䄐cZR|SɜYq,w,b[L/*)Kcԅ:KD(do ,h0v _0ڷ5 Yq)T9?Y ]I9Eu5Soo 3k5J5 +cIarirz{MAJոo55pTG ?sHZcf@Т~ƀoQ"_E"q[}6q 7x@-v3mMay1OlWW-]*2@(PJe (6X Vhb7R'?d JeI5dCTA%Za N2$s{ E }{{9N6Q<%/jۭL޺lg`]T3|=+d=:E9GS~O;\ߔBpA yd&b0:^ oRv8M79M~sPJ:ϵm#a)i-Y@>[$Z ۜmršd\{EQ,Mk&Te?5b,o: ߒilgIS6_3ft {`'2/lty3Oqib0"ٶ4 :+)3{$XA)]&igkǥ[~;e%:Uk6:]ۮ1Lsu%[a6G[;}{Jܥ50w8wSG^RE̜\nu WUe22k%Y+ŝ(-A!Mw009/wFJ{+}/*C],rm^Wxgw#g6v73Uaۈx6wi4_>6+u{},W4wI{򑇨;$%D>J wpٚzo=ҤJyM޵M.dzp] ǡ#O.ױ5G}^wE &GϑH g|H7Zsk.Yot^l0.η65z7{J cYMu6>pϭ[~k){(0Tklh ǯٗ2^up"̱}hC2( +wl5+V4][ Ru̕<>͜ J[߸m`-lu3\̄ZvL&s;t9_c y&x>-kL2:g2ƸQ5coqvJ>O͹ڞ9g{#'},C|cOC;:/ J Zc:=ΖAD߭00Aex(opٮ Z0ZvN1:,죺8?J[ gvZNz|Lͭ'i_4r<ź+sQ 9tJh\vrunCmFE0)vOwdCyϹl]_j UgȞx#ۣLV;RV{c[Tr\mt}Üs{3!?n*~)W;k/ o_o Ʊ v}K/b\&ץ:kSi׻y}*BBI,4HNkB}Ϝ,g/OfAw1g}tɴl26Wxɿ=y!3h| L|n |~2)gL}t'`~CjIw+ؐ71Ćz#J}1eijS8p=ydrޠU=K}`3 O#o6sY&9sr0Vdu~s5oG6y:${/{#L~=1by?ߏ܉YgNS P`= /ؚoBo R2͓ok^J=S`]'SI޺&%!}:v?ם'͚z"K(32dLV9o2L se*tx'ɡyy~<Y^FNfKZ%?q> '",GsH>G)yXYCwc{51^OwݞK,{9O()%_&ȗD6WɕF826+{- +E-PV@z'6L"xP;fSŚ67d~ Y9kM85anLfˢ3w=RQXqRQ/agQ/#zb[Ǣ>Nm,]Vu-]72RO9\- d J҅\5^\;)H%Y#Xзa&cf-YLSKF]=R"ڈ}ZE3ȋ: +w^F/7瘣]"k7oխAɚ珮|hV.Z-[($j0okQ8@`5+ +xDl&iCKbff̔L fc(fl1Č3T+ܸcG N̼#xSeK <#xZIG +NT/'Op݂a{[ +& +wgD -}5I6te]ز޲57m֭vkڝ56dvmLsdzXVV|+3NuԷa?*U&zD9(wݹjEe((~LLQ+*DvZIA{6++_՝yLEŪ~ÍtǣFGtYO^6KļFb:D%n(=~W_KLP %b9˥A}을YG~MsMLq{v1+3ԕ+ǽ斣 +T_tKѕ6DQmu1Vx0,o^NK(,z"wGfq#n?2?g?r4.{s #VR'{]-䨻(lO8nGa=kUavAA;a3,4?Lݳ+ԙ a-uXJrAtw6UI2-$&s tR)G4C2IsyS9&DV8_C$s %t zY0^H= ' Yr>{'뱓c%vpP"MC~Ş2fMHYm2Fd˳dy,r.WdSrHvp4OZ Mv$G+)UIK +iVhy_ռZ55fdhu3$*c +EPe`7Xа5/t+BIHRh^N!1wX ˌMFi>n"Aub϶NX5-FQb+B-5M ?/͏nsҳY".qĴ'vvmWUy^P{]Fsf[[W_4롺f#Ӈr6_U?%yY#jL +@PdH1~7U~_y~)~?~||{x7ou|!Oϴ_y endstream endobj 725 0 obj <> endobj 726 0 obj <> endobj 723 0 obj [/Pattern] endobj 721 0 obj <> endobj 786 0 obj <> endobj 787 0 obj <>stream +%!PS-Adobe-3.0 %%Creator: Adobe Illustrator(R) 17.0 %%AI8_CreatorVersion: 22.0.1 %%For: (Sam El-Husseini) () %%Title: (Microbit_Hero_Illustration_06.ai) %%CreationDate: 10/25/18 12:36 PM %%Canvassize: 16383 %%BoundingBox: -4203 5607 -1267 6846 %%HiResBoundingBox: -4202.2640275724 5607.51919553277 -1267.0201384211 6845.00846103516 %%DocumentProcessColors: Cyan Magenta Yellow Black %AI5_FileFormat 13.0 %AI12_BuildNumber: 249 %AI3_ColorUsage: Color %AI7_ImageSettings: 0 %%RGBProcessColor: 0 0.470588237047195 0.843137264251709 (Blue 0-120-215) %%+ 0.250980406999588 0.603921592235565 0.882352948188782 (Blue-HL 64-154-225) %%+ 0 0.394050002098084 0.709999978542328 (Blue-MT 0-100-181) %%+ 0 0.28125 0.5 (Blue-SD 0-72-128) %%+ 0.224209159612656 0.389239758253098 0.639999985694885 (Dk Blue-HL 57-99-163) %%+ 0.17501437664032 0.239994987845421 0.529999971389771 (Dk Blue-MT 45-61-135) %%+ 0.131999999284744 0.600000023841858 0.307500004768372 (Dk Green-HL 34-153-78) %%+ 0.529999971389771 0.100699998438358 0.100699998438358 (Dk Red-MT 128-24-24) %%+ 0.136399999260902 0.421316921710968 0.439999997615814 (Dk Teal-MT 35-107-112) %%+ 0.062745101749897 0.486274510622025 0.062745101749897 (Green 16-124-16) %%+ 0.470588237047195 0.772458553314209 0.470588237047195 (Green-HL 120-197-120) %%+ 0.219607844948769 0.631806135177612 0.219607844948769 (Green-MT 56-161-56) %%+ 0.952941179275513 0.952941179275513 0.952941179275513 (Illus Gray 1 243-243-243) %%+ 0.901960790157318 0.901960790157318 0.901960790157318 (Illus Gray 2 230-230-230) %%+ 0.823529422283173 0.823529422283173 0.823529422283173 (Illus Gray 3 210-210-210) %%+ 0.760784327983856 0.760784327983856 0.760784327983856 (Illus Gray 4 194-194-194) %%+ 0.69803923368454 0.69803923368454 0.69803923368454 (Illus Gray 5 178-178-178) %%+ 0.576470613479614 0.576470613479614 0.576470613479614 (Illus Gray 6 147-147-147) %%+ 0.450980395078659 0.450980395078659 0.450980395078659 (Illus Gray 7 115-115-115) %%+ 0.313725501298904 0.313725501298904 0.313725501298904 (Illus Gray 8 80-80-80) %%+ 0.156862750649452 0.156862750649452 0.156862750649452 (Illus Gray 9 40-40-40) %%+ 0 0.737254917621613 0.949019610881805 (Lt Blue 0-188-242) %%+ 0.250980406999588 0.803921580314636 0.960784316062927 (Lt Blue-HL 64-205-245) %%+ 0.729411780834198 0.847058832645416 0.039215687662363 (Lt Green 186-216-10) %%+ 0.844336271286011 0.939999997615814 0.295309752225876 (Lt Green-HL 215-240-75) %%+ 0.917647063732147 0.250980406999588 0.662745118141174 (Lt Magenta-HL 234-64-169) %%+ 1 0.549019634723663 0 (Lt Orange 255-140-0) %%+ 1 0.662745118141174 0.250980406999588 (Lt Orange-HL 255-169-64) %%+ 0.941176474094391 0.517647087574005 0 (Lt Orange-MT 240-132-0) %%+ 0 0.69803923368454 0.580392181873322 (Lt Teal 0-178-148) %%+ 0.250980406999588 0.772549033164978 0.686274528503418 (Lt Teal-HL 64-197-175) %%+ 0 0.550000011920929 0.455521494150162 (Lt Teal-MT 0-140-116) %%+ 0 0.431372553110123 0.356740713119507 (Lt Teal-SD 0-110-91) %%+ 1 0.945098042488098 0 (Lt Yellow 255-241-0) %%+ 1 0.972549021244049 0.501960813999176 (Lt Yellow-HL 255-248-128) %%+ 0.780392169952393 0.250980406999588 0.713725507259369 (Magenta-HL 199-64-182) %%+ 0.620000004768372 0 0.544848501682282 (Magenta-MT 158-0-139) %%+ 0.184799998998642 0.375029444694519 0.879999995231628 (Mid Blue-HL 47-96-224) %%+ 0.127800017595291 0.223317205905914 0.709999978542328 (Mid Blue-MT 33-57-181) %%+ 0.847058832645416 0.23137255012989 0.003921568859369 (Orange 216-59-1) %%+ 0.886274516582489 0.423529416322708 0.254901975393295 (Orange-HL 226-108-65) %%+ 0.740000009536743 0.210603997111321 0.014800000935793 (Orange-MT 189-54-4) %%+ 0.360784322023392 0.176470592617989 0.5686274766922 (Purple 92-45-145) %%+ 0.645780384540558 0.475838124752045 0.839999973773956 (Purple-HL 165-121-214) %%+ 0.909803926944733 0.066666670143604 0.137254908680916 (Red 232-17-35) %%+ 0.933333337306976 0.301960796117783 0.352941185235977 (Red-HL 238-77-90) %%+ 0.730000019073486 0.053824886679649 0.111013829708099 (Red-MT 217-16-33) %%+ 0.721568644046784 0.592156887054443 0.486274510622025 (Skin4 MT 184-151-124) %%+ 0.847058832645416 0.690196096897125 0.498039215803146 (Skin5 HL 216-176-127) %%+ 0.729411780834198 0.549019634723663 0.341176480054855 (Skin5 MT 186-140-87) %%+ 0.705882370471954 0.560784339904785 0.458823531866074 (Skin7 HL 180-143-117) %%+ 0.439215689897537 0.26274511218071 0.133333340287209 (Skin7 MT 112-67-34) %%+ 0.329411774873734 0.196078434586525 0.090196080505848 (Skin7 SD 84-50-23) %%+ 0.18823529779911 0.113725490868092 0.098039217293262 (Skin9 SD 48-29-25) %%+ 0.847058832645416 0.690196096897125 0.580392181873322 (Skintone4 216-176-148) %%+ 0.807843148708344 0.61176472902298 0.372549027204514 (Skintone5 206-156-95) %%+ 0.556862771511078 0.337254911661148 0.180392161011696 (Skintone7 142-86-46) %%+ 0 0.509803950786591 0.447058826684952 (Teal 0-130-114) %%+ 0.250980406999588 0.631372570991516 0.584313750267029 (Teal-HL 64-161-149) %%+ 0 0.319999992847443 0.281043469905853 (Teal-MT 0-82-72) %%+ 1 1 1 (White) %%+ 1 0.725490212440491 0 (Yellow 255-185-0) %%+ 1 0.796078443527222 0.250980406999588 (Yellow-HL 255-203-64) %%+ 0.899999976158142 0.652500033378601 0 (Yellow-MT 240-174-0) %%+ 0.769999980926514 0.549447238445282 0 (Yellow-SD 199-142-0) %%+ 0 0 0 ([Registration]) %AI3_Cropmarks: -4149.18863874597 5919.49432762729 -1321.18863874597 6696.49432762729 %AI3_TemplateBox: 960.5 -540.5 960.5 -540.5 %AI3_TileBox: -3113.18863874597 6019.99432762729 -2379.18863874597 6595.99432762729 %AI3_DocumentPreview: None %AI5_ArtSize: 14400 14400 %AI5_RulerUnits: 6 %AI9_ColorModel: 1 %AI5_ArtFlags: 0 0 0 1 0 0 1 0 0 %AI5_TargetResolution: 800 %AI5_NumLayers: 6 %AI17_Begin_Content_if_version_gt:17 1 %AI9_OpenToView: -4285 7177 0.5 1668 1001 18 1 0 6 43 0 0 0 0 1 0 1 1 0 1 %AI17_Alternate_Content %AI9_OpenToView: -4285 7177 0.5 1668 1001 18 1 0 6 43 0 0 0 0 1 0 1 1 0 1 %AI17_End_Versioned_Content %AI5_OpenViewLayers: 737333 %%PageOrigin:0 0 %AI7_GridSettings: 20 1 20 1 0 0 0.800000011920929 0.800000011920929 0.800000011920929 0.899999976158142 0.899999976158142 0.899999976158142 %AI9_Flatten: 1 %AI12_CMSettings: 00.MS %%EndComments endstream endobj 788 0 obj <>stream +%%BoundingBox: -4203 5607 -1267 6846 %%HiResBoundingBox: -4202.2640275724 5607.51919553277 -1267.0201384211 6845.00846103516 %AI7_Thumbnail: 128 56 8 %%BeginData: 11538 Hex Bytes %0000330000660000990000CC0033000033330033660033990033CC0033FF %0066000066330066660066990066CC0066FF009900009933009966009999 %0099CC0099FF00CC0000CC3300CC6600CC9900CCCC00CCFF00FF3300FF66 %00FF9900FFCC3300003300333300663300993300CC3300FF333300333333 %3333663333993333CC3333FF3366003366333366663366993366CC3366FF %3399003399333399663399993399CC3399FF33CC0033CC3333CC6633CC99 %33CCCC33CCFF33FF0033FF3333FF6633FF9933FFCC33FFFF660000660033 %6600666600996600CC6600FF6633006633336633666633996633CC6633FF %6666006666336666666666996666CC6666FF669900669933669966669999 %6699CC6699FF66CC0066CC3366CC6666CC9966CCCC66CCFF66FF0066FF33 %66FF6666FF9966FFCC66FFFF9900009900339900669900999900CC9900FF %9933009933339933669933999933CC9933FF996600996633996666996699 %9966CC9966FF9999009999339999669999999999CC9999FF99CC0099CC33 %99CC6699CC9999CCCC99CCFF99FF0099FF3399FF6699FF9999FFCC99FFFF %CC0000CC0033CC0066CC0099CC00CCCC00FFCC3300CC3333CC3366CC3399 %CC33CCCC33FFCC6600CC6633CC6666CC6699CC66CCCC66FFCC9900CC9933 %CC9966CC9999CC99CCCC99FFCCCC00CCCC33CCCC66CCCC99CCCCCCCCCCFF %CCFF00CCFF33CCFF66CCFF99CCFFCCCCFFFFFF0033FF0066FF0099FF00CC %FF3300FF3333FF3366FF3399FF33CCFF33FFFF6600FF6633FF6666FF6699 %FF66CCFF66FFFF9900FF9933FF9966FF9999FF99CCFF99FFFFCC00FFCC33 %FFCC66FFCC99FFCCCCFFCCFFFFFF33FFFF66FFFF99FFFFCC110000001100 %000011111111220000002200000022222222440000004400000044444444 %550000005500000055555555770000007700000077777777880000008800 %000088888888AA000000AA000000AAAAAAAABB000000BB000000BBBBBBBB %DD000000DD000000DDDDDDDDEE000000EE000000EEEEEEEE0000000000FF %00FF0000FFFFFF0000FF00FFFFFF00FFFFFF %524C45FD92FFA8FFA8FDFCFFFFA8FFA8FDEDFFA8AFA8AFA8AFA8AFA8AFA8 %AFA8AFA8FFA8FFA8AFA8AFA8AFA8AFA8AFA8AFA8AFA8AFA8AFA8AFA8AFA8 %AFA8AFA8AFA8AFA8AFA8AFA8AFA8AFA8AFA8AFA8FFA8AFA8FFA8AFA8FFA8 %AFA8FFA8AFA8AFA8AFA8FFA8AFA8FFA8AFA8AFA8AFA8FFA8AFA8FFA8AFA8 %FFA8AFA8FFA8AFA8FFA8AFA8FFA8AFA8FFA8AFA8FFA8AFA9FFFF843B353C %353B353C353B353C353B353CAFFFFFFF353B353C353B353C353B353B133B %353B133B353C353B353C353B353C353B353C353B353C353B353C353B353C %353B353C353B353C353B3560353B353B353B3560353B3560353B353B353B %3560353B3560353B353B353B3560353B3560353B353B353B3560353B353B %35FFFFFFAF123B123B133B123B133B123B133B13FFC2C9A83B133B123B13 %3B123B123B5F3B123B123B123B133B123B133B123B133B123B133B123B13 %3B1219133B1219133B1219133B1213133B1213133B353B123B133B133B12 %13133B353B123B133B133B1213123B353B123B133B133B1213123B353B12 %3B133B133B1313123BA8FFFF843B353B3B3B353B3B3B353B3B3B353CFFC8 %C9FF353B353B353B353B1360FFFF3B3B353B353B353B353B353B353B353B %353B353B353B353B3B3B353B353B353B353B353B353B353B353B133B3B3B %133B133B353C353B133B3B3B353B133B353C353B133B353B353B133B353C %3B3B133B353B353B133B133C3B3B133B35FFFFFFAF133B133B133B133B13 %3B133B133B35FFFFFFA83B133B133B35351360FFA90D36353B133B353B13 %3B353B133B353B133B353B133B353B353B4D96719671726B967196719635 %3B353B133B123B353B123B133B133B133B123B353B123B1335133B121312 %3B353B123B133B133B133B123B133B133B133B133B133B123BA8FFFF843B %353B353B353B353B353B353B353BA8FFFFAF353B353B353B130E85A90D0E %0E363B3B133B3B350B272E3B133B3B3B133B3B3B133B3B3B139CBFBF90C5 %C5C596B996B8905A3B3B353B353B133B353B353B353B133B133B133B353B %133B133B5F603B3B353C3B3B353B353B353B353B353B353B353B353B353B %353B35FFFFFFAE123B133B133B133B133B133B133B35FF9BCAA83B123B13 %3B0D0E0D300D0E0D0E0D361335133B512005351335123B3535123B353512 %3B351371BF96969CC59C96969690902F3B353B133B353B133B353B353B13 %3B598484A884AF84A884AEA8FFFF590C340C35133B353B353B133B353B35 %3B133B353B353B133B353BA8FFFF843B353B353B353B353B353B353B353B %A8BDC4FF353B353B353B0D30072F28280636353B135F7B58343B3B3B353B %353B353B353B353B353B359C909690B86C9672969696725A3B3B133B3B3B %353C353B353B3B84A8FFCFFFFFCFC2FFFFCBBDFFFFFF58582E350C2E0C3C %3B3B353B353B353C3B3B353C3B3B353B353B35FFFFFFAF133B133B133B13 %3B133B133B133B35FFCAFFA83B133B353B13350728F82720272E5F133B7B %58133B353B353B353B353B353B353B353B353B6B783578533B3535353B35 %3B353B353B123B353B353B131335AFFFFFA7C7CAFFC9C1CAFF9BBDFFFFFF %843458523B130C053B3B3B123B353B353B133B133B353B133B133BA8FFFF %843B353B353B353B353B353B353B133BAFFFFFFF353B133B353B132F0627 %00270659583C347C353B133B353B133B353B133B353B133C353B1378303C %143636373636353B133B353B353B133B3B3B133B35AFA8AEFFFFCAFFFFFF %CAFFFFFFCAFFFFFF84603B59513B1935053B3B3B133B353B353B133B353B %3B3B133B35FFFFFFAF133B133B133B133B133B133B133B35FF77A8A83B13 %3B133B133B132F0C2F0D3558581358343B133B133B133B133B133B133B12 %360E360E37156137370F370F37143B133B133B133B1335123B353512AEFF %8358FFA884595F355F355F353B59A8843B356013592D191312053B133512 %3B133B123B1335133B1335123BA8FFFF843B353B353B353B353B353B353B %353CAF787EFF353B353B353B353B353C19837B7C353C583B133C193B3B3C %3B3B3B3C3B3B133B3537A9855B858585FD0637133B353B133B353B133B35 %3B138AFFFFAEFFA860133B133B133B133B133B353B133C603B197C353B3B %34343B133B353B353B353B133B3B3B133B35FFFFFFAF133B133B133B133B %353B133B353B35FFCBFFA83B133B133B353B133B357C7559353B135E3535 %34590C340C2E0B2E052E353B13363761373715370F3715370F37363B353B %353B353B353B353B353BA8FFA8FFA83B133B353B353B353B353B353B133B %5F84133B2E59353B352E353B353B353B133B353B353B353B133BA8FFFF84 %3B353B353B353B353B353B353B353BA8FFFFAF353B353B353B353B35A058 %3B133C3B76B69A949320FD08F8353B3B1337153737853737368585370E37 %3B3B133B3B3B133B3B3B353B5FFF37AFCA5F133B3B3B353C353B353B3B3B %353B3B8A353B3B35523C3B3C0C353B3B353B353B353B3B3B353B353B35FF %FFFF8A123B133B133B133B133B133B133B35FF5AA9A83B133B133B133B13 %58513B13351335B5B62045F8F8446F20FD05F80C3B35350E300EA9FF8507 %30A9FF300E0E3B353B123B353B123B353B1284CBA9A884133B123B353B35 %3B133B353B353B3584353B353B1258133B35340C3B353B353B1335133B35 %3B123B133BA8FFFF843B353B353B353B353B353B353B353BA85A7EFF353B %353B353B353B585F193B133C35BC20FD04F86F6F4BFD05F8343B3B133730 %3761FF5B5B36AFAF618561133B133B133B133B133B353CA8FFFFFF5F3B35 %3B133B3B340B2E0C353435358B35FD053B523B3B3C3434193B353C3B3B13 %3B3B3B353B133B35FFFFFFAE133B353B133B353B133B353B133B35FFA8FF %A83B133B353B133B13587B7C587C587C20FD04F82020F82020F8F820440B %3C353B0EAFA985AFAFFFFFA9FFA9FF8536353B353B353B123B133B35AFA8 %A9A83B353B123B132EFD08F8065A3660363C1358123B35350C3B133B353B %133B123B353B133B1335A8FFFF843B353B353B353B353B353B353B133BAF %FFFFFF353B133B353B133B35595859585F3405F8F8F827204B20272021F8 %524B2E3B3B1337A9FF85FF85FFA985A985AF85133B353B353B353B133B13 %3BA83630FF133B353B133C05FD05F8052F05F805282E61363B583B133B34 %34133B133B353B133B133B353B133B13AFFFFFAF133B133B133B133B133B %133B133B35FF84A9A83B133B133B133B133B133B0C0C133B055227F8204B %2021204B20F85252053B133B1485A985A985A9AF85FF84FF8536133B133B %353B353B133B35AFA8A9A83B133B353B132DFD05F82E2F2EFD04F82F3C12 %58353B1334123B133B353B133B353B133B133B133BA8FFFF843B353B3B3B %353B3B3B353B353B353CAF6185FF353B353B353B353B353B3B2DF834192E %5252F827204B204B2027F827272E3B3C1330A9FFAFFFA9FFAFAFFFAFAF85 %133B353B133B353B353C3B3BA8FFFFFF353C353B353C0528FD05F827FD05 %F827353B583B353C0C3B353C3B3B353B3B3B353C3B3B353C35FFFFFFAF13 %3B133B353B133B353B133B353B35FFA9FFA83B133B133B353B133B353B0C %F8123C056F20F8F82020212020FD04F8053B3B3506615A61A98585AF85FF %5A300E36133B353B133B133B353B35AFA8CBA83B353B133B35272E27F8F8 %2020F827FD05F80C3458353B0C34133B353B353B123B353B353B133B133B %A8FFFF843B353B353B353B353B353B353B353BA8FFFFAF353B353B353B35 %3B353B353C05272E2720FD05F82020F820FD04F80534042F370E36FFAFFF %FFAFFF850E37363B133B3B3B133B133B353CAE784DFF3B3B133B1335277D %27F8F84B202120F8F8275227123B523C3B2E123B133B353B353B133B3B3B %353B133B35FFFFFFAE123B133B133B133B133B133B133B35AFA7AEA83B13 %3B133B133B133B133B133B05F8F826F8F826F8F851F8F85127F87B2605F8 %0B14370E37848585AF365B36300E36353B123B353B123B133B35FFA8A8A8 %3B353B123B0C052727F820F8F8F820F8F8277D2735345813350C3B123B13 %3B353B1335123B353B123B1335A8FFFF843B3B3B353B3B3B353B3B3B353B %353BA8AE83FF5F3B353B353B353B353B353B133B135275754BA051FD057B %759F4A7C3B3B193C37360E360EAFFF850E373037363B133B353B133B133B %1360FFFFFFAF133B353B1935F8F8F8212005F8F8F84BF8272E271359343C %0C353B3B133B133B3B3B133B133B353B133B13FFFFFFAF133B133B133B35 %3B133B133B133B1384CAFFFF84123B353B133B353B133B353B133C589F7B %9F7B9F7B7B7575517C5858343B353B13370E360E3661AF36371437143771 %78353B353B133B131384CAA2FF833B133B133C2E20FD04F820452020F8F8 %F805053B5235122E133B133B133B133B133B133B133B133B133BA8FFFF84 %3B353B353B353B353B353B353B353B3BFD04FF60133B353B353B353B353B %353B353B5859345F2DF82E2EF8353B3C3B3C353B3B3631FD0737315B315B %4EB9B35A3B3B353B353B60FF95BDFF60353C342E60837551267CF8265127 %F851F8F8260513593B34343C353B353B3B3B353B3B3B353B3B3B353B35FF %FFFFAF133B133B133B133B133B133B133B133B84FFA5CEA83B123B133B13 %3B133B133B133B1319133B1312F8350CF8123B133B133B133B13360E3730 %544E727272717271966B96353B133B123535FFFFCAA8A8353B3505F82E51 %9F7B9F7B9F747B75757C7C4A7C200C2E340B3B353B133B353B353B123B35 %3B353B133B133BA8FFFF843B353B3B3B353B3B3B353B3B3B353B3560CFCE %C9FFAF8A3B3B133B353B353B133B133B133B133C12053535F83B133B133B %133B133B133C1335355F3535353B3535133B133B133B133B84FFC9FFFFFF %5F3B353C0527F82751825851757C759F7B7C9F7B5151F84BF805343C3B3B %133B3B3B353B133B353C3B3B133B35FFFFFFAF133B133B133B133B133B13 %3B133B133B1360FFFFA8C9CAFF848A8484848AFD098459F82D2EF805FD0A %848A8484608A8484608A8484608A848484AFA9FFC9C0C9FF5919133B5FAE %1313123B3B35F805190CF8345892523B353426F8F835353B133B133B353B %133B133B353B133B123BA8FFFF843B353B353B353B353B353B353B353B35 %3B3584FFFFC0C9FFFFC4FFFFFFA2FFFFFF84FFFFFFA9FFCAA87DFFA8C9CA %FFFFC9CAFFFFC4CAFFCBA2A8FFA885A9FFA9AFFFFFA8AEFFFFC9CEFFFFC9 %FF843B133B3BFFA83B133B133C35F8F8340BF8F8279299133C3558052D13 %3C353B133B133B353B133B133B353B133B13FFFFFFAE123B133B133B133B %133B133B133B133B133B1360A8CFCAFFA2B7A2FF7E4DA8FF5A0EA8FF8461 %A8FF8383FFFFC8C9AFFF98C9AFFF8EC4FFA822A2FF8407A9FFA936FFFF83 %58FFA9C9A6FFCBFF593B133512AFFF84123B133B133B0B0BF8FD04059392 %5813353419F8F80535133B133B123B133B123B133B123B1335A8FFFF843B %3B3B353B3B3B353B3B3B353B3B3B353B3B3B133C84AFFFFFCBFFFFFFCBFF %FFFFA9FD0FFFCFFD11FFCFFD05FFA884353B353B3584FFFFFD043B353C3B %3C3B350B3C3B3C75B4523C35593B35F8F8F8353B3B353C3B3B353C3B3B35 %3B3B3B35FFFFFFAF133B133B133B133B133B133B133B133B133B133B133B %355F59845F605F845F6059845F6059845F6059845F6059605F605F605F60 %5F605F605F845F605F845F6059605F6059605F60355F133B353B133B84FF %8435133B353B353B133B353B353B13599276133B523B3B34F8F8F834353B %353B133B353B353B133B353BA8FFFF843B353B353B353B353B353B353B35 %3B353B353B353B353B353B133B353B133B133B133B353B133B353B133B13 %3B133B133B133B133B133B133B133B133B133B133B133B133B133B131913 %3B3B3B133B35FFA83B353B133B3B3B353B353B353B353B139A753C345819 %3B3B3B0C05F8843B3B353B133B353B3B3B133B35FFFFFFAF133B123B133B %133B133B133B133B133B133B133B133B133B133B133B133B133B353B133B %353B133B353B133B353B133B353B133B353B133B133B133B133B133B133B %133B133B133B1335133B353B125FA83B133B1335133B353B123B133B353B %131912585858123B133B353B1335593B353B123B133B353B1335123BA8FF %FF843B353B3B3B353B3B3B353B3B3B353B3B3B353B3B3B353B3B3B353B3B %3B353B133B353B133B353B133B353B133B353C133B353C133B353C133B35 %3C133B353C353B353C353B353C353B133B3B3B133B3B5F133C353B133B35 %3B353B133B353C353B133B3559353B133B133C3B3B133B353B353B133B13 %3C3B3B133B13FFFFFFAF1213123B1313123B1313123B1313123B1313123B %1313123B1313123B13131219121312191213121912131219121312191213 %121912131319121312191213123B1213123B1213123B1213121913131213 %1213123B12131213133512131213123B12131219131312131213123B1213 %1213123512131213123B12131213A8FFFFAF8B848A848B848A848B848A84 %8B848A848B848A848B848A848B848A848B848A848B848A848B848A848B84 %8A848B848A848B848A848B848A848B8484848B8484848B8484848B848484 %8A8484848A8484848A8484848A8484848A8484848A8484848A8484848A84 %8484AE848484AE8484848A848484AE848484AE848484FDFCFFFDFCFFFDFC %FFFDFCFFFDFCFFFDFCFFFD99FFFF %%EndData endstream endobj 789 0 obj <>stream +%AI12_CompressedDataxrG&?L&cc[UI-Ȕ)`Uk~{{$pH"~\sy{y37?wy훇{>7*l{d}1Qvgj(;7_9n~{og/o6Ϭ>l)#?_}|[m G[F5:gtHl{+3Xr۾G7N݋_߽8ys~wswwn7o6xssߊO.nwW/_]?ݼDk㟿(rx|y|ov_7GL˫2J?߿yzĄi;y. 8<|s|xN/;~kCAۀÓeV;qqc} _z%vTZ:gtP4f!n/0*!C$ '%*< xRb"9NJƾwXY:T^ŽC/F/a8:&&gDW Fc $do8)'X?B(%NW| kU͘:YQ~~ġ m]3_$~V,f?t1ZK <_zpzY=, O= bJ\ +Pp)NN_Dm .s{MGqGMs;18Q(\0lT󴌑LX DxɟT΁1vY㨴e:Ui94q +q1YDghx \a^G&s12v8R\7<'B]+L QE޶n7"y(ż(\6#X u@?FVҩD68ę)]!,zAIi2ҨkNE%ȃU򥍧/QdNd)lIg~&6N(L).d1qټO0>> I66 o̍ac3n7ͨYe,7n jHbq>&kͣ4@g2UaA2@1! +s8`PQ̠&DH Cr Xu<I,`쐉df9вVU$x8bbah1&2"<0 f웿]ڍL'Ev5"|q,mP 郷9&Xu^H0qbm , Ҟ$ l g@]g-mEȱN@6}^D*SRwDnP"K,1*hwQ# +}C.dȐ.r$M XZ +qƤX@l4!nv"rv'eSsuVv.mt ,S ]k|HQ5J 8\ Xea]A$Ab$y3מ!|$< >/%: E|;-YBycY4șp~t>˙><*Y$U^tܰk91H)"߹ Y!E +֫wQ$nX83/uV>ϓb̀; {P5!Yp$2K,7WGQ8bnC713pqfY8v,Z6KҕYbv?~VwTjT{o~{s5ƨ! O_\bP?}1'}~G-~Bt|wÛH.~(j (Z⟩s+k}<ʏ/Z:(겿5wi _հ<$4'F|IXA/W\xo~u%}|7[󷯻tf{z^r\WoSd},lW,ы߻2.]ġ">\_L,2s粘?W/9So\_ljxuGdz!"n鸣~uCP濝wݷBݿ< 4l}qG6k[kY*\E4~㓛l  H<˯1VݷocmFsY9Ϸi]~]c9xŵ_: 9W7/ %o_ ]ξ|ujA;ή^O +M{{Ea{f.z͏zw,K+, \ݟ^wb-^/n> +J + _>|&Q g{uw/~Wߏ7wbc~#ϧps+ \ 3 %y9UPz?T gXwTahbov|xC]nzq%j~j|wˋ7?@~}fonbL)u|%~yVSP#~5}V^R _U~|~ӄ݀z3U&Ϟ<+ب';|+l?\8#_b[|:i^&hWsoŹY7=OF05|۫W8O6Tέ>g7{$]ASJ uY};}ttCi$EHV|I]9i4RB$AҝҊZKi4" H! G~ՇMٽ=Khl4]w>_K&v<\9j00 a Tiڍa@nw{w{a?w_b9;w|8w9__J/ե[$u.G$Tџ,Z4WD5!H]^0V#$LS|0yЁ?HI!0H!a=]iD!a/0?9n%; Y8y:7Tg^h9pR;Ei8%qcF?b)k,\+}nX*b,Ў ycka&mӣsl\DXhl]v;a؉9i  vB~hT#9vJg@ B8# B4 +!B;)HB"EC)RGwB$+MO4C]ނ|n`0Hz荦`'TV+hrO3ɳV1t f4KNdύ}4=%Tioz%|h#u΍?Qc94sidɦM3'fNΥa S>}Zb#c?LY濞Ȓ k,Vas"גd;LPH#Ug.?A{&HI;DGGO rgSqt8@C3{v(/AD3@8~,HRi{h6\#: +!x.Qpt.ܡNn,`O#sH!HSc/pJ3t!8z5aAp0qD_|QoHp?{qaНx} .>F(NsH1)2ZE@cdX: +^ÈǒBaE~8dP46*n!KY9Z ++w\B"_GCc-YYM 6Qe]YYNL."}`u{ӈ .deADV$,sa X~,hdz^sCa +(ܢ5`AufBB[&ThL}e*NL\#0H"cjr&j633g;]=inTk;3?T+S i!p:׺K &<+Kg9j8v)Us_iF+526%')kyE:HDzץ9\t4a:*\pEsdl! y4V:Ɏ+iJ-4:/#L~6 a"M}y^4]vób8vCٹEVN8Hd# G.of "d"ߖcd#].E8df%KRR7D)I~CG=hs1)s⧧/t(yE-ҘS?""ErEE2E.uJKϩlEsX󘺉iWH"""N@7S2EERE甇K([_iSiy\rl-h9-,~9i=r4-TWW~3iG^;ۙ\!ͽR 2+וf^<#O\y̚G|fM"̓QOsy!d~La?0dG+d.d`2C'}wWv}+Oa$/*qp  4oDA;9VC2gDS0Φ+˶!WjuR vqgRֈEeե9}RleNfLNh;X44R<&,v4ӝ`2 ʅ *1nbv ɳ"حCWHQĂs4Zsu]JbfJ k9DN.nSgrw5'.Y +(ubbk#g{2k*&WLQ 1L[nM5EBLwJ#' +9ZRhQj7~fOoN(l)sNKfKHmq+w |!Ȍq{RS.$JR&OtP%6媋INl%,` WƓi뻅&TE&u?kUc4IE''B1֐򹨧pNqz}cJj.Yjy׻9sUJK{) .)͛t Z# ;ݴ/"!$7+[ŎO YoIҭϡڡÔwlQ.=َ;Yi՝x~{8?}|E'yuH5#'ё#Dn#¢'r8d<^H@ u<E 3ʢ t.ʟ(QrIr%sQԉ(" E~;Uyˆo7I0‘ȊphA\J#dƷטf.D\:i`D$FBȲI0b&ʔ?EkAcD%4eq@}Z}W+AP n>hh3@*]b| E ̶"c=-pX,eQo|-X"! q*$f-b~F2k^-{Z_p5ЋMJ2|y뗟w WF %i(ox@r˩*vlbbm}~OY:1suaYo#sd_J3 A'xvMk LtJa(RK&8Apt PbU6 D@Jw +jS+ ס.&?%6o9Bp"'p'l\$]sD< ТҴ?%'3rTQCd*!rt+\›BWpX fI\4МŢxUl$~b^CO) qpGPn%,@xBGfSI(u"z1 )"F1<r_:KMv3$;Fw{B03R+ frИ6mxɠ4ܟ!/'`@]GE+ce7F'hܯ?e槍1aOkݯ_K%pHMhc:Mhq2H+~:(L'gl=H"qO؉DND2كIJKԲ%,KN?z +jW>!]wgzRwcd +Lv,,]%U>O t<etۥ`΋$aCEP7RVxH K)Yܠ#Q/d@5K`wQus-gƪiZʧ`sޘ<8Z։Bx̓t'9V979y{IK{j. ;~ rєbxlOXyBdġ'[LWJ +2qVN >Z1hH7>. yZI$U?~S"~gʥ&ޱ͑:6 8%O.|k苦^u5=8Q[?'Zބ2gxPhc@R#oj*?o-略x񞚋ђ%V!gټD$foW! yY՞}3̑]wU\ +$}lή8 's"IH8XKINpi!ױ餌2L0uφJ KuH!!'nbg&@zMPn)0SrS”8B)M?hۥ)]"?C ktxG{: /BSJ7;KGwf~14[˚uH$$q[ن5")6A+ňۋ:+@|ZރZt0.{g뽑P~ +̟@ZM +ըMXuջ]vo\&K68k70̣e}WY飆cvRA4&~ Ttr\TZ뇂 \3 ̭F |T J4Vx +4,ix +$UVg>Nف ,BqN뱅\!}JDW?ςB)dv)ZOu)Qw++I:݊0R +0IՐI,^Q/BԾw8aJ5nJvN]g\R*BfS)|vxH&3tBNi=aðM5' ?"Sœ\Y[CҽtOFnRy΋LgUBmbU,vy~C8r99t'k(|WRKab;grHr^s-ODRRdT)Prrʉ1P^:.<3|dd:Vyt!]@8A p=Q\* aGT8$[(8T柩 +hڪE@Ijh0 +Sp` )XAPQ90*b6,e|N Kb%AF&SwѰxY[Y;YT? |HX뢱biK$EZu?ljdhvg [s k!JIKޢFûփoǂ7!'O!emPGfɩd9dO$L]Hd +Swa{+"ke{z Oy>?QƩ {DJ;IQv]3&++&H]~a݄[>5na1O*fui%'CEꓓXՙI쒶#$ҔSuiJx Ҭ)B-wep.NJIB BcỦ4k†IK-SXMO-?ӳ)i >T'I;2%E1\7п*S]2 7<̮sH4Vn-Ӆ.YMc&%ULTbӔ,(L>/J(MDt*SBޝNGi + +|ߕ'6R J1&",3:eO.D(+Z旋ѯd n}"2"8:1G|('']hD;ޅ\ً돘.t!weFc{LyS*fAJN$YN*RY +$5ZtBߦ6TOdL;ON){Z>HꞞ?LYvHݥT $1CRT8/zmM`c4/nѹ ݢKAľV^|y)q%HgKl61\d +;d/\ :A5k6u͆efWWڸUNXʬuʨ0i˞՝2g`:tT ]MӲDYFA~ QOp~FA~ QOw~VE|C6`zы1YϞ(BS~ Ze΀ ̭2>Әړ_J[Ԩdge6Nm{P҈_@j˘c^ޑc}@NU1|_瘾aqP>HЁ^-&*( ^I˅CR,oiilS=j2f|*!1tByE>b;9dR&!NE=C Ê-0$挟o0N9g(B@8$,Gq/ZF / `BUQuQ\c'=Y;}* JczfC|$Ew;oF(Ժ&)JX݄58$?c-~bs!k| d ڧ8 alÄݧZem./V~G^dRF.]]pC貟O #5t]uYiC\Pώ4kk,LKc !K.-u:ݾ ّ4ϑ}Nq>Fs0;10" 5CKNcIy/buf +t G'ta!1N\s`=8?a-'"l\3;KZٕ7(9Tي 7_UdNM`DX/jY*kREUnIU #T|B/Ck%R=Eur(Jg".# .#RJGWycٹƸWO:2~dcIB]wNŕ30{U,.YKТpZ#cWd9jc=m-GkyHV['Ц!j|_ :/Vsu"(]&ز'k.:A9A B*` Y{ED(`,-+e[-\/KeԲEWOhMS7Ed<5ޏU s0j WMWd7,n)ZYa0l-V\9F tvr/Z {GR*f4,nlxړA^o|J +_0[Z>sUժ$2=Z& [^jsÌq",YJsOV%O=%5.]8 )D_W)e +AcyHs9m`&Ffg&!i|h|r41L7}}-oI#V7#HE,ND{4]vw/0jM#zHO۸" &I O#BiBvljqK4L@("|Sb.JfTz-Ѣ)Oy.Pڇ_Rs?G-/N7bqF7JwyU=IbFhߝ+҆dӵHi2w\wHWȅ0$F0`'?zzʯL"=!SH+UrgggW<UhXbS+FC79y? .,0b7:KP9 w/yՑ#Y|Ž+Yg)8A79Z3  g K,88̟h~f5*90/RES-BCpϩg&)g{I9c:_t㒪eI-r=|.Xz.qru*W0 It!wR fx/L'd)I]#R)䜵+S)|JH$1).Ql6HXmel/'|U. */*;*ZסWG ѯSN8-\~LJv9~^pdBj}Jy̗St|%0]7_ϗWB;g!*8Xҧ lhpZ'o)|_kqJOuX\e^{ҫwδi +O!]O;t L}3ҼX]AC< 4_.wB 5r/>9)G wOJi +7JsTX>.+Ч}#;rYd]YXąGnHʋ/$D- )CRxpOu \! rqGxB/bxRx2 ~Wu?o^2]vHfA-UK)ntTeL}ccQԘx2JXS"QNӌ8AIsX.q$2ФW8gs [pwIAVw`jl*XXORm)~[ +(?W ? ۇ=+E|c⛯w7?ysQ>c3K+?`nh:,ύV~K:)vG刿?Xۏ1qo^/_꺆+|?CQڳnpD{r}뇻`?㋇7 V;ȓ/ej=x=d訬g!j+ƶ~@P}h.W+~1IFmvٰ۸ak Ipi5#$f ƍXгw +*zР AA~8U 6-(U 1>[X`q#{6vBU~hnقTڸAЄ ҄.!o=zeC; v ĺF{7@<[72dFbct_?^΢U  +`i,tP\>l E xaA]C$ m4prpF :q[^ј5bA$1lEq[ S[cQ1XhڳI~km4rXާBv%hAa;0J?P :u!hXҩ L@3ay7KɀUDCN@y W +Y 0L2* E +ıW:=V؁8W= +ۅAS^(p,h^ :6) +5a6!$'IKNhA{qIB^^Ρo,\86Sp mǼ +]J@/]P`o@x0؍MQG",Ka!l2nۖ_L[Q=:S5'-."[L>zƍd+1r/jTZiXE\_ViVꞞE5ԶXXNo`}5-NCWL<ǟ̌|s|y|x~w \˸Ϳ 0x{-א=ٔ 6.F=c`0.ZWMb\ #A $36%CЄPAR P~ Gl!&@YP8)cq tjzՄ^mh^ )~ ̷4&l&3v4O\ SqmrHMV\JߴR6x, 8#+K#B/xͩILFOOşXۮ pОe~-쨮YF,bx<.(!!CE“Ib!bc{Rq%,oC4p د܉dv{L@-8, hH t();"@SG/9‚#e:Dy-Q6+.1 JQO"5.W [O7m=n[^>M_U0U>pigW +ti:3E `@A A^U8wB60Q@Rwv"V*h&9'#BFdUlHO=xkBfϙAa!Z@4S^8]KH'eZhE4t?fCQ/݀%t!Av~ +&EEcJ 48׹ {a8 E]qrƋ:&w:w$J1pz?18ꇕ=N_0vGM&9p DAoN XL>eX I²&Hepߑ>TN +r/Ip' +Bk# + U(<ktXX#U9Jy {0 x"qz`Q8{9}#DQsnac+`u1LӚ5)0߁a gh!S?N}Tی0 "ւ% +#0Q9y|T8uA;M؜ ЋE9 Х KNp4c. . h"5XW}lW*Ea|j_&U[O2r+LcSWuO^_^N s2m#Z$O 4S`5<)\E `qZ@ђ'"ڥ+ I' }v  4>L#`BXy!nfd~ҔD(N`h)1d +ي^c8l![$Ư|̬J Y<:?шm0Ճ0 Ähr@PBOct"x qbTBj !RO1DSVNXͯQ)2\!COMݴmb+}nT5cӔBݖG^$~[ì 4{Vb v(w811lׁ`(m|Q@KH~(HC I9 ߂ɒ "K6WQB稷V43),CMX$H#JkE򜊴\raDfJj{biTo5DȊKb]эŞB^SPaI3(@A+Han^u )ҹYQZ HjJ!m=Y$)@0"ZKZ.T.I2о["S!ƅkR18~& +TiFW>0j`*trr \.EF2lA^Pgt9 "&d=c*4&})qX!g2WT3و!( JVќtiB!:^+ZS3c䄨ҳ \} ED(VztҖhhiƒNj" S4(lyTu'#k1T(0nMUPJ9s)MKQ(J3NPU[k@yEcۧ&tft<6K'a Q'7W'4h6S #Ew%t:C5(*7;6=jkm^BR篚Q{l 0*=Փޓ9FMhYsASiF TzG& `OI>Ԓ }L&YsCJz9 9h+TRcr,Z - 5aM @(;NfƯf 8X5!q%8[M(%f0!Gz bٝ;ixGgyF劈T)kp:JzDQ)Cx^q͇C6j x2P< 3C;.$ѬwஈLk=8%|KÆS40&-.vg b("32pMbhL N;k(ɘZ|gzd%h# +d{{.z A~LRN3eV usMr a% +/J֖&GէXS`J%MmV+ծʑQ56M96myl>9 +6X%#/lx ?LK5)UQ7T聎'6ලNPLA3D¨k1Cxzca8U3ls~DGNO>hu4(J-6eLH?7N%r!;YEs5ń1 +anLZӑQi{@tJJ:ɪ~k+yB)469@B01H\De<%_$JvȻ7PL$9zC<1PkB6&wDG˭6$e|4z `L łЧٱ\+͑Oߨ{H+"v$8F4'txp ǨƐ8֣Ky'Ũ%c? >@ N1JeF4r3E!":q#ԚX-Tin9i:R2tΎ1>PTS:cu>jNe-)Uy)6aPl%1M!HG)tb)Rn@4J +k̰mT/9#jҘ1vI7AXŔ!  B(*t:IĥA L`P1XO.{ U'5;"G$X|alv_+'9ךRg:3-cgDMf!;UkrĊiʩǶi#34!A"|N!TP!젚}K^.C&:"G|88$MBR_ˋuBÐ6C Sa%zHEHG[ % I0-xmSUrMU`4f;q!B ))&AA81NpR~Z6)p']7DiZhhÉhFӪoi0nL ENɌ'"jq;ǙXzӆ"@Bt\B۾{k^z8>jz$EݢkDG# wx^,k*JSuֺ5R[QvΑ0i˩>7 Y!e -jl/uv6Uc3 y^jrD ik*܄EՁXA 2 k&eBoE'tʑՐ4ԃ4)µ s[zANz: &#`1S'2P' +=Qfh}nsDjsʳbLcX JuGE`zAj81bXBXvaGu +|݌dӀGgS4z6!H]D18Z~)Q>Tŀ#u ī͔pU08%ҙ 6+QO^K:<Ek^An|۠䈢t ~^ǀ6/*Ip-3fd<:C*~8w"r&DD ф[kbD4A ~5HD& kD4VD4 M(&HD h!jp&^ hX x 4#DkDLaVCM:HD DkDH~Ml)ZH)_ "k@p rܿ&C{ȡW<䘀Mt ꐢrh֡r&C? lB84[:j [l7W7a u&DvFBpXUNh5ꐀ1m1u,¶)m+ M[ uVC84#RL3uS\[ᰒ + M2tCprROc% Je4)C"z)s3,u51 C$C(h#O%~"(HNOAK:7RaxQPBefQs2rpV֖&GէR-|xq-I5kjƦ.ߺ-D;qTu('p+ +ES.hReF1{#˜iJ.?ci[aqF .м"!=\&^,a¡7+-JˊHDHfۣ*G)Hy3My 'fABWEˍv hWv@ 2[cy:Gԡ\Q;G|^Vb$b +><H jBrĨti@ v7jS=9 y&CTxHAD`osT>U!:44E[@e6n_x204#ٴt +47K=%$!DQĮ'KMϑ}<kN[#f'pϫ|QI"5-/qnȅRM5!^aӶ-74J/!HهD'{H՚RW/1]xF26ɑXQ FkL/"2&u XNyj[,zM󴩄qW^de!Oފ 2f"]fܖx+@K\Fѭʴg!(Iɑdޱsop[h ɶmirT}gr+u0R I f(Cۧ*G⪱iiƷicks՚.=Q&`km.WÆ٣j>glѯ[L/sGߕ_ \n1Wgor1(@i{yXԵ7sĚ4ݴ屩dTHd=|U++%)KlLAU$Mꓘ2` W^DeBD}IE~d?ք&GՃvr놚2tyJ"VЌDyĦCyD ;Tn@شL\rhIW ߝ_Ȍ/Xb4ŏrmǡL8%w6b7\>Z/u+OF3 ѶXa^)ǿ4l`DUo,9޴הYA*&:cxaā8yScho62ϪʉhbDYڴAĬDG1m0'V#m<@ane4‚6>XA%AL=D#և RaD#!b/@VĻ֏ѻ{ >q( ^:b^5laYu.ޜ=+'1 }x}]b% +5Sښ[kS4 +U='Q/ﳨCpEEikX +'L!}&g8_u,*}W$3q%@H.UK'(V _|"Y{ӷaV}Ȋѡ$l_;6RNݨJ:gףR޵w^GR}ʦJ"O:U)缉0E*_+=mI 'u)):ƎBiHQc@Q^C +Em,!eJɅO$U(wuЧ͸}Kr%d.#`P,eݦj +1Зd C.* p^2W]UTK95ؐ@xIxlki*-".zQ%1bbd= Ő48}d,^s=÷1W +΍#stb6@dLzGooi#KRMTpyaC0Vi:Z*##/c A> b;$[K˾DOˊz:H9\ܢJ9nJ9l!,(bI5]S*h pic\vKpb&AE&$"H94ƛ9ϱ!xb.Z b!1S|DU}[gStgvHScWxY<_.>j0=_,X$zʰJ"1vqh@ճ"lkC +kfp7F$NLaZ!)8H4CFЧ8@HxŗrHܤWr @H͂ե4Qˮ,Mv|3dc, B4#jJ bT@oGFfT8=ueX\L-~CGaW z@#GdL=`a23t +``f0tLUdbkT(hY&MXZrg9Z'6 LYȏm1!k^仦Mx5TajYT^xr|HzQinAu%51̋{hhP턤@0C|&Н"ֶ$B1Ecҋ d Ic^~bxFi3*|L%ŷaVj X4" @rT"%k̏Vd@Dך 1o:]<܆8"/=t*㳋^IQ]M hrK@Atdd{,1l&dTb|d:1 EE;wD}c(I(Űwu%ǠJh䭊St%A#PC4ŵ,.k)w0kOPu.%U^g[]㙄չ x\H} XY/p@jH@1;_tEtekj@i|:I^vȋ=S$I +=%(SߥVI9#T9ѷZԝPhrb x(F_J}s3m`qh!1Sipbw'X.`A(sԱ k90Jt4- 0҇a0Ϩ!JS4BF"^).xW<leWe g'>bv6 + Z3pdt1_᩻Z+d#0°MoxZR<)hH 8ZfIXtqs4HI +h>f蠴L hXCfl_f|:fN) ^Z[od\8 ll5Md1TG,$T{@s+_6Kӏ +ĥ &IǤ;Ӡ{( _A@} 8ИRJ%bVgRH@F4@h5ɷL<z|\*_vMNx1IC#>5U3p.ä}B)= .֌p-MAYTء/c&hzl|7HIEhOeX4:[8-Q˄)&2XCɼD s'chwp.F#Bj,yCܦ[Be:IkQC_/JC "]K"ZT#cWlAJ2LV! 4pF +VUpDX+ nƣ7dF ete mSKp|42ZoQ9 4( !QhaBP97I"]jDKv@Mˀg1Oi^2C6TX7@LDar, N#xĸ!_;o0I{P +;"uN`ROկ4GGD-L 74S4-өɣjRr=Ss2 THNi +Gߎ](:02ccnn2E~b=>[o.R6E8 f~4J9"~ n~4@KO>᫑!0tnur&ؤhaS *Dx#PaU^T!|¤aoڕa w=J!.d{¤+knKAi]VXBHI@vax {8I$O|]|N2pZ!86IaP ?AT*y \8 tb<50ZBTQHU|JWم>?x~֡p."fdZҋYL&k>E%2C fuCL(VE@~^c*Qz$ Hp%{%eu_)B :o? +{s@dlvT:!ٛhJ~3_GS^{ ﹆][T} I} +0Toa(M%JE>*HFĕ" cV%hGX + !$K![03 3r^*p-26N%ضYe TJri5t.sr$dSa7\DB!:jH Gl2kj56ZE-LWӯ"{3vZ[Ÿwr Xb&ɭvz*FfW|vuFNT)!FZi)2eHQlxE5<蔎W#I4DjбF Yݎf--8ps ٱg36{qh89E\Ahd/(\-aa:W۵ dqcUXKUn*r4P Jpc]exGx:@]i4MZKQTb_- דmeg Ip:$ B o`܉@p{0 &ЅID峒I@F 5/4ZCc[;(:(:bYI;(5ĻP"aES!.6_Y+GeOf$ޔ39lxh! +~e[ +`ּ(vGB QXF#~bмY⌕8*-Do ؝%v 0B +2.jTv?@!$$1:F06$m/8mmj/p0:޽s+ +7uz`f#P1)' -K|MF+kE~61*4(I~BR<㹁ӳ5 p*Jx5b^EVʲrY ` /Ge1ϬS@ϥ@#2XmM:m$#I/vͰM/Eܷn /5N*i j.ʩ0$oO}ڊɪ-6m'v%tŖqb!̟ۡ6$pI[FLAB!bu!|Dz ; :ѕ,I&"4&VH%$C(6{p؃ɴSc^ҽ; 2'X>XݿBWK2wX4Ĥ 2bx8p@i:.N,=,]nE !!dtp}t,ΦFCGhHXD砀\!*e$b%Lz<>noC3^mpR٥d9>=oeZ%@pllV;|Xwex_Wj,?mXӅߎgrb ׮Jl&•Ų .dhw~%h<>j!iGs 0!?)Nn$^@"\L1n`;'% `Rȇ{:9$IdT/5a%:Gt*%{q^6i@Lap|/mz~s^/GtH43 =F={ȗ~ΰw{c ɂ{5 d@ |lwG.o.GK}j +m A#_4hܲl}NbXV0'bRK҇s2|rX0KVw2j&@MQ Fwi<'mnf¿5\b Z.<x: YNŬB&}'d_x+D܋ɵ=9tPXu$y(A6RHߋqڥ4y.n~K4h +0+Vvn: 2{=~ugQR,SP㋐avm?PPB$*섗qG&O"N48trRpjNݐ/P@9Hw Կ:2hq^>ۮ];6>JӄQVK@S/Exa[`D.jm`$(9U_Jt*qC\(vCilr4dAq jUHzGD22&7+S,:gPp))MɎ̹ |pQgG ( +aLXÀ?$a1ײEK%I48'#I%EwpPևn$ )&GpY핛l+dl7( UXfVB;xNvUX#ێ 8q;_jGPRU1t- +~ys׋F CH(bI aXPK^.S]%X6ꝲj~\}ikYuO!-mmPpJ*d KUugS>eud`).4)~% _E{Fr +ktHs5Ū*к746E6\PIBCG23L#PB#uy3]73u|QJAER7Ʊ4zb0*?kdKݨɨ6%4/2qU1VΦ%iD.K1cZ%S]~ۿdh??/HRД𠩛)A|AvCZ!+`]?ƙPn>p,1$t Ա'rC􊩲{-sGeaBQDSޖ܉O?ޒn0F葒z#I` +wZ ]aQ|y~)8bI<^c@1PZ8|lnyfF);n>+o^ʑBH7TLB9i^#^ȂV;WS `[5. ^PI̻1_ܨS};HB7-ڤZ!ӣۻrnQ5j;畮s$ER 0Tq9؟HeTKu`]`S5R ֋wJt«4:ɻCsޔ*[$qO8j9g6iY4j0_v2!0vaX& NADT^`Ē]Mt?N1ي++ } lY.wvB>_D`FGZ%ҳ&0ʹӍ).S^➞#j˵oR阤e|2aBH'0:5F'T!~fC5j.)T`,R3_Q'V%戀M{׮> 3"#=2101{<33P‚^s%(NEޥ9Ћ(M;T6C&2Τe؁>Y":82 .]60]WXfԭQNot^N~s 㰊WgLZ,I J( խjAN 4 +0DV۫3Ma#0ĻqNQskn1|>hXhJYPR:$U[ŢbÚ +>09rhJr6It Qa(6Vߣm bI +rzN_G0(}Kw]~*Culky.Va%\][vj 036,dEO4 2|~̻&* 8jWnj | tlBV(_#>]W[ߚ@dQC#`gCJtuDzۦH:ɦH*H݂n$n` XMQxAw'ٸQE8n⢢vYB>')p'LNZ^Ҋ|R"E6AKᴊ/MlǁW+T]Fá@1"ihPzN5ax)b,Ԩu.EHw(VK\JC4q%@#fu u |,2aCW0g2J鰀RJ'lr6xd]͐-غG{rX9d!t~Gq#/бH&p Y8Ա݋` +q"Ur(*qխO*W$\ B'|Vl?d[7U%U]i;N2fܯlk׷T8Ur!OG1j=Er*|ﲇUFtঙ,N|a2On !=²j Au^=8`_wո.MM%$nU-c7HoUZ|˫ PUHmjvl +4$@(*as'|]$SьBe|mBR? % OH٬w>-_ctSnSuSlfpxEn&'ALNAy+_ 1_602@E/GZ$U*[3!\1 M_SmA9V@쾰HL9]]ZppfWQOLD^).6"z z.I? j {m1B7U+b"1J/K[5R2~,li>aǡ4Y8(}(%H97 +T*JR VdwbIg*6"*qCbk*j߼P[U1ijen}6j0oٰ86g5›hCk)A lm+ŮԴ(, k, C]l`(;~FFO"}(dIJxTj-*.TƎcJ|7^JZ&^DnArUD_@MbGw0ݓҕϜbIS0\؋ +¦&mw̝NWZT&46RhI;̊k"||-g5K Q;}N7p̼F9K㓎WbNJ +*c[N |I̽J [EZѷ=7wbi!(ewS/@52r"yD+呁\[D0\Ǒ(%_]A4ɔ.ضhLa,7NqUI@nN)XJ_h))/\e` $oֳB)R|$Xxri7]8# iJ0]IZ^1Z%~`j˙PU 8.LcCc;p(H5!D2E]O}n&ڣW`y0bֱ>Inef ϡ.W=[e ab!nB`<o!DrG:7k`qǮUVw(OŅpci,s1Ui 0=U*DɜhB tru8Nh࿁l @AS6UoR%cnv+6@ +{adޣK7Gt;SC r6/C;X LmFA1h(GA + l9aVSt-1B,᭙swؓ;'ppl2gԕ$\3 9M*Eᆉ/0CcU}yZt7<9K٣qPTj  7[uS]$[YgGѮ= +S}1u/WAɺD|Kv*3o= , $r-IzD!tuT]hyi?a{R Nc6`'e@PX5B֘&9I@!&'JyPcm& lM(STTwR1S_U8d$ŁjрD8hJC_Xy=EՍUeHĝӖ@kΨh-P9;P&{Y2 m1%:EL쀹G^ؓ7'Zu!yXY+2q:Cx ^laNNG2h'Ӽ\K<1I`7eE,/REK9KLք 1a ؕYG;zH6g-SF"{>f7ChU|VV6 lIRaEXm.Ʊi2 /^s8tͲFovj[5= ", +k լ^$M 6S[!#ܨ8ب ]UֆhV4sᪿQPŦDg.{CfZ #3{WGeS`}gfbxU$jO RZxg.s ?bv2e0e39m:-ab)A(*q2o,{÷f,{O2Iрz=hɠ:,&H _6{9@fSq%, +plJ7H a(K{0 +!1Fv*\{lũ 1JnЈtE6cU vv~dR)׶atB|zOKNPqDFo g6 +՛Wc꧵}oqaK,]ߗop©MK9jBg\\p%Ho[iώcGh)+bLfY!NH3U] {x{m'8_TMۀlj֎5K4 y.';\*ǖV@Ⱦy+_փ"a5ZBZ!CSbD|Zž@L (p.O'I[xhrP)V}Eĥ$]_vX +|,BiY+h鑫{Do]@)(fO,GQdǠb0u򱮸H=aᰟocΔpېyU%$L,pM` bWHI ̤e7D& `@fV%C9POi;fF~C 5#pbƭG.36g$}{|Pxy]ѕI~9;fq0[zBEsӇR`:/W #L! ΍8Vq^^M*?{IVOWeëc2v_yߔ/b ~ָo4(HBVoPM:wMJYH6=)$=aR=dG_M^HZo;-[f^ .ߥyھE幎 +>*ட;81iyX8:C/xO2S/ j2~'Q{VE8;$e̻8Vw7sٱQum}K5Vpֶ)>)˜lM)LT}쫓MxQ.ùءYh߀g:BT\'M.[Tȫ@TU_zQ?rTԹ6)Jiޚb"<)5eYXP4o6;Keݚ6`HRRyIBLi@d°Ѩ kVFwjBiV2~~ wH@u +jOK5HF#$G ]CրEP>֚G I X<6<Ul1s>ŰMFz?'h[[TS]=/yk&jTnYk~[!]đo Qb(oBsAn}j\Sm[ +FM3_)Bͭ4 +btoJ<9U3b|Pԕn4U4OiQZdM!#-ĢnUa-`3SJ.ZohB5TV,ogTw.l1.sq +H9s*I嚫UAԏ83E, M4y!кr2xO) .FmM?qB{ˇǶ+û8JiĔ4Qٲ?y9%=e٘`;2QMNS1c[Tv/-*oȀJҼ%a@iqI{7zl GX}jyU_ƀCڧ~O s(_laQ[i8LjDyO"%~cG*zkan-164Oi~AÊMh +'U?%?|p:a\ՂEUM=X&p &0ɪRF֩>(B(T]9J rUl_b,O_䗲oRGЗW]o:$vA- |XrVe}v4zae79Ҽ.ZyՖwob>Bsm]SVF/XxEvO>ںc׍"aO%s,]F腈GU rTrڱq\ڋroM\nGpYo@̤fn! qTvǮ9MM0ykڲɉتpч-81Gԩmy ѧz Z0͗?Ғ.08X)*mn{ehoUZ@{9bnhS_bѠL3!,G]VrA#%>9,s,> P!-bq%<; oYigZl*¯[|@[`ʸUhIW)ǾsBpղӃGn7Z)JBn/ZJ~h>$h9 LhԠՁ/aYh-=[!(ҢՇXzP ׷~""[x,Crx%?hl5>PՍ~hj0_%V~֢%|Qo-Z@"O-Z0R=,h:7ƁҜRG:oIZ|⅔ZYKg`[Vw"zYVR\0HVЂF})Ѫ_GKU?0 :/"گK,5c~k"2)zKW"JdnWn)H-+'HiKU)if52D\zD\Yp;Z"چ!̧%1!"z[UIY4SUI=j H>bjHR6L-hw~:E#K*ᨹ:!׭N`q&\P>b=t+oIշwoUWN c診b(yK(T2R%eTuUxGU2%LjIVuAg}ʺ( j[U GJ^uUColiɺ^A9weφe|ԭ.!,bl[CW4]zկdsƯMBYqb<' &JcG9O5k^*,%0u8>^it)¼nW5~R8\t^AgkR FK>:`=ZpUir,JҒiLD` +T"U Ţ",NUOu؛,U) ~17'}C T`S:q,^*K Vw$'?`)VW@g1X=Nv6 hR-`#gXʩ%"efگYY*>2GCU&>+=6wv>_yW=I ";W|wLw< + SzbP,L(z.1A{HOtܒ\+ .pm7Wּ%_MB~uqP7Wn +ؑ|;QzN +;*H +Xǎ䫐Aܿ^6םcT`G"q-ʟj+Ŏ/ݿ&˽*4ͧ Rx +WuX-IR9GvQFሬ-d[YOO ٝ0[̗r!z:qsFy6H.7x`!HW&z$ѳnRrr-ZV,St ¤c=Rgx!2dC4\";4OQ {[utƨrK]nEQy)iR# +'[,*7P~qIu*|hDHKIyԍ[s(yk}e|5>Hڞq%%=S<džιV"IYN&D) \||:f0?f͵~OՌu:T炲8HPҼլ&a+ G7˼mLHPqLF"Rzhb^bn)L#*y0E*fј&v PHa +2I#!.L0l<0%l0 vqV45Yn)LaƇ&[%,'fuRKrU%A WڥVwLoK;bbi}7ÞoK9"zIQ2"Mr8N% TX+ӕHn{)[.ѽi*$R0גNSi 8I!ITrh{0NZ84eKTZ/iJ, -y]wkdG0";G4JF Bï7L%0wRjг[ +S {ڲ\s38C<=Q/!2O> +X&>u0 0(早U15#MJU1Ӌ +IQ#:nKtǮL]T$X 3Q =qBlK]MR/OKemP[RK}eK%ҷ$8 TZ@QTMxio"PD8ڕdHSX&*EbDI*aWK *ѣֳ;2SY>9l[ӼW[j0$O&NeV,9v)( >#969·!1,Ӹ ) )0+M5I:y Arl O!HGQӕr>{)'tj~ ;67QGb :r(ڶ#xVp[ 7ԣӈ ݧ<#4Br*csR``ntTKw؛ˉbo.@zJ7EȓtEJO|*Bu"%`C1TQS'vmL>+nX, [*|2@X|EI]J=, §S??Go!UT8OCjcCU_׭lHEXI p2GUlbk"?9'}y +G0Q͊B[P݊y +wF +g\_O +F?Iڧ vK/qKrNZi +@KJɥIAP 2tk~9&;*@GyVh'\}~#*rd*Y};o*ł 'ůO@7ɗvBAG#^6MPQB5w\ *vٟKP=`)vp(ΫEzVԧP:GSPi$_Gwgt.[Px h{TA[()>4kicUۀYMPpyIYVT"SkJ}}?ZX[ PE_*X$]S8 ڒC +PZ}c="p{ՠ[ +PjxnoR [ +BECfK uI*(7FVG +PXjhV}d7%@Ŋ" լGpjUt%g/@CHV$wJMP|]*4=΀ +QRxSDU\Ǩlhi`Rydb\ H =x)WD}h* ЇWM0+Qdt ڄ +77zi+L_aZLkYkSJؤkcKA&.1J5iuǜMOB + I4$1HUo?*C +Ywq1h.W>:$R2a= +AQY Lҳebf"_f[Oo=źmRCXD,?$c?o,B&- 0œIP ؛R 4Wz}j?]_(q([6/dESsOv?zߍ[pH&PP[/lElЏ<@;It^b 9vD$t&2#5~#E5VVnQ?Ro]gGOJ~j<}oCDw-',p:n1?FzI30 Wf[̏{#`Ob~4 <|aMy!ra`z CzQVSȃɒO~ b}?PzDc +㍥d P#ggL>eMGTUsGaA?C-vE}*oRuJ&"GTS&(fכ=ew`+te0U +F;^izyم$THkWۗ/t(o*sC S5~?u_~mQO4~!UO?I@v+?UhQOED -6Xߔk Wtg;^"p,"²O??PAb~+:2="~Z4@/u!S6!_BwO~Yxӛ6Qxx.ߢ}DEW;Z}$7G{#cJ7\U| -1%vV2OG{D'S +JGeO~]\q:NYT]Zz$9}JQj,b_+̡.S0cT0<26ixTK6!GU2h#߰k=]£Z(܂wTKuS S5ĭjWLbvʡ7;,g\#\GVժo֫Cdj7Z 騁obtDU?*!9WR pfCWI~rrJ\V#0CsUȻ=eP3xUr04몜ogKLܒf]M߬]FY3b-e``?̄8/exT<8{ +;[U&s=RdUc(gcd԰*CtBU17u1.wbfZ}-14H=%T]f> 3LX&:`׸E;7-BR<Ƚ寮E ~I/wC f!:ͩݬ&XG̋4%jbz)vny9wo̭PhMqԸW!}Ը.!z!c  6v7-EPƇV ,Ho9-̗cg [+ LYR[+6f&VrޙE+cWxWݪ`"E+x-dj"٤b'*nUw^ l`Uœ [ܧR,ܿͲ 6]8G~ + J$Sr8bSP}:SbkכHM!S2I|G5 +y#%Lr>ͲyRT-+E `[jc13,xG"q9"Ov"Ʈw(|SiSve&Tn᥹~4mƾ8rd:?α4zh;߅(nE,?ԕα#$AZJsS>%/VNU|QN:5xt/$vo @P1U $`и[p73/#GH!5n}#"m)(3 y.:lGh-s )= (Z¢Ei$|t[5A"6`C~Zjlu IOj61M.p#-KQHo7~uO %\Ж E9!DɳXC~"e{}*gAg YJ[,Ouj*_bA"4Te5A=my)M3}ejxRs$S&!gSxC+곆_qv^;mpbAX(V`4ė@YuPL6$L̺=uhC@F/?T%;2t8@T*8h:R4<&w̴]CyF/A°xT"=$[DBz_m˸(o扁N" t;T8]'}|;_`-G*l,)UK<~axQ@̛] fZc!f{AsAaXpPiS-ˬO/ 8wG/}thվ\,Pfw:2o8k}Ii|SXL'uB}fJ{Il4dM}%4ab%\KܢX2l=tߟJNCZmZ \ 65.+(25DN4v.W34Ž=/.3SUGqQm +-Y[p9r2xr7aqcܣWRȾ< +T!?ty=rdŊ6T}Ԍ9zw!zi1\d;51nm`b^J`{>">[zD; +`Sm/ܗDޅʍ=<*+e³u:}L'aϣt?: LNPNBe>NC:`"x;"ao;ݝLok:UZ\ȴXK; ]G׹7,1ݘ˃`E̺svI=P6jXP_Y.O݉ыi.>l ~ouVD:׳iv؜QtcT?܎~P0:D\M+v׼{aS Z'`4"$* :8OXT.Id߷ǥ‚6;]rluㄋ +gzWMY!!ܟ*xFU']Q axdNW<fn3:?8Gb`qT'cWDQA31~6DIE! (,'ҸqZz@Y(Ռ w>w/uB CFu~у%|iQC)YaJpd\lYyV;VK}/'w z9A~8y28@xۖ Zz5WC1My(q m#qgo` EI_"=kE'^OC<{%ѧ9ע~ɸt;:}ܱy3#/9 Pl#-F-Cd=N.oz0AƩ9ҁGA6+2J88I%.04/˞iJS>HPSe X/uj*Zj +Ȼ2~"OB<ٱ0jjYVy( HP 2!qBA&]W(KBC.}.&ܨKm N}jFCTW.QH>a"dzR,Mh}!UБtaij˒|%;ĒKV?J@c8L@LX!uA%z 9TN >~bw +5Q\Aکto,HgE)e\F%J3Y 1) b2j@kӱ ɫnL©K7@8 lBZIn7&&nlI +alj %Iq0T! * py8DӉb,_uCe&Q>4o3gu[K*BG>@Xq=TCL\+Dv<"YS=XxøէPKT=*iU1&s!|\Hy=OmBw%N,ke]&)%-å)0Ÿ\UƷ]jWjv݊ `nҫiF## CJޱh%m\{򤯶o!c6'ApMC0˘f$/sb\^k zZ֫ >ۋ]X=5Mx)EL >\~mxvS5MuS.u5T5 JTHU` Aeeaؗ&{XԀrbJyGX ?Lz/¹lxfGIvJx&U{EaEWuG .욺l5k 5`SX lab.A֤q%c3lg.Xޥi 7H𘮳kјGIԠhr\k"Ɓ@D਌s:%4J^kеj2gj\8&vq5Z3 4\&tFiY`N P:ND@vU!l0)]r/iR%9yTU޶);e! <e7b;{j Tn`دE,ц\mzf]LN~ tǓ8X,=:x^ݞPK+v%BpR-)IjIs/hVD-% k |N9!6‰0Tk~m[… )"?t~3}Ft`3&1ҋDwOQOGLj!>^a)i:`U|@둿}0qNDEDi ZV8V! +>s,zF{=ECUKDYUqê7<ɣ\9TڻpPtQ W@S:Iתͻс.ԬCi#EL\Y M΢)VnDEU]0쑴y|e' hK!4daQd+G̀ѐ/S@_2睥v*>˽{5\z'J4aHd7@:q]Q:if-ҽhO_^}I$9= raIAGɧj8Q~c֛N!P {{~HR"$ >0i0#Ja]b Ol +uY|Wl ڬ/P,E1vRy(J5|/ŗ1d~,5BB +qL{d7")1+6bSF8=:>6oIkg[ƞ1['xuKX/fj*NMF4Ƀ٪9#QqMm>k%MC%Lapx Pt[l]i3뙟 #yod,"R2~.=bX*GpT9<#VDaѩ@UE.nn0p=lTaD\2ec#kD )|`:iFrI ;jB6Ag =d@"DXW$M3@imʅj.b I򞅩c2xJ}ݍe78n˨? u_ +Sm۽QR@:L=`iTAi~&c6&f#\t!|)a6`e$^Eh`䣢N7r@}:pbʜ„hӉu1鋹7\՟m` dTi4]OD ﮟ7Sǂ5 0z)I4ܴK_ N4Nqj7@+'ӖqqG7h~iiSdS\Xװ')R(R ƺ6bUQKV+ k\C0l"b"Յl&3ȗ%cJ +A56j><~4KZ" ur`U v! +F))SԪg,ph8c7|)ҮR1,q"eΒCHiaBꚽ-*[KK꺑dս⢬E{Yj-/ pxLX(6TǞ_DT<.!/A~ J( r[&qz%gx-KbdoUy͹_U ڐ<=DGY"KԏFJ"P0kQ*I~ *Z? +zhJJPJL@ڋJq5eSHxiO5P;J DHeHX6V:+2:}m[V"xĽ504evuK+';E\JiL;UR0$d z{7ƌ$yC׊"f9PU_usjADݑhco띡U_`םݢxZ5%>8bΤp$/^/h JӒHѡߥ +YLYVZE%x՗@CJ.`y"zŰpU(Aɠ {L3ִO3DKJ'K 2ͨ'E8k 8\x?Ǣ?)Vվxӗo:boY +!Я4aSp&4p؄[.@$ _im3 ύ \& +߱D ,kz1lP +55=F1#IbWi'Z7-$K3*.Б{>ЭUDF D *̓d6T`%62-p@ G$P);A6]pDny! J"bdAuZ}|˅_rcgNs xf|Kk1yR3ԅ|pZmk/@/Xہ|>k+񎖾)c]=V!7Vd#32,,!d PoT΀Y1 pa 93(]LgyiBCYzoW;CETcLD+2ư "s^)jlH / 6,jR_Kj[V($'Bͩ.$XU7V'R+θ)7\ C+(ђ(7pڧ:Ӛh@-Ȝ( ̠ly^ +XcIN5b8DSgGfX1%DC2pFBYB[-yg'K\鄯" pɋĉΜˉ%+.ѓAuCF?n?ppS\NB(!:EJasV$lVHbh3Sdڨ2$.P>CoQיuC!7h!` >}gwvISE$g寵m.C!i(7@ك2_:IىEwi’"?;4DgidSކfOM܊O ' pN+s%Jq"3O3 ߈YcHk(.0EBLѠ&AQl+Z:mjNM@,ƛx4c;M=Ò0P9u @(֎r +$@Om%ч|1[b0>^b  +[ETFwL4CeK1` نʴbb#v0dh]Fu)njw5 J29BG.ZdHRؐ +j @*ރO= iNWgŶU +Z +K{ttfPuX݌,;_ʟ$VYa{cR$+;)U!b]S\5:@ճP oS^vv5C};e38iJ7Rs5L&daes)-:%5ppC(@Lɭ5$%Z0Tl̻ < .SLV6KXNB,rGli9%qbD*[Rwb"l-"t>pf.=ef3˶ aFg$veT,+i)KS-].!}oc +`܅>禡DF˞,:ېo9[@4G%:`޻ pݪVFEL'B̍MFFqhx̖RoOWlRvXYsE \?=hyhtdOUV:a63a7;;] bgfeyͿϰR5};h >޵i =ES#J3Z"+oà F#X6\:nA* wpef6}M_fA]4jl{ +8C.WWUЃ-t 0 #O 5^\))]'$W.O>JxFxLcv骦}.WXB՚ťjssyGߥr/6ͧBv, |z߀|UF?@HYb/`Yr=]@5;嚇@ku3BTgEX:.Jg>Ő9! vkHjmlZKWlzWDRB2 %~P4ָ5mH^H;XH`xtmyɑ1=ڧt"v,JiykfVuj;d (~Z#j<!ͧ E(PSnмbxЏR7LM9H:]f V*BX=9_Yq-NM2XnajDӢE} +&+D\qOIw=LQWE]bd@׻^#/uxC'aJޟp)/p'1jt+ĜBj y1S[h.7&f,8 $y%⃐PNZiDC'(][գQN-hMid"Q;S +NPMD$(Np>S1Kg>TI~~eIutu;.DSc K'㟨`3$f{|roWkL|LR Up#^8}AB|:.S fZ>l4y_a:K̿TJ +=>|^x,iaHhx4uS-\eڅ$ gwFl4)s^Ϟ(+/䳻y j)kܝi%1瘖ihu +-~n>TtANXƒRl)WSA$d2Tq{% +|^]|8N2Ua̓e Ag@v%^)'*'K05f1d='8I5>gZj$`+N(;\d0غc{ADbA*`Hgy Ѐ6f[ʹ(賃1FpD,1Ih w! :s }qL.9JNR u{u C[,`M_ڬ>)AOoejXd֚L֒!N3DV֪Цkg¸mi|瀜f4Cd#FzjZk^:brhA*♣*h/<, +q"۲=8!-%ǸV[,["\&*uj!- +PsCN~};l}JjU ``Xi+juC%=do-_ Q};O}dKZ6Ƙ\6}Ux]7kr葓:zReƔK"?'jEQClSO*ʨUA+&& ν8XR@Z(iU-":TZ +]J?bݽ6S̬h`nQPS'Dyo-yL>7I Fށ% #57UqT)1eٴeN,-p3 ''B4h:wjj Q-DUOWx$B0WY`xAI ){Kh:8zWur3wPDrjhU+Z2!Ckl87IY5\F%*Z{#G+2i$a-ݤmfHjMXO~:P>(̋t9C-LRrR`Hͼt w=.[Y.7S4(ȢE ea^*d!WqwK-xFʦ<ؒ" zbZgʧ0ֽZ b#&RCD?HUp !#}R="̬?S }NeX>^%_@5S'PR;K^-Ti0nP/b*U29w qN5B'RA@$1>.6 +%i*y4<8$(8/`rq?blʙQUZʗEqo2LJ$$7YBRX`i'[xly`Bq%['; ;oeJ@%& 3æC#Wc?`Ңr|fUUH,Ukbptx2|#NNXXcՄ8jZkHSYI%_ZKq,xx n*B XP!2%gײb ZRUqk X׌3 +9ڕS.qՍkU0X]m7I)CGp*ITO)kD#,ߢ 5|}գt =$~A1j}uz PqA~'C㭭NE>`ɛJ(@._x5)$>-&3& 5M5ZV +5R5Wfsc|F^]D[̒bؖ3R?u5lSqj_k1Ua -:$KTˆ2[gi d%Hds ke@W{DM|!HS*<0['֯O޳}"Ct \qY\O +" 0Zm)&_HV%ٱHڈ[bIoh`ۮݧd=QKMH\xz~]EzoX +`o1A\rμDLk`.Q&{Ba >stream +)kye Ȭ|u3GSd;Z~d?7B=QC8h2z!q4f{6jbRBdwr;`&iؼsmΉʱLɡ[j W syA5 (JkzD=-^w"v>0-D%|_'ݡNqe1wRkXIRQti?A$V2N7ruwC~,a!S48<IJh٢'FfFjEV#|A~b_b^Wpu:W#[5'z"m|.rjC˷B>L[b@.>u +FQ|@v{Vh"zO %D AY(4 +gX(nğ>~D`nⰨ^9Ģ<@:-/qGHܖC AB%H@gZV7Ew`$O7N`zL,Jh9=LA7;F!~7 suħVm6<ݏ́D6r^9ZAe-$cM;B)Y;*w1EPIu" H*@TtϚ,7ZTf]X6h!#VhR!t}#"f|lxmB)l!X‰e4(*rp.Ds{}$mOuޑbuƦP듄͞Bfuݥ ;JзPU=(l˸7YZTs]vH|N;29|L7Jw8@}Tvdjoo8\E>Ү6N$U,E&of>K1ч=hozMhDm]qIʼn t&ӤF9ޤ +(SCկ @YU.Qd6l0x3ɋ2WʵTJTcrZ*S2-&E&WA aB.mCqLz(W2O4y!CJ2' pهDA G&XHܺA>tP\*O{PV'T8d E6Wв!CvypRſ*IA_p~[=N,|O4D_5l"fIivTŽu= Ýї,L%[38+P?oٷC3|Jj+DmuvҔ!tM7mR:H'|İDh+#V#$طM7i9tEn1;ag0YYYbnN;kFѠc``D/;qߠ(5CBbT*q aQrP]BB\ųSԥ-eQj-BIQy܁շ7rI/(!\p` #X#$I2E͖u& t)N?,ttR$RʬiV*K=Z+iH0ﴝhJuˣh{"r*^H(k]v2"Q MY,z.> +՗R0qYh찫.pS0ÙxIdHe|.^x V;=@.;ɴ`NWDm[S06Kt;Tʎlu?MW@mۋ_uO"%pvj׹qԡcԌPP۱xVM%,C@]ntK u{x7yhg,QYIJDzO$IHs ˴dzvTn7C\2nD/M@HI$p( +;G2#J{sy|.tU֝-b[9ogP.UU_Ŏ. * :Oy?:!hX>gErv8R:_w|Ucj`>%DHTtd}2A6IXDΣi'#MU4%wωTߪTߓ,{2>oNR =L"ՂB)%x5ݱ;P +ꀸTלRE꓀~Gp! RM0)H=e4V*iO(૰rɳ*|/VbyƆ*I3ijhGTRvAC޶o0"%qq@.}e/6:KD@h[SaCAHro ڍqW&,֧,>I 35=D2A>ivA@UGל8/4vP =hV{(B(>y& G}ڰ [w&) P6nإ'բjLƪmr4b}D S& ÙHVr\X DasW;9«|"tbe;.;hp߽W2hş%2ޝ+23wdv5EJiY7Z[uvu5euk0ih{+%/Z;N#ĚuƆO̖VySº E@gȑ]іe +<#3 Z҇I@DZZU gjy+/ԧ5AMUV࡜I1Rٲ*Ց$qڅܯ*| _YxC"JPuFd}!-Q-158zHg,LpXRsKNZ$#|Ԥv@Vb +=>BWdzm Ipr"`!YmDP PJ_jک>f*eOmΔw;2|=۠ +TQmP*dlЂy+ХFX +|A/]>1 +_^ryBYpriqBmU<}Jb]@ೣ\nAN,t>dDI_i;~vL&Kńj+ѡǒXɫQ.@IcؔjzP4>I׌RۃJ -& Ҥ@J]A2K4k,/X:vf eU^g)Bqo,@RBr,0;?:ab kla.w.+{;lO +] DحqUn*/9$˲ތD4 \$?.:̉x@Yad ԐW x3<4TqH ;ҕmH+1Zv1H_J`i# H4-$j\6ChV`yo5yj C@HiCH&01L2g"?UuU%m8^KFO,;)H#KV+ 3QҥTܛCP>q(l]АHh#Z-;-YZ+I YK( mppn¼١o"&aQ ڑk!@ښ*4D ҝ[wbI,n,'X,z|ohئ eo IZYykS 8i-{`4@ Xaؓ- n4$Q} eEP(--AI< .ٰ k^/n<]ʡP#q,IxA2ˆ/9#m7G BnDgV '&( >z *WS;]5xeP9N=ۦ ڦsQ8þvOwĎ}yߋtn2bI/B\vPmD@c"ˤ5jPӤ) c;0!|)@`k F{EO!Paf`_D +'bfߩ CvLɌ6 +pyJv\ʓ4dC|2Ve4k{JKl$*9 GEה-N.$:990jC{²j y 3z.&b=Lnie *hU,=2) hИlH>$\7+<2U0S +۞\Ԏ" ̇l:K5ij̟m4,_'pB]LH%GT*Np>v(`S擔F(Beb,< +(tcC@> U/gk%,r8dClkD5 Me繪%mF("]>$DtB8= k, Yl"ZCa2LO [r~S= t{75 +]_͖y]h1N.˶3; \3Q:,fZ`ͤ ~gb)/C&9$>b}jv PB!^{{ +-.):>QQM3Lfj +[yIC&~"cjcvWE͢H,_$E:F ۲C.ǙnվSwrV*)@Ӡ7߉T A]rR#(ڲoJ8 ' #G8)\ QV]>L]r^mHJR4&~n²JωĿUZ#dk|/JKgRuRJR/sO@1L܅3a.EK'~!UUcD.TJ=}Cc\m+J&iU [I;J|"^uOHG!YQ!5U ]B4TZYLqFH#aҊ%+} &J9ch%0n JISg A6 )Q1DIրlW#YME;b8rEypU<>h')"dz+!aߎI!"b k*ǰdǰkiJW`!g" +.GId.P!OB>WԱo`X=zx⒴v @/ GM¨LЦo@zމ3 %,@Mz !N ƁDUoZôDg t"wC^9TBzRʏbVe {-5y9"S#(+ +b = y 6GCvGZi{R A^Ow* kyD^ +=-j))E_PO_-[Ё!@FIG ª0POf|$g#jU3:N#` Q2b +8M,+1'ܘak]bB+t[4Fչ)(Gj!(a_' a%/ |4kZG،T X`4'q<`-[`K/R1)W';̉w%Jk;g5PH rpj8w*1RznC9ȕ]{@Ř!.Wڒ ט&Sf'>[U90"g6Grnw.fnѢ@#A2B43(dUKLGZ-D^ 9ۡ?Wʧ<{G3xu kj`IYQBd1-B"*,$6Oԁ|FϿ,4K^y)/\|. l鵌bCD#ȊPy lVVb \X?xUj>=:G=S ug?x=yOX!b7ޑeu^~Hwʗ Z܉<Ƿ9xOԺEuTXЋ98k%"}ҥGle"(ڨ$יtoqB09#inFxVϧ݃Aѫ+)iF3qEb͝`Z5FGNx"`Elt,]DDybRyb(j'>޵Z#JL>+_GZKO590$msГ-*nK&:C +(R4ÈIæɋ3Na +m[Ҁ㖽 ]oҘ BKPW S i*[d +H r::/,Ȑ?-r:4[ 6`Uf%tΠ5^Kd3\J)#f]QnrU)3̲ +``%5|ז +Н(legK͝rL} +ș,y"t#*j*fcN5N*JR + 5|>aa|S##d7o.v6& +LrdҤ.U-Gg#oNoؗjuɘIώ,&lAj:-^6@[Q3ӼPT.pD4<ݺLlXʾI6td}n(8ˀ.:jx!TYQLࢃ$-g2S7sp@ѩQP C$,C1&|Z5I[/T<%fo/#@m 9GdjDeJ%H{^4`CpkKp]kSd6-k0I!|d} 5 ]SAQ_jcvr<mЉ`PfD҄?Fn8PjaѴđ42@N F1=*aЭ\ehΎ 9e=A vD@Fk]3jt]|t5DQBVKOvW 2S+1ICÓP$R2َW# $g Y :g({$brd3, +$aw ȏ +f,mXtIygVQ:#*䔝]q+ɭ|pH \V#L0}>'E~2]B6]9%eՑLn+R>VXB%NjHv#TIt=}+ f0JiGg33x)i.QEz&} /t ^*ڍ "I1VN|-jT@AMc}3Ask-GI%t3'ƈk}塾p $Z;ö~AEu$Seo)t^vxnLΕc4u &uͮϱ+$x$"1D΄;0|r3&~I.s^ Xfu\L gt!։^nDI?!7¹T[nZ 0gfr%a*hFOI1E9d*a N$+xNtC!0.S:v,cc$tb/NHN %pS3"$P&doR}J'eH&JUG1$~]3]>7LT+_1,"Y8*"_2rg]WrX8D"9.-RB,~bwv+mؾYP䇚bC^veQn~X.l!Tr.- '_dq!!$B;][>/<#}d,@ˏ(AW>\8F›5tSe7I +U9]bx,[I)˰~K<4˨q*6Xg!_+fbf}qPgMniA&Ms_B449BK.(=Rm[BX{k|hqQÊ-_$*{Έ9 ;{U="$&auӝ@ eզiu1% wI ߩՈ&!XN9Dx/px?TXAsm>(mB(Si +~Pkn:]Bhk:J/E3O/ sYC?W'%J%"h&G +v~~j XOyA#5ӢOF >R䩴L[8my^j=Zd );ބfvԱMb*pSuǗE*qa~ Coj a%-Y^$NV `񊏟dFO/%#!i%ͺmq=p!S;t_Bh[ߣ׉ޑ(&TgU%;<[L$h1+8% "ٮD9bw +;&tחbP+[JHU-Ĺ52FpڒHR>yE (NloaH-5>ƺ#U4s6Z I\"`9=|QH9ɛda VK7VcLǶP|$ٹg*"ibȗk^5dvtX{2 "*>?S5%0 X1/@viu)gҐ\)QAfHI(E_ϴ+09-Ȉ]{&{gq=/k4ۅ{eG2X dj%iKt#ۚb!mEK0ęc_Ҕ,#F,[r8%~jfGAfH0]V9(yY69o.8#JW`jh^juhrVv`^-QBVc~ x5 #C7h7(zj' (ѩ.PDETQfNh3z8)hMb a^܈1cC$ 9geݑIJ ҄xDWP@ ꮴI ;LP]&4U,veY-=} aR'@U%2XviQ4z &AL} ΋QϦYL >\I`  \PamO X&Ѣjo QYIkŠLB ,w5rS|]Lqο|/K}%'a ܘ~BxְdRKGr~ QC`)0R B0zXfo?H[JQRJ݊Zd tsGJ"aqCVpǵ⦳5er' 9MSʎIHg|؁Ҵ$y~U?XYAN>c{om~هmc7rF|nrSf(fFYt*f_M$+>{# IJdXJ`UA+-P|~yUPDrXgLB\ڜ8-9}%lfܙ$E@ZVMr#.NcX4>uBuvqưj:U,vX!(x4A=jx`*5q:At\Y/aoVɆ;ٟeW8"fƻ;ɖt[/4R*TRpG%.4#X|vE}ugD%n +xO]{H ldɑ ,=QB@Q GL*D$1qJ ;e!JrC(6(~9h*7RnQS(Ҙ9)D`*yAflx9A%$^z{AŖ"sKuը=|ÚKQ LY8Hn+TqZ=듖5nպUWE?j;]<?)5%0="UIjqSs53R(5̔DԼQt')쳍I54 Ā+z^,,lH/WT ;abCq3GPt(&),χt0@C bD@ܡs!^\ϙk`6V#04ADmԪK"0C&⺪[!҄\D +#my!9!fy&@-v?grͱ_;q1ظ@Z:Q-XzǶGh5YE 3JyW~gij C-8^gyY[cWro[>S^4R]R%`AF5Nvg) +}iGh[t9bRggcC"޽~EB嚉ʒ}62@{w0~3)w!Y jY3YdֽįCdoTa\@!`ͻĠ?\,LỌjDTSs*IeIG7 - :!nޑBr`&URW>`hbl߱E+zq8cJ])(-Ply8f1:xKvZr,UydHfKfΌb,pc!*M۫oQOH ՑSĽe<źKQ~mԫ +ß +r"f/;zcE&pSC^:^o2;ԢX& zd6kUA?&z2TTϋ]dÉTͨYH'hg6bN6'+5+jm@'1_BXAADKī)+QX<cB:|x~wYJz-4HB uWf8SNXdڵ:kGZ#YlYg]ajHjBx"n%h]Q^XrERE@kqm a9>?0gI]ܒ]` Y6˟rwDC1eƅTk`6wiYxlaz}#d۬ f{k:Y!¥"dqh7IRcLFRB: Zm@Q~f!hC25o">\zC]bF8Ha^yb%0I/SؙQғ젴Ւ{Er;-M X*W=?W6[Cbܦҥ|B-I]TGQ-:ֺRKiJ?S :rupNēlmիtyUW"k%yPG'*&xZuQ .l6݇r!>6~ +p 4NeVEb$LNx"oN1lb@JJNEhPc^%IC`+mȄ) 2~=̰t9vR9?jEq_?_/W?旿7?7~~˷?rdIG''?77_|׿/4} ߻{I?zcmߦ?s~O]?yÿOw<|oo#~h_Ws=Cw~?/7p܏_y~_ϣl/oٳo{?W}Hos ɸo'_/ +'ߘf>|w6U3^~D ?9k +u!_da5*]&HD?em08c\'PD$Bm%hQ086|kw7rcb#2ژXyc&3幯yscſjtY7V\c.L+S2=y#qUuLxqŒBld#N JyR(`{+%? 0۱16 xfFK%6v~0c*4$âR%6 |{_ IH;.6#/}_9dz姇ZPm\6}ā^)Fϯ|FFc CR֯F$wb©|1auKA~uN7x85o<'NRGPhFY{돾Hw;`:쬸b38ǑOzl-MʒtݦFb㺟g_:B>nX7wF΋djlۏrngYl+!؈P7fy_<]Y6tbsNk{b#~w>!6?;#'_)##9^۾mGy_WA5‡ z;@8[l1[l>yU; ?}s\x!#IIkw[/1dB _*Z-zRUwڨ>G|[H0Ҵy*8@yڮ|vϯ^+lW\}v7x5>n1~t(Wh 26O=|m KwtcwG-b'7+G1Q&P1bo!Ŷ _]u~`1~2|^U=:2+/54dp7>c3ZKi؞6z`n/l ~ p}sDw]|ӝD$FNQ)|WM6ς3yZWKmSRH+oeܑjfv_5rfa44zqEAW'~.6m)?ߗ7leҞGkc.w'c_#[cZN1š@|Fјv>O+6Rjw`ND"|qEOm0c"ndR#4/RwgHm,bE߶5#)Qw3d4OP, +ĉrd?Dd݃޽VO-=""'J[+Wp~rm7h|K [ö|K~IGͻ+Wb^ hǝ;xKblԗPc=\wh^q)'/d_L'q {JKƿoayxskVnx V`ݸ|\@zReCܤL]Aw3e{o,`b6  b +r#ə nO(Rw~9m=Ybcqg 7;7zziɯck0i7v?m:p3KK4,Hme3+C?1m뾅o۔ znУlH~[3B=Ta' <{_ا=@zF(H;$RxFp?$oGbЈǽAF(" ku#"S;kEXO{GqdB䜓I xR8aL2 f:H$$!(#D3li{TWUmvg𡻺 j;h5QQKmB94e`fzIsf)86Rg ]tXz]#e "8 cD tMGhS#؂5Vh@Ԡi1o9!pl ![-&곂cM&I%a-@B'O7&!3$1:kJs - _;SMuteG1(l}9d +z<t@ AN8Be:d0R&`I&XyA J(4DumHxYo`pɮf hChP3 q ! +8(|@5p0TK_Aٙt1p& +!Z8*1oLV*]-`@ FKC}] ij^ʳK2~D{;)@f>D 6X+'`Ou 4enݤmr) c= 0L2}YPG}5&&C:d1::uR + U&3([R Kp"w@KTXc9؉?dC86y2Wl0-8@ [v2Y x#ژy6a*98< ĬғC/OEg'Nwz^4ﴛAD#1ac1EtЕB= # e}H̫sXyr-on +ԗ16= ۔[8~fa,g$wt=dD2<$Iea{; ct6@yN3J3 L_2j2ϲ;9 - NzNI(`] +֦Xf@-.ZI8 ~:`hW[L 3c;g0 $@Gb8ߋFn,'K s7_xJ@d=3QJ`V3s"[Όe3 Bq,S"gX&kԩ[ !&hEdk,ӧ glر!WZiL ©1鵼iOH@'}%" k%։N` +=Rn*fNk,2,cag}dXe͔he'0q$|L})(f D1%  ;E1΂ fJrTNl Džamf j:_I'톳L&f("+qZy6_h $ P"-f6GuV*}q_'ȳQgiƎ@5@.odL| @B"^O/ T`뛎j6kqe!21oWY|2 p.>S0q,4cHx m 6_2yh,gXQqjendkhcc3Pqe2. eT5p R,; ܑ5-#EqC 8Y9MLuyuFquB^/tWF#f1,#_KlPټl5gnCDްN +,n:Z+͛lz־"DbL :5pDK !ۭT% NvBI"3H>׈a`$ب,' U8M tcpF3O/ZC`0$ Z&.@Gy0DCm'x=S*UեF0լ'ۡ +O^r-oĕ|s8٪Jv8 +nbf rDT qdi>B]gf52YQ$0ZUs? +4Bf#A]4}48 3*ќFQFLdFgEbNl1;2sv,H:4ްfv1eB|vP:`p2!-Z,FD˙R<$pCY;ceYԼ{ǥf+yۤ!*YXY ԘNٴ6A$ب(+Y>*`,~ p~-M]"* ) ~d,+4lYm( Q|iŌQjx +W1D)^"FFlzW9Ch%KH]s%3 V&Jtj&&V/,/Pqo-RZf0'+^r6:ħy((M]$ ?OY(HQƒ"x=YnZ`ZfA8,ڎDuF: h2cI,v]`wN%GX`+,o-'-]og2SaGD&aFyl5S&t@u OhҹXhI-jd堄l73稇f5;]HJY)褂iQ닽9t3 +NW6D%N2fr8$3jS:Xl D>Z$ߊvm~bAW..3TSGfH]ϵD`k-'@4;@VjtYX B'3XTC `IQ:FpдxQJ"\B0dPHkI'e(Dt^7)K38ȱ-s+2JּWB"C2DJq9f:7bKtq mIBT3ę#0oR},)vDҨg$ +rǪi}N1b897p2 6"LS :;|d @Sd9WfzAC/s#Vd@-OጂLhXsj+}{XcC8Gǥ< GT%thK + +g{}*xU$S Fjl8M̤XLBf*p~At7Oé1d}X6bg*lʡ `wv IWNB 8LLWYR1/$` !S',Lc3/vcpz-Ąޡ_"JEg!t;0Zeb2>ԕθ߄<Ƕ  aSFͱήu. 6ʲxZlJzeF 1 W/hȁ/ D}^lwMF#5JybB2x $µ45 cha[flZ!$2{|ce ctĄ1znM91,M+?n~(UNs6>7_6z;QP)o)'N7=ԉ5c,6;5$,&XC49+۷g#a$D.~ y18}A iZΌ +b2Ϭ8X':Y!`T)\ֻ3SU#D69[ ZD>N5~8{P@[l?uȳ48P!)6t7ͺ{0'a Z¡&v\8}VIGC# +|>a$S4 I}k;>w=Q֢fܝIUo&BsY`is[X}PK^X'X'Vb%[}֯eݳH#ȃv+YqZ# WrLOX*<*## +΢q&|DNHi"Z\l7+"(*D;3I>,36Z`Vdڦ_P/km,jGo8$DV]ڄk"& |lDo:@Mdm&}6[h%$eXB킉 :@% fWsV0=E"#ed^]KtYɉO)%D(RDžP['#Y0 @V Sz3hZW@v&UN 1Ƞ$geIO҉W1 %Git(0}<].u2E;x}=<'+LqYLphu*7щFElY+*,,5ݳEpʆ5g8iFN}*a66]`uXi;-i9RDʄ cnD +rYNϳ $d#bh&&deHh?0CЬvfוwp~L} vZobY9W"s2w ۹hj ٛ +DڰaȋRѯusЗr,m>X.Džq$DhJN`ѕ$h1RI "9V_[L@B6L*,RѠit0fU%f0lDmL]Zhk) rhWc +}'_fQ_o8V3tXExb@fx"mb*iNg6Fεއ&Vkr$d D&Zl6}a_ U8bD8}{9=.AuP +@$v8hܶ1z[}L$AYzUfrN6ۨ%@$@Lff,t\V*&Pm]8C`\8 HHmh +D(ha&3qsYWXI(ߦk7_`LG&p>prs`mLʟ`S0@}Qhem);صV0-ƒiK4Zy^QxF2t(V D>2nWp !}Oլ[p #wU8|nHp@d(Au&N7Ѐ|Y#BmЭhu2dZHYX+F6ƙ+ %%hb7Ja[x\hcgrH!6Y|cbN8N#LYY>6#HoIG%:Ȥ163KQf`|=̾zHKVڍ$Fs7;vEH8vvޱ2LuD3ș`ݽa{^`76n,,3pv C.}N*]ނn~ 5 D;KYHS4ƥ0U^u_ .8)mg^XPE+r:x= VijUBBq~qjq}g]8O7gfoOL ~=ߟr 5+dѬ lgbpqcric3 F0:9/zN"vg +hg'/@  ξn+#ZKH•F#OsA2WFLҧy5~f5X&.Q u9^A߀7kY?ZY Mu`:XD&8 m8[H `e=gć`Tq6>l`i`@6ZNZ3GNN<DZLr~mO.whHWC*@S?̼"_KmxκԶ1H 9ty>շ>H {0RE{lgE6Dffy9v:+ _D}`&/D̪zy-V*kmV%LtݜNPZC +v1v @LxeoVM#sh3E1Z<'X0˙9h"3Yr2ZD2wfB k0= o]> h`;̕3?x -aeg +|fiu *5[ +[ *n'|$F;YV3_[|Nyed= $dgm:;"kn9AZKmvv?BJ7oj@O~㘙a8l +ڭs1U>Sɬٗ62g%~DȺ }{!= =R4! +y^/QxBzB+kUirۿt_D}!-HsYŇ]O%DVOv;mdI9e5ԓ>8zVqHц?\K}iAS:1rykC@PB5# ^%&1-Swic&]@|z6X[:3=[ "vQ@JR[9گ_z;/v{N6')7F}/<Μfv5beTh)ffh)yP;%CPaNji:,&%<=CّvB9-<} t^E6' =[+N{c3 :M8zֈC\0A&Qo5 +vkBT//fhH/3XifK=O_k`mc$mF(TSY%LD9Tn[Mnexc<%Y@B)/ u\@NO-u.sNFբuhSD3Obg|:dszcnڭʢؠ| =]%aF FL3h>NyTw9Yk~4 I,ʓh &2ֈzŒ6:ހڨ&8 .'d[\F3CHq +qvwt ۰Sa};9-%zVDjjdv优 p/X97Sy$jg&gK,"eM3T)`.q rAB >n3*”?R7>]ÅM|U+UD)_3'r yz4n 1o5&0Od+">#}1 xlÆ7j͌x4;SEIfM!l8~3Af34!~Ӧ~!f [ Q]Q\QyB榷%O7wNf +&tɳ~vZZ#= bk19i-YGFyPa>tU*z +6Pw ^;I}ew9keqޢ6C"ˉ ;9kz)j ׼d-fusRh R.ܴVZRYg5qQX7!l~sAF"/j~AQfD4>Khr,7@o4o;.Yr܅G,o@YccڹcslEC b]$56C{{Jߌ4Y՝].)?X6:!o;an+xB$2[i{vPʻ%/(Bߋ_ͬ76hu<z ~ɫɪ#eb2Zi9 /i)X_[s֩׊j6T+wײVRSʻ(q%7EMԲ/k?u(/.U{I.XGM[ML*AkAGp@lϢJziyA^;)>]SqFͨ"uZQq-HoMC2r_'EܥGk~!J_+˻V@{~NYn_ +f'vj)Ɨw痶qf6 5 V"7(mUyEmC=H#J_^o'ۓx?5KKh.jƖwiC5$GZE̚nZ|^{m~V[OfuOovu/yNF+anv+9.R%uɎ^oh}i aΞ̪Zje7)&ZM_Sޚ>J{hէ͞j=Aj@+;³ųdH |pO>  Dd.oJBa+%#4?%'>ZٮawGjۇh lFP˞Zj `,-;^sJΡ{yJ mG޵dcZE)[i 7=[E9ԤE =%h $WCПCՒՂ}=IJbRI)ajjnmo%eo53oU5Ek d2/4/)#մA~CĈ. ;ߌ@KA#$InDA{OHS + YMFleP yv urvAZ>!UlU I7d'Ė camĤ ;j9K{)K*Y+{j{ 퉾ZŮjabK/QRK; C]WRҗvonV,;4J^u*~ϤlAc{-lcKOQ6 +; -5bSxwm-2=7%q^F+%~rrJY'ӳ".@sNke*rbQwD"Zx,{z{0btVP,Dh& [N@<*ggFj# b~A^F~Nm-GG?lx&wP#eTvѸnd #3[ wP ~I-?2BXSRF 0|cM[KEHANJI-OdsO-@^jq2*߽AFf"]^lE1?#9X l!9Q+zГ츬%=i]7@Fax2,ca AZSyV)@A6oد/4oR$ʶ ֊6 Us>,?\-t(i{HKyu&^ ש{Ʌ[()˺,^ӊɈY{H@dOrIG9ouo|ϋC$uT+bHF<MLK-o#A`*Eh!y AYKM((-8?5 @9]ү*̶x-l mƊRusҲԬ=ԄNrNCyɩQRÍ7_NA! 7Wk{QVE]~|,h#h-'{]GeZ4~r׽-1d)<2K$9cUDV\]-1TYzx#A*k#JN hn9Al!eZbaG5cI7,`+\ 3$aəDǂݏ ̲cH">zuɻ/ )#/:tfe7/N"86Z^ ZV QMέ.rTDBy顗äMj+%wty1HqmљQIR7 4+hk''/$',$T>Jw('Vv*",][|[͏mhxBsWTFK+1o{1XjtyD +=XAKC0dcNn)菊U_r*G)4= d㿯,7L>\{_G_[ʩ)e!-l|~BBBeG܌hd 䌕ݥYB `⟀|2/Q9R51 ]QCie] +9{/*m31mNDnkBjX6 e{O0d [?N돾ٳmSAͫ,/ +/ ́xCʯ> _C~vAS&td ك"ڿ d/@>+eMĻoӵׄ/Z~Q2WPJw a=B Yd!SuzyVӖvB $ 0CyE:bI}ddd U+YD|ayG`[[& ;&+2, 䗇I6Mk؄bA\ys%6D?]kDeuB㖠5;abo7|/c+7_}]lS*ۅ_=]-eE\M9gӪ& GIo{@I*r _z-f 1O-;3JzIg)~a;SW@6Z6Uvd 2{Y$*de-YH=H@{n\sְDn jڤߑ߽,;A<4RI, lȔRnx_0? bd%BI \-=llf$:dW&+ue, ' S'OuwgBIG.9_m?\j?P6SRzZo-Fq#:4B9#:>)ndn+o-_ SU7[>t{ X-Av"XϗvR62HW ˪Mg9yl|3"W*7C:c +>?.(yrko+NRw]$EF[ < } ؓwцA`ZKB@Jigl#yPcA_/-jVV߅hōPY˓'}\Eaӥ7rҮg/{V+w$ݛ lkrY C@ +191y`뾲+?y}>crۨ; N֛`*E[IuaQREx-e Jhm ^)l~}+Fbd[O]zeyc_f1ݥ눯`O_. )7T9{=<'ȉ䷈ۂ랍眜V)ȶZKN[mk%qY`&욝xR-n$UwAy4_)h$/-h)ŷ;ԓR:Oxg^m(uȆK/ZOM-%wPJ7to43];% 7K8+{ϑy.kcL0%{Gb< ?k_t\FIm֗X +7ulܓt*؏9uDd"9}(+`=aa{FOɎcc;-Cwa7UGH95=,d, +QENFs䒼Hiнc]JN ` zN,n~C*>8W×\mt^sʶ>P..l3;|Is k(+VT~Y)2l{-? `s5~ ju~A;qvBK%AO" 0|`_c[*'hm60Rjz_O1F$sA_Hk=z%惱JQJF]/)*5)ozzhz)Y -cU#y  _y9m!&F`2|׋#m^Zk5ua'Mp< Wּo=T +"6*l-G-l#F dNJ 锔@oy7jKyWi' +`Nj6Aw 4'Ð<hߐߌ1@T>h/RǯH." An '``[o"wo*$&VwصEVzHkw>s+_ts)-,5\y[xcH1@ОGrHI֞mްfBg{q_NjuhGAVYyҤl +Њ6B~JQ]?A0^SEqYThq'oC\cño"VtuXˀ{l _]q| #IX!ڢuuGƸs_Zj~'e/b JIog)o6~cМExs悖#{AK(:T?V3aIScԥFjEuU/Rg8#C` JKY| TRժc97\xͽxo[ov`=sTYӂ\W›sZzJ@6@jf/8P $ dT:f vҎRtzkTEZud~I+Eu˳xpO %Jѻd"'@.?Twø}[!*w8zn3usMl! !&#D|u뵩bn}oRf6sySc2'ΰڢ~E/ LK( !'/h|B>м6Rdr+/n#`o*;Qj7%6=/~lxZyga㉰OŽa973Э6>5;#y Cz-rphYA~3g!9|?!`5)W;~gH~ ?,Âq+ҙ*a,rGj!ѼHMw'<'hy}_ ?Q +kPQyFl>N ~rt^ofm/lsF%RA2PIk/Kr"؜u"Y^E;˃) b{% +rX^u,n !Bi;7C&7\q%>+ w7CG6q7|3f Ң_ʳdOن{[TeW0,4ETZ+1;ۋ݄Ԛ.!ZIA~'L:%/HP; '`X5ZabI |idK÷kMH>40] cѺ~W7_}C`h2_RjKlMm0@90V}ϢVtl-'rOɯ\(e-fǵ2jzj/9ۇ~ru[ +9gHh囆 ;dIw'Hq{:چ>\\h,V~d6!>U/.7^y |1 !oRC|i#"<(b/ٍŴU :'E,) ~rMA(M: `z*화]!_ClD|7sV1;$_iWY|Xw=Vq`c@Α~gae_ݦ<cWt{~ c #+ӝq'xNR~Cّ΁C<ۆf$U˻)>C\c#O \-&z_6ͽdq͗R}05}Fcњ"E7Evq«}#ҭĶBʊ.bR凣B{;VaLlS>[w>u<ϓOUV2ÿ˛\!f"$U.:1Zh*O v&m}< ~f~+V]-u˭)0;8&|jXC# ?N:7^W+em-t_%Ne܍▻ߧ!{p@ /DEymA~{/dKZ|$/yjɪpr Eeٱե'^n 1!Q F +2o&ҏI%1]VM[C՚VZ>Z.`buq]K1w$JAc?I|̚Iܪ^꒝Ñ6u={BdgKG N5ct)T}tm&oWʫKTvsVNJ(cUF?oB?}'\ Jў!;nq{#CÔ#Kn +AO@>^1⺏8ٞ*i+wϏ6^n2Q-_2-GE^6%A&c!^DvhzH!wRQrپ!G@I_][c/@o&m3Epctˬ=U=k\1gmȴ3S.;JvklE<ȇSFzNX|ĖgxM3TN%0'JkJšj~jjU7-gu@n3k!|arH?%291 p4WXS?'`Ka 3v/(h瞗 4 E¦sq7v ȯE2bV Y}Awe\ 1! +| ya%_~)1.92u<`Prm1xl73pթ;Sa1߯89V\/lY=L8lď]Nv4I>$T{<7On-N=ҤO_x0o|n{%p*3I[In5:{%wĖ!/zV49RxugY!/Ctuvs"^0PtiIoC~bױzg$זo/b\Z^+ ?&l6y ]7fiFa, r kE;ϻ?|[zmqwݷ7-wvo xGoݍW^>@< OUգw4ωs|.m{0mOƣ[sR'&K1q{ ^~9ӻY_,l>y+n{q߿=Ϧp)P8 /A{?z~@r,|GhA ʉ;w5C}gOM2 wwEx/Mx%/j iSUl ^AprGdɂ{7ݟ2;ye Y/%G)jϞDeiꮧ3OK{Yʩ%/9kL_sԭ[Nx׆!~#d!5~Z;eI~)^s?&zէ[54zn\)C󨉟}riw9޳7w=C#N|?칬S_'iGyݻ~xUePkN3Vvݝ,kW"_)n}0I^hxnvvzXϙ t%W~rI^3Yҹ_#']x$!Qo1g>=u7E'xT|'}0Bp->D<)4QQtItatQOtIU8>̥ޞ+}w7My|<󫴟o.wWbE 7.}(GH_H~4,Gv)Bj '(y<_ʈzLg÷FߧMrI ]?UT﮻#Wcvˢ?/ ?w!WzmU *;~~ǩ&䵼\ 5sH|jׇKzRzsgOJ.{Mu嗪V}>с:U=bcß_}v 4'?Ggt?9s+1oz߻|<ςM;++˵wOī_K|y%sjAOy~~mvV|Qڙ?^|z!IJya۟ZulX떐Cߤ,|lzrojϮ֨On-QY=L07+u/y7+=^]d٧^iA/Lbǯk兽LͨҽgI9|3{ꜰW#S5C'|n̍{1{cO!ҿ{Qy +,x؇7ۻ1gg՟Ujw/g? K\+ ?Y7;[ҾؐmC]]ӹK]+.?g.9Hhz8N4yǏ@r~8hV/sܚo?|>^\3k|hهCB涚1-OՅko̙7ڶ-ɍa}] zM>xGP +Vy|zsK_Nޞ9xW9#?Uww=euK/T|zdmϟz~f'XyrµG.,Z|I]❦uķOڏw}|NSvȉ +1ŵkR z=ѽؐWǺ>]޻4ч No*bwKf?je׏]?g>x*H_݋.Ks]=Zzrdu굋y{JkY~rdy|xMaW){a/{.^^>`Q-[w̢(0b"HtM6"F cT9,(%#9jmΙ|yصj]j.mZLdCvetkNQ^/Oy}U +e|GJ^hwFnz[|іH{]YͽZtfuf6[ڂ< ɹ{9*/9IuNsg绫 +{W9yR7lW!]񣥬-Eb?o3o_d?dQ?D^% TI(Lw' fvmU4ve7f z?{u+(z{H<*ۢF嗷DǷp?C̱'su{TvqC~A^'M1n=ir{Hj?[?Yj$/7pNSښRѡtѨ`AN\m,nE_(ezW|qc# +>5~z!`_~iIW+trLͳ(7gcJbSE]98{![MMg+ͱy_I>Oe_Żt'_ȞtJZ:B`n(NOnI.iRFg)˚b S[RJ"rbQ/}OOՍ*+j=T6LJ.(ymӕii_< tLWQ'xn =[{3$'0'`3/8oO#'~!mjFX{2Pa񓘼y!my{vWlU|xB7S7M"y_6{5-LǛy^__">D|-=}S.+_q;l^wo}sN՝[^gTJSʴae:N}K[&%? N,Wn['8np?r{0?1?߿;>dy}9k^nI۟- ȫkI,=4ZyWY)ߖvF2^KE?d9\ў[zMYr!&È"o(]Zr<7lywЯ2YredgNΗ5o7o8vlyem_RYRПLB)Xy:5rN羬qRNϨ7mDo%-=5)ZDc"95קp7sϱL6<}LqlGzۏCs/ƪNDԧ"aTEh +4wFRjos[α r^o-lx),~spGae-Ķ̒>V=J(yXxKcTHovag_@fs x~LY{/6~Dч1ypɹۚtp5+iFs6D4K7vwoЦ>os +4m5Ge*r߸-{N&L?u+hQ%OGW47EhR^l̫hS#5=wEA[ݩLf~ev FC55S#8 h!IǤI8OA3HSMеA6F"mw5sñnQ|9!/%@9}8]ñ5ɏ =k|ǟVUg jA%V qT6 &h.GuLj7jD: EH >¿kf,BƮj97Si>G@Wsߋ1zUQOEV o -in/˼[5FM|+B@@iLEWcp/BSu%Sx9H{=|! M0؄*-cUVkSߏsy+o'睻P^iCATI˓p壆ʳ"xzQx>|?q%g6o-M#>χqd1M4I{2] 6I3- !қdOEi> {>!Xfx<^<8w!RY~aS=NkǏD=h mT8yّjֱr N#:` #x52WGAI6 h]h-M'Eh,M"@,ĉ6 +кі9kOf޳ [*J=[}7~t ʻaO ?t+?wv> /Mj;'7Z3xcx6O8` l48;DM9鏚<[iC:qCF24}kVxU[nny+u볺$Р7n*;Gv~h{^ sUWX!q-mŭ9=6ۊ|p6s:jS M܇cC{?jn2 +O3<&enpn4< tJAsb4,CK=ufn))<3ANNX{]z榰aZ”/[CD(ε|ȭ3_{T:jzHo4ܦx<[sgHoqߍ\ +4Iw2@FwY (4"M -ɖh(-q=&ӫ\} |_SyZ̽߈+v7޽|2&)+p4_~`z_:e#oԧ8?:}ЄFH{4c<㿑M]M[Xf8ivhS]#7[pX_݌ȺwfNT~7nۓ{9מn+x?iGhiٓ\-_lPŒA-<H> -,}[Dś0XKR>FSWKOq0~h`1j.: MjaXXNc1xfM"d8Bӗy9Qh-vQuYaKG\&}y'|v}y)>nNNƭtE˽Ɔw?{npvq}E 4Q[o]m8!JUdh'1 $g.݂Yƞh\>e=2rBL\5M[@iKh^) -hŶj˲ތZ}h6mx͙;}>r;yVS|OoN!宾My]OUg#:6oh>7Ez|kG /u4 1Qiic*\#X﹩>Ǹ)ss@On^Ww}Gՙƭ|:jMa[ƙ]n̜ +|.g-V@=59h+P6Dx$$qhֈEP# +cs'(cEh|{zC[тЋ Yx؇\U_vKce+SGL2ѰUĶ6-4m<Zs8knN:q Q UsD[v"[Gs~},yD{jF_ha\}q}LK7GfAxH@Yhcj靚8Ípq+۸5֦>ʻFm4pSYsLc}d憤f?l-M?{c{I}b7G8<}~OS8In̵o셏r+޲~'FT?=X5l"4m22މfY8Z_A ,ќ9Vh*"RUV2tUnY=?r÷:-(AOo?_ؕ[`[ O8JʹKz>2]( <Η~}Ju}=䒶߷3o_ƴg6̌mM/(2mU¸T kȘEkPvgG6>YΉܗ}E;ۏ$7nϜ';y?u|ǹ٤7n%}Cg'~y9ZqlLx7{w:]$tD :RY}7I_(V@sum1Pun"2:Ijo+;gNfǙ=[,m U?UF+";s_nG{V9cK +sH>"#:gCljdge%c$zM;K dDZڿٳ?5߬5z[҆.X&DF/kA16հk4c%VK o7~x|p~6XNO91(<%`NSq/ +c +*߯m3C+(zpc0TQIJ u #.|Ⱥ(:,H&}?֝)i5,/}S 9zZmǨ 4\GD٣ŎAxIuĖQNcE'mnMM=pVt_KNj]Ϡ?H>}< yzm}"4/94rv8y0d[9y }qw[tMGl5{Tvχғi){\yOD WKkw}#sƂIV1 5fSgjsqu\q q%M%ۃuVZUk"5>2OYb>sc~]dt2g*99UY&̹6Kxw+8Yr7[¿P[WYjOGVR=kc?9wiW|Y+MX7o:ǽh +>G*K 4V lc Z풪b~MnE7WE1oo½?fy,ɟ|fo2.YWo?YF,ӵ7G&k-7^7kaŢdM8-)~K +;VJ‹&0qeUe:ךg˃'An͍q.7v^"&Bd8ty~h~ߠ/uEYѺ'n:ͷQktv9 +;97S7qal,YMcG(ϨYlLꥅN"dį$)ZDY^GOXSn"VOx {iHj^j ܮq̟?^"J2SPeS%vueKL],'߈*fzVgw <fYŜԶޟ7)ꈮsf4JCa&[s _6T6 +;fH7vE6 W"!U%.Tt$qaR2qd咒+-/+WyxUnH}_r7IS^/p%ouxk 4~T= D"Zq>p4k49k.G;̄E:-ɾ60q@7 +<M-Jc]k3 3TLl^I_C%M'-i3&LHx8AMV1;בYI~׿d:R]8$by9q ה'Y;$l k*@ֲm*= ٧o?16mEB;h$]C\c'3 #'s3&T ڲ?\cOX dكϗF\|%"Yjm$T)F7W+9rIWc?DKɃezĮTpxqeZgu(\AU‹,ɩ5>gb=9ɬpvݜ#6g1[CƵCNf%ziBd^'ɹ<_|'?6^qNo8wo3<56n k9D~yc-h#kS[d`^iEZY;!u $x t[7ɣ #SL62q7 IX.{dDѴ/T~?}#şu9X癉Cǧ%ɨ +I#aų3[8qsQϫ~\tkFNwsi[+;/i yqtVX. )Ԗ,/'d7ZgA뗬Bxޑ,xȹg+=)ew̙~=+j?9RœLX$*b}"z +Cѱ 7N_7O⚯uͩK(ދc?K'kR4ncy{K%gQ[:gicE=s'odGQu +(|]$ۣ* ֐ f&fx-F!Jjޚqb\U3|i.~:٪VTRվ>< \N-ȄکTx:z +̡Ff讞=GRr| +vQŭk#fDM'qL" Lm2 }yP#ycS!q u㝜эj+qq@,:ym@*:97ґqWQ[d7[g][Fx-ʻ\ԑk8DN):sʩd%TX'}77-vE(Le$ޯgakѺU9Thg":hhm`Z+i̳LХmk|\W]$aC"ILޥT ֵXK/f˜@<_jo.%e҇?s=*4y%}3uƝb3ys Sk(3\@P ;r7s,Z=|-C7T}9XLGEpnlO'M NEEV|~|]*H1#/'ʞ*ͩod{Ko;'{1ӐT\(0s@Pžoƀ܇ EU?OƍRΖ|6#|1L","LQ{7ZNh%htdE!dITLM!kœg+͑F7 /K<6G^JZtp +E,Ìч&HqL)RCIYZ{u}!}HS3yaʉ}L0Ȼ̹F&!>fqu潐8݂H#!;=i$)YßAκPRd U~͋#w}:`Fe\s7$?9'5-#*a]MMYٿ4QܱΏ?xGexy3am@Rr=h\Nlfg: +9سٟyȪ)={i\!.jX.] e),m^u6K ys+)ťa,ww+#KOswu%On/ӷ&H2xkN׼1"r$ _hQ+s`"}#kg<͡C=cyA.xW xx\.>ʞ/ ?~,x>ى~4o31/xډ= Td$*Y\_8VP! +]&(C +%"q}1ԢdcwE"č&q..pCxl*[3)x0yVQ:s/|< |z6wk)9ZvT~}{DxNup.x E\HJ>ޘ-7L_lqMN|;xr_U~u{' S^ʻvE6i;bFWpKC! -?q&O%Byg9u泈:],<݄;cT*֔9ח~Yβ*Fg{Rob_h$ +13z$c ~A 8J>$U/`{{9.sȽQ$njAn#x,\))i]M>4fzKP!tRK#tb/:m*]i94E :E&sఒ>!aLPAE<:6LWh?[+X]b#E;4 +esx?)X̽jJ;hŵe0.Y{ϩ{'fPJk^8U"|rt)#)YC~ qY2n^< ^&+XM~3HModޯ'u#):͂ +OFt;mC@XĬDgp 3p(o5qUI7c ~[ ~=dbLiݵipYsg+փLRxiKdNN! ^.;x 'U&xθ8 M`G7|$hsX{`bOg'3FOVMl98{8g_>߹Pexg6yb:\\4.+z+ >` f%]'D 9UڿA^mKUބo.}0aIya)Uj&itPҲ6K`2g{܈^%+~kֽR$*_n`O׏x -ez]{{GAk@ m*Ph>NDoUu~VBy%.qGf1RIw'(΍v: +Yp EiE`]vPvUn; t)ۇ㡏4b +&fkpfsPˋ:7/{@nT^*<I >ik+eTGw#y<OwV #dG 贓suC<BekiPwVZhu:f..z&>V9y^1pp(ۢ*yZ޶gpx^ qң<;+_ۿY)nwhYTxʃqE):q*-^˴ aj|<5cgOo:Jދ8[8O7a,\C&asf;n6dG;^5Ӯؑ7*j5}f >O/Z؏{}\.;"F;J2rcH>AY.H(Pt}7A5Y__!\B'Knp%5vM:G* K_c!WwH~|gZp#Zi0i_dҌS )'̶)ԑv+{kkQoߌ)m7M +kR#aƊ-<7ʐ:ph γps_vsRbgAԆ YK?Yу,\T>s6|;a R^_!=td w}:?pˑ`ݬ("!EjGXv03{KAK сBN"DlUĖL:<N9v`N{S5+q-s{9恝{%WU`gI(Qcβ~]~ E[=ugH7hdv|5pvlR ` C_;Yqi=].SQV<9@S77':C'b$'>0ҐB}2rw- j:0SVD$7qHLӁuD?P߅5 N^X3iVdo+AioeɵsJY'8Z ߊ8gwY3pY wY'IO+k6+L[[1u4Ϸ {Q +y4= +x6y`&^3 Eֱ孖T *`ka?eʧBK=ʒ/.H?Nܩ=x ¦u\%Y~c/w=P,ݑ-aCE[4a`} <_)b,BYT$>GMe2ϗX!O:ؕa`qX7GM.-sXsc⋧B+d|ouoQ^3˺La},,{dtx(uU:M4. t|TzGp1YU +׿coE#g +yp'A[yp`@Lf2NϗUu9>pb[0MȅWM(Pž{@KANs$kl!;A.6LxZ#6t@H?u=`DiU#p?Y)bZ"Y2tA rz]6%G0ucxiy]Pe`N3&:St /}F{"F0x,ISO͇<}Wh+gfL`MDW5ߐi-Q>.F?ݰ Ty`xt(6@EqSi|xAxtd]k32V͜qݥ._񌚈< 8o|bF ΢so-(ui)qIi%[HƧt&Mʼn><0b˦ۈ9Uxgb 0Z8ԩ imc<0x¯Yͅh>w +Q: 'Ik{=wYʥE1[.^yTu95C,m>j&ucƟ&Ҡ]vU +kjaU=[4?0%D⊵E.41*x%p=9TLUx'UFK<("2J`S?kYX\Oitڹ9NGKO(^`ROmY26 +g3a E¥yc3C-, +oAmϣYs a} M. klUߋY^ xC$?-ֵ<x%tL <X5\_1@Y0 Xt޵> Bp%߅Yǝ#rbyRqN ͛()T^I]Y 8Pϋ>*81/An=vb9[18>aJm  +GmHºuI:Zqg9_tr]c{=e'): +>VdfܗxO/{vuiT޴f5{!ߧ6j X NOC,rd"O + Q[;bM+E><.s@ "i񹰆 + A3JFkL,A#k͖\3x<%指=Oi p,߇Z<X#a͹G!؄gDc=âʶ-`l1`Y[ۜ@rUTE$ +(JI$"JQ13"H(`9}έw}~>%PUP{5לcε%[M8;@VE: HV4-W]uzʷ!EIJBmiEtƗC@H1>젶,di̇  G/1PaIP8P>r4-h&x)$>4$ɹb zSgn~➘BpQ9hL4 {}iC=TG#7AV,ݳmhL{&r?)qT +Z9&!.O`$Ǧܜq&dn. IĠ +ayP'w;L}6>Xw6ܷ}&Ba;j$hanaubB7/E1Wh\9;jk卣vyx,4Y){9zmR'e :&G[i}i֓ŝ?2v:!q` +ܱ=o:/R}?ߏ~|?ߏ~|?ߏ~|?ߏ~|?ߏ~|nrQCgզg˝l\5 4tgrݵj햮KYiRɛ-=l\g7U6'@^=u̹gXnӞGچvɓVl:#yhHq +q +]vn5E~e{瓫m'Kot֦jLј<=FÍ|=<9ElmkDcƢh/Z`aΒ3.y?<~Ǔ/.v6ҫv'O!mИf}^O3gGO9[-j8NXg>kƳ)zef]UZtC"y6r:?92{2;WIN/ѧ/j*b*l¡ߑ\r8-y)cl,ZuWuJLq?] H~9cy[x?nWy>q08 iخXٿ/MNS! }zPߢN u64bdbEH΀6YdQ TtRY{J~溵'-[Ž jhHk`ʠ7E]W_`Vo0d/k]۟?s ++vAl&MkkG8p*}N}E~1w&KsP}G*3|#r߶~OwWrGK%WY"&^vУ@Nsh}'Aؼgp3 {{p PAAZ>CY(Ϥoկ/3|FoXOE9RGK;Dۛݺ;xho}K7pH6vD"41LŞTMɯ÷7}7Bo HѤ}B6c(VBf2E~Kp_S byg7ՇӛxR)%Flu}FN}+u\Ϙd)vw5%#]]a"8שc]r!sުԌ+_N}釿c$buN2U3sf1x&8WO=z}$rguS9;A} CуN>}j[w³;fyx{ޓM68P!]Hv &^IvU D~|"\žSp=}$d3{}d8GϞc( D/,gFJp8 +~Wވ_V,ߵw?Ey0ޱ;=&+ά~#iY1rctx<,$FwO#>WP' >m~ .?oo<ùXC||S7΁gvސl€J[(c71>I2+n1soX:lZPsjWw޿xrે,ܻws =WOjG09oGh_qw`A ܴv#oSчc[j|W^+A|!|ѳ78Dא.|zQ7o<`[#O2?c$x~Пy|d{hϠYቴ;mx'.#?8(GԑG$81H'b8[n` ~gʽ; +C+ByxDDB*-}dP.9F (\\ endstream endobj 791 0 obj <>stream +sioyB?g(hm𑣇sA/a@_џ`/QF>,-%L aGO{3J-v;;zTk!t&㷕 xA9M9.lI\p Z|WW~gw4cOFTn^Hl Sb3b})r'r z Hmܻ$1d#gO|)5%s_tMÛWQ\Or.d +Nor- \);}5)t'܏`€QԞ5C^Qj (ᴧo`;!d%8#Qr<LmGJl}CiO7<R獕jEy JbހEyR]; ̠}F fpZqQ&g\"kWLڣѷJ1\pH# b_)˹hPJ` =9H\D9ܮ` oO֊>pG?1i>8vhSOF븳 %4N"x{us>-7F^/d3.n̢\1~xa+S'y~&ӎgwvxqz -~~QDY:|FՍ/2#̂M,S⥽=O$>)OQdhO+o8+h6pqO<, r+Ga\#^y|o?#[G)l\s"vg?΅B ɓϒ1=r,pP> M{`==уxȀ +:3 \P(ڏ^KxC_ xd-u9;4̜+?;xr +pCΑSϠ=Z<&`fzBvO7J +js]LH,7$WƼ ɿ$Nʱg_kĥg'Cs7z:\i|3A' 6G?{2VO: +LI]1ps.{5bbC >d$'3#֫0{] X('GB!rV޳d|K/K6OBClErkHN} #'N:gI|H|24k8rY hO;G {@b,oOrXG2l| +MbNHAKtާ'8xeIB8-49&ͫZy+9u9KIa)C%6]yyh±{syARkns@p Ia$PH.> +f{&p+S1 4X9EskV!B ू tOJ}-Y<vO|v'ߑ |¥YvO +_m䏽0j<+9?5z;u܂F_KD?V% ^9)w58^>#Z uWXv{`o5&d.ȑ+ 1wG7Щ?AWVw 8)f$C/x)<4\?voO)ɫINcdj V](O%yJlƻ;(;^*2[]#>uKNuP hѨEʝ7 !I N };S_7˒͇N18CS3 +}ȱWsG,Y +p+10_ZVroQ{2 ?X$_!w!x-&PpŀS}K "O1ʽ4I<)^(/-_ND D=Ig#ObX#+|Ef>Y'ܙ D1/b-4s>=sʦ?Y'>d >d{ǜ(]"orB/w$Ӊ]ʥ-᳟rkɁHJ`(䥔 KT 9M1yQqgr u $ j }=IgN +szr; !"$$v: sD?-9GWO+N#-bk9f2jM^p-uSJ% Zm/8T3.w$ GAD0z eWp t"鉏 $߮d}j˂8rc?A9xhM5}ǧz(2nPsC- q^i:~%~P<5 =3>"8#C|g8?ȜWރ/{ D}6T/'# gBO,B/Mc^R+s? . +s)WfKV@?87H@b9aژbV*6f,f9|l}i Ä33".8#1[V:_#(sn :|q&˧X#i(dlC9Wfg;r1xnjaIlBũž4Mֽ^:̼2;9yɽN7d 4ooH 52 1_D;^XRDA +/Ï5Bnvn= P1!S^͞h,^7yjL=YKAvvEN'IύsMɉRN,4+D+(u~'z[ʋՙk ¹QNBDɝмُ_'`Zc@_}r*rz!tDYf".,.62@FngZ0<8w,Bp&αP;X!64%IL/xW .6ESХgUs0N5k\2]r)w ŷ^Z3@RrjeP[Gj\}5e⠡D|,|)dyM+&Ԙ lP 4&XJreC)Z|Ә݈NЂƄsL,_Ԙ׬r9ْw3pjBDEr J9(ͩZ&=v-t3-&= =1,8G[ lC9/rWpYO~Nb\S}\m WV~M;gIXDboe;c}Tj**8"&:Gҳ:u?5zw9PEp8]r)?MA ܶTc""WQИGO?hL$6760q#'VakOL;xDk S;|p3zj+ 4&0J NÜfPs~48X[h=ɿZ + @9?c?{Klܻv]ǢmwL`),ЂD= { D1练+9]@`*.b}m&3 _it%ˁP4"x`&1!! X20T0ƛEj,nZ9lܺjX"{oPG*M+]+wu)N C;ywx1h) KR#!Ɲ*nڹ> +;SuARkB5(vD~z띡Ƅl:!cCcc gN F3yl\B`Tǀ#) =9ݎ~#^淯dVIwz[x١Wk1Oy@ ?aʩJ֢z7$r{brjhA; |㲂ꕔSȅd[ F a~2~#ݸe.cV/@VS{hehBu3aSZ$f^ս'ƛkXmF:wý]>}dv"129QW\ڝ]Ę7iWv!J/~k(fėGO *6*כm+S 2OYYjL- qt;:?-Tc"ScBjLug-eŻX&q,O/^IkQ'&ÏМ+UKvzߺ?ԡ+;~boHHzќ\ȗ?B.8QAul +XSc? wV{Ll_VR^jLI^?DܩQ4X&$.$ݘ/:=`;1Vlv2!b _3`.nDe(ͮQp6D6t꣢O%u|"0XއB |F2>r%r+My,}{&[ż\Q\d^zfknaj՘bL9Gp/2QzN 3P<3j k@ByFH?gtKBiƃ\9И{jsd1V@GsqttbѴ:68aswWX1upVYUČ9;^qf"jTCGB |ܱ)}Vٵ2GhBm@Se;PVQXc ֕_L5!,^}p_U.ټ5.* )2顖UИ9Z0s}h^"oNisx2j^cDhƄve!t$(? +7kS=7Rb:W?P'f ɒNިZ}?&l'9g3Fľ|>3W6>vz4C#jdP\69z{&瑫.}ȗ:7;{y ]Aݵ^H;}GI]C!ɣ(2֎ {~H\ui"p,ք(B{s'w Ok[zn)$>>AL6j7@d$Hagnb]z_H$Ea{K`w& i\kv#O\Tk@2Tܲ-կS,"O5z#TƄt](4g БOHJAN[mob#3:ЗZ!$WIAScqN`o-@VY_9m\bnZ`?t?u5W章}t~DlBHǾChQݥGzR썙oHr3i}|Մ =12!2䡨`/ :ƭˁă z=I;5$A Zɨg{tܫFk<)ƪܹy +0;3]e8teO7Sa}kCQ`<$O+=Ip{`iWGC5>9#Y#%Z"H9Zu|*rЄf҅uݣ=/b +;X 8oGN$~l,0H+\Ne⥙]t^S\ҹ҂KN갞C'S߈LnϧZDZp]܉8#;رV8V_0pYD@/tn`9%nt-<$ou=Xh{ҽ~yFG Zi^ h#Ofԁ`#B||`;5zb:a۽I8gcCGV@L۝8^+]ԶeğJ+WB)$ߚOu.L'MAΆaлa J4A- =49}VH-b̡ui27_6Ź1''cg?YF1]8Ib}뼨i`?p>[ԱISD;PfeOJkw!d'g$zJZ:t7е!T7y)4c(cH!>u؋:ܡsOՎ-PGXݯγ;tɡ{eӟ-\L.\i2xMhEa_ +p{N=HJ{bd勠EKy[a'j7!94)vMƖ< >BY<0 ԅI~!0 x{h=7 +h@M6~ԡ5A a51?x&qk]iXB=K=T>Brq6,iH wS(nLpFIa +nx/ꇒܦeXbA"_D8l(˩_F>24r$1k!0QI~<5o1yi|Y +FvjUۻxMWe:VrI pKz8"7fS|B998EF>3SS4P; :6F,'=i#{I.n -w<{ȧMw5l箴ɹŽ |Ɠ9yA]]% dNn֘}.,*K-+ޱ[3lzWr>#ߚ}e9'z\u\^j# +V=4֥?e[pM+ ؙt}tjYAjpFP8\Ҽ8Gopʥص@JaN5@{;RjZ'KE_s7:;GmNMv܅p<{gk3L#Rb'K,#K|2[Qؤ ++^qQq +XFqF~Ir*JV^.xjٝ_Gdb+y-*+eɏx?| ά,X^Q'zc^{/7궙]u2?WmeVXc_N|#߸1ӹ+凚-=-3+ZgS><䰎T XC|Nr'[xbh"^n'ndGޯ()|?jŸk82s g6N~4}o̟mesfQ<$W\]S\il]/ɯ]&=ؾzgǕvpO8s?f#A%YRO4R||iɞ}-a>l,~Zoc˭rFK|=Гn[#yahvmvpcO3-BpRvg]ُbJLv{gI3m'}WrW*^]jdވ/%+o%&}h5 =M4MjTϻ6/ٱO$CӇ!/Ú&">^eT=G{lޣ_2 ӿI|޳EY%x4痥bއMfG{my(~V6FQ,j5XЛ X6LPsh$fүFҒ_7䟞? +^FG +Fp߆ߗ;(Rh*H /J~7ck۩46۽iT)hmfk``#9uJgͮ6;w_۱>ȸr8yYpI,ySQ\(zW|䦸S,>uopٲ^m߮#XxP"XB|qaR :&5sM:*cY[;.ܬY۪ai!}۴oXHKT|g_~>G*>U%ڶ_ΐjc+^w:̸o Ig wgRkʎsz[;n?s6Xa8[onvl%wE_{i&wm;䷟o_{a/^m/ބ#V^Q#V5Vl/Nqxy6񜭯.dټ!7We5ݷ.|SuE7[Ne;7ddJsmt|Qf~um&GG3qpx, +{];]6.I1Fr?lh}`r_iY0ڦFut[Rjiq&uUO_|nev7ͩt[͗sJ"M2hxܧ{Ow[<evb'HqY[e~U8jAӣח>ϕ&JSϕ|ܔ vk~1վT]e]S;i\{OKͲ$9?r&l^Kq^z3MRfJn™m~7UBs}Uݾ-ORb6'OW3qO^l*^Ij~ʵ?ĘX&V_yFG/18 +*=g(ȮɊٗR)?ǶBKE8SKˋ˩;;8fji[;P~7 ]=s7+o~.Q?ҟ,A~煓yEY_Rr/%)%f(Β^ UԖl}y#ۮ~XeM 99a9yUAᵱ%](#' +P%O!כQ4*5b_{]FחSׯCw;-7);+Uߨ5&ccC'c]97uj:hbK>;M!^Zw*#۪ }\*>y{4i\kvՅg{yawfBբ^}˙,k-r z7(3ëS}S*S*ܯH,k_\;##\^TZ|/pYPj\Yds}A hkJ?\LLd͔;)w(^i"hN~˝v+4 W/CjϭQfJ,T*W7j*R*>f4B*cepM|^Lݾ~u3M8ҦfYv=S2CU*k={$mH|Dx3FOE2T|W^aAaJ0J*bzTJ8^_zEqJբ$Ģ8ֲ$E|")zFZvQ"bx԰[;_5a1,_+/'kSHrzQhlvkTśb [-I\`q1ͫ1-'6036$ǹHy}!١uљYʓUxMJ3풀%igKeRŏ1BkcYu^AC|Z!/P%vURX[Sþzh|OejҠrJSܳC|Mؗ@MCc= SÙ Ub98Uhb:__%?RxǝJ~)S{$K8!#9|U~`Z_UJfL後!CS}*S]R]f[uP*^7$(^6*^D W~pWƲT#v4e۽<ͭT7҅ɽk;fҸUh}Ymv>3.{ A~C &޼s|u43!$3:8Ͷ/]T_zT +*A2Yjʍ*Z&_Y%ߜ8j&/Hs9~թ9gz5dPtTu VoyeM}k}an@UJWefɇ!iWxe}3]yUtrD?:XHl[@|gymǥ MuϣOMQ>_MjUV*lNlԦ*W_VETDg+IS,VŤ85ضH޽^{qw?ِ8n7۷ZsQSߔ<"8@yIh+c'#FUDg^|PTD|Vig‡=qɣ>ljVUٽ:v?=Zbwj|cxY2#黿ֻZiVgԖʙūuKb.Y]=93cJfBCfԯ:k۔Ue_Z˒RމH;y/45aTZȴ1{ vp$Sx:Ҽ"ykL'Efxyip12Lh~;ĿhH:#LG2{>cz(iq]51&3̌ mԞ#Y#tիEfGmYe,3q(f$3k8 P ͌9<7j>3e +f3z_ЍT?Wɫ?dUmOEC3>K~\;̈ʘʄ+H~uWw F=d6X^eد37Y8@^mc_foUKu3O\ibLОŌ6֜@a(a2џ aՇ2k33?Y$tw76}Qm7UiV=Zh"6v;Zc_[qxjPG!JS? KZ⯼7PIp*ʛ$?||YpZjExVSXUs_֖lWGkB ^.2gfDmf:KMaG5uCYg葉3Fcz2=nLW.u 䙾{wu'??hLafejkϨ oCc7S""SӟM|vaXz 0ݠdn) T^(H}\擼2f?s[.R맠=wH ~'11 }c`3ydbzRWC8.̿x?jjN Gk?Z?Pf*M$n|Pe#|<~hɇ= N%>&v_RhE\ka`W}, Kul9*!ʿ!>[|rS@_UNk|3w(3䚆D] .Ʈ7{C\6feԋNWm^VY5Lo>^Qq.&1"0y@ g)%nnSFoUL<7=U_j` $#5}#۷{C7΀ޝ)vF٧gnw M 0kY~NpA O"Aeqi+HU\ y%^WMj}1%?40`N둘Si *]㟯p^&w7ןNԿ]k/:4e.qd:jCa|>ѵ`>j;~009úGyOk}N3à4*Ŝ +f`:;=56ɿ$&ό$a̓tY~X5Z֦TDȴӷo | (كܛ2/= L+OI#".wezeҺtnJoڤiL|{7y70fhM2NOIbfp7 L?^әa+[u[@5% e1omk,Tz|FkWrM)i_U6 ^NQW SJg< ^ פSo3bRfŌE̐A}f2}9f_>Ū""T T c%MbߋG!> :Iς +U|ST]V柃kuja7O?Nxiufv"?'OHK0CNf 5w.3lZfd0s. j?t :gމJ=co֓Af? +./|0 ѣsOSzO{\ӢZ5u֪7#zS=dcFq9x>3Js>3|OHuF FuбQ8f^"_ǪYoťRh_ՇJ2JBg#8Ş>K}?\r/-K[Jb'{RЕ~;`oF3CՆ1{OfŌ3CLZ7ߖ<SEf83l6Ɛ1b#}mI:̿VcK*s{f߈N-Uw/$Ap6/K3Wf|_SS LJ1~jp)F =v<̽4ȫÙ}t}2Zf<8̿%A˘!6j3j7ˉ̷>$}ʋɫKT >y;4APF2Ԗ2s~-U-u>yI.V\gڦmv^+Clpf:ɐȼL11L?2cpоɵe4/$ؤ3b3z33vcL3Sdj2tEj}üGQbSUES$ƕeeTfzʺǪ/۟ j},5H(FdE|fO̘qRfŀ9AњmYJq,3zGUWT殪P-2m GEG'7ΌKMo~Uo>m~%)75 k/McGSV1c7X 0?-">32F _ƌ3Zk%3j!3zˌkL^̔3^RĦK~XVUs7 %[.KN,va@{ie_T_ ï[m*VF?^WglE!doG08iΌ$Xg-3uȊљbŒMA31o3jb) Yflʕid3[oMljĪwk^V|PQ9߆5Jrz~$Յw#2sx4uIj`mʁgϼVx&/ MV%z4hlhQчb>+0n E3̐~3c+>vuyۡˏƬ K)+In|" K#->zdF ɌLy2l龗Έ|}n^B~,? Ⱥ \q +WU3Vת82Is1դ zu*Q%~PHfuPa1W3PhdH COX!2~."xxJFs:Fk3i 3SLef#2:󌙹EPf̗q[N%OxwN@_*睒ߪ=Mh0MpgWb*kS{~bcQzN)6uPkLempFLJ^Vm[NdٵPz&HqIȏɸoFw3aʏ4O~d~ZLaJpnnQ櫴-Y%U6_UՍPMճ6EyY@JfE2:.Ep'5]b{mjaҤ]"y8˪j-ftׯcG}҂l9w(Bloz¥#7!ƚzҳ1}3RcmE0V̄3ubk,{FWq{Y䜃H(xΩ\uP9'@( eD&l9`owO{_oYk7j-YXIU~RMl$ixF4weeM0Ii^L,dbN;U޳p~1']5ڷXߛ{_h5n%O?f4Tfّb)(q'wˤrgx?$\{7q&gC-Ħ'ks*/CO^ƨM y{\7|C[\pvo3m&Zg@b%,V6qɻ>g_H}3H%q_)%+5Ξd?nU.H|ו#Nj_.ا~57Ym:[{[w~ +`ËK;8Rd21ƌr/,>[/iƏ;YWd8&Lh3O7.-f$[qb5ZOp6&~ח%?V|}Io^ +J?k8w/q%/ ?\VkZFԋ Z^_KtfZg>\淌:ݳ?}t2qTk*}>lqmk9f6#0+#e؋S_rln5G) eĆ  v'h7:,b.|ez~ts֟;[{~6[5͟y{4p57fY=ǧ)eOOLj춺z161:otZF5`SeG.p% +#?翔ʝĢџ= Wn{()0z?;*=46%}=v^)lzmȌJR]a\ +>bb t '\-sZf6^ϗvN&~\+SٝXovgd1 +Qv\qqFl% ~C(i5]8W>;G<7Gy N=3B9|7[G#}%?<5&ŝwWpW_ܩ +>s ST⼾. J?6YxLZ-%Mp|`f/F fF{s+sf̦ͬ+-.Lj?2$`1{8OW~iw+wϞ6ݓc3Sh=W/W-:'Ww2>},c%dz^8/wg]Ui_8=7k}Oj+=>Xfo/~O|}o 3 i_``oɬ?xk>,RL*C:"х$_]9rn({!f_l+fv>^u(: +-Y ń|vVϮwT +3|q og g/ +' )Mls _~C^uu`G ֞iy$zXu {t_ ȸ;θlYa_ǞilbVod0ekY4W;*-r=b3W{|Ӟ 0'g==\/5]Z$N2FKyVo[s=Su߸r~Q§VguMX I07֎RwBv?$~ ]~G!8g*f0/<<|?]ˍ{v5;#?/v^"z=gO~|9|n(y.}TM9##\mSM}a&l~ݎ{!#ѤnZ0q]Ƹh(Xph3X9\ g1-CRkaP+#b6} e7|Ҫ1U!W?q[K|fHLKo4p/-o5JON紎fmp]|?U[W]ͥ31WߖeC0oa43{tl(O =]B\s+ySIbzH>}>k(v?; 8ƙ=F(ctH?=o݉obl`mP?{>x"w?򀿦㙞Hfؙ$WdtQYY\xޘbŝD\c/$#L+4k5jFEeZIrlX gZ3U8mW2Ϩsɯ5|};`;_l`\[;s@e[xQ=/ue=?Q6ϵja~vzn&W{f6W,viOf}Z0bRfѨ%777ןqJbɏ$_`zhZFof49=mPSNG|nJ|ZzwtK(jg_NW`bU yXǬrAJN~uLp-Ρ\0靡?t{paSݘ])uSaZ9ԛ 3цs 9k91Kf֯xn%~S@#lx\Cm盠x:ha4Ǭ?/r٘#%q`wP6m?wWEbVX|/:Й 4e+XsaRb4L}7? grs*/CgL2LuA\tMtdJleZ#h1Q0;x5 _WLjU|l53H гt"㳵$/p03x'??]!<_>*Tw/.lq$}_GlACls-`Iih0SiiB؉aeaZmVb:_3z5Ԕ 'eB-mL2%eY{FI5W1i1402JL VƢb`=WO纟m:91* E9H/y;-? Gk/'9}3Ă=㸆sSxwWٳEGiM#=\כMlO}Wfm秳G3NW2}xBK'IM)et +1iCLvItv'}wV:\JȶKN\]"_Y%wWwo7KQRG"NSNI.^;U?8$3㳭۩<~OE k>UmٖoO8O}o1Pb3Wl#OzU'w-\lˍR`S | +CA5wOﵟx+ \~%鏼qv_^{O+3?qËwg95}56cḪCpb~<#*Yk!f\VH/7{?YE IȌ\=\6T31RQ8ܡs]h4;&R{tru`R6V軟o qebk G륞=_ ?lO/]*P~0Nǥu=CL#kwpG_';:ݓg69mf[-b߷^q]ت 3E=@5߆r#gS=!rbpw UbH#=0BH$yp0?yw/Xt,bH]Xa/vLI%H|w{o WH#z!aWl'$C!TT33Gay| T1j"uNm'AfcHL-p+_sU= |Gf4z'!TsbXrg “:?wO}׫X3`IПI*['#ozwǸnePAH:26 +g3'nOdEǦ,U e7y22ÅZ%#Wh , +;}DQ&\L{LW>8,̠,|<:[%מY@Y)gp/"TO85/jY;g ُх[ f^vuݪ%4!(eMRd =iʇ찐3vjŃwgcp ׽ K[ǿ}_pfrI-$XP^ծ KԺӋfo NZ  mդ놾vg+r30Cnv`*g)++|5X&ȹn*Bf(!܆ KVD56acXZ)Ą۞aIJ; @j=FAfJ'AjthuIޖc0!i$0(lVKyRsDyU:z{.] υֈT^s7K-<5 l-g0'/G޼؏,fꛒrmQϵwCZ\1!ƞ SR{ ly~ӓen0л m(NQ'h2M;TF/M9RBbAJm0"_^"-|Vl/)okh 0 +'Ӡ`9C壵jCž 1:処+.pG{^PSbTo͑#\i"XqQ5C/ l"מT1m9_,z,w~i|k|+t-D%nT5,Cp|cg29/Y-&wm~ B~~"Yˋ) Jb-r]WbN4'#P;ĺyWeMLFtG?-'Z(J~ӕg?#UM\B-R#ltc6?i-wsDZNdX hTםZJզ%B+x\8Rr=w"yWiM=UȮ&FNb۠ΡR;th'K/EYd,hw4쟌4cX)qĆQ)+:ԼB_ m=z^n[m-g(t5#t|yPDy8>Ch{Kڍ<cVX)t=zNjeB}6η|RE`I'fPݫw)=G +ÝrT~fWAv^k<o-1s uH uD)eH,!7}z[iL&/,W`246ҭ6y_AXttVy?xND@܀H\/кGN%9ߖ5T:GuCB(S18BM.F2? +.8;z?wg%Emv0z#2la RS+V>s6\zZm  ?Z"fQ 9ܧ'}!vv7NN"yhzsb{!"qf%֎V +T * +NM.&ב8*T;G:0ľN@;k[>4ڲcƊѦqK Q68Lِ4K2m m)SygL|nh@7tfBnaɑ[:2;Ƞ;7،i:8@]}jÆ8S>\T/u}.MH̦:C9¨voY_]Q/GsA2@mMA)g +ϰ?֧nrK7jdXSZ YF#V;=IVRxZɝ={G1z1̄@36| [ RiGf(wkp';ЏnGhĺSh:GXwa*u)`$/G\7t?crNW \h"z5zͽ-HTzaɖJ,]>WYeU,%کE&k&qw,1FG`?70S@^+0L +kY4{ux$ўHr0.j9WQ7tHW`|p4LPw+﹵F_Gj#^CrR9jMZYh>s"0kfY 3Ƈ1Qj|͠vVdRV=!}7!ֿkgv3Ԙ1EiX|lJo/]-bv(X +NKߐC|!JT x >p]}V+Fvl|?;?B?]x ACS=4I)F['n"r@n?bLX訕!7~y9~|X^2؉9aQ:jP N65 a<7_~]"$ t5>,뾕jg%Մ5 ="Dwבadj̶2DeX))C̡{&'VT[ 'hP>}JVW^qRv^ԜO5Z +<R]yNIm\DX167BJB' );qTˉL#xE~?og9vʠdf[;xP;HscrX%.:@SYCC3P-cxղ`nS>{?Xkh5|%n {Zg ?y}?hv,ID@h~owz9?~ yq2M +"LP;WhbKg !+ifȮc,=4 :˩)NũP-؊ǞԬ܉+7,암M +#@;8"GnHɰ *F`)[(q$~Bdg&4F{5kIjJ1Ƃ.GhTȝ#}T`sS}mӅ.-T#&I3Bɷn1d. 3>0}s }XGr䕖; 'EۏZ>YbgvV^3|xSw2XTzg?2@?YŃYΊC;+ueƉTIގ& $3Ug"I!Gm70R!g?x| $/sP}!Vr}B<|=H3/j5Z'Ħ C|FǓ<re >Z |D]dU<,9@*;guEi|/jqO,P_i:ڕJB-aob(lw]Z>JSꈿEPUwaaj~xb2tNbcg=wh 6߻w0j8Q{cQ\5/.r8bymM0SNY7Cdt!&bh!!~4Ogݏ(*ϗ* 9CVbŞ{K!ڦIEϓm؟~~I ]Ps {] +CqT,e2N`y j% +U栦pàS K? ľhþ0c`oh!^X*h-rEWv+g"Y%Y˫ F~+4$~-ȇWW sWtN˺QY+7P][sI.a'4Εȝ_w7szvޓZ}i!x!"Burzꉇ<"y̵~;-7?Z}247#1cBLGgW/[aTؒR{zgP";1,sס'uO7H|p^QRX|`4KG^Pf-@5dԌ I&5}cQ$F$vs P>U gŮ/HqNfpj4M_yC[bK %mE͓Kːm֢~g#2-Y-cTI>JhgO5uXWKzg >oC]?Gj8HlDll:YhϪ<<Ն+'vO^mН"kT#|׃ʩ<k:=wbo2`|>'#.^I=qR=ymɵ$Y&EUOͦ5suJfq@rja]-lLY6zF32BD\?B_ԓCjyR*g@ +&QOWAsrt΁ԲE1Tv]^"ֽ|h1*ϊ3$CGЕs> + M֩YCodrgE5Ä]T\jCa#H{o t6ԼvO5M*n޵țRRm%$Y(iGޛ7C݋-'pA;,AM㠩τ{cBvs?o/*19g~yRsbzQI*X$F#G{3칶yjŹyRFhc Xm8@>>KUkpH,+=ȵ|kr=MzsVsn,c}L16J<rtoc/m99o;͆+}Q]M ~3 ~A/#s e(hBRET|figtjUGf,k/B>G?~jlE&X@'\wM;_KG^N",1\Y!q`]Kox{=ox{=ox{=ox{=ox{=>fr s NrZH_#9#&)*2*P>ɗ"ek-^l*GW,^1x5W,uZo?W?=ˏl:Ν( +vK]υGTLn 'Cpi-<5*4Oqǥ_oωಥWq48.#]VOx8$l RO*ŒL +KgLrqh3՜]cժc ]S1F)@+^qdc`,3i0k&LR] #QBdCRB-EfOSdMzN0:Pp`F}nWmKA#j hì 0M|* R 9* GJK>J)0|*DYsQlHK5 knc׈D3o?a0a) wcKmY1 d3/w^@U$>0\0$ ClR><067Un,=*C @jGHqVU`?RLffL w,EށIk++ yu7). +#MRF-Sa󁙍㍉9vtCz( (aG=B ̄8 ηl1Ni? crrkEA&bJM%Z vXEGqqbxJ:7T\ԝ[lH7Fͳsa tL/c:Sb T :Rվw7`QDEŶzq2gߖuOJʹXQRCaT)b=m(%+nt/"B(hpSgo#=@֛!\''r4MeG1ƙQdLxY&Z\77Bl-|x-f DP2 YRFJEVzC^X + +х6BzMBHl/a3Jh`FMmHqPcsl +3HuȴĘQyr}4ϓ^3JMr!EMSqrݻK0Ql*AA|/E v_Zny|JQgr0_`K} c'QK%Js،!dFW1FKOhOM)AeCjH5bT`?X,\:::JǼw2 x_ :V5UoԎ Z$-0jFǝ˻+XHޞrVh;&ϚPpdɹ caX¯ɵ=b\ 'bdF݀]y{ho_+[3~FOC,XC)D7Xs>hX&@ 3³,|+`mt bmaD5\3L/URkG7Jr~^n Ƙ*,́T{)B5:%d|#P+$30 ے}IǞNRdPK#~Ʋ#4njyATg&&)VRk.oR+O̅/2U:%F$Xб-[Q;`4Uͪ!g4bȀ2@<ً]4[X, +7Y#4H'|&%*5ґۦ+019!CcTL_Oj3f62OƸ=yXKq쁏#@(1=cX!,kQJ|- \p~(o\|&XH\؞g l.dZ$O"F""09 hc$PnK1{ljiU#0̑\ O*lvKot4@u@0~S41ܔ-xC |eqt6tL~14L'<'Q{~m1ȅ>*x:H7r;\CP%y\FdJ)V#bQ4&X |,Pt +Cq4tWK`&1uBqS>)&xjbƒtLժsMJ>7Xl?0t]1fJ't8+H3ɹ 5X1ĎJb ![ Ev/6Dl6ց"b;n{P!> k1R_DtȰ; xCpn_Bc$*E[ Pwu ][o\bkPpt|1^j'<_lyQjRৣ͔1ʮ K0N]iF!?Kr]SH"Q>0X; +~G f͗*yB!>뚾s$t\GAt\otc8'd}Pl +ɅR|WRpK>+챎c,~fF~cx/tt^4#W9#w_,6Y%6fS_Ij욑́X>9JK,FsQf."XJqTiŅ?k FS!74Z?CJOAG pnJ-DX!-f_X!OgFa#\VXSXuP"C8h^:Zyv.d i$?=R81Kj18zAFh%/>}<5a]Ldo~&359P;JrHj$V >ޠ|9k(rhBL+=\>_e!0OJ;CW܊SkHDH?(HBΏ\ h%E&~ĖDIn:MHAQ1nβ?XMё5,uN*;O |9@auv(&G$Fpa)Xg@^X~6́1fExȪ`ЖeDZt>qJ*S@bEjh3,y!vt3F׵,U  cLuR$Co'@~L|b2ɅsQ<)hs." K4`G0.*[` u.7!ĕA)ZJF3E=z + L0‘"cI.E RJSHjrIv:l~f]Z0)6g4d &p~R\Js’,k@N̳ߤp^#z(>0 Ac rltkjVH3Lk +&9%pNHn PF` KBqM%1 %47=)_\"Ss0?jRDM$p+&P]zPTJ\ZNVMEk!q0˕3{QZ3)yRudU|kW[c5R@嶈r@pඓJ)8BTP`Dž;oHUHlOssﮕ=qʇW2,$qeRq (%=4?&_JҮ}g2`~>`N +kp"䷧ E$gtmG)^&u !B ͲDMDRJͭw6 X7z1TʳvW6wDjQF{u@5K9ԪӃ8ԁ$K-\KQoi'į_#?9 9 aZ5}Y \Q;94?&p$GiyD?& P2z})襐|7nH!1cq!?IkJ`Ń}CoX;(k:pa,fՏ2HsbZp`My3pӻ/-䞜9 Tsq񵳸5b)rvxq\͐{$楐<@i"zoQŭ>qrÙŐVӀnF5\{qd;_HޫK_*ǽ)!EX Y9 VDk޳W2I]G[PcQcadѺ9\AHc@_Ssr>jzBD'?ld8Oq[m,힆DLX>?ՐлVH]tl\pq֒$c3a7+I:U )-JWH ǀ\t]&6u[G۬汸f%6Q#1szJKD5eM1 *%jQTRZ9(p_Y=7Vu.,"diFj% +!$=DURa^Y #ߐc"ױ^muLW Lz0! A-;ͤ2~k/WKF3QIYr}wV>|Ŷ}JBDsFr( fd6>%?aXx@^GN1"B?$brEJyjI +wzWGZzu|(ÐAX 2ѧKiz E-DH_ȷ[i9f JB lc +l8c8PMRA(SRή I%!kʍtOAN JB(\|@#Sj ~"| Ӟ+E<6k{ 2V᜕m,ns4$6PD{Ŗ)=WHTݑ<;}Opn7WR:9hPZݵERa#_f\)Z눘=g(\p- t4./ dߥHk!FPT_Ր#ÿdEi8 xTu#}:۳z=IRR>Pzm&r.9ˍ$h~;@J-|TV!r1mqn{&O}iH$jUDm<rKKB$>IXWJOQH"eGJj"*zy7q >PF7Rd3=7Hȇy]_X I @5ӎoR})$!>=YYnD? {GAc ?5ǁ%ɩĖ+9gBg/]_lDޥ^T%$#|]k LBEЗH;mҺ8mCRP> +PyC5l*W;2TMq1éCi>@$T4ėbw +'  gBb=T<ց K0*KBt>pUz ! ͨ͠]7=$!p Ԃ( 1J:1f(2kdI SQ;RoəG u~,t~"4\F)oݰNB;UjKiHlSbjjHA +xp3EiZfj_-C~9?zXcЭ·ٲq+ UZQ:890Eˢ~%1BQ QC $f"'G@ \% z~ʞɋUĆ$ 8@|# $-g_Fh`sĐ>2![4JiEuBrq3I5o|7{Ztqt70۸b s}3F8* A։Tub6rJB͟~~ @_7,dчe B%!%!HC"R24=aHI{'К3kX+7{og3Co< Fk^Q/aRI龈Ѩ?BCS#҇+A +>|JŖ'}(SOw xy0i;SxYJĮK˱ 6*lKH-Ϯv>\F{u?(ۑxQʋJB_X% $DP8H}5rzkzx=!!DB!oL^30bHV?L*+CVnd,tD)jyt كW'^j>fC=qM}5|f.~LC`UuVTVJkYH,R\tR` +(ݝaN}Ͼ<]뙬oo(!nvSیɴmV*s-u)x#GG\n+q))7[/u wlDw׊^lx_``}sEVj0 eTB*/䞩PDL2`#}-{9b-Ir8]kR&l/S +1u%l P[C QثZ:]_\zED>_C(S'B B`yf m6) 4zY zM7䢠^dG"GB2[8)Я4r Q@jv@3W5.懈F<p.99E,^KZ&=?}y\@Orva!r{}W㱾>[FUk#ٱ gKruh祖 +G/c}PJ8P8k zKHonqy;9 +G̖nh|@/}1ەP%"plpɝFծ@CN%-YHG?iϗ9J_%.IY 9/k'%8v} /焅S9Ha9_$jrIBLhnK҄#>:3] Y*NlҦ 6ujB@T!H{7Oj(u2@C Ww2c:تA(_;Svd`GBQߥ|bk\jG[=?.J+g" ѰA+x.W t@'9:#K϶(pA526^\^&́rQcz9@$ / +G["qAw6V!ԩ lAn(}ZZ*]h6F&$F*{RjW!GGv`+Wr]OJwyu,q8,#sie@Q˻X%|蟔`'/:*6Re3Ŵ)Il8\he4gZz5>LnA"{{G?G~g } sUɿ"9  6oh3޷Wpnw]4i: 腡N0jf"l'7鋰'BtXa(:36|&sWˁu\ D8|vgp=蓽( 7@SA}jC^kBTa؏DEX;/#{R EVp5@~e8f4.\>`W൸ nm@bJmÕz.P8́'W8sL`;G24g mUO 4@䕹):›M*E] +ZBM +( ]KjD萱{9 o؊=fm= uTo=})9χk(Ln1)9U;5w@ԥN&A:~V:r46v&q{ خ.l\uA 5O!_rk!#c*NwK@GГ ://6r>˝ŴO*" _Ym"gvq3)l quHp0)т`ODdʠ&s[ y|Xm)I٣D1Lvv%U|̀"& Yz=iV!H B4} w!$ckB~Fj eq5{9oϤ~0z~M:]&p]ZT(MlODqyiПdJ&:Eh&Lyo5KEVG2**d;q:ԬN4ӚE)@H7s ;SLP*WhBԷ_ݶHE1~yyR04֔l3&3QMn"6;iU.F4|iF-A +S V*$5 +wIb*!Y'hr:U](<{cT|*+ӬͯZT@+z`WjZ7{;ڌx *6CJw=YR=Oԣ 9(8~I9Σ\9yQxYMB7)ws*!a,%媨u=U{)?NVQ";D=S/$W 'dN>ݬK5q:tB{qm[-&fIq\z\bKg15e(jǹ]xB#}Ø;`d3Lvya!~^X~H|$S؆=›]̝>󠝦Fݏ&d֠ AQ̓VaDSke[qܡ%LK$wCdxdե%٦ZQZȦ,ݭ7kfU}Lq*P >)ꂌTz.uې4 }4$3?Od̋>zG)8B|14$[,ǭAr̂G_ _g)&aỿDem$eUW]4{^tJU%[ ^]87&8o+ή`(eH-fL\⤢@A PwֲgzLE}2ɽ47P=qjңx=]V̍+(yvF48o/xo'w艓>R=/j]oi?TxXyY2P+A~9M|?RߜCVFH=e f]#1*w|%ۯc+׍YRYfyNIyOJȈ/ضݢ]YN^AFEFXdjޭAI%uh2 7;V$L[wLxR䋐z> k?+>FQOK& n0]s.;C|, Yɜ.>#m/!(W__~0zTڐ.߾a'2 2C@<&~ Ss).>MW~8OWu#_ JnlOL> $ E[DT~zAa:P,jg!E + I +66|&ePt9K>@TN]ťCOs/Ih'kk _g 75aDvA!]Yj+a]iYE;WR[ɫbqZ ӆ8vI>v[Q;9oTgGɧ_P/nOѧF/kuzM2X-M~%)̣7*Zđ{aNfE%ҎfogCCՉAUinrc7GC$[")i6k-\m9).nEZXe#-7ο&.i }]wF$Bۀ4,y&7w -GngC5! ^ 5zJ?U~!GU~8Gw7кe!egdٕYGՖYv 샌x0[OKrOI?$4Cʫ'Ys cbOݎ=(``C\VkM7cJ2-5Nf=CrÏߋ9Ӓu!6b]TعmiayPBGK1eAJcn n%tzq;]0tĬ}e{ܼ`p7f[awsGbHC=SDQwI--;߄lw)9hXӆbOkRd"mE_s2V145LKBУ"Uat ?5 Ӿk cnϖS==/}yH_R^-k:2HdzhӾ`QkEOQڇ.<),d*xONЕmߎN0'V]5eWM6Y:7b\kcϷ$~!R$'#c8cmaO5?2Р|1da;?-| (+֣܇Rn%LSv=&r?^L-yvҴEZV zk.LM]R//@<"ueG>92ZY+Pa:Tr)6ֽ7έ769ң7QZ|o?o>P$wn Lp#<%r+LKzɖ{/q~ߤG3~ sY-m[w.ZYѭWStiY?l ďjesfogFYu< =(BsRm<ң;Ԯ?į#$IYgWgXtɿJPAmPiu@Uu@~]QeTZz58>$9ԯ3LcR`e39QY3O>&O:-DytWMIzE?F:/JD]L7@]SE 5"%( 2뫒ӭ]v q~ Ysu@u{KOÍ-^I +=8ҝu^MkHD@[؃j;yaMPAu&w1&0&EՐlÒ˝+\<|"dX/t U=Kr,-%ZΙ5w7 j75$iBɓwM%&b)sNt'Eymlj; bvӿhĢ& M 'řb]n_"`Փv9,6)25Lkjt$w>ڙU$[m GV]SҞ2Ϙ%.aop?O+^c:(:0:x06ckd }1Z3w!Z<|ZfH B|heH]]t%We.Rhh5 MP&+F3/DsG/G ֣sUT6~r+va5+vy|Z>cY$O{Q>}}p~m" +2U>.U1q="ss"*\r=ܢ﹜2|)(r@C%.zNƯuLճ9 }ߢz_6f}cv^DrUQtxpR&WhZ8-UZ60A͂U/=4O}aOemL^EMCIO"UFEMw~*z14=im]bP/98'VzD\e~i FciU'iZ|!Zn%4?>C5e+,DD4B#p>K߇!^ǣ5R'B7[@&F_*G{=CËF\K.p %U<'),63 +Cߗ] Q|}n$~|5yU(,v=ޞ*Շˡ?ٓݲ-?a4w# xLӰM46ݿ{܍o:^k@^m5ﲫ#Lgϲe֌˵uao`_$aa0o^8riShcCxg]c7{ :YϞ|gmtKXFv]v>0\Ur NO7&Ĕ89l(ti~\S[nS8ϰga1aCtMĭJ/Oou1kNGhnĩ[ѢBJ"/g=tWassߺDw)wI(+v{YSP. å/wyxܪ~^f8~jCEeNX8|2l&8M6ϓIs_F,C/E)c֢3tj'j/-rl&:UK>h):&9֕ ،֭v!wqif=a=)827?JxO{tJ0&̉[i,Hy4c64mF4m4uz4݄fߛnB;Ld+;٣كW1sMnwQWv@Sr_CBK]LYC,]Io? / є$<`Tu4}J4j-RM͜{-Z}?-GMǧgR!Wע# "+9T:D8F{)4Ea~X\U[A<Mc9>9=2<*Xfy͚͝Y-YKhRR/EsWh~ c:A=AC+Poyw#ifanrgC쑙싕؇ֽs }W(7Z:dnl['=9 ù?u58F& +3Ѭ+Ѭ)МѲuRb)x!|GsVќ$@3ʚhl pסnVۨ=hڙDߘޡ/ݢ޺`^!b.b6r.!|Rt6ќO|Iy?mMNA3FBs-CƯFScݼ +͘]hԽHYi/ܕfh Z$Z牶Z=P=E5]^n7>\ >\Ț|>>.2cYf,4EeMa"4s4n֍͘=p9ZZZ-5 +A|кCvxԍ]Ȫb?$7_+85ౕ9?/ Pm6z6.65Gub?uO_x qxMs8;)Gʓ6pspf):Yg!EZHyZ9_xⶀ Y*fJv'5,οugKc o骵뫷\51rIrVxּ)~?&`c*pZPCZu +1동; 9yʪhbc4oo>Vj:Hfћ[~ߛczY5~n5m68?O^\XK컅KV/ +[0m.&IRvB% qmc8X =M4cZ4eZhKl-^ru͝hZ +-(FΡFh=y9s'lVEn42c3[O zr)-2ȸ7"O5ǘ:Յ$_ 说 .v gMg۱3͓2?q>8|ЗF>\p,D&C%*?>jn T^+TyʮY}J;r**尫Աj&sOiїB'皢ALS] ^ه^ n. t-q"4i8(昿l9'xʣ根S֣k:h%iV +Bkr|?rWɘ-nGol'*9/~yO#aԘ7g6eIeOkJ[AQ!k*Q=ȇJ:z7 h3d \㻣:}Gњ$ZV\nϰ矎upzkUzakN|pns5o?l[YF'zk[ Xq)K+YsaiΎPl"ܲucU7h/aªǘ67ʲ+n~qC/oȥDm SiR4gvl ڬ} .9;|Wpwj,"܉_QcwX3J Vn7nL7ɐ1ڇFzr(ϝ<3YsxÝ盒wd mu|j$IxIi]t.NnWށ`?:q͈^w'Xv|fIX+ADݭVna5 `ԅ3C"+]N5~!.CòݡݪSj7npϫo5~̗ FԶDzZQB#ԤJ$9Wr*h1g (gДLM[$MU?;jf3al*b? XVDhi^v%>sł==c=߈uAKA kk`-I{¸e^:`hv7|{}F'c>W:'8=R6xj?܉ ӃM+FW#Í0}AXBVO4e勑p'n(A=K4dr-–K&ii䭏g,ȼ/X[b?gm*k7.k}UGVf=g0b}-aK~B~r5AJhM&tMEg[S#rȏƕH/z}Ϸ oX#ͼyO~/:ha0w]RN;%̣з6]^$ >:j{ ϡEr6Z˧K.GɊخ܂V2aa=^k5z2W?]sC Quo~ЅC$uMҲG&gPB\twBFΏ.{m^teZHТ 5ۄQ3Ld^zJƬ](C"h]mﻋχz۴`.gL^@kϠg:]R8<9:A1fEZvk`t4ȄoLxK}uF|cl{UDDm?F=dޓ~'z$`Ɋ;5E ZtPf*[Cr/ ) ެbUxy_v?b5M75e^Ualy$FΎ=t~ݵٰOM}QIeɯ|_waػ\бFηf/2I 8nqzn_*6q&y1BIߞGޙK򞠣4G|=l<$+e +KAD&AdfALV2amDJ!_vыhydy1ӲJgˊ>ŎҼ C2qzӵno顸vOXFxǡ+7#5ǂɚ^&|t!~sei;!j|-/O=_M%z`8u}<` +j"m;&ǹBvK3"c`AF%"˶~9+)+-zR&l7s:| :թڽd”ҌJ[#k.6w5KAtm\i6^|o`m=;NU-0ƵtSQy%7Fx>|]#n狕z)ڹl ڿz 2RWCfKESwP88Yf7{|EÖ>Yֽ_x-i᝱i };ߴ[QwwnD^S&N]CنL$6 ZmzrX-QƏ]w6U+ݭ=JXC7zq.o|iǑFgM,N+j] ;".9 M~/h9Egr2}e]PoGyZH9F͢f .V(}Ae.L%-пac͓"#eEɚboב"mU]v+w'贂R۫t5Db9ۉf.KW K\ȤgU? ڇ n&Tʋ7•} o*k9OgQ^+1ʰqg13tN+ZKarITF㛃ۍҿ2ƾl!klR7IhG1v51Lw.2g4l»$3]x)p +Otp]hDzh;hXzKJN@ft֊EDLV %$u(9Mt>au5Y4N3|oԏ*/^)l;+k;!]]xk"u}"ts.?aW&mvq Ue^Fak rՍ"=ꬂ&٬r#YWvӣ6Y繈ShkVը"Ab^DV!雵 F8FMyf.0*Zal+E/U4&/* /M8QM-iHc{/27pfqE'Fx";1p'ڍ=Lj4R*#ޮ 7STI'9@`Y[HZOp K<&@&9jd}4yIƗnw FOc<1Xg9ˉ A ŰTpH}KP|IrJKF5즣[T78ZE_K\HHe~*~U~XЩ|<%S44quڻ]A|aϒcВ Jhh?2u_$xIo<^DV3X%2;=/!Zv|8E\']0P *`_z̿ j .K +n$] 'bq{}:Z\I]/Fk3 an7t~Ai7mn5mc򸂶T1uM L%((c(_`YO/=[iϬ 19S" AH5D\*EөO`Lhrx=ا!Lh+ y1 + oLpsh?:~=p$i1A5֐:f> χ˄ݼ;U"j-+6uK7=7 ]#t@60HψB:ZHGxS{ EIKuqP Il>@&f7qi坶l$W)٥=S0KtN(Ω[%Խ^c"&EQ5g޷bRLDۭ~^)-[Kaؿ[qgnOtVAOh5gqy8q&`"Ց6@/G{#m78"^rJi\8|?2dbL!1x小ہ\r'kC'2>j/W)|^<}g*'>r6߄ +zg"B_m$<2 +nu'zqq)SGf6ÉLAq'08{HqMϡ=WuAs>ȳɓcWGv$vo0q9:a|.[ퟩ4J(V?Bf#J za&S,tI+H*HP˦ :` 9 cYPtHmbf=\}>ڻv:G% H$X*xXsÁx4x?[ >*W Ԥ&S+2>5~J\tJ}X֨J_O]B;$.?qGf)ĥD~ar +ZU`;Kpb%55#cV'p} atR'.TN.ޤQDR>%q"yd t􏚂.)ru%p~)pmAh0ec,S +/c_!b%i2| oY%y<:ބf$0E )qCX/{DJ::)Lh\Jn5"#~bXLj!*I' e@pn#m!2 {tś YWZ)>Xg&#,N*W 7 LjG ]Gip E95)Z`.Lk,8a7Z`za8"pvѕ0>髙[>9k=aic[!*"Hjڋn*&:2'[GtFO^'`˵UTZyˈya*{޻{\k&Q :VN%ا&*Hx{<ХNv8[虽Tx1|*Zj߆ÍH[1%:3z"|x`d9EEj CY{LLtv O ͈0E W6rC`;  +|c?:pE)ŀԅ)S.ɳHlxC8P):ho%ԈvU`\s\E~8Ή,bCEIB0=nH4Hu3r'Dl!qDf Cڂ=fÌsyz e & 3e1(`h]xHqѤs|UV,~md`"B"ט#8@)qԙk.g!}t{0]IsKSpX*x=}3y's ╹qԖܩ#,=y%F]5󨙒4^7o rU"_Cþ|c_DSCԻOrh 5ڻf'1`:qvx#VYol%-GU[=Өvqq%O[N#]v[Bf8t#f 5ȧ|n}Mg- {/6L$G{]vjũOr}`& N9`2>u%")<|i!BN2DZ x HC?9Nse芧2¸EwV^aj?1n-;-0.NC&5~ TC^oyyy"av'o#`,c[)I_ +f,>`BcHF6E^3=qH Nr8L̎)p8.Fb!/q c,{<ɫc OW>0H(s)b+>X*H߬ӡ*TǛ8;뀳$k/^8ꅵJ f Qaۭ`E/[,DaJc]vLc\$U3 F0ZSkv؉4U .]5txؗ>(ǿLnR'-ϏH_FQV&2xnHz>\aE/ owꋞeL2Y-e~2șđ# x|8mGjE @l7'yp*|&@(E簌]tLk!jv?kˌ}h/{:*鑀SGG% :>_-M'Uioocg6eϪdTNXM@k JONzZ]\`cd %Fq %,~7 wKX]Ⓘq O+-\]l#o$ra7OrJOc-㫺ֵE -P[%ך>Wb$ĉ+ qww' RR + A\{9םҳ{sN5=nc\9͒joUZ,䪻kSsa{`/Pu}ALWۺL /e)w2ڊuMueb.qi[ۆkx4>:ר^) "pjUEhXYXعurI{郠-U$V³٠O+֣ A[Hn^-fM>}7vȺKRa`j/SKN束 ?nV~+C"z;[ZޤW +쥳3$MyŲKKՊ +`׼!+ʫˠ%Fd \җ\0Q9#ت1C+Xik5>_oM֍8c̝_;_Pk[AZL .-zbb\åR΍EЊG 4h O!sa[3-S67U QJ"Ԍ!t|T(9RM +.*jwmX&Odcy]stP}uTqcE܆1ź)LLB[qkS-'4_3Ӊ'?o#;XO9`e׫5KZι XZCǗk- nFsn1s\ FRdБ}cS3]Qe쿿 o#9ݿC@\ves Nxp|؉Х< m" +F#+Pqml4hE.cD܄79zd rw_%W +QbCbr8hiZW\X h)-[ӆ۝1K=,c8~|cu>{cꍠx1>v!sSHw0X]> +e1!#~RhҮJ[ug j^0>\\ؼZqo-ބB٭o>62mݽ_\oԪWAA>Ljqut_s{lax+J-U94ZwbqĽJ8nD/u2P+LhYT7r.WB2+nƙ';KW-HSm{ը,QC4EK_9à(=XZbnx ]|br//R[ڔ5%7;>s5L0l|Elv^jPs|ᶋUOhqoXa1ujqX6ܲwj|EZܨ)ۖz.4Q([6܊^du MSZD5F= '!Wf¶Ep`J5 JcKή X ,.9G|3C]*z('gBGsHc:@6T|cgjef܅3xG: +'.Bxhs_s9G&YMuprhnNgnl*.L>,!|,sWB_|߁!vdcͺ5̯Z,7zE< 6߉a N 8Ur;u+h O,;ksLok{n`jEZaUKT0NHSvS@w4mrRx `@}=S0Vmߟ1 m>L9v-n9ang:?:^!a3ƫ-4wʾIÆo_'jZyF`1Y,fg(sagiw +!6(Wdg+6MAlxҥϰ,j}51VXxVCHƧȧ8'y[/1jijc-3^f`-8t!~ McH1}41|y tuڎux+ZG;?/kգG* ͅ}SoClh?g0ӏN /,@/ѯ%#qϱ +9'Qq2V(#mE"^ xewf7C}.7;+]TX~O^4j({>V,6]pϲUw7ֲg +{ML|<Ǩ'?@ |&hzu xx& &,s%id)"SvNJiksY|˙.1h `w1,%׍ 5ꝃkVvʁyC5F`TH7 <r*hs0b,_}{b 1XU>R d\[,ߺR?R6(30Vק4NVoi[d;Eu;K(Y%`gu5XT< Ml&bg'R߃qXm9/壠 rԀ6>F@gu^oU9t +9qK:u+Z}Oo93y®&ڪ֯?:wr=PQדqXM1i !#"~΁?E釧W6ZdV|[p `83%i2XW-$2j)(Xoo[!hH,h';˯Y{g٧+ v]pmcT dn[=7T '=+KW4e^K!Y,5qP(qTu{ _7\Ʌ`S/ s2sOυ<=*GKh1O/ Dww 굑bեDVv%;YÉtM|)%,ժ`࠿Nɡb1yj`! & +<,@u'`þ`\o0ꐇGgK#Wļ +ࢀ#E LŢROz)-&vw$OpMOt2 tlhik1/瞙_]v!Xvw +|qMcm5#eSbg~V*τZ;+%X |%b[YW\}0[EK{'Tjk>qwrXtKb7~~K9YB5W+4II9>S .wr72NCOCsC^D庲߉XTk.Txi $s+; &vGGTeKPo5 eXu}M- bɄdE.z҂Zfۼ}chנ8aՈ`w"+G!53E'^ѿ-yGEF fKri ƻ~C '"Վ[`>l!\WԣFYM\r.- ^Pp1PՠO P)mV!' j#]{ fߓL~bi((zJƣJ`5 7a1}/,!<۶A>h^]]r|!t(XirŸ,NVq +IU65L>7sVQ$^&C9 S<6S?̅_=N-T\Z,4`޲rִS>@*Ppjmb:w*ଣ +++eqYH1{!}dn|Jd塼sX7֞ з.Tȿ0cKH'T=\|aYC}ǰ{=a]=PW\YJsv]Q"yGOC@/"vM'1p8*N\o`92s`'<3=SC$rF'?1XFsSwN.DFgOI84E k"r8>G {fGk lТᨳi9_0>0qljs`X<W]PZ-r 0 ʶoTKXypWӺBij'sOLkOk体xׂo]iZ[qK.\ dX'߸tauȥ_`2NRBx}VU9BX&Sz 4WlPy1"E.,J//|M8Ȋcb\w%K uEc/ |L=X?pXCib>JP0 +eY>*3ol\}1ޔGؚ_HDe>b$XD{&VKky4jԻȓ0*2={m1ͮ]Hao _O l)quv +b9h(jgoMKLk2" әxXQJn8ц$B&'=bY;ا +XصfvEAV}DNȗY(e`ߓxb?> hDMd6Ƴ떴k"Xt+<]hI`alu<2&A_#k FV|Aq) b,&U%;Mneƥ" A>G ^ʮ-x"Ɩ!8V;|=LTl|de;tMŁ)4LOMجx|<>x|<>x|<>x|<>x|<>?&pXmkOXoŠ lVv[}}`3kj{_O; %`Qa}lf,b̶a/`:h:{sͲrs3F쟍}\]<;{h/gΛhѢ f\0w"#fΟh<~ן?{܏ϲbS_]/q=Vmlaߣ+swt0?-o +؏9FBŘ+SќFF:ϷΛC3~}=qIҷ>HXojG{U`Ofg:ngz]0w^ǨFs'/q|͟?4>}ΗteM@#]b4… zk֬2l05],xgReaYli 7nX.]8iQ>> `/ Efnڴ5u6b3UcS2hѓMo-m84N9NrMKJ0e +U{JN[=b>RCl +CݭYwZhm͒-:tNܺ>Qs98-aZ.Ҧ.[ $F֌&kKť og Tl ^q=}8SD(9aQ9_`D ;GT=BV֗@‹>$7 6ED}MZ@ !B>ҕm h:@ N],캘X(IYcӅFBe)@ lݻj5eCsl`-[[)f5h]!ilfpak K{Ʀf:s)6u<ؾZ Ko yVAtض Dp[ƫ^xkd}[_/~MD6ln= s0(#Ԩj#4iC gxo96(Bh \hbPPDV&AᅯJn,M1Sk{6U2{ڱ PGXoD;X-% ]z&le6:aU#D>GXlݬ$Zi ta%I3ΣJb8lw5AVp聍E{|_ },t],y.$;6c{Y>]jyKT^q&MISvUZ+̏xv]Q>U}R+a}-AV>T&+e&8@ݟ`S(ɃD>?\Jv endstream endobj 792 0 obj <>stream +6qb96AB\^lQwOV3UvOQH~}2ٹ!d3 vEnٽĆz،3ric56D׏Ŧ%x?e?7a~E_)6'혠ՏxWq-fl$DgA{[_)t$6Fڱ26+bKDgRH$l ar!Q؄'g`-*DpK#6"1nM|]5o@J+0[\iL75Z$P:s`|ε+ M̵Kw λl^|6acm!61clamf:@+}!%ACM it AQu f>c(3\ajt%i&ĆD$TQΓ B~)36`6|2!% o`%~gfQl 1D1 1N6ٵ` |?m~92~O'| &1H75'o|x!1IDbh1 1ovM=X`Uߖ^[9Ec4ؿ R_[,dEiǦLbHp1TbEV[9C匃3죳靮]l @ Dtg~,~}1 +~GN/%@<8ئO HJ}DDk@<6cC0 $r!#6֒|O@\K>cX +#~ЦlC,~QGL: $yd:i3.Q%(|%=R? +1Hr$ ?sα΁?-6i뜼ƒ+GǦccsDO{ *MDgfH\a"&`]"{Y`_X!O_7Rpbb~Zm)XKtMHcS!:LwNbwI;ߙH {&'A[/`;BPa[xpᕟv@Y~X= ҃c5o "$f}Bvb 'G +B"+v E1_]%pY'CI> >y5D[ >'h, Lq<,H,Sl+9Ci:[(D>Xݰ%7",vc /l~6C)g)z qs ۹!؁fk gqF"3:ƭ+jF;- ƛj=\'8 ,Ɗ.`1ƁcPwc`ִb:cS*mxnV3C\  >3r^r_}R*y-tN^ݴ(lMs 1_4ZSЯzGL֯u٣9`z ƫ+)I KXO7QƍayZ =*.?9\WռTh|cok+,'`yj}YJY~u>@pc@ IpDz(. D} **! ST+ZH!Am59 + +,WH30S,fBNbֱYL ]܎G$xJ5^_@~OеgF߉x j ލ=}! ' pHD8!籼{DXmecAA,.lXk}~0spld n -2 )gdC@2 +:VW[Fc)w!Lw>a3]D{'䜂cjmv1|,F|l?@/F$ԌƅT8Zܛ 8Fgn'@+@33OL| q!Um-zOȲE!7 $"h }^ ^$$LﶲQJth*!CN(_NUN)$a1rr$>cWt%+K~R:?bҖ\z|/q|1x8C%'당oH,BxEgt|PxcX~TٲJ*B,b,DD]JDD\%ΈcSN3N +,46jˀ]h;ufWSau?D!dDhl2G+oWO Vq%/rk+m 2!H@>Pwk@t%$ "z6!\"RI|RѩR@P)!%(EC!ҫGWIߢGe5<Ƌ sBjbݟzXkW|8zݜz@d)'?5d|䡞k|b`ӶAvCM'mApgsM)I c .K"zm/'?Ec- tuPcH2t4Sn`S\1惯I;5vt:|"Wreua63c9 R֎A~":!$+?bzײ#E2BZtgliﮀ_Y)W_ +r  N5!Ů +IĐېagJ'K?y욢^'h6Cz@(RrLj4A49(_RyB|6V+A#7^_ zfW.f xo1Vu/@x}DՍU"FRnu/ؽs|x7R$܄>.&HշM,m:mpa܁N,ϑrONQWV3s:r*ԏ$!.3Ob !왢l/)SA:lqTzu|(<̆:Tjuװt\ŭ%qUXN `9)l"vػ KuOE|?ُЬa]^!}0vYrb~v!*VA1Tpb:j_8+e5v깒8^Ү楺7 ZANkg>HDnC⋅ ?~E;1O$eV[4>ĵ /'L; s4bI$"~vdyU^kb:`C-tH|w9tn?<.vEcG0G l +2"/E +`2Y-LO9 #bjOOBt]Ch 8PfCv7JhzG `BѐMa>g DC{!OHOg]?.zv +v$E FDy4%Lڮ׿rυr|yXBޕЯ9,_ǜ|7͒vA4TpWtj[eISZ P If1ک=O9^`5<R5 ȣx5z !Z8пd9Pz{zr&5ˮo_+غki]Z|l]hYn0oܕ(}Z?f0wۤB{%g}4 4WR'w`֧=)`c #?eOf.U?Cl8Ltja}g 9xualoEu*>x؅Vەl}Ov{D+"vb*X SpNѨ Ov~X]||΅9xT'_P0*l5< \$VBfs sF a~wjEQׯ5hV~^8,z.}3a}h.W3/". 3#n' ?ZfS |ma͋%QC\`Ƽf 7*5'7y {Cek%@gXٟ.K.,%NrO +/D HS۹Bi5$<{lm̡胘/O/^69[n.h34|mej-+jB1ĥѻ jM5uo}]TXn0ޮh].&49vsPwkL u2)`}3Y,NrNWRO<{+R**r_bF;nD]KG{"r:1| bby¡0_ryc6!RjY/4=6QݵSK|i|p0/{'? Y +],XX5o0_dni<ưPM>2Sc3[SarURysv9 h(@?yB .zXs-&NPӎšΜjOD=QS⿾qh'(q0譨k_w,~`}ǁj| IЩR5Eb*mvПpJu5Z3i]c]/ N x7Gr;f yQ]1MYyv<^BlQ́ g"8&Ĕ&El'B.<@ _cj#˱:ĒٿUwV5-k>n[9ro_k̊EuekCru}il \*jtY$kN^TO4;Xzc<7SQԚhxk@ő SkG?C̙I,#ZM$+ y(Y f3-,@?6׹VzfA} +/{"r;|NA ZiGg@0߀yMУZ%ʈ֕L98@ВY ۃȰxCP3^:P;jSW93l`WmeF#/b +n/AQc|%DkQϦj],Icc3k:1BΡoteI{'bMD'hN s = PzoПI98+>@WxnML>24SL\M3a8.b$ս\-51L5!/Klj9>l,.@Bc)Qw Ã.>G`s~s}c-'m9Z>/΅Cy~N^uJyGhC1A݊^jIToFPXZ8 fJƱ9r\=A1%X>LX aΔ^G cy0(OkfM 1[3k'9G栎'^hzjm[81XsfyJiC 62U;Es>O82m +j6xZhzBbLYף+XJ??ll`msN\1\ ~a1]JKe1y^4/4ozA[ѲXMٻZI1w.%,U LHp@@9os7%yTGtQwꍵ(im\;{vCoƳ+z::"FU/n.XX"/\a,,s(UX"fy +>CLsS3[ťzV5։T?&&MÜbg?`xc3ļK )gE;N4ʃfBT1<@ƨ] +i|ɹ4V7z¼#zqգ)b񌫾 _|v[y rY 9ϕ\ZH`¼ᗹR)ֱb)Rʁ)ַ.j+ۗbNϺ4yȌoxx>8`v [_~>s<b|xs|@Ђ+OjK \= )NS|%Wrs}##ְ +9CЊbq|r})oľ. D>~A# +cz^=cmuF`M2|pQGM9G#1fX!]!\%Cu~9]u7vzkGi]Æ&[\û5ʩ6g}oV3EN,+ z>KUvdtqzXݺJ>gtKT{KgWsJ.~CtQWrw?#gu\ݥQr{F镉PfPx%M\m2Ӛot7/-f~; kxEl_%@3%yTzуSS395/PWt%W۶oh[/7K 7`z5 욫ykG}V` k_-XkZKӭܕ‘A@V>^סڊG \9\uju침n٢k\Fբ^m6v@W+WKG:$KPrgI'@qPh6l;n};6:~ rf&/9o#S1;A1BPC +)'/r A 'i889ZwlE9߯ў;p^MַI/& +~o/qõߺnξvOo7{6[Բ5jBuj{}NM*;+;-mwkS3Q+FU3??&astž'޷Ǣx$~I>uY:I߭*|\Jfş?tOq'~P ;MWpnbWX~ĝYTŚkE 6j+V>^eɽ_751jA3C/mʾ';RmLlxi,|; .1$>B^\ENd<\t_ruo+eo[U?Y^g~*oKo'Z~ ÿcLW]-Vϐ_>M?{ifwuT~$]|\}?G>Hh;v}Av'z+uVt,v?k,{J.F=cCwv8콫G>Y#꟭-^ՃmGm6 '+ɧzxCO}d{ꎿXw8)oF$ٽ`{Ϗ:9_,</h /uxwl_^sx}h}^~*JVlh*yw1KUnVa59a4Wt󝱸1|b6h +~lrv.:>;]B7;#WXǝkFNc](tү +W휼R>ʮwm_L_Uf$ψOZ73+.Wr=6PO稿ex~|ɦQG])j.R:8Zx_N=B`c7rM[x{r"Z|Փ\t ZymU^L?}Gsӳ3,yݜ+=z<43w_lKNMmc~aGmyy2MVtqҴ + +Gn(vdH>RV[ښ_7 Af^Ɲ[Q]}5 JsHΥۡ9[ ʺ~u'8c7"nl/ȸ\,]Km}wX 6I;_| mG{/w_^ϱ}}'_x<̿[N?߷ۮ%ol^ΏnɬJ{T޸BdǗg78Xb_Q⬻ ι0(BkPgn;]͝u7V݊.VL%Sw_!~'+nRW~h~5t'W˭ڦwtoV)MmZcGVW[ťN_cq%_رEߍ+,mp,FVUu쫴}}‹Eo)?rxy0^TI +GUkY],iK/}ZRz/*osx.}aFm%7b \*~&=imN\$_{ܺ5ujaʭ[%Q%WcnV_EY~ڪf2n&\/[~WeeJWvnܻ"M/75oxo5YfWhVto̽'< {7"VTޡ+rjF9[t$ݫ ^hp~͉|'X?py;m_L0Ĭf'GW6bV6?d-wdƔލ.tz/>o{{{{{?8oq~f轲mőtPmNv}t"nAuĊ%!%5;i҃(P뇙>+#*BSxrd^ЃRϔʵybʚ)5Q-n?{!leVcJKJDO-~iO^=#{{+Lxcvp{EETIbD03t+u HQ AE0;QǜY14:a=Yb}9syiĪUUoUl3;^ReM]W߫}96vpkm]쇏܃3?Fb?{2+ւ;m.ԝQ{bnþKu/eu_)h|}5_Kʚ_ɪ;5zYon4T.c[WpIOxQ/ڥ4l{ty0ôC7mrB˭r.։?%qxEb9ly.h;#OINh4r&? +YMutFHF࿌!T&XhqHS mO+R+&ٻeGeooGT|RQ}]~լ2j]ͫ캳k.\ˬ鼑P?Pqb:_߯)yQW~Eε"ylGW4y%ncCW){o7t^2q%tp4 !U륂gq5_*9m3Fg +5GeniN5(;_RxJq}  +뷝/?p.sjɭݏ澫9u/g_Ope˃s46y}ӤF|C}|plQ)Z@hE g@ SH]Y5 +֛fE Fo|⳰\ +/Ϯ~)~ǕzlcjN]ά.l}{_̪%jag=_s}Thck7<ήuk8k>w0:>Bxd{>~SmϢDjV?vF8mq r*}:}7?5#{(''j5$mnNt eq6lЙI-=z>լƗ72j埯{s|>p .PG?V Ə@3<#_^7^o߸tiþ4;trv+ٍ6^󮛙uk D?k=܋:GS9cwyWO\m>|!Ba]z Tc^x+.M>s*UMxMFQ*hn'l̰ &ӘFyKr㲳jܻY8n|B}ͪF*caSF@L W3&9g_H(hK۠d+?SlN'Ѻs#21G##};d3 f }x9i9 s"}>Z𒏎z"*,ߌ}Ӌݏn}~%ݕmoonp+ݬǷ26gAr7B}B N2VDzclmX4J 4l4 ƱG6mQv*/(9|[mq!7g5_|bN+9==}%oVXw:\?&Mbهx8#<Xm<2df`̍lbd6YX L"c3w4j72"* %~ɬ$n腜:54]-qf#b׮e߻]rV=c|ÊVso/ pbT!845I42RL4Ld6z1h@Dmm2*Cfi4zFQԋ6SԈfq{#(Y' +Z||f^ά{q=@FӇieݽbRx]Gmσ7~U 3D{*2֟mdgǟ2_ "CŤn!JόES|Jm.WyK@ zTAMp;Ϩ֟ +c̮g:=Hr? %ծEyP]i?g&H_gHx\1g2?76oì(nsw.r7J>jm7px~0Nƪ3{O mxv\v/nVx/-7d_ϯ M,fC1-5pkifЄ U 3I[[>Lq?3GbM @f|32灌gxV9+mz˛,8Ÿ~zԻrYMl;XǷ37~Ɩ/x9 sIuOxT>]\}hOAc8Ko\'d2ۊ%h4 5st10vBb2ωFh\vXyNލᳫk:,?5/|yHQٚ*n+|!ټq/aOA_\%{4/%q_^CMD`%5Iv21aS{1G;;Ϭon?y`зWsv޸nԪ֫^yzߪn>:7D~h_C P x<#}5Y"C]d2Y-񪓪ޏZ%G ıMrnh;$a~=9G~G>NrQ7~ZkBNÉ+ken{-:}lojˡBdl< @"UȚNEê6%^Ә[pic33Oд+{mW@.y)9 m\ 歜*=x3^7Kş;M@v9Vu"oz]RW`iEMT&mv}1G;!Z&B3"4*F3eUh*wuKN۹-(7/Ge +9T[ӯ䉁sOnG98>)z9 /*nW?h-tٚ>PzM轿H[//CAGD?Y .NrC|4p?qB} 䑊lDhZ4cQ4fKݑ>OQJsXwYӥ=n>@w|(绫e_9E4'<>[^OBu 𡒇G2wr#tr5^!rӂۛm*ltm4n_*Cֆcuk>ī⼹olgTG|}0{h>y!gų]-K_kNxԵe}mBFPcOΖ=®<ֶiMiU6M8w==6co|/<>7>^2;:线/KW[w#y .NeV+#ۂ{<p|#เ`xo9|¯y’C/^8qTT۩ýWC/{ʵrckي3Ãlrś~/륉s4rh;4n/韊cگp?Ƹ$:/*׏ +GO2xd( ,EUyK+u%aijld3ܩg1kI;>.ٝyJo.=">5$fָɋIE3%ȁ+Ur<5 +¯c{-bK9S z;yyQ@|Zw^GWW=Llpc`l<÷䬅 r$y?hIӹ9Ԏ́bI;IVhpyi$ap}&Ԑ˅A'ﭔz.=Q=ܨv}z;mi4r +3MG sgp~ |>k^*ˇ_d_r@QiqGlD~)r`m)pGT9[ٙ˙/9qtBY"S OQ-Y閗Ҏl9LkWAzjj_ݨ36?>E2% +^ v_Cuj+y${kO6̧y'NfO%¦׳_ -Lj[ ʹ4Es̐\.sTDF) <՝,Z>0!W>q$(ӧO=5'߆]\vz{$ϥd]ql 7ϖ_8wgx'wWA +kpdqxc |ֳ9HA-_?-:˳xgaVa2|. u$ǧ2+ ASy٣%Hʮ {v\Ry`[ͩ~;5S2dYc +ߑK8 +`0{&]/]ֻ 3$?*3wʃo$L?: ZRRo|/|"g+_!~wrH'A/So}8}f$Ϝ$Qm7B٣Q5UvG@'NCE.(De*{dPZhX+= :\D}xXReAY1{^ +`]dgs%-]5̦׵S+5Q· ];Q)7y-7]緓8;z~|~垟x74xx_-UT|=Աή M_D +4K#z %]el\68Jqo"h%b4H-Tvd}\Ro8m>]xpؓŭy2ʕ4fSkLE ٮOSv^h_=D]MǦJj&>_)[8z·Cq{o|0/ 7tK&q4[=zxnV+ x2cU]='>-?1pr +3sTtdOjbd:ʐn-h%,7VP}e ewPRW"J}њ*]%h04 +M3 nq!b$DRP!\UG"ch\W,-\] m3S{DU!Ik7.|p VPL*;,L;GL&˂Ndځԑÿ=/n}_iAL(C7u#$jm.{hxW*^Na>ȒT.s# tAψ %>x.u`3ئ09l&:R^Wg(~~G'q;?8I~Rg^1'^+BsϗR?E{vŅ-B!T`㋷7/]dNS{>@Pqix)n<M͑DשR"AkU\bl?s$<6*LF)%i 3*:U S&iVP**j1S*m=AאI.דfl2f*] +|<7w5!'m>ёa!+==$@йN46(:*kƶc2F1L>UVޏlTL@|Ժ!Yyh~c؅җB@xN`{#}ړ6NrYX͜$iptJI\Sv`3 fR&Q%M]%z(qRg@(;y1'D fAnnn/ya߆c@0C|H"IA/GA돥Õ)=T25u]AbvL`w( Ƞ%=V\v)hbIwݓWH=3{ +Ԏ'nP[eBmob}(=,B篞֒wE +#2ԄU>%aX*IW<]a=9fZ`{U?ذZ|x6\l6%MDW, o]wx7BjWWj+V0˔E!Ԋ@6H}M=qH#,w8Ō-9dM5ޛ 4q\1Y]>^UKfkR1A;-c%ЁAF/XqVCEЩ8o%MK6~?&5pQOvcqBHI^g'qwptZ``NC P&:-sE.Uht K +H,WD2>WO-] + JFreǦ%ɗ ^!"KS4rƳ- @ 1&cdxbswZ Y뮘7(x,Ņ>]xRvrp@NJͮMU*ɛ]>F.;;'QITŒK+6q&gd?y,C֗XE*͏DI_baz{R]I#4-iA]{|& p9f̺*Cp`miՆlZ1I6Ʉh`2eLdj(:.M"z;[Mza5}Q%^Ao+=_;P +#<-. ƋﳫxOj磻"nI:L3WX!iHÚ}F\r!cqLpqZUQJ`vЭM YyT9zD:k,h-m+-抻-ёi8:m>?n_ zG{Oudrgv +=޾jYнK>ܩC\&a4̮w~8ݓF Il6ʅy bTNIb>Ģ.l FoCt#vL"<ȌaU# a]hW xx_Y*sW 0LR|HDwo fT}{h_ТfUźL3&Y_V0uF\FC&ވQF=&q>JO2O^UCc \\|2Rm[T3'!J4_ l&b F #rЌ!T˚-b ZOtݙ9=lItGo3afu6jq [ +8 @lGACZ RMPw$uɊtn<&ÑbO(ETx4 fe0@/G%yrȟV@ӕ] +Z2,nET~}$iIDiiD+tdlS#'B\z= +AF~AU^9*¾|1H~!9d5{qEE : i7 @ӉU~#V) T}n#6baԀ_#iv 0M׀y2t2$i +=fi01qYc̕l%nttj&wf';JN]yAD\泶˥'I/?}zÃ+mr&-0WE5A' WrZ&GK("YMWƹ8EPܠ? O't5iJ!Sg2@m)vߓ*v>fM'څc/}G>YZhjYP; 'Z-B` lzY#cTA*qM(Xո%dW㱔b<.moCtq ͆ūC3{m@ Ult:Ա͗0K[zHu_nvr 4C 7; t0eʂ^.{[̇1 l +Kংf*ZciI"֪+K!Mc0.\3䃲Tף%\F >O5=tv| qcz}8iVO,bVjQs4e+u*E9+dl!wg SƨĬ +=Љ-UN*їgTOx'g}*l_a= +<:n3M3%7weT3G`1exl(?F'3NzzJAR!p AʠwHɑX ZD#:.]O֠BתMyl mg\ JP}0~u ~qF$j08 j3yqPZt;"'XWJ8E6N ·}K|}3b*9.dWdiRxp{4Wq̆n}PZoZqQ64&b$Slo،6S6Ì'fp8I;y*:-7 QRaw-Cу ot[TaqB=6\/n0y.@woqW,.U?C0Ѣ_\M(-ǾmsȬ- :6;t鹨jAA a`ǃ| Q=F𛠷Zܠ7LGR#{'...+hva[o.tYpkrc" 9b<b/Vlytpßw݇u\50$th69,- o-U;`^7EWBlѝ|+7Z}C7#= +7AcIů׆\7]p˔@[[g Ot$]%&zVBEYA&qkd#e&l%^l%[y&c E5l3OvQ| *\"_K +ǿ ЦWtM_z̆Rmqx=/G;'CE$x`*C[bn2p7qj{-/9<_ H*17y엙C$&lK|Ձk(ok#_yɱאQhe6tzowqhҟ9E|.~pV+ :]Ɲ;kY8 :zei3 7!45..3l}){$ @upg&, g(YEag% +!\ +H4*$¶I6a]1 }Ovtc7ҏܷ5a](eycᘸY\d0+ZI;z^ +QJĊi\q[Ymw庞z#h yDwt]w ؊=Sȼ!p +ɼbšL; EUc)+ aĜW \`"ʣmeԁDx5HP~\i ;?Ye]|<4cibc +D8w PfpjᾹk>a?FDFPUDp + *S^kihqN|p-I1-i7 8Y`>5w>ЬhNch80>Vdk;J5Ϊ`wA. YAH(I0tu7&k ,W';+2}xPƖ1Ay}؟幚ەbJiTY"Bܮ|-ҿN̓c8b9Cjlz ݓ}B7 ySםԝ9(Ϻ\@w>(x* MyfsYNXdu,_7[[>YTQG-|siGGS3!J" ~J8k +F{R5:(Ϻ*K0g=m==o# X`c sL & qW+0׼))H#2$䢔 w6:7bIi\N01/@*2〃y9a)c s[{"hÚY]os7X++;Kpv`;?|bm<1odpLVHt0lDl%6YZ=P#s5kX̵^]|WYrQPv%0*7!·S67nht 8o!bwl6qu[.AuZ!)&8/Vܔ+m"A;=ag~ITyb;vVf3T|a,㔹mMvvbg)';+qB8b^`go}oo@L,0ER1fV yt)|rP. /?4܀!\b,z0`~қLsپ׾- +Yi|\ kӡ*~2$qN1  8(LY@ s"phU|7x _o xND^X$~[ +d=8T:K=#,HI;;+vZ =CVuVPV?豷\v$쇀KCW@䵣6ثoABwb<`0XCr-P/9%%TnB6f 7<8&;0/c`88;4KZbEx燭>2M`ˤ_4Iz ' ɻܒr~N(e.2Vx\Ӈ6a24Ssb6tu}֧Nb7{>㹬NsвfȜ)* YC,ivl#|+f kb*\qq5_3Q^{̎k<3pmKB^PWk͵;K;n*Mp>$/=2CdDŪI+wO9 ;4Edn{Љj=?pEr҃ӥ-WK.8B$":(Q MV9\]Wh*J -];o + Kf]4·8_(0`x40Ab09MTd6 r>iv072ϔkB˸LMlm%Yip=0W$އLV2xDd] 6Bp^!%v1dK; J-' TEJ(`mqmAO86vXܓxt6sAl-.xD$Ep0jkL 8okbg撼-\Zud6㒶KR%8g[&+ʼn> Hf]a4kh$37v+38& nKn@I0 H, +BLT0^LE;01P",Od뻬o 0G)G9\إ1jڂ)~&[4FgjPUQk貢 \&UX6%VkVys/LjEKX՝-8Ꙥ(=ikoW^v{:GGV%Uu=gdml9>4mkX~d4-HZw +/ i4[|.mЕjdwz3SE|R`!8%TfI aN7΄uŲXeW ++Ʉ#xܳYe."'2KӇq3vc/`0oB\ n+vCX)a[bV^bcp[K=` +`SɵH{3qj&SĆQi ukcLrUoʐt p9y]S`AB([KXGCǦ(,=9gdE¥Ԍ5ll,8~e>.C /5'yDA6\ZhȳuLܾ ^^>G[pBpl9a]uv|{~ 10 p,\%Н;n +D=FXTۚ+q-oO]Hvm>]wz}<Ɔ-f: Gze #.IZ3 +OQ(֨@.*9 Ǧm~XO)*1Q[gFͶ_]՝Lx[D-þ`%r\! WmIomM_q/̣^T6&]lll։kHrw.>46WK` Bq<ʕo6t48҆ko`_7%Obʒ y]Fy>3|"(ѐ@ $>˭L }ZtM9ڣvO AX%/춂08z,rgGnR}X 3$~xئpFt&o&:]Z!IM؇&zW& "1>`mc_*oC܆-I?-nEo<6.?2M5x ֽ^sD[KՀ.}X݋?ė=YC m78=L!؃qźɸ>0ZD!2U] %J JD*DR݄c\*"CTh +z줡תKWPVkNIPOKB0%vKՔWK(;.@yV TH݋OTe{`G(zQf,o8.ŔY[&T *Cfi@JPl⳴ZFF YNj +9]ٍ VΓҀBBAQX +ڠ,RB|rjKbؕ%G?Q,VECsLw7?;KAѕ.Ԥ5%aj-RA(-WK1JU*>R)@54E]bQ-Жq@g JPvU%P)5"qp*We˳YڲE#3ύUJs />eY&Cyf3EN%( A(YBb4$uS|~dHh.; :fX{ umx +bwݠ +JfH(" +(JwI7E7vw (!!{g9)c<-v ?C#ۡO؏nJ❊;f:FOظڏOpkEƧy`D i>uW2t2DZ#1;GLæ0]GGO F.܅l_tPFX{dg'B826J8Em4uu9tt=XEpg &13^nf˷C#6Ax1@O#{[N]&ĞiscgG.xE;̏+.3i+Ѻ&H BDM|f>c-/`,\*D>sL6ChkQ5-,Z&CtV2u7`߃ߣ+4G[>3>5@l+) x~A`W50Me0=;ZYpG Oey#mC&qV.9KЅ*q SMqt.K 2K(3؇LNMC̢w&v*'4&*r.lBes )"Xqo88,@7?;v&#̄.+ܑ抲t`3>kwCWw\v!\ ̝>7 8 3b;Qx~Xk_|`˛;|3gs#ʝ0ظa< w:ge:Bb3NQS1/0wwc0p,Rc\X;񰾁pX^E4`Щ0)#V +`W:A}؛"A !`G$2U0`?c"3# (S9ii>mo<ؘ^|amAwh:9d<;;=:Q.a};.BQB#́P  #8KQlQHFΥσe-'O0y><3}܅K,>` q ˋg& en;:؂85R9CT` dbE +g kQl :bн=8( t!7nۘ :Ǡ ̒2 ~70C)e]cXwdwЩ3X .i-%XKXxa UB@(ØhbF`:|0@8<`>7$C@]@~(`% O;F%`!\rr@"0b\8֑ \ӨAYby`o,bo.ƌo&h+IC}.^:2ì')#l2tp8GQ<EF#_bBel +^?{V`r8!J1NMG6E6\k`r87I>NS]+K`=X7b&_>1C0S#;;ܵ虀;6ٝtm10&|s10bt GLM ]wN"[` A63Y 쯔Xa@'${X,6`lL$̖;=Vxuij 1ǸN;?px6pg:Qr _Y`9!*P؈z b&J2t xfw. G;%M/vQoVat-YhE6 +&* +7gtf9I+_ڡyC G9~|*<x0<<[">p20K4S4`#.;c Z1B yY`l&d0qh>~ VD`^BvWG> ZF1$? |A Vq{90bnUdC$J| D;L5 Q`;,啦9l}\`<WbNM]ǔ-#n#`RAiXA9yu8T`=(р(mcJU_?{e>Dr}D +|G[K *~`6:P.V^pc1(b>cydTeVM&LE/PbP)3M$`4US6ƂZĤLi8Þ +70^{ ьS֪o Ǒ'n}Q17C0j`y + 5Dcrl +?N3,(\ + |3Ҷ13)~IcˡBsS +/pl`AF?P O Յ|=!CA><7<7bX.#M'q}Aq!S81M^\M s `b~Aة3ۡz47HtdZ.lVj8Hkqah\:^%gQL`2;i? +O)`23氦prm# &`E%9D*(`Jku#d˛OG]`f(z*{?}]Ot 3bVk_cScA?{d{`wvU +-+.d0Nti8C &8.pMYQ,)P\ x(Xk`cZ ߇/"`F +?9 +&-hKQ4~0 2E+yuz(50$!Q}:lyFB,BVXOd8 ֡PB{C~w,Abd;b4UB|f8vQ C«TE XǐH)(q9uxE"SVG P␿ړ#y6Ģ i~`Fxc(-'K-Vɳ8B͐s +W;F2*FMr@$-G8PEѼ[L5u0FoST=LJ0 "♤ y)fJK~⓭ctwVRq52.i udW1{# `!Dᵉ4F1ɩ1"&#7!;U 1W1 ' +yy`f͟{XGס3X c!ǂ{썞I(w^f74Sqr>+K!gB,L%o"_B! Buq8fl͚ }pCﴹWAQ +> j {{]x\T?sIӁ W" iFԡ@AKͦ61G@)XF~A+F*)Q @@RpnH3|JX5o4 +3h"ef}T8(;׀"QuT؃堈8oC +ڰq}=|ԍq:UuX/ﯡy;1̞y+|ם|wu|a1f6:V_dT̵!}@z V@(aE )ڄ{v!|fG*g@= v|y %Sfqu`{{:!<00( A jPĹKqlzPkJR@a(r+ʉ[wdP dNqh Aj_(WO5aH%P`FJ#Y@L,2\T`Ԙ=0>`Jo2 ǀ +pEDI(k=.Bajva^^PEhb"xfJSU>6!섲כ]Tқm X 2Mxِ}]Y{4tEe- +3_Eto +-_9,GIP 6Y- *tD)kA4vq1?vu#`C6 +^B T ja_qj4E!6Ӗ G =l 䙰xrcNx=G2y>r{ ~,z3:)Fy2XK;Cr m0+?z sx/1yOWzh籢MqPyVE7 Ą.G`K`v q +(-Tj06_j.#-^^Ģ؅v)ʉ7+^\ +*ddJ6**P+c:RaB&PdN*q7a 0J7Lb:P@6v{n4eUPncQ<)g%N9?u2p,?(+T')j"  %њF'@ '0`q@TTRv6J<\MӪ&Lbղ4]x[{!@j* w#&>oaU'K;y50a=3jX,o,y800rZ\BTm9ua5@PdO"Ev)>?*(no;x%C' Mq? 2jYH f6{P9rG8q{e>AG@%UѣJft/zxNi;ϱ8io,ό3fU\|u.80Lxg_jdrveSbPnR;eLL\e8x|=RICg!3*Ta~L.4nEYH?^1*P/->(%Χʷ)ժN2E`> s{&lz~*CK|X|!-#SHIBېqa`b=T2r +h\cZh9Bq pXjc˖YWS͜lꍠ--R#@Y +PT@9S" +PnprHxC @͚=?=Kt*bSAOb5ǰ8 +] 5/'y6VT`e7fG^*Xy 婘MNWљu8?hQ=PE;QhOEnu8OsY8X+U}dTx`;xOTu`/rt?D9{NdIS`-VRiJz&KxTElAͽ>; #ji7]l>1ʘ lA~Ğ9s`O_{Ί@|yx\?6EyluXe]A- 寡w0K3.P74ez-e&$P>JF69E~SVײWr̨#uMT4&Amn-EZ2C6]tlF6/oVӅ=%Q'}=Q r'Ie@QNd3Jxhd#ʔU}RP  8ymtl_6(w!RK`ӪT#Rآ_@a5#d>?;!wy@E?J5}&fTN>:"{y.(E⦈\cBNqS `όA(6YA"Ԟ98 qVkD~@ꙴ%=6i7xV A3 +\@xj[S fGy> gC|>`Yا=U|UrPn=8P Bq}dp|FCk0C9`p&7ՊKK|/3fh s>pg 13*\j&>rbX_./g!  +{eVAQ2JPHf3=RUS\ t +g"Xzwgo,%< =[&u2pԑd.spvN޽Ln!"| . _r5Q^_ڀ}T)!vW F ĺ~2=aϏ:>1y~>ꖮ {NL97T!OuQ1K{0%!`\o>=Nj8hCKz/;B-5"oYUK8@8k,7 aF@/^g|;ׅ`a/ˇ?g&bu$k+@=|3ae2먇k '&x*0e72g'Q'F=8f(2DMclj"Œ]PWc@~b +ᷗ- ·2 ӶW׶jٴO +Z0b | K qnŰWSllۆ~8/~r& +>/ 5 8C'{R0&L,YI)5w&b%u&Veq"} h7`go\Ѕ%#Yn3>/|FsE:zCd`xRjnG8(Оd|&X e.RgkAt R裕r|a+55IRAle8X8?԰+آ8f81F _e80<~{.\DvbPEP#u12Z;4{ ž;B/c6?eT$nV'ǁ7WA=~T}bF{g5( 4u!}y iAa/?k yu.w,iaO,Z0f ۦM6mvq6R+!pQQ~jެ߅?s[{p /5R*sԪP[w2{U  +zi7rNF_GfvfsZ2:7B_ 0 ϫ> ugU=u h# 2ίdgU +3]X.b-?c+Eۡ>F<]2DiA(iQYTzn7 0e"A 4e0ץ?E-TZ*(!lpEՠfuB?M#=ff MjX{WUl$\UϜ|8sGV7kM$9uuqZ~*e/žm0G˩vU|֡j8<0g/uDymnUr>} +oo|զ|Уot~jwLbUQٝ5tQ/W]5vMدe;6%D+U S!lQ죳= a]w .~K^?@^9$>pPt!:ԃq^Z~({0{ F(qn}1zHp競g.xDF§_ݎ+v1zѣ7'7%ԅCT޻potLzدH죘+3k _*1:3 +ꓰjXAҚkpW;Yq~H|dZ5ټ^m:W~ ԬHiF S6 lv&ٻ o;} [xK?a@aݗ/TGCI[cWpm1¨BzY=G|0S{+it@"{wŘDSZܮ=L^~oɣ +KzE^#/ubwfcqWMፏBѝNY,jF鵦+NQ='.[Co=cE +̭V,l11܇pA+o_Ǜ>}fȇ:O 41ԫkW_NXggTW^%x> S$m4HMp@&4YsLѰp+2giqñ}p#r~ n’o&dgSi,6'L}cғY2ʰs GD{r-GN4-rĝ-!d}Y<yw TϚ*%ڎ1/!oQz8$+oua^Z%Վ7sliy5ޚ+hw/s=VY ljyz9=[ Bn/O[x=Qq_S)鯉d{@9llP7c?e Xo?0ğj{%pZɪ^ uOGz5b(~G-yɳ +kɝ*3&C5~V"|C¦ܳv AC{vsʅT{{#ժRIf؁ ʟ-s _ѥ6tkQXӾgWS[S'l-eԇw_SQY٢ mOff|H}8j:Ҥ@j\_b8޴E\HQi. a{+ckV +|$5]Ov>L6쫉aښýo5TI蓡?t{EԛTUQĴ-wѻ>uy[oإ]kq̪-71;!').0ŧ."tkFyhs{8#j{/TsF21?^cuw}Lнetd:]^-so(&4m;4锪7E>㞷[V{˫ܙyĖFZ/-]%|A(/9qʑ'ɒ0m3ͩ~aia5^aⶒ7R&i~[̕*X4޸`Yhip\hU̾1!{wdԓcMWgMVܪ~l6;_Z/&۶Onfz5]UL|/XPBXc:yCx ?neߴ9DfLFsJOPe6(~rZto$̛J[דL;븝jג,M sm ͭ^w-w*o>Q\]T]VY]Yv.+s[[^hݔ`E$;PbP*l!/7^:\Ke|U.tԭo$SuFto}룸OQ;osg}YQ_jv5x[![Xw\R ~_iԻ."=10tky'2q_qY=7\wlMݬq;F59Dhvz>48F;F=q]f,K^-M|*)%x5}X|DŽ{jkTVcTfY˾n[33\ϿBB2=jRRxwMM _4},mלqjQ_1‚xXkciS,531'պ-/]4j躑T)R׍jhWHx$>.q(s&~l e:[%5+ށ-mr*k]`mHK!WTF%zD%&V<^+㳋}e qȾҢӎ{ |8??$hn۪zfdMŰWs̻MNLei\'W;^uͮY[F^/w^?g?yVZ\[RoӘgۘ5_*y*¤T9R9LTtZ̓_LZl[2Oy{#p8w㙏w9R}췚#]d&z^#Z#]c/6yki}۠pc$)-k*`E}n}je=Wzu{^3yD+ok_j㹃q-toDr%NF5AneUVx':5'f{CfOәm5E6yĦ:U'\)И0I}eIoQyϝ3i! u1;{Α]]nLo3޻ VIgZBRO.ov1uÖQӴ".*(` +I*"'R-/jɉ5K9Q/>!?~nr輑[zykW^믽>z!~o֍|lq ઐGoܥ%ʪ#? bu ! ?>zhvG7'G=lrirhOgW߫Cx%5x'k}Gawk$6nMݨF^XQXQ%tpzߖh4/ѱdW^ dYEҨs(v8ٜ 2쩊9q#EQA)KeQ_qA- ?DgWyʞ#|{}!zC )Oth2ebPEb6H(RA/1X5c{7K\In'tSӉĴ*򈅄\Ē% O;kޔyڨ4oBk%n1я޸ŦUzǗ'TzWGO[\BLi@GRaׯdKstB]}dc?5x]$Mǜ o*jQѼe;ߠyߪаPU߂;m8a*1M!F5}DL!T'6;UퟌQK0Kߧ?+hi$4a[zPWՄ%%*^z#E['{P.}Ys;+"R +oY\Rk0:KcگBweh[}orqȚ{E U+6r.(jNQp_0[@#F b(~W@GC_EF= +0<%,M":/> &> I ߜK, +eŝ/YSz3 hm^/.{]XL +b>7 u->E+g[<; /Fv8 ?ptWrx07w:7x?OK 2}G JLX_?ajv)17#&O\811ϊݢ}=Hۼ=ib_eG^k[({s{sDR[VXyv$TLEcC|,dqg26_=܍Bo*Zv'Tۧ_jGwp'meu/P,l0U _"3 sN=~ѧ +g/}zx'<,H#YW/ +"I"ʃ+dU(t^)M+4^MQ3w[r#1Mn<.O_)|cax !s>Xb1Qa>1Si/x%8KN~v3v+6$Xv-7aLeW+.}t(_,D1{cC`ZhG N>jPtXWk(Fx" H'%n$q_!nEVgK_b;<ٔWWRZ߀氱3wzKGJ][מ>ed)2x.11ud;\߾5 4C#ǣw'',KT!;rY>fMWҞɮ=;uWJEwFyGړ"ĻEqE~R8WHM{EjZ_c =˜(h>q4b,bE4O&D>~61Ya1~|b< ?ޒ#Eaer#5GZT*mmrNX١9Fۅ44q! V Xc*F, [G̘>y34u8i1ejbUĤ+I5sj&|:]y0Q||_+B7^}o|Ͽy_WZR^ +yJ~x7 NRRP!&UB_GOKfS.&&_NL2f-1My/1g14#04J +shfN^O(+'+$f.P'f%3 %fS Q +(b[X*Sq8nySb3YBř{\/D JK_yĽ*vCcb!7oV['a(|('M#ZLL9m'`X1w9,KYb\1m6[N̘J?^?V-O73iyκ23,qH\ߤƗ>)%)',v-sOrMx_8PZW1^i;4y;1eN<6F<ʊXD7)%g~~Gȑ A>yX[Ј橶5=\g[VG{FGKrwKEw,Xvmc%?$7$2$&57E~6lb<|1ur4>ՐMj36Zsv C%t2DF1y$=򷩻5d_٢HW11bKQUv]7YG[BO[bGkb+ӵɱmxj4l dS"=n59eBibhFB=WH[gI,@"$fr$f;;cՆ9r[ǫ>2=OF?Z/_vA rD"'4V:$9W۾|( FDk(eU#E8?YTl9E49Ĵɣ lDׄ4 ƄJsbΚ|Xbf(&;s4(w>;Y",S_i /Y#[YG̣2ط5Qꝓ߷:WԺ=u` _%H4[Zp:B(_JidZ dh3kJ39j#bVˆ77D6z_Voq A!1Ʌd;^Xh|k[JwkZ_kj*7%I:T6[&/8XP1f 1G*1}i?mBZkӷ3g$f)suYHbZ bRA:zWnwň5Q>ٞc"~^Gٰ㞿˘g"/e<5na[(wOV;נoC@Q8=Iqrb& ֘K5LK􉹳w^Μ]36R$fjJ0b%H?X~mTטj]{?:}%Hhx۱V/^&hb$γ>6)1*7n?/Zs0<7O 0~1hb) +P ֣1I.bʸ9Zļ](>y:tGTٻ!_=oӷJ&o외ųb#vWNT/[ϫ}mu?'/#lAN]עd֯g/>ZVz#6[Y~x 5Md{MW:-~o#ӅVNypmh)n3N@%cf51/ְ9܉艌ydZCQ}9yJZa×%f_jAa(B1 0Mn{xdz9ěi5!,`)H7 zq +~וv1K'wAfd;O~oyuo]6H([#z\l#yNW72{MTثUʸy"Llpq21a,bҸ9(@YE:Hl:~u覀1ۯ=6t?w{*sAJ_TKɒ@I S9yt)a:~;Xk2=~tsg Cu/mҏq +TLff7˽huŭǹz; Tg=,*rX)T9v<_&!|BQs{6~o5}m ^s|}sa 7#6nYCh[Vлݷm~aӖВnwW&8S3Wju>ZhE;)~=&L60Bqy̓mԥoڒg%Eug 2>l 4mܘl9c-C~ڥ1AiEfIUY =Nx[џ>ba~Kf&|;G87[=)MQKM8u APO._t߬ҷ}Ђ~AB{4/.8k!X0*s4*/ ׈N/g-F&ÀKIRg2z4gk̞=ܕc[lFXap󫦨wF7ըvMr$[~ۏ+Y^ao ? xYaWC] =ulֹͫ]SlUU*33g'lF;M5u=7n~Q'_wXpUU7 +\C& r73Oߙ]S BS403 + [ߣcư/+]`Nևک5=*_~6!1u +1yPxQ4A߫D_>z.jISgyo Ro,C~cS:aK`(K+9Lct u=O0|0b2"*"6U$FLǗo]"Bzu(k7\]h N{W*iѻw5wLuG(Ö lH$ZH(tB,tqQ;GBe#-#ˍ[Л@zlfC$$dw{{[6>rH3?39|߷fVg%2g\˨:m|v$1}_WMg]A컷sg|^qOzrKo9v4rKx^%y||ggΕf|VVw$?0H2"OII 93tjgVu0敷2Q2ϱQZו,].L]a TvrT1|;Z=vʎ+vǥ/r+Toa<(!!Ymȣ:_|KK|ן6C_4ҋ7gSH-[_/ Gvp7<ܹ;{x(gk=S'"A5Z&U\uc\+ M 3l*of;0B+ٗnk%d>՛0hSe[N8۾,WOd8xx|Y8MKdKLuO5kR oy!5 6xOnqTιg#=-QKz h+$&LddfI&LB ǓsYdRZdI'ThCEGY< f=foƏz ɐ\3 WY 0w5'Zyrb}j_i򵃼S'O3 D<-Dz@Tşsm/}[` ^f9G~(soc0T&'tsWÌyV2!IL$7g9fDZy _'&%sѶ>?}=6#Ezare~5roSgfr5g$|T{8+;_[$#WyԲ ǚ/E^1|쟩O|`lrzavk:n e!qg?Z/Zp/0O50 /+&ZR?^I-0д =~yICóHW?.]™ڵϦ[.kBߴl"T,y(wZu'Hx\/0zI"1:< &/-Ktd( + J㥠z{/>5r[oGQւgQuǼ%5\Oò`5kK1:dxպ0'h2~xdX^ i_M9xE4oy1Ӆeg_a?︡0Vnn|䗱gʴW=;TgrrD+SIdJFt1ϛs~8st{ g*HnR.''npry7kζ[4̲'O0κxO_rΖ^ֆe^ܧ=I-ԙ*d/;pwKr--eq<9v!ߞu/,˺ d]撥 brGh5boXv4-wr Ai)65uҺ#U{] awm`@N ӏY:^\Ź0}[i GO@P{~p'?5Z1-qS.R?d@~1#\dlѴluI mnaΎސSpt]ln!/ _Wv薳lj^/2p> +4g"o^߾\%P\>1v,3!Ĵ1 5Xqojr:I ֛wUeF=|3[_C^:ȩd󆒼W?99\qy '#rrbK\ zAς_m/ie!G|c7cB$3v\&gyTT~TMV Ikh>͐K!to?1V.6gMOt*ⶭ97!L:>rnU1\Ƃ<+>5KpI4_[4?94*wʶ'RH66T{@P T/U1Řy;mFγH`d$Y)mL,j)d9 Fhc*ہ,Н,{:)B9> o"uI[=GwINsar/W_ù!5j +t핛wszCWrɲmmH?G7*ݽG4yڌ"SL7Ub(jot@kdK#9&w !)xB퍖K~Y{[^ CAB&ڜgo N rbEBL/y/^ae0`/7r"Wv6 k6 s e5yFu%,[0 'HA_zXWn KOx3' +#rV"˞c,>߱0O +ۯ\Ksc?I%K=stԡ?$?h?Mq{LӁ/SHƃ7է-1! 'JB\OD;D-'i$!/g~rkȊ !OLEsSm2dې+?tpOdMWĴb u)?OI!4#X^}v0gȅg6l\><}vl&yI`O(\!y9Jb +״|}M9qZ&;:ۢ<8޹l?wfwB.%|g?Rɹ{ANl hC|}7ȓN<d`'B^zkaI{ׂ-z?`|6S2JLim #Mȷ!߰;=?`7G[BQ_=h]sx 4xCmqF rql1mиL;~H"~6zjeß +- +XNvbeǤ #ySpNC:)z!)~uG?K5xq1[qQA7jGc6}޽X3?3t Ugnu<<T?>S=ĜkɎs\'?!?h0[[N\wbܫU aw9h>XKqx8ݙo|u<˲-nf.]|\zuzȃh-ӆy$3;U9Ɉ +/t"[q||]w{ny{Pns>1w82Ww]+`YY].m +pN%3Y`GYeHBNѽvVm}r-ŘHB^|7{ew۶w7\Op<򞵲kܝ9^Ɨ+U16ꗳMm>=z|y\ɓ%Y:w͇iڏߘj>h|_C>r?([՜l+dbEgX5@C@ɧXv1z*ۃ%g/>(Ƹ\uv( +~ xsh-I\>L;ec5Ymr-6$ ɭWc m9.;/8ּ(<갇zl%PYeOv:|- rBg;2El*0`_l9wrCȍ#0jǿ|BϫV8_pR-[^I9e,`>`> {1q$}"+Ca朥K1n֬+7#;Gh} HBUˍ:r=~rQ'l:ΚSeMV[53q;˻:}; )_s.s*?yr sDn 83y> ++۸teW[ W, +*'k1kN 1&=ߐ0g&Oȑ8M\ {텡3_渎nn"t4B: `g;2{*iƶc`lD8/ч!3=;˱ C7'yָ*N0XPX s6}GO֢ys ߤTAkN  n83º%WZM:x$|9f.Q4vֶԩϦ@|Z Yyl3p` @9:,λ7o[^U-=3ā?cI'5wCCq^c\?wCݷ3[^@}/?rVhV|'_~Su6%;+CdS | p;4tϾ#0͘s|c񀛕eom8jm\l?KFrZ.Aa-[~b\ݱhwg O?F|9p hDv`y$s$e:ژH;QNʓdM4 R}hnG[~p S/c ?쎠1uZՁl}$sxQkt1ɾcmG J!bc fד&ݷÿ3Xkx ]Xӟ,>'c9!u$uzIKa@7lv%oag-?K^m`BGن`u.03O} |t3*7o_xNJC 6[cǛz7S]>f7}g_l'ʆ< x>ҝ ?y|lX?@jImބF$Z|GggĶ"Amy[XL$%Y W9w]t1)UAc:?rÙY~ʰn{] x󀝕g%2V Yh|Y~ߝz:*vs;O-KF[Ai ^'`w!l[st` پkcF'`SAnnOkɠ[0F*dw,Zh\aJނ3uVkמ<) 9ȝc-gcgQ{0 +cg-YmZt\S; ɀr vV=L!ҁvy;~7&,0g*>l\"TڌfKA@WF?@v ⥽xQgO+0v:)C_C󴢶p܂W~Bqmf]b ;&+,1'lqD?AisccWSL)& ۔}kO ,_lW"my\ت`?8oe>UL9,vVU;c:/oyIf4@oJs=xqÃ\sw>}w+@zpip.{+ٌl3@R{{vD{c-{<]m/+ <{tyq%ueU'˛1Yw`V4vn~\8 (]RCQU{o vės+><رBcX/+n>7¾s^ 5qRjs +ƍYO +ׂ׆+r瓗s,d[~:kxoAwǃЖ^ٿc-9 92/H].~nR+Hs;)oUۿ^S(I! Y+ιMF8j> ^̷Wu]hv{=\pa#^8D~Ox)_rr ȭpw>zǵr/ώ#_0p Ic +oAP! +vUvD dK|[Ν0/x0߀Qvܶm=؊8?F 2.b0?5uS'?Y\쩀XqzV>Ӈ1!;²} `g9|A}3M3XIs~u8gCsU Yh,Ԟ7u#p|=>`=LzIeۂ^uQۊ#b';zCqma%{Bߚì?Lxc,Q[<;'dٻmϏ'plW~N¾g}oGmpK,yqZpP3;9+CG9KfΖ` X?uۤSF7<k` \`wg[t?`nVϘ8) ,d a%#`?c,I +6}ԮFALľf`~l!+X..0s.[Vc1z ءHo# }cvъR +F;щi=Ѻ!yZu`ƨY!8o`/ <,jkJ-϶9qӁzM;OU XiUa,NuZ~Q6š*Xw,;>n0/8O ny:1ukf1Cn%~` `ShR/8˅輦~8 +cs2|nz} Ͻ;ꋥ杸K(CgED4 ޯ gݬE ﵯ0{^e1oFljap(4`(_BQb4I} t~'1m0'}u@Kh2Ss0sȗXUoX[OGR|єoAGsV;Q=tʋC1> +L}ĶY2ۖTg1! bs9 8Ňpƺuڶg`㱆xq-0Įm57&#-'|s;RʭùܷY΋?Ϧ\1{ qȩ`c0o͇mBŻ%W=a坱NZw1`K٫wv9=!$-{^Ww08 _1U^2o82~:{jaϑߢ{`E ١dѼ{p:qs`Z n'o(a-H"z:NR[TaY=osoY],cXK{sXA +&L{no[{AB7d@,pie8Sh1pF3Mkм=M=i +瀽s`|U4o Z_ 2Ͼv$ˑ/'1WŚ  Кì+] .>te +Sth|}> #}hyp|l;VdT79ڂ/U`s&5w33;!֜X/+q?ֺ -ӓ3ژ#]Լ-k@_XcG燙7ʼmy[*xTquGc1>!YrjmҡK:;z +퀥QcH^s\]` MKgwVuWi[Zdԁ~8·|&oz#Ξb7vZќ6`L#ٗ|Jur>l9Vg7`]A?`^7 ĸk{3G_cW$SLg' Ř}bsXMX?O`W ;ָus<S$0`B1{%R4ϐvA)0`{_66O C<'Z"> +ёUކ+ߞ<30^] $aӳ#yyWM B8/   clp?5=]wS'bx~(YT`Az`8^=X#o/%ė_K|/%ė_K|/%ė_K|/%ė_K|/%ė_K|K +&CDjR }7B`bV``hJj((f3&HGIeAܥv K .T:\8T.S# ^_:nT~f}ETh^/1IK VZR'S+JRPPL/PżF(H&$&ÆK)2~˦C%,\Y$+)JJS.Y b hIO#ُѬ@>bv? fWKOI[A_~y[Dt׹3/zKwtdFI UAF僇KGK|TlDվ/w1u%|LthzH0INpStT zB)Ե@#*]*L`:Njr+_:"+@W6B\NJ  endstream endobj 793 0 obj <>stream +W(Os/G\-|w7-U \ԩ¸ 0-+ WNSI`DQ(Xֈ>>`$5(=&U(^|$Ek$@x+~twAKF+5fhY`Eab+5;qFZBHw%)iW \Np1_r>B-PXX 52wgc +or)J%cYmhL M D +>YSV,t{ჱB Uى`= 8rz8RPjQ +Z`5d7zENJE'z el4 -1PGAJ2ErPf4:13,:jMC*GԠ-.5a;%Vd`m17piLH#1>!Xf +b3[B 'D)e BӋ!?V5;g#B@h#rd7XNƟIRkCr!<36!2GFP;i X:= ±㶈-[i@02r7'b| ։C'qn#㫤f;ldg|Ft֟@Q_ f'chx) +Qz!G>Z/xŋNQB)1J.)^MD*b ިl*[LMo$4]:I.eF|$j}:p8#3QL?8zLO;8#"xpF<8h5rZBĸo}g0}7G|b\v{ť2g7"k!ѐrApqf#)xLH#W|BT-ak &DRL8!lI^ W1Cb]6Eē&([*& mCB\gv +o|Y|47aZ!)9n )-➳,97@̛(A[Q/v8ea*C~:NZT ++B'y `Vk~B/"S1])EbZomZ+JZ1,Cp E8pbq5>袠[2YHk+|74:-Kgt= uCپP#\Q#&}*@ǫbџ >Lݔ̰ @_ =XU4nѨȊ--Q"+Јa(jѸbXb0G 1#s`̉`N8tCs‘91ˊ_i ;KȔ1oh5he7X=_(9Bb<=pB-G= :y W}m*T*TJT1ľVċ3[VQժ h>VO@ow&.KL\[B|?/@0-٧pBQ|Bb|ĺP yC2ނuIlLoGhbg!Vu#N\s|yZ+p\3+S4͙,f)P Ib4[`M?~i[aC#??"?C7) ?G,u1!?*sB(FsN47N YteT1wjs2|e޴wV#OS KV撀1 y c pZu?,4yIyq6ZQƯóQL-_צiKQ~1]Q#JCLWt(eQBftHiMp +b _/ٔJ$T/#F1L<|'&<&ao_ShQP/ЄSgЄ!@ Xq5uoam?ȿ^:B>`I? (zi^Ƃ(_h^`=%8!Mt'nn6iR:70 + L"Z# %+; µk[%>`k[J`T/3l FoGaW͟aE(lm2 ihz46|3s. +=P(ej0x?3 EQ`"ߒjA_(cѭтhaaW3fF󿄑DS%]oQ^G[IF; +{Vf'rz9a$Gaj`K8(ۊݨ) IAeg_N0n(8ZyتӢ4룀-;H`#>s$"jf񚎣ulmmXOCejtڭ`/&'֧!8 p ~2ޖT|[RS`/ QXgTpL:{-E5ki1wq-i%C V*-.[zN7Bnq:RZ + ).)+v;uFNDMbƃMWbx~ MisV<ڄ~la589&PVPWV$5$)"_ ĬR܆X]'K.(+A"ri2*7{N4z-UrPuRPiujrFMRZJI( +J +4ZZS( + NQhUj^'W +)N;Qda*rT)@ IrJQR!өUjiqbz +],#ԄJPzN +W+VPQ)M4HS2B!Zif"TժB.AVLӠ LQ(qR'6\nT-)4 +u*+zr^P*ST)ijF:As I!Cՠdh,e:A7BnD];{Q^ dQ)8*^'УOl?]j9p +ϩl3H#jTkp\uup/Rv24O5"%L:%jWKL#ڵ) +( +t-B*4i"`a@SPKJ4j?hvz .R)4PktA` +<_rR)/-I ` C1W}z9Ze\;$n3wAhNôY# ֊P9꓀gcPR1\:ɖ1F 2\#Рz K.G4bZ+UP]T%Өth)4h kЂPRJU`K r%- +%G$XBE:5_͢9w@D, +5aå8UBMVf= +J&4EdAͦ->Gxbk+Rp vE-$Pz] +1T)$PHQۊ^!~5E v5QI$FO&5zE5E6(mhCpoh"`WSD`W 2{%Jz8У F!M:ڬCnN)AW),@R/"^&EQWK^ES/sP-p"KZxHa"Jץ-~G1H6pM` #X+ծ#O}eld o"aQ =C\lT1b!E {Ar* 7)m)Gh$7b~d?ÕHL}lm|DzV9[rD@ iy$5jPrr` +Nk5kJTX)BUkxJ]̲U4TWf +& +vȣ`& +vy/?`GI/SfN4㌪^`ɡH>0@_QY@6STG(h*4r&#D*HTDi"~D* jђt%ӕOS%~#kr I*D(h4 r;8BW'#ެ'#! OMۓCb=$*oC +z)(gVfŌb)g&ΨC.VmNMiF|:lo)+ӐuV֪{ܐYU;a%8!gQ[҂@mw(f;MӄjثT%lIFxE:|@Cj->> +W_&܋mepd]J4\[LM1ӇaG&z8i. vX *B+5ùç))Oy!bO,z [xG_il#7\TܡFƒe{!L挞 ΠD]4cJ"F*5,YFX|'4J!(5SZljK_Z}+>8#(9MAW Q]=[$ 7LC^)Ӕ_SW\펆X5j + ^O X<59#=0$ +Vk`JT(UzVC\0 Y_<4\&2IE4c_YDx!X  _篧JfF3C12vN$tZ-= o憤ŷ>EnݓP¹iD#xy2F2"Rg)*bNʱe@v\}d SA S^azWB'TrFj5 +9 +=:!UhdhY +5jTNj5Z[^)Wp,uk tUX.VW"9EjRBKPi 䁠i40ATp ZiPGᠾU)rF[2B֨:S8ӫUH V)+H5PZVnWk5#jurD:%R(*"s\DNuV*h1`7 X{t ٹSe3'6ؑQR ub ~_ikOL +_M;USh{G1_<0.74ұVcR* WKoZ8Pb􆯁":o 82rBDM2:I~n5/oj$ol}d€Pq6[ZYRϞ]-ʳ@ +AZP/W2q:MLҳ1(TgUx;rܳR\-; x<Ê^o!z!n"rlKm+㬮.dwUZ^roN i}dhÁgI^ +Relco k(9C\ +HiQ|W?;7/* =}g"wzpB*΅cw\]zNvS#JM +(*p[ ɢh|429WF:9-!t*~a +RiMTqeLAT +:^ۼpBFn-Sj^8Vi.0%[M49\Ebq^ Bj=]~^VQqUk !ke:d,H5:]^@z-Z%q~ ku8goF%ȑn_pIz]!jq_FBKVybZLУe«Ѫ5+`qaنY.籏&,1lMp?~YxjːQ[ +ZTE%Z[Z080l,'. Ua K4#ex-ࡂǜ0 EF-@@l ,AʯxOdB-Z%aX*.p]cK SK]uH5Y/Q j>*M-BR9Dȕ<)e^œ +0۸"k" m72X*"N]0",!PR"L'*1:$Y)Z%cZdMhP#ө. 1(ceHgn10n=̰`mKЙx aS$X?Z;+Bk +X4]v޼ecK[3.{eܡBlqtZGƣ.l`H/Cv3<)w\Ƶ.`3m;BѻJV8Lg1%lXP<1[1v"e"4ax<{cC[iW.wjn<1E,iXD<1guV _l<1%ø.Qr<~11!4+`V75 q'g6x c$S[lLel3^M0K=ss w0dp ]\0oq%,x%M^q/žC;3_ +'֤ +ivЇ1*40bu,ފo;N &j- "tź"uJ[#4Mwt^B0] <]ߖIR&b=&'fIR'')(av׷R4T\ڄ\KB[,M\ڔm8w.׳R4 șK kFl) ؊Mٌ{ sMڅi kF ڤYSTv ذR߲k 3څ7sp|v<ۄ SPPoí[φOB[>pM](phmmڅ7Pȭ!\Vw{v "LM-"\&Q=ܺN<F}ij0f grڅ83 +`"zuFn1 +d♽۔&q[MlZmʆS=`blSxvn-Fřڄ-)[MٖWڂ V<ö[i3_kq)W<(hU=jܚs6m-%gkx*MLX>WS+o~q+oq*oq6+oEq{X[8Ȩ8#"Ӹciqgdi gdjUdji &Gu{3ڇ'|r F+U2-Hzz\D0L]`UKT鄲"Bkp67^~*D'G{RA(Sz&WIRR,~n Vz]d%lj pۼҌj2 d&rM Ւp:e=%`U8&9}Z=wU>\xCSE!UieZ5RQl&K~W?P!$ 6GāNƣ >HgcIs_ +MJgšBE ;(yu*{ ;\7LS]MfwIAt$< v! g>ĉ} U %kr[J *1ָ%'$;5rp)Aw +pNgA@nN}cUZ]]]V_vV:jseRtadV) N7 |B(g k7uۜAB:UPΠ$AO=.h6}T^u SӄFjx\<%U;n(KF1֤) btѹ}u>*؏I+:`;Z9DEd0d2z`~Nw=Dg~1Txc 7ƌ2fj0SuF?ּ9 B[/!S`ƪ f/xWkrK8,#'إĮ/Þʓ<ě6 q'(rM#V+n;p {kV V9=`9S)-dACAUdWX߹Oυl5Ī; +c'ARת4R漢BvHe3qVX2Z +eyL)'9G2Sa@>$-;Jy!R ʓL!л&|CZp=8L:Oy$GRݮ$ CgWjjRLUI4)!&d4g)50e }e/af=xEc2R6qj|* J?&WyLDwX2#O %xGҵ󆣁̈` pMi {:_30,+á}W'q /2JgJ`b:= {VB5zZ}#1Run oTLVF@/:F%5GojASOCt w>|>m)`nIdP*n:#>L' { [y +sf3&HGIy|ARK46@К.] 0xm(= lIVHmOČ_*$ 9t 7 +$/D (KfD,428*0cy^4dҢV 6=UoHǣF&6),(L!O`3*쑬Ym +bo[sO  +#5BbNn.VPӭH&NИ&ԕ  Ց1䢮"hI Tm;]u2Gv%kFO(3­&ў5\Eraત/KąoA]Y$M|R냐t<F8OӖ4Кw5[j4hbV\-fVJW4>_|l$12Ơ6/Vq +T ah p萪s^p])V Z~*{˕7Р΋ t)L"iSf]놊]faOǡ+ Z#i=kq*>9nb'XP;٘Pq1/RNbݬM6n]Or4 B ?|aG',6cs">v\`x!C_ըd PpPҞm.-N ma>^Oﭼ;ҝDAS8^T8ga_CN1VwV f\0j F +g%}tlʅdwJ^cM\*+AˡQs564Vvdre۳Dm${a(27 Tɒ<H ̣ i +HaD:nxJkhdRbQьw88˜H)MHjTP@0@ɬJ<sB8 +dKB.A9AQ0BW}/{~k B7۽PrD44TD "G3( @:7bwh+eRyЩDe EkCyQb{- dMeɟ {-gcEY,E"ɢ +QXB$ +GA KTDFw`W,`\c'VQE'I$I`={ r[9"Paޓ%_@lp@ClTd? AT-8`DD%&&C)±[4LLl0;dM +oj`:ht h0 y XWܦpK%]0@͂2d'c63 _R s08Q\;w[{S]B*wS(h +\đk#iPRLp+ed1 +K ]3 CWbGuIxsG.34DBo{ 5`spw&y@Hx@*6T\&yc:;vL T`4 #HFYE dHz!FNG +mxë >Dо(IXz;E Yo` v .^FYARa4"@`%P9Q߂^;2t`i %@;a y~/$JC\]6(0gq72w@0`S! +ܦRmqԣj/ TriL5 wȮ MÔrHoBk9-JjY(4(bjXI"x "JJ L _MȾg-nm Fp#w rAS^h%y q;˽<ϱys{hLDbFQqM3)IjCCF(ղ JwYo_V2QծYcPNE:zV ~iMݺ\8bc' `-H|vg\%V9"p,]z@!d1B1.PLͿA"gtA֛ YFofa Z %03 Cu m2P(<@"Th ,%b c ƅDt.lkj!Uo ÔG|d** IFB)~0x ` GV"Ȗ Uhae3qiRs^Hh"<8%ň"u0!ؼHŠBM0H+DDV&D@POknLiTf%0 +H!Qr;i<& h͓5=j(BI`9GC&A)tCKC[Dat 愀YU`i@܊t j `UQIWňn`b@wuе`)_2P, X$!10*2y XóP\G"2Z: ;?Y +AIjEE*mdY\jS暨D+ ЗLXiE="nhݟE+%zX‰CC % &Dy2SDu\ìE\z V*-$`\D$Sܡ s`.< +SШ.sA)1,A}^Yw\\$+@x6]i:vf8Q-&^ u2ppʪ`Y]DkNK+35XAͩ.t-/aqD%.=A`<4H&)4ku(bK!q}PQ3ETyѲnyȰ/hL@$lŹ #|]J{*x8%92p?[LCZs +X܆G+ LH莮@ ZqNC)Oo@C;BK d}armx0Je^)R[aD(8I\ +6b"x4?,p>5,,Xbt- 2Ws`DՍD}y0$LTEB}&`&z ]RP tG$t- Oڤ,U(FA埙" K0$!Ie)k J$`&ճ((Ytt2jx̀sABG@KTw'vy̫ +0U*`|tI%WDC @?Efxj<^svM`T,@+4JqH:YzHl9(@`^:x@ll-UK1djڠDc>,{T8wtpA]D7BUT%{v61sM^4_4Ȋ: F N!\2/@zD"F_%)cxΕGSNL).20 oAST!3(@JVe~tnmoIrJ1#vtIPD|lPpx!6|:eL\*-¤dکZ[IY(TퟟtOjXu@wŠP  ڧ8gb3'E@e_!yxZiLipft53N陀XJIfGa?i{n`,JuOBI{95P\{ +/fwr/?&*WzWTǰvN*OҨu# xL//MS2(udE&k61vT'yy3o4؁>~jOyfɼv#k)xBw祥0i:f3= cgv>u*˝ӛXv|uY +k/TmĠ2hy4ۤoZ%3M$67zVZ2&v4̬5/)=v5Iy^JljnV5sŗ4ߌ ֓y%tsIFnѽL%X%PڪNXT5v9"ύ! +ۙ֨QqƒVoq5|xl, 'PsҒjhn T@ EsڥGܸ] +82}Y>>!?W:7sZ&8ԭ`YoO{+s 7(k5HUVsBr&`,)Z_l[>m59mGx nwbIG^kfTۈ듌ۋ_Υy|4ٌpyIq8nr[N`w8τ؆?_Bd?r}xTKGͅ +{OMg{Cn~NJDoPp'fm}O7ƶT\>>%*Ns|oӻi676Y7 tVMvݻF5Iޅ@>۷yzi W#Ɉ(G|} +ÝQn`ɗTKz?H@8y)sstskjFÙFE{湘[o{z?ގOD@CӖWo~m><ߏö 11pg[O76uToEN _05]ԣ#/6c;RSMqOIG}? H<*et섔#͛z}qz#E/RdU7>_3ZN!sv<}8:m>᫿{i:> fi%Q947hw0y1.l@ٻ9Z#`u@kPx.x:TD5QލSe"I${C+ӧ+q{Eqgj)~crп΂ UOrg|=Aq;i9JY*ï^"uV+8B+E03N𰐳K/=߄xifP8hB@!$-c(YXcdT="b셴|1p~[X^OG;oH'% k'7.#f$;D?>к|lLUͳtr\K@Easgh+w:C3 +šQ.Q̦o_Sw%`7U>bflcI<,oGz:w6盽Jc۷t:j6-ʁSw) +@g_ٗ_6ӟ ~?݊=jjp,a, OˋM6[f>pjgZ-qp#K ^_-z Fϒ0ƌg0;{]@l?̢-{Zm0z>1>*j|~ǖv1Qa^GBګ9 3p +&\|9vO$ T3C߿ގ:doLKʵquS\hN"t`lnvXE1]bq5WtF?_NPtU2_r&Pr6Tg>Ylq /lkH9WH|cXh/2ӱm32_c\.}$j^HG\Dž,N@8Q5;$%en?j3wu6E%6ꆟh{儴ݬ$?}R{Ob >oκWo +(+N7*Ɔ?;8&x1S+uCsL6:]$*8Y Eit{kh yCa (uuT8$79s5Mha3ʟw0`U>"@}⫅0k֯E$q ΃rWu~qh TB^^X,Isv6e*D%mɮ8a+^vɄ9$#0MlaB[WL50t[2*g_}2/yyH rI ncR x]r-(# +9eSg0;c݊l )z'$TKo 2ɭ,@W)VlP/?8ނ&dg{r7OFpY{ȆK=_wtzxvQO{s /v3K%;8^7|1xO7n녷A6opRE*>;;QSM,G%6 Ĕl(r:ot [ +nPFgHK7NK87y9Wޝ]\k 9hV sVk*w1$g^Bo=]y9J \nf\L>H3^dfXd /}9D`@OP(#.򘯓Lp\}FA#>ƍܯ\H +Feii]ĠUqzNxxyp`?Õz`G +s%r)=k@/}ُoSQbAG U JĻdqk7l N9v83~Ɯj{Xodg99ɄV/|(W - +f3RdaqL^nCݿ,鵰PQ:kAm%{aWɾ@q%u^/OeSh VT'/U-mј8n;sHQ4^aOv>_X]60IiOHp =(ץz 8z77_^O 9Zx+7Q YAݛk. 4 <49LBGKL'5Wr%qf)ۙtE+]=Ͼ͍n̩mw;of+ޚ dK >1(>jL7Kϳ9gE nEӧa;Ԫu"f'WYDJJ}v,b$ 3;"WsY܍Ǭ@^dpE9m7JAx#X_7`=ݺI>>nwjin+']vx z`_Ws9:vrmK+IlͨZ}xYĖ%px" <Fчc:{(snݟ;aWmÍov<W_k FdovF(gg+lil6{'bCcҲ~œ[ficgٌ^73KWёO&ˍs_AܿzG7 \Ξ?-BzK{;ۛ^otsïɅL?ЋW.<#.__Z.7s@ &ZcRH Wj{X# R&}J :GЌhb~`+` ~^` u>@e͑1+|H#? KB:"d,:@Ƚw%9l64bxGL"Dcf;:n=9}6_2Epm x.íQ|AV|lo28y 6y;ukm"ï%Ԇק0xi[e7pv%5V%Ԓ,kE%W@2IO0x :n'|Rޒn㾝tҬ"~= Ys=拊rVՓpcO g + Eܚ~=9=k`2R-izɆ_=EѿS$&;k%_AsANA0dD|ĜmĻb+|Qcz. ś\E0ujY\Ob:y~~4?t.'4#^_nO޽4;JyǧsUhy;ɼB Ʊg|<иߕH7 oSOmoxv-!\U`aQrqʔޝ7 wyʼ{Hk\tǪ}-8Vrԫ^*:jsѫg޵Ż_ y=9lz}>MG߫7my?|C T`_ᐷPj-%5wwoz!xާkr}U]o Qo'x{{A1~n?]dӛ7a|36pیoܹ) w]l7OGf|tj]7/gf9,<7si{߼T69h)|-{_7=蹱6@7|<2پV|і/ |v)+'>^|r@ 17|_;)sY_s+=]Jaw m(#,|׿J|@Y}+Z/R`S Da@R7{%1o'@N9 uJ`0p -oi$tF#fn[yn_?m'vXoo˴uP۽Bu{҉>: .^]39H`_Z~:,IN NgY RRH-B/h(JN=tw gQz }t5yǟD9s|"uvN-s200vNkm?٬o\#|oFacskdJ_}]!= w3l{XvKnMf҉DGሺIDncyjE.N>G@K&x)lEhߍmU5}r,5=y&b%(>J/U.LpⵯF;|M3}U/EC?,ly"ˡ7sz +|O IFppzv9SU(P)&k&Og}+.y[6Rl +Kj@:oJw;[ɼKcqk,;;YU7\*嗯cŐ\49cwGUvvNJƿ(dTʯJ*}@yUճr/gw͑Q:n9/j''C, }}Ÿ YIOneu[Nro/uۻ7[T`_Jx~.oO'w{}A<>(jC{ +|4#ãzh_ox;Gg;ׇsa{8DR㣋qqX(hhX1'Tq;^z3Lx_; xl'2fyHoA=_N{ɳ!7J$spT S p*O&F5w޺jb>-FV"=|;/gbv&2ODӻn߾0;jq2yB99 %쯝>¡ NҥQ䮕9:tQ> +k +֍yt,>^nήLCyٞp*$7vbкy|?ޛv2u^n }EXm.JV]\yv~tl+叟ܘ^jeQ7 +Jձ^hi9f˹UR +ͧpETJ{b9iTwj7C9~y=wnCut~doCɲM4׷v8)'wpp9݇߶uQF*?TvL7;gbR=z +ּO):GeZ] m\r!Ր9"EzIyף -|2nhYNiO@^$M. ~Qp}"\}P&npޝu0hvu8RhƝf먢U Lm" +>pā;Ivc<Oq<@,;'=iϋc^'ZţF8cYx6/lƧc:ȖaE)]Pj|ek}<_gI(X^nX:=k/cв.}>gZ`A +jjhov0cat0OWw v:g ]ItݑcX4E,5c*!>/Z'G_\#m.55u!}sxG]PFeƵZ q2g'L{.&3W=;Mm0{=?Gn5=sf]n$TzTUK gHB|Oh_n='Kz1Q!1%T0&[j_ nS7î"}3<6dw`::D&3)Y9,pmHy|q"_ %V1#/s:Yڵd +qUq W_ڱ!H3Vs7Zjqg\;6r%92ԯJIFNE}v#obaOߦc %Bx鍯H@HI1dH80ng 3Y̓E57)#!Egj36,=$ +HD+5{lDO ٰ%/B*KP 0 { nYEB'Ē_A`m%U3 -NڵnfstKRq\#qYCJ}КwEVHˇUMIk!˭=~;Iٮo<=ꇌ4sq Zn\o=s^}!2ƅ>*zp4>.?g'Hev]7&Jd:Ծ`gN )ZJ=dqIF/qB8+]|[k< KS.Zb .J|-gW+T gP2iKUkxVI.&f${կ&;~SZ'U6{qF/+GMǯ# d{ *d`"<۸\ƾ[E}Qpիvz,\V'y8+#1a_2'Ool*47G$9yW=oS&L?-{8 qJR}7`_l'Di.̔0@ ~ڊM + xwq6up*2 NE(M"=$~i2j;-uE-dvo }7non3w|.Awз4kN!D N|"ۏ[tzCIUD 3֝3}I2ZvEmz5-:1Srmo!ݟ:Epg]phۏUiؼ!Q·ob>S:= + R3N/_gN=~(iXܭ'Vv||hi{yNqz:~K^"!Sda8dZ98ۭ;$uʴno[w_u aL +ӎ=;m34w'V:Cj?P&yuzU`8 FLvQCffFJW#)Ⱥn1IΪ͑;+oCn'ъ;MOyƢ8sz&wL!+I-;=}9~[uf{SԋmZBlo۲UE׀D~yw|{Kk05i:UNd&.>Nf,Ot?z=~ ZG4{VnMiǸi3Rc>;ŽH"S.X +utH + f~d/΍.E+nQޛuX6dz(:M1)NRxNl/nL8Oޗ :eΫSt5婷tҔ oO3u:OSÉ s_ go#@zA Z$4cXtǽx~l_Z>u7,9y~2 Z>rGIGʜç]˧ۏt:B|~=7>~Y>=oD_H|z->2>i~f_sc˧cݔկ{P|5>[= xݛWfV/Ti#2ЮixQӳv}*N: +4:3 ^%z +S"ԾmR}׽PT? 5N o"JHNj2ͷ`(.!:s4WX;vٯ J/nPOkqFݜ=$:vN;?h:jNeyc-;zNw ޣUm©Oivt쨝"[0 +?t-r:yL--:E ,:Zvhn-KZo)H/N ބک(tZve +NA8ӭ4'/BWOқ>K5/cfE; /jjTcR7CDc)|%pZ1N>S&g phR%b7ZJu֨) &@K`!X@ "8_1؞Ւ/ӆ 9Jz;z>!()ynD]<(0Mv晽ߏp{ $àuc\h,i%tsr^m}A/}Z<ݶ_AgG/bII +s(d4:216R{kB_go~Hf#pjW%'K=aIӁ]SӼ+W=乻k*k1X3Qw%K8z-a+=+7Cݮ\4|~O"ͣ@v/ &gjz/.} z9^ P.5c!!@ûlX,SlƎ|Eo&>_EwNF*-Ә~E̻nRw.KJ :0 BPgXPr?h9U3# + (mJGMW=^D$%LIf$QLچ3N/ z޳ c 1z$Q}I3׿aI+bmD-=MzTK:Ykrm0rY DnH'ZSjr>o,e~}-OiVPѧ{f̘ӯ9KncMƆJ#uK|mD+LhIq-- زqB"-Qrj/^Zņ+kەe>0;eק5sxw +Ni˖:PN@DCWbBK='zْf :i(ޠF-%n(^K+&Ev1Nh.p|Bb¨$Abt!;k_?}>t@]uC;{#I|1p-QօK K<~Le6=CM~muo]0Y9+M/o='+iy0!^Җ(kR񹧗--$ц^=iF}G}μQf2O+>~8W%=өs.wSlqP4h@gi屇ʟQF|@cLt{/\{5[HxB<9x Kx.EZ@VNDIQvsDpg<"ȫy>[()Zb=1zY<1β q:(dY +j7*];$-.OW9bc[M[oyLMcyIaTq]pxiNc+v\Tp;''6.n* BzyT ;Ǩڽq+1.<ʺM#ɴvB{XE4;i8  #56D@/`G4ʽVmDӮ Z! w}|R )8I/+O\Kv}D6|KpPud5{;.)՛ǥ}0޽̹+]ִ (@+Hؒ\ vdz-wG2NCD_(ߣ⤝#p}XY㻼X5 5g!ќgbu`Zu[]VHgS c+ӝb{,1yΞ,oixo)=ta>D釥ah/hd6KJ {RV:2t=Jҵ@ZӌQmqgdB^jr $G8[z(9`j0⦃2$$ֹAsM?.-:Jt2^Q5v{50q='[ h9vyOcn-6VCaP7CԾyVJYhU{(ƫD5c#$B1ttzb#pb#тG!L^K })Zp::ȩ::S1ttjj1tx5G9W`*(rҠR1HՑN.:i!8TၭKĄ9ho_y~_z &&$]-WF>&tӐ,Wv2͙&dwð%]A0k/Һ֖^ +q㷋 P۶v&r`7gWgK/6U5qb]A*HEh$}<ks?N|NɣyEǷRq?n&.p3f0gg3 `p͍UN"ǁYI tGnN7Cm-EB7k +)D:ޅ`A{Tj,u ܧo)Dܔխ(4h1Y,3cNf=SNk=,kM0|m6;uʱwL";w?&w֦=wgF-pKyW1P:fyZjCr2LLShzar:ʯɕ?ufZGyXBLn| y5wH<ٚw 3f=O/, ֤dg:2lYw5(;a=j7OzLl3Xdy""c|ͱGux&BDb}xК[Yd:0%-2{d@V,261v."8|"Pg^X9še9S˃Ί0}6C&tCcAC9y[iO .y[%oj(fi@.ab%jI=[#5:wGuiVGK[=N1mDx8qK, mpKGs\O<H8WQJlCx%,2pmpҮ4Dx#xE$['RtQD:E|irX*$FVq+q8qvedp钩Pu1:gs'7BPns&fsYb Qc&kcV߆hEjilb Z1n%rw{7}J`W8%SA3+3۰ )Զbt]`s@:L-L:ھHM:k F^'"g:"R!^l:"R4[&Z+J:a؆q6$ٵu +g{/P8lS+K‘?i +tpN- +9\_2#bP8`Hg2ױ͈:Iƨ2ud84Jf;݌ /p&]v^vNN1Дe\Lkzk>$_*wQ BMWoo\5j'}W%ZENgC?d椏Ʋ;+xβ#C}d]4Vn6v$i):YG_GV>Fص9MX|ttj v._J]B&0d&,;v?"p=ߍU۵]٧]ٙک_2tjKx|i)ur}_UǦ5EU%y7wnJy7GO|m0(\nltCt&ڜ*q4TI5V:V?3@qsEYI 7V$G.*9U'0 #ul +{v9\lDsw̷k7mrpLi?$l9^~iOJ4i8itX:rUHҶt$ҔEWMGz4ڼ!|@z,MGͣT4z}tX:tX:@F)/kbH޶EӑVh:%%K˧h:`/Mgi]k4)Po tox-MG 1$g}4o +b*幏#5`㥶d4aow:V댦\W4%¬54?"GYFӑ&Cft0aVɤRE@[ /Sic.n?N];%LtaU>XQYCo4yjZ[dԱ)PY)UG=$Z&Ra%C3A\)\ IF<(' 2Q[!ޗ9WRxC/zDsH*sb2wb.tc(s2wYSܹ4|;/e慛֐/X4,# B˃H+Wz4KZ@:7AEQ#`{rq:$Hp"Y9HsQ;ACDNA->WwTnPcTTP1n{f|k| bY:VmEMX['*Wu/4iSiP7k]Y)EthXisr*!zw|#fjʹ `ccB^MX>*ECNC?U Uk 55 ܪYVB<;ݹZd_U:v7(a juW:W*l*Vk- |tOd[)oJTsԥ)+XNEr;ƌ +wZik 7DZbMۚ YД +b/h#WKj?A;T GCԡLuYB}2ɹF]˳QtߞLALPٯj^R1N1렜`n` +u)(AL4cXݮ c + b2ꕗ*mp}w1ALPsBD*E%*Y-EzbY?;҉<^pcCc\<dhlr[Wz"i!D 8Ǹ0 A\[Ԉ~ܟ,A[xxgEcgw(GOϊ4}$]޴&\0fLKwP>v[*]T)_jou،axдwni9hYOc_R_4ś|hy䫖93TIDP0 +e [O`ΎE46a6骊Ydm!Q"k2åkK[2iAKTdu'9W.]耶LTk4M{~27uMuge^v1$CgOnHZ+JKK ҄7KژM+jKqaWf@j? 0\Hk0/5f4 hc͕]s <h xn&Ɲbcl2-^ŒiQk-i[kԑG-Zc wfj:CjGe &ަ"s&J$dvYܕes4+`mBRLa*ρ,q 9fZЌ wz?إBdه鈚[4E 9UѡrƜcy\4fsnn.]/XΘ)\R:7KGZJ(@@ i2 +6žlHf- {sێicG/A].ЕtE=& +PLјdQ>-|+p)'˖KeQ>'y=E^pQ>\j,gq(D;OiYr + gϤֹ#¨Ro p]5rGmj]?9n l{]vUt a袮H}g&U[-[QVg$!uJUu+TO%dujU}|2uWSρ_}U?.ٯsT:VsMǖGjE ]T$_7Ͷ-Vr\ީ\Ɉq]ϾZûβSm]?{ѝ>*mNCuH2jQ귦z|3V9Lu{yl~ZYsU?B-( 2PiTǷl]?}+l=>wǺ~V0;R|ƺ~4Wul+?JMQ׏6*m~ $T3F/[^ vW~l͢ǷRo՜V~k|k*N_]˪&ۺ~6wso}1OU^>>Nε}3ő7xhVVWcZO{L;@| ًb.=^GJ(Y_$~n[{{K7Pl.CE^sxTR'#J4Yx:ym)} #'[Nxx'K'zb3pL:;3}wgH;k3jfW%.Ym\JWI.&QyhJ˛j'vT }@01Uڻ6/;"#A1Q/s>$Cp+"q2!l;FsB3;C1bsJ~5ao:. |6rL +e#uv:JA1y0Ջz\}ծeAW/=G"OA;owGA\`g໤?:` |Ķw~xƂ~WK!p:N<1ass^fYZLr؊&Oy,rt~"wz{a¾,}\s!Z#x#ZLjԞ"iM, +<]$ƅN 9ex_к_]&lʒqNx"!NQQ)鯏'w}Kq)h %6pU8~?mWf47偠ʱ oN]pR@RH ol/׌ƅ w\#"J/V6P <>'6䏏QV'?fѐUf:̀cssJ|`|-{㚑B{ }ZP!Mg.jߛFJJ%5oMw Bx+-IgQ@$xA YIk;_E/Cgh#w?1hhnbP +W7l-w 8=4Ax0Ye.ܙѪ +y:׆]:&<ג]v:\[1oQ4wz MN ğ2D6kb?w4H*PgߪVΩD8Ph9b/O,e97H9D_7%Cyrݪ@kĉCYy +h>?h6R{}34Jx \c|a1Da(חBԯ cyQe\saT@!@A0#;t$\6a f0'XذB`'}fo;܈Ljt5u@@/O]׬}X`sh2oow=}LX6ݟ36d;1,V] + -'`]:-Nq]O hm"Ur_E*K-0@%0IEw*A,xfmP#,إ;PZ6@^Bc x{W3'N; 1xp4ggTx'_>ȓ $I] }$U+ةdK)(ʼU +2 6|PJ] )&$$>m%?q+j<,xkIN(\^~ |QOڕd %WCܕo,dvӠG ŀ;1* lV I^1QSeqvUE=[l(9#>"Mߦx/$3f]Yǂ/Uy +S41Sh̑Mc0qIcU#JÛʵje1}tS)T Im_9K>05&{Y&ٮTxFJU<66}AWLx,?JSezu |I|v3胠gp}#2`;}Gw3|&/fG׼r?fbuI%Z]8D:2̄&bSS'{ }ߕxkX;m峙Q(rֶʞ }Wxx@S>U\}?jp: +=V>ԂQMXwNpP?{?]Q=iWū'.X8k߀느z}$G?+xo);]|ᶏ@j?&.|!63ӣL˻v5V)L`{aoĘa 7.Pgz:g{hJI gu zw3 t :WyM|3uWJhŸ4w*#J#u9! & w֍:? wQ' +u<~9MwׄvO"{m>۩{Sm?S }vr~v/U8)H:xN6-O|Jvio`0ا6׿4]M#:+]K8"h /m_7솠T\iP k^ +x +FYΝfvyX#>p޴Y 5Ql23|`p"^<2?.jhb +\5XQ n 8f-Ճq*%uf \B 8s{*ђ ƏtX|+%mYM5/""*a`}y +םz]X,8sB^KtKR3ܟ'@1*4^HTN*5^v/[`_'d߼ЗhU>aꝅ 8JOGRpeb#+8ԙ0x(.GC ~S0EoxDIZYRџȎ"Qiޔ9܌-_F!Ax[ok$|wp# .r|M@$ joer"V׍czE x3e7Vh$ǽ#{ԓyʍү)Dn]*; ?8N}d\ G%!;*-rDEDK5 r+\#eZeğv[E#$ #&A}x p>ĩugYGHGKW;;:sJ!19''-He;YktB"ؔ0T5/O&8 +H5!ϱ5L 1gMTIb8yQD|cnFo# |7gˀ?lI|Eǘ?y3&!Wn#Eq52g[m&-~\j9T{ +Kl%]u@w+G)v9OuE;| =CJq4nQ(lsIFk1bt&|}1~#ݗ10T$u|ԃyNAp+qia4iNW0DSݞM|A{{RCJd2DXXykǙu VP{(xX]M)eo5[O_O6GY}b/ogK}ӠD~<3H'mz&0(/g!?1K͔Yj2 ZCt_*%! kH7ÄӃb^vлxWY4'Dl`Ko9h̐EeRGi*\=zͫ-jhn#AeΜߜ`|(R/ )Ɨ YNjh[(*ژpn d+,Bu>tTB/bw$u'tb=gcQ5*%Nh5oʛ+XLw|`l,߭"ԁB Ç0NJ`b!pF72JfFV WquEx7>>[8K[Uq5ޯXCw"v36CW4 '5hZZd> "ИG8jlZxg'c>Kz79#UP39+Z؋*N(*|CZ1N!1NC#c밗a|3r cSeQ,ER7#;=eۭq΢ YWnC+4c$pdK} p"[0g51 dn1Vj5.ɖ j<;5m%` 0D#jmZ$%.& +^ɺؓ )1Ow 'ZUyԋu6Fܓw tRepXT92odrxLZKfRT)CdYO,G%dv9΀$~q~@" +sjS}RB~].M_1O^ +9 u^+"鿙G!}<ˏ`+Jт=JS̛*AX!4Ȗ5>f Lɑ݄8Bij>0@tØP 5 pR^Kr43lRE&1orkBLݚb>ĩ ]%ns4]ko`>g#čhGe*A}<)=;=C{ @ D@hµZRzg$Qӕo)toy]㗊QkL%ԔiJT4o~a{} +IZ)pWGir +i=֣kt_֡I]d3Fo34εICPPf=܅TS!]#DkL̀KT ]dzJD9?e +iyVEzUzE#W4dJ Uޫ`]b y30NlY ئ|xHfkl})W#_}=E 2 KEWuz2;Z8fvlTch[ M$hJ4DD/r#ļ(g'Bvj*'(Rw}`֌a7yzbk9=Oi|A8~P҄̅i+ɰ.NY_<6fMP_d/'-GK86V%$_CZ2z$`dH8XG^:YI*SM*I.t4|bAbS`å5**S,`k2+&/Tj %^څ:{;6{uFڐ@X:~s᪀czQT4΢3N(sYNwEH,&+M j 6ez٣{Σ[/ެQsś5 +7gzϽ +'>ˢ5V_:- T YyC**YaT.]85yvnM.|ṷ+#)\iB)~v8OI2HV1B4ߠew]lЋ7\k,-. 8aBIΧJ\KlqeKiD S^=lGߌ[\:e$%Iw 2y/Ihپ  xH*oRf 2J %!mD_5Ph2C%-7R&r8Ė*iW;<z~qF%M`pV#Q> +4Tg(eZFaҺ;$nu/Q2Ipy1>i3? 2wo錻?*V)Kh<J}?kâ6 wۼ-5iکN&:dJtm{a!I{$[xIy?3/"휣~"A 2 Tbxd/&9bjW_玾; ?_ҭGv'٩#X6d]8C-$lU0K7UpWI%d/'g*Zzhb Ks#BcU%#.KZ3;qF>HDѪWqmJ:x]yT)ZY껊7B Rh +oP# 7/(TR9 Z^E 4Ѹ/Ŀ`3xWƓqV)/YTP̘5ٍ BH%Et +J)6$Dřs%:$@ʇ~d@ġ] + sIe +0XrU`ZTZիB ًK_^AJ@ Y_>j_-cD$9YDIJ%IP*&:Xb <`U #\KG~wɓxv+N[ɓpz.&߭tz6_ǿV~+Y=wTc=nLgMi [ES9)O̰dYFސj>&!ol-VL=Nc:5 C}',od-_lE|'t'#8; 2t(hzCE >e +|P>1O:ApٳLo5Eo<ġ`dEE"{WWe\ٓ-q*2{J=EN3†RLJ].T%fg偡:Hv] ^Zѫ,(ڡ^[|TvRZ=2yIr/'{.L۱Dx[>G +zUC@c6fU0hqX;^f3A[ZQX".;!uvG`s+r%M}.RxᯔWW-ݽ>j-HFi"J[Ps**$j>>Ie@U?%֭`p>7p?JG'Wɧ͸rKK(g7'4/j?-#h.%dܜq=([9ɤ~)>?2?ɌuξX]=zw|ࠀ[O6ME;mV7`{,cC.&vA/$a YҸ L [ }f:XpBt-~P.eO8doq$=]Eks\`gj+'3&o 7u/"'Z}%(rd$q?Xm^N 녮t&kADžD֕"`."1{~ .+\y\NJlfF`?\Fha$չW`z X/!'kFK"] nX,gH@TCpEg#ErIx ="cAŕ)KZT\y JU66ȨI.*\~βtLA:ف}pC S4:`AOBHΫb= + v5pKư7$<ʣc$bu.p@TpB( {*Mm`]D{KF;T ܸ!Y~=1^ •!N/NUÓꦨL5`vTVkUٕ9c`D0ɷRn"t#:ͣZؕO:vL&7RGJ.'%)4S 1¡T#5 ti0*{&ю> c0.%;SBRZ sQxwתZ ' ݒjtcW1 Y^D*\I5KIׯ&w$$I~\C~Vw0 mh +*R4"'cW]s5=ZzeYFl^Ě͏(p?_d{XmK_]jԇ,*D[l ک<.T$#4Q|:AJym>j(;,<Ӻx bhWӯyl>+<6vslXʎꩴVcxٮ⌑f¶;Stj _R3} ) V$c% eKÿ%ǠW;;N[ܨMx/1gDg1 /+2}*ZϡϟFN^jڏ;ۺ9{waRuã ]G~f}V>@[r\C';#o(=/D]`GDo§=_>#§{C- Jvݒ|KK0엌3։j=`f|JX#v渰o/_oQ+Kَp.akQ}xV a2)Dרx9[qobB;aMyIH~7(f͋I̊i[,I"U0b\G $3SxJWpS HrؤrHbZLnٺ|D&CL1"("r U **9z T|a]TY:"G{LdD*"[&Apd,O#ǂ/–s];KJKW5%U;E`mEpL2UUNXVɿ8f`WMHM6yHXh'- έ &lK02xȹ ,?KzyU֩_ uݏ` t.VJegYisҵV1hܠiL_41/SG˛&OkEjm=Ȧ1 \0cK])"Z-U3 )+r1"\,rT$zl>0HTX4: zEzqwZ}i1Z{7|-Ջ\.Dd.`׹@ L<囸 5!E+r;\v_sJҭ6RKud_puy, [ ʎBY."[C^EIIԉnMI<"Rd8dR}wp2;+1ޚJ V:b/f&ebz8ׂCPAZU- +ptD͎`DY>Z%63 TھClb9si`3YnՑo#\|,j_^p4ܞE.j.|G ׍U4#`&XO=>p'H-U?hvƙv4_t!D +L*0/z٦߈\e T>!?QV^,m8VktUgEхk5X2}2 CR`ؓ'>PW](~YHvURzp_6! X9*8YnW9xgY^ ^ |$>Dh\ ~Ŷx.a:x +h"=:6@Pa 9NwǕY?sgn3Rq1/S!e+8/N0dRSe<=qڛD/VA)Woi!_i~x<Fq_E±ʱL!Zs4\ $KsQ4&˳F̀,S"x.>?#"4ː턪>s$(Y( +.V)AS1kY(RY +R%E R햫DIDyV) +rYMbku +Ŵ){˔eM$7;HHo + &){B[\8Ppvsw1c[0|l_>R +TAN&)J91ʕ)JPb|(룈|בr2;HHk+';HDO*Ua k"l$SMܝ5u]Rσ߆3@'|}vFˎ.cktzכ]RXc۔uʳ-cTn -}^ K9%%2R\LN'Wke$Y *K5MskTKɗoQV+=+7XFlv`'&GM>,uiBi}K٣j;?k(BvS eoI+|jW/+zO""2c(Vhtޚ8SV5%>XvoyXxo%Zh#AtF6x){>Ɣٸפqv%Ux*YqO6!VCd4E]$uˎHq?񢿥>~ݷ7tuo1^Z.!o .JUe~UW<[^{y=ĥqfNJ:tLlu<\,%#ŔZ6=;Bt;OA5s; I.OW^I0^s9uU쪪N| u@ɻu<~ )7 >.ް;I;4NG}U "ZBVzaKjn[D} .y&tf8??+)(y0ݢ .t'䠫[Bd\"ט4h 6uy؍HZ-"#B=MI=梎s潱FWPl(% %s",J) 2bJRPCK*g(sZVKpe_+PF (h5P%xz +8H#9}s iehIG@:(Oq5t ِ wڇt\V +JY_A7&}s: ?n[ mqps +=h + [VlU}:m>~.nc+~|/tw+FܣߡP J־?ibf-<ĭ{篋T~*JLGow"~Q^E$\7fC<{7Iߺe&OY6f\G [$s4r[Dcx6ɲ>tK,j;/z]m FɖٰD7poe\ePi>˦$e]R,H姇g2|Ycme8^0ԨBzӸ[j3k>2}}=Lk:?A+yyCݯ}"VN^￯ zp?_}~K7Lnava+ d Yin&c@\ߏSS[.ݯh2}fFɍw//L@EP',piz t·o,'09Ϊ7i#>eS{4>~J^!O;t~ܺth_ ?tw|'26shsBA&:"3<+It*eSI!'#e><:'R?Y6y +`8Y䉧y9s?c-/чN=4<ɇ=ͯw|թOhlfSBrd33/&~˥IXPo՞4'qeG4:)ɡ|+X4LOLGK<w*#t8LdYtgė +,@2KjǿϓY1BWL +%^ +m4Ò)csh)KZ,2Km2,> BH'DX%SFzɱ #@$X H<8r3qlt!Hl%!Rs&F2b!6M&cw,d[th2~deyHGB02Kݭ' +o]^8O3TR`$T.ǥsH +`)tsPI#TR2*<T"B% +( B%PI&htsPI*PDn* 6C% +(0C% +iYGܘ岔x9$€*PDn*] +MhfAa4p9$ T(h" +O7A +MQ?J 94PiI )tsPI#TҠ2*<T"B% +) B%PIfhtsPI*iPLn* 6C% +)$0A% +=NphJ!kݭm0`J*4SFJSW$BA3e4x9$1 *i`L n *IC6A% + ӍA%i&BA3eTxfBA>B&K 9FBAeTx94vEJ*4QFJM栒0d3TR0*<TmJ*4QF* 0`J*Lq)!3Zcw[D"  +MQ*PD n* fJ4FJPI&¨tsPI*PDC[% bX";,nu,'B.ql}&cO$;y4f ,KNm,4D%6Z$ D6Go1ZxAƂ2Km2RBV,,ZGdH/9vA`<|6!d&SN!F +n6kA%6H'ç 1kf +9!cwK &m,OKK$C.fl%ַH`IMY!mwqDvAH`iz&ʬն RFKK$4Qfm2X^"᠉2+Dn`I#XR @) +YP"FAeT94uEK*4QFK +MQ!8h#XR᠉2*DXmK*4QF,@`K*2 π)+^rn}H#XR᠉2*DX"%(B́%`I&ʨus`I,pDn,6%(B $ 0% rLByDWaҴA$ ,ipDn,]MQ!hAeTA$ 48h +Q7AMQ!?K`.@L~yv8e3BO:[ +{"%i44evm,JFc?3YVHj"AɲQ6G Lu9Hh|{fԮA#y +xMsbs H|&¨ tchTg" +D7$.3!$эA$y?aT@1$ـTh" +J!L04UKoyIg)ts IB#F,D{"!$ ȢAH}&h0tsHiD nIC6b# ȢĽoF*|O,^rn}+HFx>eT 94uEBH*3QFHA +MQA`8h#NRa2*4RmJ*4QF,@`K*Ri 9.rVݭo@`K*4QFKSW$AeT9$0,pDn,6%(B́%qFAeTmnhl"Ac9 ae:AR[DzKm0^ƓcnI90 rO^rnpiAUhX5CEӜY H/9v#!i>&qΊm۠6=/8LvII_0roöCs"{Rqω7ȞAٓ̔Qؓ8h#{RqSґ!{HdO*3yٓ8h#{Rq2*{mdO*#9dOIy&(${mbO3SFÛcOҠMIy&ʨxcȝFߙT8خyݐXdY]g$$G4Ǒ1Hk?t&"%˙hxws|I1Ln3c6&a|D֤:n3IC62& ϙɢaލ%iF8ͣC4ȖT,g208h#gRqw_;PNyݙIEd!E$"V橮;ٻޅ t:'/+u_igs:Cmr: Pv Mvf@9(7뚃N\ (D3ܜhzw3W6 (+w;qe3̀rhzw3r<-_LK)v 8Á5PŽi@i +G@p`z"P(a$Br6 P@9(afer|MOnv MOHS<urv6@y'IonVvMO٤7@y+;SX! z K iBhzPNq`0pchzPnFܮCC=4Nz 0pChzPN'C]!4}F(`مF穹nZy85Nai0i + pHz"JN%B@r6 H9#fap rNFM05h%IoXx=l~>n7c!l7<N'flvµwMl„;[ܔ;Ý1c6bÞq_>c!l=G| ^{&l~F7elmG|" gް{&Fl~>n7c!l -G| ^{&l~F7e|"gspw6:cƨ@Az)!z)3Nv0z)3N\ke^ +٫2uq~v.e^ʌhw3WKKwʘn̈v{N (7DS\[nNNr: [hzo5tRoN\ (D3ܜhzw3W6ʭo` 4;܉+- [hzw3LD^)v MOHS<urvvL1psy@9n)n|PNQ`^(Ѡ<^)Pv MH3<urzvLrsi@9n)Pnɏy@9n)PAg +Ka:3ث2ai0i + pHz"JNnn!$=$gsޭ2ÿ9nmvG"I.K̈v;3wE٭bݳwLhv{l D3n%opgFOX8߲p:e3yCDry,Mz^ʌ=l~Fn7clcL<&[/ežI6? w6| ޭ2cfaG,܄X!pg뗛yg37f,F]l3q8Nؼ3sg,<ĝOctһRf,ܺBYߌGey,Mz^ʄ=#6? wC|>IKpkA:gdf~3ڈqqp6z)luQA#Zn-)pfl>Ɖ_aF;3ZgL͘norpYgLe-yw{F̜or<&&; ]N?+7[?c5܃>Is&qOx?kSANwsLipY2/̙!gpYiLa5;ph2zANwcLagefgL<Ÿ{1q6xn&r9 giLNz7Vm扻~V&n~#YY52<K3c\sVKHh϶!g[q]%= V > Cm۳M 7\k`'.k֞m:uzYn;cY{-Ѭ=N[v&6Dl[vfٶDlM[v&Dj~T艾!_r9rZrGyjo[@zo5tEɺ@zw5E ''̕`rM4naN\'7D[ < +(a 6KYK?cC]14= (#MNuLO![! ChzP'C]!4= (^! >#PP`G0P+4\pk<u`r=&@fYD J1õ#=G4hMyG@o#y0Φ#]|FXwEpCr0/p Krm;df 2ΦFnN\gYfYs;։˚h|cxBvf&aza@h'.l mvFYݭksrw嘚Lgm^׬+Xo2pu2gbqÝ闚qpOZgfJr` w&#|>IXx=3;6?# w6:6ٜ7<.zf;šJto65pf ~F)63kqvB4V0g9R謌hZq%K=v:)8^\N\֬t:;qJ;cY endstream endobj 794 0 obj <>stream +-ѬNK=v&e٬jaR;Y[ZݸyǝўSϛBh[9D=oF{)HΦ +tHv⺦(!"$ހһÝLn, [7p'l7l;#nӚ2CGi@9ǁ)Pv MOH<uӀr~v*@9,Oz7r +S4= (ލ #>#PP`7rk!0='g0W9ai0i + pHz"JNn\ 79Uoc/>'blλq3aUNrm?? v*^! = mpUNqsi8^\:l{qSX,v>#,]ES\\0o헺wG;6Ct*oN\gىw:qYStMos o@\ 7n v Dv¦yÿ~79=ڳ[Yicj^{g3]4z];c=m і9 .LԌ[Қ=3Sw{NO31Y,Oz7r­Xx;lλqluL~>n7lTC<>})UΘY?#6{ g-Lhƿ&af]si-Ѭڍ;'NKޒ}˒r蜅-{6M><9tr}/-F%gYLOz_>e .1VOAFٜwy39Y 0g-i My0eFo%J!f%dΓG!ߵb>< -&pA7_~߿'~?o|ş_}g?_}c??IP/󏗿~ᷯoD'ۗ_=>̿{gs}@?߾7~&w>կ?~ׯޡѹ߿׿O%IkE[Wr)BM[8cS؜oӟ }/z0s΃H[ n!;z,%ZI-ӟ[?tAwyCzۇs__~YK׊X/y)-/9r 5W'Q|)j%Z--h7/4ʢR6-mhtYBnEPcq2Rnp'PLđxJY$΋"U;?NA,;źrzaHc@RdYI7Q++*IBc$#k6y%w1k~ =z^W+ڃW:$͵-^͘$th+RYć$ʴeu;MF!d;ooj6{Kc~\{HFNPIlHҋ-IQ[NJ$!yz5==4ꅭZތ* B6ܝ`8S$ +EA^%@LHԛ#hwƆZ.<:R_mrF!θ˃VV$%Xkn5h4El$ |MVϩJcw>웝 ;QLo-{,A[;Rܹ4/nWĿaCPc.n…rbVj%VzY)iGR*]YY% eeKT#AhлmOyKxP'cM$ -ҳt| ]_+3Ʒ O>]ϽgDžBbtH*_NhJ뒶"EEF~ +(Klެ=($Io.(%85/CCb۩֥p$!fdOE=h}l3D$Ze-/'$nC2jBBLkADV[AcX3&i&|CA:ХEbF: 7~3mHR!'}7x›'w[BlNXɧxO|^gsiŠ㊴A;hՕoocEdh%$)mK$)/\G{gh@ўodoShRR oV۴f_8V oHtϥi-H#) z)4x+h:ڳx $/&_t}yDX!Vx}PLyCnG_H~zD{D.  A{ #k7 {2}a{E+(W(_ d AоE{rteO,f_* zh 7787o3\Dwih/WfO}O>ׯO_|jOͪlWbld }뢫^е]Wv ^=f+I]_\MԼ(ӻ +~y',аB^ȿY*$y&4w^}xiXR+UOR#do$]Ry9)Hq#B"=a>7Iٚ`ҽp)(H#A!rKkM{愜?ْM^O[lwy?۝ f퓱Lv'73-Œ \e{و O+fnivH>߻0jw.c}Q3.DN=|BL}TBpAby~E +COhi{ z#F<>@574[o:B\@BC0B"֙↔K ~oGՂ:pJD-kH$jh܃d*,|d"a wK6Eh s8Ұm0m-םfZf!K%yqG"ۣO +-29sT#3(q[ Th(Hj/F~ˑ-\ϐdK5kBc:YBa &`(EH:{G|uwku9puCx`{^|h`_8Nb׈KHns'It-$3՗gv#>a@(b[6n$3vu/|/{x/K/7]DGytc̦A .D,OG`tb-aI[H3IW~wwAx=+%ܣ R+q_v5̅[(E$|yC;Et)o17ź?\&`LAB<5݉ndG}ez`!]c'v#\{^|ߓn*\t#e;;1( p\P? d#Drn#XO?wrwtk@iya^Z">HREx"5[ק@RC!JOq[k'.#zD$.X.Lԅ'!7= Jv Atdxd\Yz=E(]G^…uB ,|!R{^ WIDcѱMkϢ1D&-Ü'[[N]h $p/.@ K^CGʋݦXaG M,l\%B|"VZ*Ho;ku+dhMѶޑA4t~3G@_o-0۬귍Q MOLں:kū'$Fzqd>f{@B9=:o76Hh[U C4~u<& +9S3az{o{S3ʔhA!ʌڐ&+/w*{o9mAw^Έ- ^F;B{zoN捿_O&cȮs4(4ޮNG~YU') U3B^%DʋPAҞiד/0e*K{ݸk|zk2d˺xw/lS3N[Y|rWD3$G2vWw^[1a+Qㆋ\7F*S3^wHTXIX L:GIVj58EHpFrougɷ-xفQH]6Datz4EaB}W%dAYS}87/>wyea۞N=yrWaM4 +Bd4?釈}ς+Y<1Ş%_[ R~.Jk%"<1cTa#U>\#je=xD +)'H!r]{XwRmX˴\s)X1]@1W&alw_]ץѻGjPӋX:tNJ@H}9E{ + nܐP}{$n;"ގ_Ԋ@-/cE;iTt=U* }Iqw;^;VXHBΏ65)Q;>fkfELJg~O%ֿ%n3!.򱏠B:"}k"kE.FL (&(JEtMU^ԝ"\C⭓x%eWkS?d|/W_g9}v}=2rA9UzеjR G!XeC-HD +GxNOnM Evw)aI"iTC+"Gx~&%;4䬬3E| URH@ҽ\(A$Q'FzlWl$f0da&kZsd R#&~oP@]"i?jf'J%<꒽`W#oUOG+ЧskΔJ+0G!aX2j*m>~AQ/f{p ++j0 /}1x"Ǧd +eJɾ(@$WP" m:+QbKå#OGBA?V#X(`>h}Xc1\f*F<;t|ˑmʁ :omRbw e8ZhǠlʝ:nT%8"Vln(m8Tzgj ઴H- ` J fA^ \y,G;DJ{#Fr&#VDO%JoRVao՗_~7zpD_ +mRyt״%aj2SW!..jB#SS &mkkϵ}`Gx4i +s\ixԷj7_b5sbDC'NB^Y(~g[ϿdC_ 2,̀*Ca?}>0X@.Oӷo~w~a=㉷^O#?|gq WG( ~ѐ{ϯ_}vE#S0{ÃWSnyQO$X^1=/ kՅvx\޺ MpҞZK?0H0.:%,g\@0gAǐ&AobC|kf,ԟFo &!Q2X,N/GO$ P$oڙ-P8Gyy)<"I]0R.E_l!L>_ms}0bu q!8"W^L/N1*VILBs iД" t1`MH@cwls#%%kJb܆cs&Zvj72EI9pds 3 +a \3 $)$K$55=A3ۋT34p]uܫҵ3qyR0$F /N<)jjt,^bDiug @(K֮-k{HvT$S$ qTk Dg'iS=‚[!&S 4>lՊr!&`d&iQ -7}!I$@؞\^ j#.n[SB`dz")WQœL0\p TAKIbj(a$&X:/) +X#( u*"jx$G3\TzBB8Y:&9?`3Fk T|H}@9P, %$+ GBkV"ɡof {.%bM: F..oX ov?.FV⼺t,Xbgjntwт]4Ll {s ;!AG\U^^OI(Bw"FF ih v'_67 G))-֎|o&mxDsI  Kjt>V5 +N7FbU@S Z9*"`6ZRcJ '3ԪҳTzZ KT\;ULF X1!AgY#i3[ڒn0Ez!&<1ٞ!q*nT7DBCӆ"TYE#,#.A +7t%VX#k D-;Q**@f‡kk'*$+ ,QQr $x &+,iC)IU$t8jCUk,]I]>Nx2ul] ԹHD(  #$oc儠Kۡ ?"^ͭUIJŘɒ$ x1m"je!C1 /PXh0GsbW{xȭpfڭ QuFQJ`C0PPuaknƺ\$[/G3$$u$[X0$&-)R.8"Xan|~WuLe_e)FUi9P&jh)fKRҊx$8WU0} Sb;|tahDr@kCpc)^.퐦𖈌D>#F#V>x͟:d-*~ +uVnJ`R^F5 4f ^[|8.ÊVRrTpQ=Yl@GMgp!]%^|z φÓIjM$yDԟ8G'q]`PRtM E&J4F5s!>BMJSn ĭJ蹻8qݦ8QFPjEv? -xM4Lvdǽ68/RD$!%슢_$RNoB8+ k}`rVNK׷hc;`BP-NHm"nc MH(F&Bͤ +:Q>!rLU gK=\cy1mm +Mٸw}Wh531tI׸!vԥ*@|;=TiYkLFL\42>D݊sX)DEAXtwXaXfCG L2>IZ:d[ p Yd7?JO`v֎֜6 psaP w+o~X,EI0-l:k&~ HMmb3'ן$պz8f:2mdZNHGDRѸ8+rHu"_@!YPMq5`-&7"zLmdk8u$UDGU?'u(e2YzBR'O5S#aFA4*0sE+}95$,Ꞃ$dX- n8V@1P`8Qڥdo$b3X4~G=@z6`$-_zZ&MWJ'&)g?^-֓#iY<U&BO+uҮ$bPDYdFsھ@a>m?߿wN_ x $L ]qwZD}7Ѱg҈C5:+(HTMo$yRytfX"$j u"Kpt Z(OHO'hW|"$(N,OTmc$kM\A)+WY7}t("dے0[!jH$.>ȅ" +G,P \K]}p0Meԋ}F.TnSJ[.Hi&Kbs tBH+5 +([ Tf%iA|{;הOBEYVr"P&T{1B@</)i1f=cCZuMbZoZE&¨=!^)FM|qs2(e骆UOS$RuotI/VRЯj\簫nՐLgxDڬ՜_B20&Hu +\j%\T#Ѻ(A=]rMkfuP^2[b+6eOQ,%P"]AcCe;[$*PּDB>vF$0gggS E< >3=~!XcSi 8Bu}Q!RɺmZXnKS 4.wȰɚ1u\H!㡓p!uA"$ҿo  V#W +sAס%߾8J4R,0.YbN PUG0P ,Vs +IЄ>wwQ鹧r(f\6qAXVڇ~ۑv4T,M+qHj]A)E.v=z8UnlxⱿP'%"{-I F`R4Gt{ 3hH}eM'xV),K" (KxRPr>,JӅI3jz_ݐ@F!gZes3r!ӟB߉jZ\H ďkUi(d讄`y%lnZ&IU6*w@}> I dVOOO;A=D nM4?\:\V~YAꭼxrz6{ItXF#vx{j|>w8m :eDas "/1= 3l_xI(3>&븁Y_A I8H.źо4&O'e 7pXG/Rl9BAVbAqXo1KI'fyVЬ ݒ؍b_-}P|HXz=,p<5d` _ Ϊv'mGd{{g0/w\~|N_ΒzYlM1Y =-eu\B~N$GF>7P$>-QagE7ʈЛY<R?G Qdܦ}w n(g \!1mVi apD@.cBM7HQXR4%enZ=;lz~8wVy!L@YhVO7+W--ĞFg!ٌKy5B^odyc*%~ȴ~N݋H˟҉(ta~FZIYGiH?l#ч8'5 +b;%i-^$ˢc$N(ө,#2v"X`7 2ť-CHxa{Hc"!@ʻƽ=9Y91bE֙풛%@0Rzw;I~bީF"I4rTZSjD^AKf+drL:cRP'T*kK7!ut=n߽] +XxqHG^K@:r3Z~D˴~dsQ[̪ θRӝz.,ΗsV2;j/ۜv^ sy>[(0aTu*Ј*cD`P&PRX:HA$pY$ o:Z8T$,}SG1b a~USi7  +%C'@+{ " ALu\TJuhM *3E@bLO4@ +F]F-_j ԣJ+ea&Ghw^jP +%Yq~r#p4aFhRq,n'nFUS[͑Y&nhrgFc7_S4TG7;mByGKi} k6Qi^lt.q-oR5Y^;e%V_e볷xl",0ּ<Άrm)7>_gPI/:Df*/Qf ' : 1Nc:$wߴF2$s KZ(eK]=Oc>kF+Kc'"'RwщhU6S:BD<x3U&yv{uga~SCuqWaYx foiةP6 +M{ЇB%Fa`FS6~Ta*M|f w+:4v+.DT(S(8&q٢l?:n88t8SԸ\}31LZ(G96EN7,n`s +z5C8w4ۜ%NڻN]J*}\DsQ_#/Jp+#АߵD/$P:#X`Z/!ax36N9YaaH{tC߱Nu8$'e,kq;HJ6PiJ=%!P#Bfh\ژf̻(ZA)[f&H#^̍e֠z~P2= [()LFǎF'~̾{5)F==>X;q]l "#27}A0q,fy9n)h"2喖=nG(N C諵1-b'z;E -Y,<}['B e(2l?=BCE,AAH'i8P)Qe]J%Yšc6%Xnl}6<8#A;rb̓2S)jKx<&a&7 Jr5QoFMШ!UKPHbr&;3kIoa TNVe"kL׻7YNT2BZiC$>Qo{zzrCjW J8pZoh^/GnܒHѧVFƁ˂N]*܉z|Յk"XY#$͵dW=5\Ƀ$SnCr(Aڷ!SV&BHffD~yiI5< г]I )QN/0j`el*&+^3fp>/5Lg\it;Y.R])I-H(]>^I7FPP5pcZAV1I:8Z\`r\hdDA1uQ_Ү$wO{܎P2ŗ w5SGՓLJ5nJٓ +s^ӈLOXb'BXɹNBX>G#h + }4[Pj' !n/"~ KPfIc>ཅNx3;XLzR$QYN!Y d>Np)ՄJZÐwՀJڶFH,M0T$9JSiYoMĺ$nb&ċ ,E#tAJ099aۋ2+eZK{\Ђ+] +d}$ҫB8QEz +Hs3{DVru-3Rכ +CM b}9lO:H_*CBeGãǰP՞PD̝= ;]9DC~= +f6HHC`ifBK)C篯UbqVIae&NcHF&M|A",گ;E A>Y >U\WOO,9HAHZ05$h\b&Mwl[t@]j\PSϸ"I}<&v)5a88*~~S J8 [6oe77pKCOC~^I&Јզesyy  SAFVWzRSjyE@wV(N*9:Q >~*EK?> FD ))B"+9ИͨO^.I0IhrI=x^B]%i m׻QK?ÖC=IC)U:㘝'2@Q$SK2~ +;'2ݕ7RD'zKOo :QNɚ֥f:SÁsvďgVZ.y~G~ꗑr)>#K—()+DzC( M56J5X5jVZY)8[iD awNasBKDm! \>B=AQ/2Er;A9Ra%k,x魴iN"B@"n9XK<~#̞!c!ѱ}N֬uFىH_R zabc~ }w$BTݙ`Bp$"*!woDoUo,ݖE\AXe- La7N:의LOl^It S)ƅ[wXѻ.(\D]F;@E?  2Fkgv ^Pf<)DRhX9JNGѠ8LHVdDT']W=yh]d"¿j/eo6d):lxBpuG,U,Sp[J{JFe'N2#aJBYHN`Ps-[/=?Ph=JfqK$:u,%eGv?l1E>r}k8 鹝q= n* #MFbh AJ2AےC%Ks] ;~0 ?O7V3UoOF\IQh쓘oԎaЀyWt҉{n5KLi?cuŘ0*v%tլ0jb1Pxʫ6c i&D!"Ny)g3+DBbsz%i6/aD#rVE[hwbYޗH;iM$}ۓIYH=+' +Qz +MDSX;o.aT(NCp]},M;YNX' …tsm2+BÁb~d2i7=WzYuv,Q>yڙVcl :^%YDK`!lr+5IM5 &1 s0J ?H(Z{^PU;KRJaO#״qz4aTJw3DgXig$xLw(AH{%b=Bnlv&QD`4ե(N"_ϤsQ>8n.D$]Q`/_R6 +1p? {j1{܍ϞqfM¯{| +ƣ.<=~!ΒWT^bC`Bƀ\2܋$nL?"޺ͣ|T9*TUg=6LٺƛT +f`NDњi;iIHcU[3뢆;y y,K3r,q>cI雈*r83_"|7ZK>-<(KmxZy9Q&J_sjח+YtTJvg$:0Qn{>zo VI Z4|^щt+~P~P + + ++nW[#NoB3!&*kGEjeA u5})hQH x Y!YFRa!A: +*Bzh3a@. N_~DB0ۤ7܍:,n3t璊b[M@g+k%],I҉VYpq)G O[H@ߋS3D9%l0+1V$ByAIA,CP 21 N^ӣ_Ὤ={9ۯ(z3ݨ}]4z920@ÜtC#AQ[@/$1Nz,倈LmR7{b3ovD@9G[pбRt4ڡcb=}aJZMd<%ZXt\!3Iⷅy21jS`;Oz+/~?NhB+iJ]^H)CdO^ty\~ʎb= yƧKǑ6/4Nq`RX뎌0ELA՟H4@Dw\K`IC#&ZKf{܍yUz4E=~U@Q֘ A8!$,# cNZ_S6\] f'mYHA{pNRnq(/p,e/(tn' jOKq[eXqyn(o (#-\l~!,o$2q4 k5#: +>D4l`q4mDNh"_3>fJ!kכh`9ִ#SPyY0#Xυ)ߖ|ϭGI6K(0\cZ$[ѣUt  $XA,5n(P5?˛M_Õd\AG =(M1sD=nG(UYtٹnl8-,lB#P 4Jg;øJCqt4%,;22Y纩BGz^{̐.-"5GˍZA`}>tmufٰ2F<,C(/y*7K|aQ[ E8ڒS )y~Q}`hh\5ZP\Dom 蝄sM;%!֎\Nk],$Sn,/֟"DJXP *-&(>`HUMWbwtsvn|aJ/g{$ƥx:N9rB M4 +AD6^%Գg2+V\+҇8QѪ.>t .SKJ\qtxjjz*րuA֒MǝxބG7mK%!SC5$n ެf4iz%P>Tb)OZKzBtaU1?l%\L#ǵ :H| ʬu(fG|c,&8hlM4B9FkwJyڍW;'h^껫kWCT{ǩ^LϯG/Z~=398L!CgMh =%Ҏ2Ԉ7;)+Q5cs<+fHhxE(ZpcƋ5x«u$5ؙpZIMO>޵>`kP=Jk`$D2b_[XS51 -Jblg{40)"r֖|у.2`,jfp=8;q?:OÏD;hN*)%e9iH䁡uJw91 ΁EOb#ڮ'4<[MkUzK{OGH4fc|˞I8H*[y{Rۥkr +R/yô!!Bb Rߌxd RaNb3Ttl:A> YMv|WHL%[%L:4< +e^ҏrP +Z,-y;E}RZp `Νɪ{T$s6CW$y=Ip}mW~).҆Fۺ̍9c@ٌ1iy^X"R +3&;~st' ̠'&iL قz@[ R{:([1y@FI&Ȕ2_&Ips6IBbS+ܜCQs>N*pc]1ou^@yЁeꄬ>"ثN !a8"VJ{2lF,*)_$2WWq9)Q-9 &d#"q%:b.E,Ȩ [w.*W[?V\!f[\Ł۠88\k6}Y}~#wĚBWIK*On?zn[ K)#锗~4q +iS;k~'`˿׿OK ;f7Zz/NT/WfjѴ} +J_hbr +33u2<PB_~5G(ӂqo]9E[M6DrPcd 2cAW +N`B]#_mnNH(SptrCoO^~;͏6ڈUcGs4Cij^9&}>EL}_}OO]&gg.>s^=|/N(pB&W /.?[URRgí̡.+UYNM.lY +b̐\U+8*8DڍlsP@hQ:w# ʐ"qݒbMwr Ț m&G`H %DMJ5}絘тt6ziu9pju9`y|H2בQϤ]'}oRu9 %kU6zMn22m-(_-1rȀPE/o*\[5d}>"4c궝!jS! !(2:82~,۽pXsAE5j=|(j⽯~wK=oj}7&X;a], + $(L(enfQtG,_ N*;{/z_y)*:Z+ Za*/3,S;}vAFEsÂɚMc(om[[~PGH^C4w e)e˧;mq.\6cHݻǐZ hϝN҇+)oޫv}w$.^M\>JjY Ify0NB|5S.r!oaEq(#~j\&l!-1pŶ. Z Pd/u +k@AP5I2 ɢ}Z0{Vwz;C|HB7dv?(?Dq5˽ S=buނ Q--H**~gAKo/9^lځ-Ϡ]>\>o/8}q5΢{@ xTt+%2 8gq4`">(LUnt ti#XӿSpRݯR 0TSqվpBɛ(FF]AFfP)Zgz?Z+BG8Ds]:2[7CʷTzjY$[p>ꂬ):RX34U/ǣ#IP]cq|~ 1BV%yمd_ +(h(@Ri AM( ~^nhqg>} 6g3McnuoA!׾|+!ʴI +Qg=d) s'#I[rtV"h~Iю99d8o*QOBcZ4$t>5>2Z(}aDŽt>c<%攐XpdsQeXS?iPךhsǐ=s_zg7_蹳9^Aϻ={z.?+y:o:a$t + ^R9A*DS>P\=O u؁EMSX0rt^]?[r+4 sQX%'8s|4ѷi`ߩE5:5q3Ӱ_}A pNu%$8/kW-bR/fuR𖷷x=Ӕ?f_ÔC nS/DcЭמ.:e`<q3U* f8kyBsInA0I`/- &:-Ҥ/LS}M^R;C_5+P i [!5b<2i?S+D*-Dc1 + لK3$ɝ*۰Z WI=rV>~34ܡ"ju1!'vZq|THn$u%DwjSm_e1"҄v 'P3 7SVˣ1oX D50`D2˷{̽.yzKW.k+yE8_p6T0g^ro&B f,;rK]%'^ VN }9W-$!{tp<7z!SJr  yF>k\O~g_|ow{^ s~+y:o:B8تDpL|@`I(J!iTF EP‡%t^umҭi9_@iXmʼn^g\QTv3_y*]R\t_8t[K,пNtAiȖ NNS3P* fzEg9^N\諟qNB{?f򔗻퟊sg!q5ج"8t ~8#[ `ڏlG@,P7`)@/e+ aE/I#tw֟sg낝_|owvkrn7?_+ +A +h1$9SN#L2Xy”lA{J Roӽ[2͘Άov q N+5 +Hw^4ʒ`WbU޸,z$ܞiDQZTvk[ʺ7#htZ8zsL&Q/Mxh 0a'fV_y۵::ZY踕g#-$OԳ#51N{w+yX9_bcn&%[{ g+QGrp`Kf[oᇅK:Y) +yVEb1%9&й@/ qf" =sPm啗ɭYB_nv]mߐ9U|ӈ9^:Hi_f=B]4F9 I i'ؗvqu |ҙk=ӄ?^_KZ |\~o?O@ XDg(TY]h=LT!("N5M'3#1u:& +*zsVH@)H/ yF lt؆rűZC!_f=a/6HzkCUXf>)s3!T#:|@<%OTz}.~J)Gjg.o3.LS}M{ y!Ey{ +ss I91ż ~ Fy( ue( Bz92~NN2L" +Ul&}+'(d?~34!}1/O 9*Kky2y[\ݲ 9FBS?Is \EሣoJWk{Au?9ϟZ_xQֵ~`g3McnuQ{/K;^aλ9eyœWsdYL +Hࡌ_I)tICzt0D)7Fcr=kЛNMc9j9 s榐9ʹҝgzav;-OXCޮT aN]_p> + F)uϨӖ¦k!c1 c1jNcV/K.[/`xG-<Şgs t{I +t!%y>~E;h+Β]ՃY@Ya7=XBFv+4bJ֛,WnؙB1{"y~CD:]+ũuO^kPAs^L:77ETegAXɝ:ݘ!$JKh +t\y<`iZAKo'yh~_z/}P";aJ[Ԙ_˳Moa"%R %Puf-Şisu/M=^λ:%=`|u^۱&܇l`䢃ITP&=}3H[.yO99[ˆJ%?NT: Jv6#4h6.! ɎsMO: }:Fw64g{Jt3_-:3u3"CrQ1QC "#uݹ`[`/m!ΨkoCΟqg뢝_|gw v󳟼"W/?RBZ'T3\F93_USk-͉LZ~Cܲ_8UЉJn}ko輕Ϝ: ݥu]RI':CP- %RmW ֽ5cP))ֵuRs +HO/J)!\S:9uyY]i_^jƸ[WZoD]4 vЯ M2 +u蘍۷gqq)VzosB> u ]|Fڻlɭn~]2םR6zWp@o]\/^7pk +@Jֻ/g3cn5|zIKW4BWv.~7x&4`!$MN]Vfy@N~jBzzMG͋M'h_k|txu1"a,tGvYhr uN%1U2tAO4wSh ba6mi)ai"@&~+HXŎGG$Oq؅`2璋4lې\G:BRyέ?m$2K2 REڋȳ245#6OsR!h D,PяyJ5J#}R!w&QEa9MaP\EB57IO& fbnsNt"ZK?c˖?, ,BNsqlzPIVw'Ahʌ`qVLmywz3s-9*5J>Yy5fhmA/At¡1dg[S WNrj)0?&icJUOGQFoJrOdx;ɱXۃ{Qft&܆ya~@:>J'q4OpsDM~IDt #h)e` j /1`W@ʐRIW@)leݞf#ZP/x\s:Ĥݟe@18A KsXʗ;]W<̽e#b7go}2>)xrủ%RU Uk'NMY҉%/;OΙ6I_)t֊ ٔqr b!mdOlG Y‰/껏!f +fkF^0Qyn]:yWՠ|Ákm2mQkKy4i.o-k5`?]܉R\ +Tф :#+P[pvj1-h2Eh#-K< )z8❎3feT +xiPiQ!S>B +pC}- +>q}'o$(4ڐN#&&z&bjJ)Wx.},Ґl6 +zuj;S^MQ {)F- zXڇJw>!S J'BrG]#2˼&m:~{wgߝ7o>_o_ryD2#CwOގ{ ۘp;Uͦ5ZLD)'J&p%" XH 7ܺ; +Q\﷨$u(Cxe6 +FNO)V—2F 4 BN1 6 +[=pⶽ|T]49%#訠hsΔ6wG Box +:-YґeO4O^8T rJ'w bܻ4,G>E1w2cmG.vx~x씃_'-_ Z,ڮ5Z1B '%An 靪<}UTX剥KgGN) qk*Z{ɓf^,4Ɇu.9r{DeQ]}S +x-u>g^8ĂQ>C'++Jc4N^ JS&=A?L{œؕ8'9󡾹 8[/\f +,UGjv1 +%d0H5Ea(jGuP_ʒ +Me2T)csyn'zUd=]eڧ %^3Ew'hAVsn,>F;/,S}F߂Z)ZEc.>s^pV<eݿǿaF_}_|_~{^+DR'$!A3?SBx:{.B'yF(b2@U"8j-$JXFi#Zu" n a&זCRS 1#$4Cm ј>ڵA{jw~љKt6z?.HZ"݉+S"/AZT> iV +>VbMJ_4lU)@T-9Lu|xĪzi7UF3n6 -YX?r{8Uuؗ!$9j8i҈ArƦ@|r]r R!` g⮹Eq<yk3?OYJ>k{"aQx:MȜ 7H^G Gt:S,vgX? 2aT{ºѻ~ !˒?d2KKjfu@jmRgU"ЁY(]QaQHC'v2.j]˜IYNr[N. PncBDhϲNNKYwdžxd㕡Zլ'nY3J Yd]\oHȄ*_<ݭ{急*|{bCѺT f^Q ^V:9zCs(CX>{ SvYAJщM>xά#RrAEwC6EmNT8\!c2BtVtocFy8#~,g,]DJ  +(r~4L\?V֣J9])6[ N[ +.=obLs/ RW^v3fJ[͂o4q&хx!z#(ћ 5D9%tV.qR/"2699]s+kkD z=^A7h22]7>bI$N 2&}SWøg܌kp\jH}A}z+]ҐT>OC&tzz3䯫N.{ܪE}|fl+C (&ҰFU37[yL#w^Rt{[:gO vvfgrs?g2ij]edn>DfCtrdZNO(ңm!!D; 3"7ČkQM4@@1KC0OHgې\=?kt1Qz=~~_aDC"̴+yk-|vuQK7Ac cb7)#/. Cd:捼7}cnb@4d#*8H)*B]?(!c!:Ϡ +A[.'2_xK4Mʖ +}& /TK.\ tn>b(يOnףO z㉘Sr᲏'wiԩu%fC+\ZT +S9ߋB2#v#tAѵu4JT'2k4] |6!tMW!CB)y+$-xH#G|&bϨ/kj3sZS)OS3bx:ެ H7{k)(QF?4":SЊSsA&lϲ:|ٳT\u6j4""hyǡ`Z9nC944;Fy@YOPK_n!*#ܣ `NAbl{8$4S ܾC4kqώp 9vrg:[eg;ְX1/s=+U]XM_Ӟ $KuэauXkՒJZfRGhς'rZ^Ӄo +We0^&R+X_e&ɯx%h1׾=NN ѴzhWb3H $,&dg mv"(LqG ]+nG qB!w= 3-Apև~zJ3A'6ڠ@үϑ}Zҙqdم;K&F=cfA,yIv}U<"! Ow,f/G'ũ!BȶSdsu̝E*NT XlIs@H 8ͻ\|a˂i~Q;1p;8q 歹 CqG:*mX[Jڷu!0<+B@ {+Gԃx} + KOJD&S wN;{3kpF$tGgZmj +ͼwӭy9]?ӿDrх_`!g ٕ~*b;\.}.7?;?Ok:7 ./C,RV,>)^OT B߳A4&[`4B+Pd[:cSRX<9fD|đATZA@ GAti|Z ZV_GXqB2Ab҂5it\?OeA?1H%=2GRm>`Tg޵^noTO™\@*xXiÖ_bp%]54N9|btMLV $^\ @*oC;C$BdKكlRs+=J#(vK2'ߧ˜ʙIhѴO7]袀1!ˊ!>2PIF?NӗJU}S6י*kB@E=FP> !eh܌ $JTfSB:X|Cz#ZAL>٭B7q_cZ:N]x|7FuS+h>?T%D${eY"~lD&V0DY4U >aC(lv + '&w_(,f!+!vQn=_&j<1i5l6 HB/7 'SjlQ +!ğI?u589+'\E Ut Wi*7<@Y s i-c4ςփ5OB[ܮNnj4bb2Y7@a+s/ Ϧ?HAb +0=W'$po*A(,&ahV˱KL3w/*w:oa~zo~as {ͭo^dQ/YqK6%Η~?2[=T_~|bc_?/+1M?}?Ԭ}??}O?J%W0}Ç"..~X&YsFᣝqm`Zq3*Ns h1Hfwf=GкeMf :5{9d})辚A4J,F"ɇ] +[c;b.OaA_LoAQ4"@Ov`N{.޺>DߝAWj5d{,?Vrl+cZszQ26`2T"Ll\O5oZHީIrL h{$L ;K8= T8pX äؖ:t>!=,b!n-D}&.~n[Ѯ0N|g]+Ev"1Xqn;X\`kLT~+&V ThlNߒeax;C~57b^žridAP$q&0uq +r\' Sm$VG!D-\"4+*)98ns +!@gҜ>Y^G:G(hM?n{$p._DbwyB+t&yH42C~4Q^J,6P~ +gg{.1+ȃ[ls6A ^,DE CH'De q ]tF:ŬTV&\Q4PRh! ٳniH%A9LRMybNzus,KsHP0`@ȥn6Mqz^-oW/BK7o^dY{6/ZڷX^fyKN\wRZZGzr/5g^S#,o|qP,7ykR2CUְ>uSy>ϐ!:,5Zm8B39BӠ1wf8CpE&Z`i<+-»ŠFԩe)EGC5. + &drC }6rJX'!7-ЪcP6|jk,̫DF֊ ɰ t#)6AA!IvR;KO[v ?61iY. +qr$5%#]߂ G,ﭞ?A/8.8^hI-ۨX1wv {'}"[zR}#T k{*eyj #i 5V;`'bEeaw6D\̘\a(Iphlgi!Sl\OĪe78EӨ$*P^֦G&S@6A+J!4^V.%ܪ`P-32bӲ٘(dr*fkdjfM*dx)Mk)uʋRߘOHF.oXB>EHXYcz_)2hon`h !/F7n@ 3SD*7VLȄ k'LfH#3fR'\s4s!i##l[:CptiphΆ*4KV +6Z֮^S6ER,ʴؚp>ԞhPJnfCrdW?f(Vj10X$*V؏`weO:$22k3ZcHJ0AxndA]v[:}ozd 1L ZЌ]TmriP6+=A pMz-󍇁>)?LzrNI +IIhu-aϣcci+EZ\VϷ\w)4/ߡtR}o +{IiѨD!z | jnKXr7 }s4Hĕ5A<#H5.acìF-4`S{6hmWjMBΊx(N2rhס~8;1E1-{ 5jN1>ٲˈMTTRً%L($8'Ng~RhzdHqvН4oʃe;V6M/-*.AX/>, "w}̇^Ar >4n{M=tO^$p{w92\"\؍g{Nx܏`Ǹ^dèVo&n5Z&J4*!T$Ʊzdґ1;xäTH21DLL:\v h^F$ )lwO[-y݄#IG1Tۈ՝Ps81:o c2sHPv4O3Cq XoC6x0 +m7:F6 .zCI ZM&||{;'bD.sMXҵ64BC=ﭝoZ˘77}ni\ڳ҇N1ZZ;N6_MhdW,n>AaS":"qM_6xEgXE_3Zx wâp9\L@mjLhy87nysB%T1 k/ޝzvpQB^ r % 5.EX:b/?]M*U^Թ<2*M&.rhsz''!*($pQ݇+#fMހ# A!BL-wwK=ra/}K:Ȣɼc -lҎa/]7)7%NP3dLHo1E *Ag=ćfMI}'}.NEd?cPDF&a6* $g,,ѱiX+?rSi+jmGsb" vf+qߐN)(q/̏Y_ɑJ:)|  +LFh à-Wa@V-ϠGG{%!s0{ʬDS1m|#Ft 8>mI磴kefMɷZL>m'{LwlJ9:s״@no=kυ>R Va-?Bf=b=ǰZѾ5}:&޺Q/]۷a/]g/lε 'x݂]rs&B9M~9Vv \=z rmMQeȘA7m L՝\38=n ssP:鸝-(Eos BÔ'H"gkTNǐ*u3(OD˅CJ/A7~NPMTIu[ ,w"I*ۉB ̱N`6:d&ko.ԐFA 4HKQ! "GtQNT ,ovꍅx0R. aU2&2)XѵBm +ardI2XU`-o;{^\piCxhuZX TYxlimNܿY#'yu7G AFU`.q AU}ɔ:9J4oϠqLWsC )%V}BH9FX%Fc@cCE]pMjv= bkĠbՀŽf藯pxay5 bGox0K6hp6%c2w$$ΨE_ZhY4BCӌ-BG`}wo:,0QLv6>%\ qMmd"/2byA[v\tGɵFa zwB?bEB[8' S9oPk{!sSMsPfגSҹnoawڴ4ҭd$TD/ ZB?]4I'wy@}(M!{= 1DDcȝm2e^am/(qJ{'z^ů9: ֢'zϦ\LG"+lfs1lvt@A9i6'jgH{=tYc-hxt;οu'}RJ *H|9(ȟ0MByV@p! = +fP=B\%K69>Q0*ͽa/gy+'?HgfX# MJ !2K e#)SC'N3DNEv2&p$y$4̦c%hct9*DM}w|[; Ӡ [9jB@ +E)^')!nB*RXdNRQp+bFNMWM#FZQَr _l50ܖ<:ئzuLXZ +iPG*2ۀ3(N8ojW 0۬آNV&w7ܴþ`?+ȋ"ͤRX!&BE5>at́2CG,o@(M]! +C(y!VHp^+nX6N٠Z̈Ku5HڪF3uFDM4~B RNg|'ǥkQԧ +Ri)ePwDC &Wq9 WBd-X0 Q}{mCPê|v5Z0%\Td^(P< ̉xb&r44h7$w @&kmyL$NJ J2%~`pZ։xE{q um+ aޥ?ս1 w(bMXĊ3Z:}GNI킖b<%Is%#efB4Дv lFDT08'!yP s ++ t>xcK ĎF H}y8iBL؃ Tȗ\¢ .hB@!*04! :t#sϑz8A'BE) A|enGA6%gU,!cf)FHv;5 Yr +2k < *c]I t- λb2 0TVη\wl.CNQ>q8D-3 .)j QdYT&BRx83m3\G6k B(hwOCgV[KY>Fy/¥9 /AL qXx6}cQ ^VZ@#* +IFrqԅ{<+k,J,؇"] j<$- +-DGU!Wͪ?#8:;1}w2D9*4{;ABRH:7ݻ[c2;6$t/veʖi`o +0XP1,̠*>zH"ҺjOz"1ΈᅅlGm6Np˜,OM5(Z7 |} +%ʁ bKX jêێWDPQ"/d 'A$g*.Va OcMjB.?0~s]R#t-fQJs},+B;݆KH_b"Ksmr7 l+  lH]-I \)(i|l +^^C-._|j^hEǽ۰X1wu {{_۷a/]募9L}^ij(Y # cw\St쌳 )ȘI1Ar=;.DP> ⤞0,K+S9/Mctd,<[vϵNM|+%Ơ࿻Ty; PRKLy8{M7EN~U qeX mvĦw`\fZ#Bv J3ezkL cj!" ,kzƛ2H6Ki!$uȲ"k&|VQ|o dzCYE,2$ПFy#RfQ/fwm ,{:FȲpwa߆V{?ܘV@2xDS5<@X`"D 8l"أ& 1S qmST)r&LQќ"xW)T.qt!@(QݖSE;(:"xk*b`*DHR:nÕHFX827._4OtDuCE% + 8)mhQF4Ԕ(g^dx=r}3_/91dG9@F:pmjĿq:{f"KLڛyPWX1"a2ehz.E;9 Z14/&K]ʋ}M5Dˎ@@|c3´iR[BڍUmn:lAK46`u#u[3 .bY#*j9F7jxnnwMW09KΣ[K +\һ"-*upR4\{84Mvsֻg&1mڢ8Lv1w\tlM< C7|;CfZ'< Y*axLihpoʈq6\:|4-20s^ێG,ox1&F5$"iBw SCB+u=lUR.uKy:-vsTX-b9y_Ld%aY@Y=(%2^/3]wGZ’AZI#D i0+TUf2x~pw1KdRH|x]PcP2 t#kg kf{+g!i 2[Im%9YƌB Rͨd&Q]g ӵg2ꂏ"hIu>5:ö|yq'ZOjZq+6EtLU^d]GDʾ {iXJ'f&XVrsNE+I{\;.!€.C#}fMДK Pvkcr%JZ\R]Vf088 /em MIsI*+ rH +!y#V-͎Ljwc\0!7mA5({ nz;=C'jvz M(% ^Zy +VQʕY🅅UcQGm:< 1 L(A,XH́׶o6a~s`GPf[9/z[q]1eVuw=ǨY1wt {Uu^bekw!gy 3'm;ҟ#]lSg%>Əw7<}@,pMJ7&MUh4Y3){#932@s~^>x=Mgr5͍Ca n}N0.V\A/5qe=Rx?)nuNCtUru\]yh3 &TQDuTq;~𗕴\4`Oױ@2:m_cZ, 1Hk@[G۬^@NG"1Ȉ%k rk8S<1G4]$\VO< 95)yLRd.CpwC]jY r?w1S[[ t4]y:^ 5{o!k徠ebү̲ש!o 2h O0!)Z;OuJ JCZT4kQ0bܹe5oL}hǧ#f.Е\C%mop`7(7n{ݛ^u߄~1NY0X WD) z-orعn9$d)`ؼ6E*f! >q#RR(!ϣ+(DT v aqN}P2pL[j$W9oOdWK ^tqr .v(Jmx\ْLdqPzE l 2\L&/2Q]rRfpg9dfHu)LVְ\T*w;f#\@l ߎLliY:uEOsPs\+mX4;*vm. +B{d+rьB' F4mBy룟P5GcpPcQ$JCנ< 霍!1M fdr lOΖ)AS#U 1dR͔{Bu1!v?/H[lu>}l4z,meU _Y݅%hX 4 1kUSxi +פPTuP9փt s{L1}t6f9C +zSB6mR|P.-8Һ v @ׁ߈tv:5t2iu?k[8'NG0B 4{ xH&RHhJƲT1rk(f̞{VD1Q;heZ\(UOEI +D#/o]7u!#h%W֕d/cвB+=B#95L!RjA՚5A$;[o5xVL-! X1vG@jªk-g11͊dH0Yܪa 8UZ )C*O$؛vyćz% !DHKRS΂Hw=W +<&OpkpvhR^ґwUΐ!RHОjd$t AN,P;21kЭTTأZ0~L(`yDsFN68!)كiĢɴU\G_z6VN=X!7{%^*xM@s,Z϶mlGɼW~g[>$J~ +T=v z Ǚ 3l$tPbӔ|BA>U()ac:G]Xi9O]^0Α5;=X#C:EsLn4}"|PܡZ8K{1v4" e3䈃 bV0vj 'Bn3zT~#n/N϶"Re^W7s:uud'Z/1(S TBO:ul QtCTmwve c2D{yJ6vF(Er<&Jvkxoa@쒷"[:#{01Uy,V q9]X_Ѳbc(k˷X}3BDuڛ܊>VݟGs fwpʐQ쾙J#>- +peEvPfqu_Oo$ +ϣHdpysԉw392?x|;+a~?O]& */.ӯX^[NEE, Lb]k3>QPyO*cYȆvK.Ez +7:{kdրElR TLD#CA(o_LeJ>fgmnS0ENk28X 85-ZTRWCe®"x^or [+0[S/GO_%gx!ϵéF -[爥HNZd4˕TMrHQs-7XPq*93'Ff9bhЍ߆]_guVqP?YdnϷzE`+KtB7Z "Z=9 QiC HsCb!h(\^`ROq1F ߖP0c̓G෩ăO6M3j~Ol,;<C ZϳU q(AY3ߒn|8+e'{  "b!K&yO# w t=5x%:3ȠBh{i&TgHA:b7s M$Nz*jS[Kg]Ⱥ|dղ vTjk5aȄ. v={xD1NF\4t?,hP߹Vrhn}dv(wY/:{9+  jĨsxh[hn7P"sd)@I}HdDiJ %;e_^k ~MnBݏ&CTiAvbZPIMnTH)-sxk,qt>O;+ Mȍrg +F~`;_ +Vh%/#Rt mʁ-C2o#W%b\&D*'|t)Av155zڝ0{n0۽Lw@> 6[8ǀ.B2@I`٦ T|LZZ\Bhf3bfV#Z,2 AL ]FH)* !w.ɹ-` [+D.A1> bUXI;a`߃32q;902mIl8({Z@Xom,PjkMR`" j4{ }% N)y8  Bap+k.5qfdT挐6SeX[j Zcyζ%vs=%yQ`ǘCˑf`żs~B m B4ctk9'^[bJ)l X# рz JX^5# Z۝0}nڟ]@\o_\Ģ+7/^>={wp׬_]gOko˿?OX4|36_aoegƟ(ȁ$|a_9 z·?}?{}?~⛋ IՇ٨or R2hd4)0Wd35e?3ZL9ɜJbP3he%xŊd1 +w(zj'qBIhS0DJ== +]So0[4#r$ ڼ +Tew|~;(mE8R*F ՈiQm wme +Y x 5?H+a0dx$ B pI}DڑB ߖG%;c,2%PR&Y}mZ!ؖ5Ya :ּmRr%ފ +V>4VŦXm"=%HE IJ +dMb|w'L{ ɢֆ&?ݚg2[ZMY\sx1TW0!-56e-k qS3ʠՁ!CPӽ2@e_׶ӯ,*" *Lf +=K0l]wahHѱC2цO_fH Hs+qHsVC\cdEFF-ށ3sc.HAA<sv;mGs)%uS6#g*fe!,P01agu>6yn0dG-v'ؘ< !*B;ӌYIq +)!K29m$9}XITUUɜ絬Hc-Za RJJZ̉b&u9BJo6'g,N”voU00CmQ%f-p065K9PteU():?M:Jة#tի]S\оnQQ +gas#7J4*aGSi>19䯮EI{=O]RWs$#(ZN;(^ܨ +_e,/;cKaTsy Ir@g|4enߋwE˺z `P3.oXhyw|td{}C#rc4.kqkVC@P@\c!'} t퍽)qI @M=@p[ +U4|2ҥ k0ޗ I4`]]y"5ԽCK7V"e1#R,Ҍ*92{ZaWńܤYvʒ3i#Ek.&F(AwyBڹs`TkVrx꾱6E =7X?s8{tޡ@Ga.7`߬$ نDzAS02bg vl<ҧEz) ɢ3b3QzYiBBYK=(JŽq9@9q_`L_7rw>hӎvgΊBqLώ +Ѫr5ŧ[ˡx4?FZ;<$UH +(cU9Ihxg/c&X.e(#C({55bpu[W(RjQ:?M',cY%þ9d/]7F؀IfL6R>zrCmm 3>.Qi6 5X8YAgU-fMu{DaiZAD+cl jmh ra3{99#Ȗt4VsdZf^ RЛ97"{/К@Qce!S#J=a8=g\p g`'f4p+YbEwo֢3,to*[#['kge[%ԩN [d6ըet鑱Le&j)W(.⬤c؈%IgKΐ:hj; +4dEݪBW|af "!٠p]5ɚDiS tM @H9i1T)e0#PK@q;[@}dnaTWB*!TR׋) cS<(i'F\N:%ETt3kMHZxPG5C {x2d4%E8G$߾ԛs,Z#Ꝟ̀Hrvc} Fl9G.guYV;8xՔ B#1OP(/wD9qgg&\潛Hw,yF +e2kψ_¡Y)=4wy+neޔ3F64Un ݈C2 dN9̶hh)Zv@'L#D GB6saKX$$@gqcF4/fQi769ŀuI  +-&$hN};\ &Ut>4en$5i 6(DLNL'׍Ӆ. C3t*kx$FޡVLׂEwD]Mq1B i(H2g7a50!#c vaDkw;" q%xy,_"N{s9\>'W7)a¨ItU錄&%J5<& +.&aAМS:BƖF!21$r3]ĭyBN4dI]]\e[6FQF*w!zM+;t5#C b@cþp(AsG+^{ad18 ހbx38 &0LTs]dhrka\Q!$j>(țli$YxzJm("c[ t\ ($MPZoHPk sg[)fD).-DsgNh",Y"4 )# + W#3BZ0cT>݄xZx7qzEԅA%͢,<2峱MQݦA&GrAxl:Ε/T&iu S Oc2M)&ȾI,nՀ?q rJ>"7uw tMAYok ;ɰnKd^zSn7xnH e'H.}C#{m}ѾkhGw {r p +oV8":}kBh<ȯ%NHoSض 9Z`M t@u\w[ٛB/MJh[v:z16u4C"&*938JZ6܄dRaUlkab`*}O/F.zvmƌCH &>輟GF&qh'Y5:Jtc1U)LVkUE7-~ wH$FGFQ .$wL9'Sɒދ 3Rdޝ0{n0[Z -Lß!fD0,svS KD6XH0VkT)AI61D1R#;m_C+C1qaZ#ɐ|mY=eKnD?ԽGHђ$쥻\>YV[(}2cJ&鳽O-RYe ڕ,Z~;z%Fp ˛Iը x*|>F@CN(ػ&sU-mt=+jIBx4D,"Ud~a`rcS UN9VotmBLe-uv8ݨ}+t{~\rF@hysJ*TZ /nQ\$(TV݈}aj^ЋF[#튠 ,7\z}Υ sgg^HY`As#UuA%'g+QyHjm M>0D6P+ľ9ohmBن,}W#~6!i8AoZyi@iԍ'%A`wDc$Rܭ*6)Uj`Y,qLKZ12Dm]SlFպ5jܫZ 7:t)ܤuJnN3 _~UЩj< 2QzE UƑJoD^Kނay:]31俑6hL䔲 !λ;>wn0kGv#|TlWr)AE~#㟣5ߜV(R5>y`6r̮2H3m2!ȢI#?ndMX:V>F(d R:8ʼLUfmz1a +Lū)4$ `NaMAx˦ހŐMYPh*t@Ă!Xd 9WuۚnAK3@PIndt +٥⢻s'-r-M(oi@Z%c fb$1vL-E&!91x=2R[tT>ـ܂V[st5=ێvX4MC +Mͧ]UDBct#B _#Ԫ73bP9,W8ӚIzV*R,>d !ယWY.~1 n#޵= +%T %n]AJV$ s :P_i%74YH&J@AF +t +h;@ Ҧ&y[W.yW,U(փɻ& tKuL[IKuR): AD[,bn)mCx\N "ְnnij5H4y,_d i/nAcz4K*~VZnAul@$6T n28l&f(8GKjS;ςQAŶhQ3Ʌ # +e= ҁZZ*7_0f8@UʀG˨|Gx&wDQZn@1E_3Vsƈ7t +cZM~G˄$5+f[;N5dUCT/] $ey֩Xk"g`3 +bLoZY2@5= fJOѯ0ek.LLM! +.BBQ{]I>o:1 M!@b\E16[̴M2m攡U+1(ac>Rf 9.XX0.MĦQ^&`@̭~It>m:H>܄4pVvd(֠ ?`ܙ2h ԖnHtm!6lrrrɬֳO.VgSKe.Uw{?ݝaslc쟾nJ'dV)2b ]g+uϾ)Z%FJ$uw\ g,w*K`1Z9VZVndIy%vxֹCH p>TpV_A`F: Dm=80[:=d"k[<,o 2]'eI,W5G f H3X}qt@  +0-ZB,d4)o=Ci1nH-ǂWkX[>8< 捷kDX@YGI4d&0Ihׇ21lPKs*|Z Kg@ 2A=#@aR5DOt`DE9c {m:zK(;?}oa;+]Ӈ fS.~İQiy`tՀ_3qVfn2~Gpv޷crT˶v |4J)/ؗ› s.Me2)qq;`/0$ ,dQ@Yvƅ)Z$RFٵ~g߾z~#zL'j6`:SD M]5xf4):8,{/x<ռ/m<~o^=}}CoϏ>L/ۋ?_ 5)O|?$M|z]ҤW,E~'Zf JjF8(TXXvzt44HE3 8\c/0[+"Fh䪨!v6P0tһ +/:Y:uB0rMRxL "Do*nyɡ<>ېZ9 #+ L؂zbDlh(WQv,G:`5,吀B[k[QόFA  RlQ<|gLxlB: 2t_ߨ耮$ _2@)ô`"`-ʾ!Z ĝ|*4k'f)pCZIBS>R \O Wpv0Mg>i6tK8PBk`p+۴Χ= +;`~$_=⧻G_\Gtw<^{jCSBo+)4b:g甆a+Qh"[`aTl{:YiD`EW#E׉-׶A" .wBHW@╤Ϩe|GK9͖ +XFjIGitoݢpQޠ='[bW.2L5DmHab6 N ><(q2ՍA3gMZkE|E$3X=0)ԭK)@,8 +jCQ4g}'? RofUm@bhʆŜ$"wDDk{V`k3kνJ0r+`B{:gvC|#3/}ȵ޺t[GMD230G_nF[6FZ9?zߥsQ@7 }araU- g:͓{O6zŰ@V=0aU-^Orb j0n`<tum @)zΗ\(8@D7϶*Dth x'y2(=ކm N.-N>AV_;=tѮYOUܺ5́sӪ-۾U^u"DAazN+r׺>V7az} endstream endobj 795 0 obj <>stream +#KüO]t~{t[>.%u`u:# h( Y1ÍA5YMeS[yGGj[}/Ik1WVVK0#[9yw\*k|w 5o鸄|ˋ&󕜂L : ?J!5Y8t\p+9.ݴF#Ma?`)V-JgkPUހthm5fOM[l8;.q9lˌ<{.炂$sa)&XSGH#DdV_c˦P( +|bSa54YK@?I/#t~K_MYqf-ʭY8ޚs1] 0)o1H]F;I8#Qi=V0ɹL"zr۷׸Z p5Vq#u7}­n[qi3F_-7p~o{Uj%i|JoA-%ꜩRL4G +eRO佋?ᔔii*<0WNlш#Jh'w3{qܾ;CŤcrx;.o0S豢E!J5ao)h*O~yhN8Aq< o3"C5bUv/ueKAs g($&]_n[m5dmyn{U>._Tӄq'˨ U+nBm ,et*qlU"SmX0YAoXbI>HdCWɑDK6"'`bGt1i@/8TyH" P) 8&){[J]4=R-ǭ,|+3#]#: ek26݌ !@s-ݕt,K?{.z{ԹUei&TdLy2_mZ .8 +2ڇO,$υ^ GAu r Xd<:g n!G=boπQl,)s.-Ĺ@kQ)0A,ՇJ#3c62 +x,Vx.7 spT:v\nVWz]7gST+D\ˏ݌ >@q\ާrpeWQ>{1@98:[hGQEɍjj8\^ 6wuHhK@$yU . Z8mz2U|wci^`cϨ&ʭܘ:S׈0WI(WalV< +9F[%2/;.uC7Owv?_~O>>1IcԖ 6.6)4U^MSo +quD:b[1@:Hv$}V]/#t^k`۬`%`Н{#No22@$b:r[z<5TnTx <(؟p+ u. #BcQnL\w-V٤0yf#u7}­n|cKǼO? ؍ݗ|p~v]>*ץ=\ ,IHH uihMbZ3Fڑڗ\RfFK~gʣ:⌴VDTXuǞ}4qsX4r1 [{QEe#`4_}%FOU4YW)rIx?)q}[l,6Zcu7}­n|cK컼Gߥѻlߞy&'S}TO| +7 Fo" ںQR3.ufC+tCEݍvx8Hﺠ. Vݶ?.o&4Ie*4OPhkuT6E\xSb 7Jh;QyB7MuO ?VMҷ}+9&`ųmQhF6\#-pkXp-C[g}-gn_~~v[>*}g%VY~KcHqH%O6j3RMf=%Fs˘:#m>ZH,3ݿDkP o;tq-`W[e+E/$t֖=-BMQks ?N%=8Vr]U, +i:CI[\w-͏PU?P4khp:/`8;/y9vcۜ?v_^xه|x` +#r|:qF[bX8qOpy("hStPӍmt]3ݻ'RBڜ@G2$BI6 !?΃T c>%hw0<Z.^ooR)o]b_m6K@G#9_/"7<~DHpg_E6#QmI+$}&t.2KU/ueki4{ '/sdOM}{la鴜1qiQ֌0JesZ@-$mIyfFN0S+d/!@إs/.JGɩ_=SA6Xg%xZ)|knCmf|1٦[8ZuP+F%\`SJ'b(g }|F L#ޟYאָq+۽ҕ\Jq==i"'G5j/u}n|#+쬼GgAq~<='gcXk{6fE9#UA O1Ldn*ݩh#Pޣ6hmI~,؊8,e衸Wg?SWG +oL+Ac8%/-Mk2X~P{\g=:> GW PrB; L}F?؅ +Hv 3BoW]:Ԑll:v@I 'lsDQ'yH +{ :)?ƣM2bDS#њ+ +TйzCGd%]fΪ΃1 ؂"bB5(ƅv&s*9CpcUcȩtCƎSג _k(ZqkJ.;QpX;nVx|}4X 7Ƙ>6ʚ~tq;ui-N2VT-^twtlhM̀L+LP6Pd(<[{ԝn) ?Vef6u3`E~K B('n>YOZ{ i?bYlS:"82ُ Su_c9L@>ӂ(ˑ~'XhM1&kRZ<~M~6 +8; +UPN +Ts؜{( (BiW}J1dr&r.3v:! {F" "5<90>Z&+z$9nlTB;2$>m׵͹JTy|_ﴂӮIvdiпkXp#\sxjPx&w AK q=4 Mn ٭wCX[CXAZwF{C֫۞sN< C;e5bFT3IlL4cxjv{[rY`1Ā=t<^uR荓 KGw|4 y>h*2@ re޹ED, <-IMbF)c"1Va_T>lC(7ػPNf:?3VЃlJn* Oa}J +,VMEU +Zdʬo"!F,0;_t?(\L4(EcezBUz S,n]1{-Chzg-ZCRHpD˚hZۑx^)-FșB۝~W/J`HYo, +Lmm칦0ײ5Pz7gkJ)#D3{գ+ +L;[` D!ut%BfF|5NU}+65i9AD1О #iT{9`G9j*J]8u7Fܪ6}((:`=~&!vMv+}QS'^2<~-MCSQ#$z٭~W׺>VHÍTo .H"ѷȝW*W ЯxMh"g'+Ԧ`KHo᎐3q쵄rR@NL*$T3:?NJTfuIH$;sƠn*v3H9ݤVcOP$ͤ / y̜'ģ\evF\}'ֹ'p6үc*)uH9x~@1@!YY'' hP uLl<'~1͒MKPL/F=Fo  L[D)r+ԮhZ{$D`gd I[},(`ȌLY),4xe([9(4 +cp_gߪcydK +ъ'YeI*|b!@sl~B^6/*@)G'ԗDpANˤvKaD<}(vNUirٌ!;ƒ-YDGKMTM0djYP7v82QtaT pExպ ٛ>Ifl!~J.L\*QLZ%D=Qv=)I#Qw۷jQ]%3,(iHU,&Rd#ys8h2 4-恼طαsle;lOh|vv.qMA6 +a[&|Elm<ߴB+ɰzyڕK(&E m44QjnHLBQ]:ٴU9(Cٞ"~E͸㇃$ͦڬpXg#iI(7*A^oVET:N6thQ1Gޞ*e7'(=M;NfVa//+V/_߶h/~ogO@b\\ MoAX~~%mJh&G++5]Q6c腬SFr{":fҨ L^"m&e4嚆MjoD S2/܀rMx ⳡtFKDo$j0+T{#PDQUj[:N7JZxwV=T«䑙qnwlL5,VM A(2_ɎfN +{-+2F@˙IZtIp$:]Zl6a,Om9}a u)i!+Z>:u2:~9e`,wh|ȡ#dR +^h9ҬֲY'!83pmJͺbFQ2JdTXjc8ʑ~K>Շ +0ӣi$GA2Dmړ"ing=kh?ymG]ғ6^D rʱ1M.rp@[_i*Dp$6*3aү?qVͶuqK]YN>eLCnh95 :cc>TlL{Gg]RI\]tGO~_J~Z鮶Do^OOY~OYqOT9OK<`@7ZxvG_ ^vʜix(YV +c3@i]8X+J=]=zI4e-Q+a@kR2 :,hGғ9UVFuN-0T.:"cؗ\ɤe]Y2Bt#<%Bl%D$V,YADw(iycI{JG߈ sw.7"m=}%8LL'W!lAr\F^^Al-_~B-6) G&y?ܤ"ƟasIOC橃4Nr,[eM} +{4 tF,F}К1TQV Zu@NF?c0қ:ˠ^YBU (Ӏ +_]c 8A.ATh݄({NPh4A5.0~PAAHID7X΀|ZR젙H*iiY&^f]nuYsd)|O^^?6"t?Y6=/6mw[)$_-„[7&6LΫQi$ͱMH’WaVnЮI(N9}-}rF 7Q*yƵ& +}bWЈYr[qӲ̇1䁎bC)! M!,!&dB&)fE`AM!gX+q+?#7QmǦN ,N|s53(: 5lp#x FgK>-|ΖFaNI?(:l ZTy{b E-쎤l/BAAm׮pAft&e0 -{'nPF Z0bN,㶗gXk3(ƟiM$ЄےvBۨt֌)<ԩm4 Zxqm:hѕᴺjcs7/g"d ?v?Oa3/Ia4\enIOMOna7`8 rO2uZ0 +(lcUISg4)L0WxJn"3噣sFGK:-|@Wa/W!(R^XZh+C3um}< em::-D;!c$}L֩_ȨCZ[<7 +"X8'5aE + MO^=v٣S7h j^;LAO8#M^ 7)ktҼ|`EFCQO+%! !tZ }0,LZ(ltG>:1bU7hۛX5b15O@e 돜` S89sh9w9Z^ P[>ӰoY ِoȭpLi^;iny&@E +X—+$ؐߙ]}S{HE(=ҜNb>Bdhrv):(yXG^㓣(5өлp ߴG?~P,mnڋ:58:;LNF3Ji@Zw/̨ꆀ=Dۡ@@  $5U]ܟt@'L^ա1Y1H)`Rr_F~uZ\ +XOL29ƘpiLh{LR 4{ +A2ddM׉(aQG.Z+|"4F 1BRځK)T>tPS7GѴ Ēz Ec l +8  3ea6T q=Fbj$ fl!B>|$DF FVSfؽOךf/4 N6Uۇmg4@qF|~q]C]M'Y'6})9Ac 4it +`tݮiYQcT9 ]dXG:|,Tю4U?(lȔ',#hFyu86dSlkC,x,^4xpʚR-,NǍ_b[fDdۆ +߸OGeoaH`i,M4i!;RC#SVXP TU^'+dEsøuP +׬5q> ,dF|5mwXL`3IhrQicN.cnscJ'`i +H[Ď-NO6;hYL+Vjiԗ P* mNk\FNZwƋ WWnZSDLLx7LkD +`3o%8nsL'NNM-eA='^.džz_70ۧxwV]J? {4lp~IFsO>ŋGi4ɐ?jh$%N7Z^mB.˥n,jGBQ'}dӲ iIfVgXYф{52[ˋW/|O_\{//Hoi~c_ɢ[K[G Ny߿_{coŷyFO_jA*=uSCo1_|߭߶P(7t=e˯nx-2h8(~EKsbWϿֲNZ)\_r.`$$wtHOP=}/W`{W_}P!^['AFg*R C զ rcҴr5<㶂,HFU+Έ|"JxPCȑ)ă|N^EùY&|0LF;P124xO޲B%W Bh:eg6TnfHXiy=M NyA$AC) ?q{^oDWVn!UHwӊA[Y!Ӻ? ֋E9+FH(GuE^ ?PqrN`/-;,D1x42ej?(M"3F.PaȱbdA>*cw!=aܪ@]Ď]@h%&;NbJ`V0 g8^&a VPZF?t0g=xonF)t@6( 6@NRD(p15^:Y`'U$3I̽DoNn\ T=Ot{}Jffg)ZE$6̧@?${yl Ѷm*F +eOV+bq`$Gj8ȔVj*yBE`!`w->qzkwpMAsi[ԬP2rpMNf6IM=`GSA 7S3}vۑ g:a潾=$B_۞b8 3fxD@rT,ʺ&*Nk4k #R!#ϩi,e+B >BA3)R+SEqX +3wΙ5f5*Q{ 4k<8Mv#M]Q]W0O4K碹 FY· c0 +HCj A}acZ'D5j"%'6h(Ś-s)0x0.d4D |-Hcaȶ=ix2iԻ#j i`WJ_`l序1^i+z(wh\&kڸ Ez\mva|{ w ԘPjm1`،f+V@yN@y| ѠT +{|ڭ1<9h]j[Ƀly p x[*M`z3;/F,KOcX&`h֠4B_:3cWH\.5 x~^~7p2]({  M{92q@< B͘eoUٹ(؋u|h[:lXkss\J@ROdtm'klZTbJW6Wz PT0e&z[X?y y|rfDwt7Cgm젤!΃}p8`N >PEx1L'B_{X'WX p B$W.;OF6 ?ED( o k*[jZ _״AE@/F\o^K>=i@9`+`^2Vn)Rh8'cg3l +w3R~W \T|1fg3iX3BEAx;40 YLOИ9 +pf=ف0D!:Q!@|mEjQ:24emHÀO'#r]_כ-#uH# +Iqlv Wb?moz<Ӝw;0ko1=6 dٳ{;T(E0B|Z0gcўjpLH<q,@a +"Yd(3baBxqp'&C@8`)Z&c(m +|#ƬRLE: |&EyUUoFTvmmfV +y %ag0@ZΊp06Ɇfc`!^$|>OÇ~=~W=˗zu߾}oW6_׿?w߽ endstream endobj 745 0 obj [/ICCBased 762 0 R] endobj 7 0 obj <> endobj 8 0 obj <> endobj 9 0 obj <> endobj 10 0 obj <> endobj 11 0 obj <> endobj 12 0 obj <> endobj 99 0 obj <> endobj 100 0 obj <> endobj 101 0 obj <> endobj 102 0 obj <> endobj 103 0 obj <> endobj 104 0 obj <> endobj 192 0 obj <> endobj 193 0 obj <> endobj 194 0 obj <> endobj 195 0 obj <> endobj 190 0 obj <> endobj 191 0 obj <> endobj 277 0 obj <> endobj 278 0 obj <> endobj 279 0 obj <> endobj 280 0 obj <> endobj 281 0 obj <> endobj 282 0 obj <> endobj 365 0 obj <> endobj 364 0 obj <> endobj 366 0 obj <> endobj 367 0 obj <> endobj 368 0 obj <> endobj 369 0 obj <> endobj 451 0 obj <> endobj 452 0 obj <> endobj 453 0 obj <> endobj 454 0 obj <> endobj 455 0 obj <> endobj 456 0 obj <> endobj 538 0 obj <> endobj 539 0 obj <> endobj 540 0 obj <> endobj 541 0 obj <> endobj 542 0 obj <> endobj 543 0 obj <> endobj 625 0 obj <> endobj 626 0 obj <> endobj 627 0 obj <> endobj 628 0 obj <> endobj 629 0 obj <> endobj 630 0 obj <> endobj 695 0 obj [/View/Design] endobj 696 0 obj <>>> endobj 693 0 obj [/View/Design] endobj 694 0 obj <>>> endobj 691 0 obj [/View/Design] endobj 692 0 obj <>>> endobj 689 0 obj [/View/Design] endobj 690 0 obj <>>> endobj 687 0 obj [/View/Design] endobj 688 0 obj <>>> endobj 685 0 obj [/View/Design] endobj 686 0 obj <>>> endobj 608 0 obj [/View/Design] endobj 609 0 obj <>>> endobj 606 0 obj [/View/Design] endobj 607 0 obj <>>> endobj 604 0 obj [/View/Design] endobj 605 0 obj <>>> endobj 602 0 obj [/View/Design] endobj 603 0 obj <>>> endobj 600 0 obj [/View/Design] endobj 601 0 obj <>>> endobj 598 0 obj [/View/Design] endobj 599 0 obj <>>> endobj 521 0 obj [/View/Design] endobj 522 0 obj <>>> endobj 519 0 obj [/View/Design] endobj 520 0 obj <>>> endobj 517 0 obj [/View/Design] endobj 518 0 obj <>>> endobj 515 0 obj [/View/Design] endobj 516 0 obj <>>> endobj 513 0 obj [/View/Design] endobj 514 0 obj <>>> endobj 511 0 obj [/View/Design] endobj 512 0 obj <>>> endobj 434 0 obj [/View/Design] endobj 435 0 obj <>>> endobj 432 0 obj [/View/Design] endobj 433 0 obj <>>> endobj 430 0 obj [/View/Design] endobj 431 0 obj <>>> endobj 428 0 obj [/View/Design] endobj 429 0 obj <>>> endobj 426 0 obj [/View/Design] endobj 427 0 obj <>>> endobj 424 0 obj [/View/Design] endobj 425 0 obj <>>> endobj 347 0 obj [/View/Design] endobj 348 0 obj <>>> endobj 345 0 obj [/View/Design] endobj 346 0 obj <>>> endobj 343 0 obj [/View/Design] endobj 344 0 obj <>>> endobj 341 0 obj [/View/Design] endobj 342 0 obj <>>> endobj 339 0 obj [/View/Design] endobj 340 0 obj <>>> endobj 337 0 obj [/View/Design] endobj 338 0 obj <>>> endobj 260 0 obj [/View/Design] endobj 261 0 obj <>>> endobj 258 0 obj [/View/Design] endobj 259 0 obj <>>> endobj 256 0 obj [/View/Design] endobj 257 0 obj <>>> endobj 254 0 obj [/View/Design] endobj 255 0 obj <>>> endobj 252 0 obj [/View/Design] endobj 253 0 obj <>>> endobj 250 0 obj [/View/Design] endobj 251 0 obj <>>> endobj 173 0 obj [/View/Design] endobj 174 0 obj <>>> endobj 171 0 obj [/View/Design] endobj 172 0 obj <>>> endobj 169 0 obj [/View/Design] endobj 170 0 obj <>>> endobj 167 0 obj [/View/Design] endobj 168 0 obj <>>> endobj 165 0 obj [/View/Design] endobj 166 0 obj <>>> endobj 163 0 obj [/View/Design] endobj 164 0 obj <>>> endobj 82 0 obj [/View/Design] endobj 83 0 obj <>>> endobj 80 0 obj [/View/Design] endobj 81 0 obj <>>> endobj 78 0 obj [/View/Design] endobj 79 0 obj <>>> endobj 76 0 obj [/View/Design] endobj 77 0 obj <>>> endobj 74 0 obj [/View/Design] endobj 75 0 obj <>>> endobj 72 0 obj [/View/Design] endobj 73 0 obj <>>> endobj 718 0 obj [717 0 R 716 0 R 715 0 R 714 0 R 713 0 R 712 0 R] endobj 796 0 obj <> endobj xref 0 797 0000000004 65535 f +0000000016 00000 n +0000000983 00000 n +0000083393 00000 n +0000000005 00000 f +0000000006 00000 f +0000000013 00000 f +0000591190 00000 n +0000591270 00000 n +0000591346 00000 n +0000591421 00000 n +0000591495 00000 n +0000591571 00000 n +0000000015 00000 f +0000083445 00000 n +0000000016 00000 f +0000000017 00000 f +0000000018 00000 f +0000000019 00000 f +0000000020 00000 f +0000000021 00000 f +0000000022 00000 f +0000000023 00000 f +0000000024 00000 f +0000000025 00000 f +0000000026 00000 f +0000000027 00000 f +0000000028 00000 f +0000000029 00000 f +0000000030 00000 f +0000000031 00000 f +0000000032 00000 f +0000000033 00000 f +0000000034 00000 f +0000000035 00000 f +0000000036 00000 f +0000000037 00000 f +0000000038 00000 f +0000000039 00000 f +0000000040 00000 f +0000000041 00000 f +0000000042 00000 f +0000000043 00000 f +0000000044 00000 f +0000000045 00000 f +0000000046 00000 f +0000000047 00000 f +0000000048 00000 f +0000000049 00000 f +0000000050 00000 f +0000000051 00000 f +0000000052 00000 f +0000000053 00000 f +0000000054 00000 f +0000000055 00000 f +0000000056 00000 f +0000000057 00000 f +0000000058 00000 f +0000000059 00000 f +0000000060 00000 f +0000000061 00000 f +0000000062 00000 f +0000000063 00000 f +0000000064 00000 f +0000000065 00000 f +0000000066 00000 f +0000000067 00000 f +0000000068 00000 f +0000000069 00000 f +0000000070 00000 f +0000000071 00000 f +0000000084 00000 f +0000600536 00000 n +0000600567 00000 n +0000600420 00000 n +0000600451 00000 n +0000600304 00000 n +0000600335 00000 n +0000600188 00000 n +0000600219 00000 n +0000600072 00000 n +0000600103 00000 n +0000599956 00000 n +0000599987 00000 n +0000000085 00000 f +0000000086 00000 f +0000000087 00000 f +0000000088 00000 f +0000000089 00000 f +0000000090 00000 f +0000000091 00000 f +0000000092 00000 f +0000000093 00000 f +0000000094 00000 f +0000000095 00000 f +0000000096 00000 f +0000000097 00000 f +0000000098 00000 f +0000000105 00000 f +0000591648 00000 n +0000591731 00000 n +0000591811 00000 n +0000591890 00000 n +0000591967 00000 n +0000592046 00000 n +0000000106 00000 f +0000000107 00000 f +0000000108 00000 f +0000000109 00000 f +0000000110 00000 f +0000000111 00000 f +0000000112 00000 f +0000000113 00000 f +0000000114 00000 f +0000000115 00000 f +0000000116 00000 f +0000000117 00000 f +0000000118 00000 f +0000000119 00000 f +0000000120 00000 f +0000000121 00000 f +0000000122 00000 f +0000000123 00000 f +0000000124 00000 f +0000000125 00000 f +0000000126 00000 f +0000000127 00000 f +0000000128 00000 f +0000000129 00000 f +0000000130 00000 f +0000000131 00000 f +0000000132 00000 f +0000000133 00000 f +0000000134 00000 f +0000000135 00000 f +0000000136 00000 f +0000000137 00000 f +0000000138 00000 f +0000000139 00000 f +0000000140 00000 f +0000000141 00000 f +0000000142 00000 f +0000000143 00000 f +0000000144 00000 f +0000000145 00000 f +0000000146 00000 f +0000000147 00000 f +0000000148 00000 f +0000000149 00000 f +0000000150 00000 f +0000000151 00000 f +0000000152 00000 f +0000000153 00000 f +0000000154 00000 f +0000000155 00000 f +0000000156 00000 f +0000000157 00000 f +0000000158 00000 f +0000000159 00000 f +0000000160 00000 f +0000000161 00000 f +0000000162 00000 f +0000000175 00000 f +0000599838 00000 n +0000599870 00000 n +0000599720 00000 n +0000599752 00000 n +0000599602 00000 n +0000599634 00000 n +0000599484 00000 n +0000599516 00000 n +0000599366 00000 n +0000599398 00000 n +0000599248 00000 n +0000599280 00000 n +0000000176 00000 f +0000000177 00000 f +0000000178 00000 f +0000000179 00000 f +0000000180 00000 f +0000000181 00000 f +0000000182 00000 f +0000000183 00000 f +0000000184 00000 f +0000000185 00000 f +0000000186 00000 f +0000000187 00000 f +0000000188 00000 f +0000000189 00000 f +0000000196 00000 f +0000592446 00000 n +0000592525 00000 n +0000592126 00000 n +0000592210 00000 n +0000592290 00000 n +0000592369 00000 n +0000000197 00000 f +0000000198 00000 f +0000000199 00000 f +0000000200 00000 f +0000000201 00000 f +0000000202 00000 f +0000000203 00000 f +0000000204 00000 f +0000000205 00000 f +0000000206 00000 f +0000000207 00000 f +0000000208 00000 f +0000000209 00000 f +0000000210 00000 f +0000000211 00000 f +0000000212 00000 f +0000000213 00000 f +0000000214 00000 f +0000000215 00000 f +0000000216 00000 f +0000000217 00000 f +0000000218 00000 f +0000000219 00000 f +0000000220 00000 f +0000000221 00000 f +0000000222 00000 f +0000000223 00000 f +0000000224 00000 f +0000000225 00000 f +0000000226 00000 f +0000000227 00000 f +0000000228 00000 f +0000000229 00000 f +0000000230 00000 f +0000000231 00000 f +0000000232 00000 f +0000000233 00000 f +0000000234 00000 f +0000000235 00000 f +0000000236 00000 f +0000000237 00000 f +0000000238 00000 f +0000000239 00000 f +0000000240 00000 f +0000000241 00000 f +0000000242 00000 f +0000000243 00000 f +0000000244 00000 f +0000000245 00000 f +0000000246 00000 f +0000000247 00000 f +0000000248 00000 f +0000000249 00000 f +0000000262 00000 f +0000599130 00000 n +0000599162 00000 n +0000599012 00000 n +0000599044 00000 n +0000598894 00000 n +0000598926 00000 n +0000598776 00000 n +0000598808 00000 n +0000598658 00000 n +0000598690 00000 n +0000598540 00000 n +0000598572 00000 n +0000000263 00000 f +0000000264 00000 f +0000000265 00000 f +0000000266 00000 f +0000000267 00000 f +0000000268 00000 f +0000000269 00000 f +0000000270 00000 f +0000000271 00000 f +0000000272 00000 f +0000000273 00000 f +0000000274 00000 f +0000000275 00000 f +0000000276 00000 f +0000000283 00000 f +0000592605 00000 n +0000592689 00000 n +0000592769 00000 n +0000592848 00000 n +0000592925 00000 n +0000593004 00000 n +0000000284 00000 f +0000000285 00000 f +0000000286 00000 f +0000000287 00000 f +0000000288 00000 f +0000000289 00000 f +0000000290 00000 f +0000000291 00000 f +0000000292 00000 f +0000000293 00000 f +0000000294 00000 f +0000000295 00000 f +0000000296 00000 f +0000000297 00000 f +0000000298 00000 f +0000000299 00000 f +0000000300 00000 f +0000000301 00000 f +0000000302 00000 f +0000000303 00000 f +0000000304 00000 f +0000000305 00000 f +0000000306 00000 f +0000000307 00000 f +0000000308 00000 f +0000000309 00000 f +0000000310 00000 f +0000000311 00000 f +0000000312 00000 f +0000000313 00000 f +0000000314 00000 f +0000000315 00000 f +0000000316 00000 f +0000000317 00000 f +0000000318 00000 f +0000000319 00000 f +0000000320 00000 f +0000000321 00000 f +0000000322 00000 f +0000000323 00000 f +0000000324 00000 f +0000000325 00000 f +0000000326 00000 f +0000000327 00000 f +0000000328 00000 f +0000000329 00000 f +0000000330 00000 f +0000000331 00000 f +0000000332 00000 f +0000000333 00000 f +0000000334 00000 f +0000000335 00000 f +0000000336 00000 f +0000000349 00000 f +0000598422 00000 n +0000598454 00000 n +0000598304 00000 n +0000598336 00000 n +0000598186 00000 n +0000598218 00000 n +0000598068 00000 n +0000598100 00000 n +0000597950 00000 n +0000597982 00000 n +0000597832 00000 n +0000597864 00000 n +0000000350 00000 f +0000000351 00000 f +0000000352 00000 f +0000000353 00000 f +0000000354 00000 f +0000000355 00000 f +0000000356 00000 f +0000000357 00000 f +0000000358 00000 f +0000000359 00000 f +0000000360 00000 f +0000000361 00000 f +0000000362 00000 f +0000000363 00000 f +0000000370 00000 f +0000593168 00000 n +0000593084 00000 n +0000593248 00000 n +0000593327 00000 n +0000593404 00000 n +0000593483 00000 n +0000000371 00000 f +0000000372 00000 f +0000000373 00000 f +0000000374 00000 f +0000000375 00000 f +0000000376 00000 f +0000000377 00000 f +0000000378 00000 f +0000000379 00000 f +0000000380 00000 f +0000000381 00000 f +0000000382 00000 f +0000000383 00000 f +0000000384 00000 f +0000000385 00000 f +0000000386 00000 f +0000000387 00000 f +0000000388 00000 f +0000000389 00000 f +0000000390 00000 f +0000000391 00000 f +0000000392 00000 f +0000000393 00000 f +0000000394 00000 f +0000000395 00000 f +0000000396 00000 f +0000000397 00000 f +0000000398 00000 f +0000000399 00000 f +0000000400 00000 f +0000000401 00000 f +0000000402 00000 f +0000000403 00000 f +0000000404 00000 f +0000000405 00000 f +0000000406 00000 f +0000000407 00000 f +0000000408 00000 f +0000000409 00000 f +0000000410 00000 f +0000000411 00000 f +0000000412 00000 f +0000000413 00000 f +0000000414 00000 f +0000000415 00000 f +0000000416 00000 f +0000000417 00000 f +0000000418 00000 f +0000000419 00000 f +0000000420 00000 f +0000000421 00000 f +0000000422 00000 f +0000000423 00000 f +0000000436 00000 f +0000597714 00000 n +0000597746 00000 n +0000597596 00000 n +0000597628 00000 n +0000597478 00000 n +0000597510 00000 n +0000597360 00000 n +0000597392 00000 n +0000597242 00000 n +0000597274 00000 n +0000597124 00000 n +0000597156 00000 n +0000000437 00000 f +0000000438 00000 f +0000000439 00000 f +0000000440 00000 f +0000000441 00000 f +0000000442 00000 f +0000000443 00000 f +0000000444 00000 f +0000000445 00000 f +0000000446 00000 f +0000000447 00000 f +0000000448 00000 f +0000000449 00000 f +0000000450 00000 f +0000000457 00000 f +0000593563 00000 n +0000593647 00000 n +0000593727 00000 n +0000593806 00000 n +0000593883 00000 n +0000593962 00000 n +0000000458 00000 f +0000000459 00000 f +0000000460 00000 f +0000000461 00000 f +0000000462 00000 f +0000000463 00000 f +0000000464 00000 f +0000000465 00000 f +0000000466 00000 f +0000000467 00000 f +0000000468 00000 f +0000000469 00000 f +0000000470 00000 f +0000000471 00000 f +0000000472 00000 f +0000000473 00000 f +0000000474 00000 f +0000000475 00000 f +0000000476 00000 f +0000000477 00000 f +0000000478 00000 f +0000000479 00000 f +0000000480 00000 f +0000000481 00000 f +0000000482 00000 f +0000000483 00000 f +0000000484 00000 f +0000000485 00000 f +0000000486 00000 f +0000000487 00000 f +0000000488 00000 f +0000000489 00000 f +0000000490 00000 f +0000000491 00000 f +0000000492 00000 f +0000000493 00000 f +0000000494 00000 f +0000000495 00000 f +0000000496 00000 f +0000000497 00000 f +0000000498 00000 f +0000000499 00000 f +0000000500 00000 f +0000000501 00000 f +0000000502 00000 f +0000000503 00000 f +0000000504 00000 f +0000000505 00000 f +0000000506 00000 f +0000000507 00000 f +0000000508 00000 f +0000000509 00000 f +0000000510 00000 f +0000000523 00000 f +0000597006 00000 n +0000597038 00000 n +0000596888 00000 n +0000596920 00000 n +0000596770 00000 n +0000596802 00000 n +0000596652 00000 n +0000596684 00000 n +0000596534 00000 n +0000596566 00000 n +0000596416 00000 n +0000596448 00000 n +0000000524 00000 f +0000000525 00000 f +0000000526 00000 f +0000000527 00000 f +0000000528 00000 f +0000000529 00000 f +0000000530 00000 f +0000000531 00000 f +0000000532 00000 f +0000000533 00000 f +0000000534 00000 f +0000000535 00000 f +0000000536 00000 f +0000000537 00000 f +0000000544 00000 f +0000594042 00000 n +0000594126 00000 n +0000594206 00000 n +0000594285 00000 n +0000594362 00000 n +0000594441 00000 n +0000000545 00000 f +0000000546 00000 f +0000000547 00000 f +0000000548 00000 f +0000000549 00000 f +0000000550 00000 f +0000000551 00000 f +0000000552 00000 f +0000000553 00000 f +0000000554 00000 f +0000000555 00000 f +0000000556 00000 f +0000000557 00000 f +0000000558 00000 f +0000000559 00000 f +0000000560 00000 f +0000000561 00000 f +0000000562 00000 f +0000000563 00000 f +0000000564 00000 f +0000000565 00000 f +0000000566 00000 f +0000000567 00000 f +0000000568 00000 f +0000000569 00000 f +0000000570 00000 f +0000000571 00000 f +0000000572 00000 f +0000000573 00000 f +0000000574 00000 f +0000000575 00000 f +0000000576 00000 f +0000000577 00000 f +0000000578 00000 f +0000000579 00000 f +0000000580 00000 f +0000000581 00000 f +0000000582 00000 f +0000000583 00000 f +0000000584 00000 f +0000000585 00000 f +0000000586 00000 f +0000000587 00000 f +0000000588 00000 f +0000000589 00000 f +0000000590 00000 f +0000000591 00000 f +0000000592 00000 f +0000000593 00000 f +0000000594 00000 f +0000000595 00000 f +0000000596 00000 f +0000000597 00000 f +0000000610 00000 f +0000596298 00000 n +0000596330 00000 n +0000596180 00000 n +0000596212 00000 n +0000596062 00000 n +0000596094 00000 n +0000595944 00000 n +0000595976 00000 n +0000595826 00000 n +0000595858 00000 n +0000595708 00000 n +0000595740 00000 n +0000000611 00000 f +0000000612 00000 f +0000000613 00000 f +0000000614 00000 f +0000000615 00000 f +0000000616 00000 f +0000000617 00000 f +0000000618 00000 f +0000000619 00000 f +0000000620 00000 f +0000000621 00000 f +0000000622 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000594521 00000 n +0000594605 00000 n +0000594685 00000 n +0000594764 00000 n +0000594841 00000 n +0000594920 00000 n +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000595590 00000 n +0000595622 00000 n +0000595472 00000 n +0000595504 00000 n +0000595354 00000 n +0000595386 00000 n +0000595236 00000 n +0000595268 00000 n +0000595118 00000 n +0000595150 00000 n +0000595000 00000 n +0000595032 00000 n +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000145828 00000 n +0000150900 00000 n +0000149591 00000 n +0000149675 00000 n +0000149755 00000 n +0000149834 00000 n +0000149911 00000 n +0000149990 00000 n +0000600652 00000 n +0000084230 00000 n +0000103222 00000 n +0000164980 00000 n +0000142823 00000 n +0000164952 00000 n +0000142709 00000 n +0000164704 00000 n +0000164828 00000 n +0000150778 00000 n +0000148614 00000 n +0000148760 00000 n +0000105352 00000 n +0000136269 00000 n +0000136635 00000 n +0000137151 00000 n +0000137665 00000 n +0000138180 00000 n +0000138695 00000 n +0000139064 00000 n +0000139680 00000 n +0000140075 00000 n +0000140588 00000 n +0000141102 00000 n +0000141615 00000 n +0000142129 00000 n +0000103286 00000 n +0000591153 00000 n +0000104788 00000 n +0000104838 00000 n +0000148550 00000 n +0000148487 00000 n +0000148423 00000 n +0000148359 00000 n +0000148295 00000 n +0000148231 00000 n +0000148168 00000 n +0000148104 00000 n +0000145765 00000 n +0000145701 00000 n +0000145637 00000 n +0000145573 00000 n +0000145509 00000 n +0000142645 00000 n +0000142860 00000 n +0000146181 00000 n +0000146270 00000 n +0000146572 00000 n +0000149375 00000 n +0000148906 00000 n +0000149042 00000 n +0000149163 00000 n +0000149274 00000 n +0000149472 00000 n +0000150660 00000 n +0000150692 00000 n +0000150542 00000 n +0000150574 00000 n +0000150424 00000 n +0000150456 00000 n +0000150306 00000 n +0000150338 00000 n +0000150188 00000 n +0000150220 00000 n +0000150070 00000 n +0000150102 00000 n +0000151148 00000 n +0000151400 00000 n +0000165056 00000 n +0000165372 00000 n +0000171582 00000 n +0000183362 00000 n +0000248951 00000 n +0000314540 00000 n +0000380129 00000 n +0000445718 00000 n +0000511307 00000 n +0000576896 00000 n +0000600719 00000 n +trailer <<8F30BB726D3E47EBA5037CB50EFF5B6C>]>> startxref 600929 %%EOF \ No newline at end of file diff --git a/resources/herobanner/Microbit_Hero_Illustration_08_revised.ai b/resources/herobanner/Microbit_Hero_Illustration_08_revised.ai new file mode 100644 index 00000000..cbed0b0f --- /dev/null +++ b/resources/herobanner/Microbit_Hero_Illustration_08_revised.ai @@ -0,0 +1,7012 @@ +%PDF-1.5 % +1 0 obj <>/OCGs[7 0 R 8 0 R 9 0 R 10 0 R 11 0 R 12 0 R 99 0 R 100 0 R 101 0 R 102 0 R 103 0 R 104 0 R 192 0 R 193 0 R 194 0 R 195 0 R 190 0 R 191 0 R 277 0 R 278 0 R 279 0 R 280 0 R 281 0 R 282 0 R 365 0 R 364 0 R 366 0 R 367 0 R 368 0 R 369 0 R 451 0 R 452 0 R 453 0 R 454 0 R 455 0 R 456 0 R 538 0 R 539 0 R 540 0 R 541 0 R 542 0 R 543 0 R 625 0 R 626 0 R 627 0 R 628 0 R 629 0 R 630 0 R 712 0 R 713 0 R 714 0 R 715 0 R 716 0 R 717 0 R 799 0 R 800 0 R 801 0 R 802 0 R 803 0 R 804 0 R 886 0 R 887 0 R 888 0 R 889 0 R 890 0 R 891 0 R]>>/Pages 3 0 R/Type/Catalog>> endobj 2 0 obj <>stream + + + + + application/pdf + + + Web + + + Adobe Illustrator CC 22.0 (Macintosh) + 2018-10-25T11:19:39-07:00 + 2018-11-08T16:48:35-08:00 + 2018-11-08T16:48:35-08:00 + + + + 256 + 108 + JPEG + /9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgAbAEAAwER AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE 1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp 0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo +DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A9U4q7FXYq7FUHcf3zfR+ rFV+mkm13Nf3kv4SNiqJxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2Kux V2KuxV2KsP8AOvnW90C+tra3gilWeMyFpOVa8iKChGTAFOt1utlikAANwxwfm3qxp/odtv8A6/8A zVjQcP8AlafcHf8AK29W2/0S23NP2/8AmrGgv8rT7g4fm3q5A/0S23NP2/8AmrGgv8rT7gyrSPM8 N7pljeXpSC4v3eOKJQxBZJDGAOvgOuY+bPDHICRoy2Du9EJ58XGBy5/b+pj+rfmJqOkalc6dDbwS RwysFd+fL4zz3oR/NmQAHWartCWPIYgDb9SE/wCVt6v/AMslt1p/uz/mrDQcf+Vp9wbX82NadgqW duzFuCqBITU7AU5YKCR2rPuCrefmf5jsbo215p0EEtA3BuYYBhUVHLbGgyn2nkgalEBQ/wCVu6v6 hVrO3A6A/H/zVjQYfytO+Qa/5W7rAkKmzt6ePx/81YaC/wArzvkHf8rd1gSFTZ21PH4/+asFBf5X nfIOP5u6wJCps7anj8f/ADVjQX+V53yDj+busCTibO24+Px/81Y0F/leV8g5vzd1hZOJs7bj4/vP +asaCf5XlfIOP5u6wJOJs7bj4/vP+asaC/yvK/pDm/N3WFehs7bj4/vP+asaC/yvL+aHN+busK9D Z23Hx/ef81Y0F/leX80Ob83dZV6fU7bj4/vP+asaC/yvL+aF7fmzrIQsLS2Ph/ef81Y0EntaX80L Yvzb1h9vqlsG8P3n/NWNBR2tI/whp/zc1pHANnbU8aSf81Y0FPa8h/CF5/NjWeBYWlsdqjaT/mrG gn+VpfzQsi/NzWX2NpbBvlJ/zVjQQO15H+EOk/NzWkcD6nbUpU7Sf81Y0FPa8h/Cv/5WxrPHkLS2 O1ekn/NWNBP8rH+asi/NzWX2NpbBvlJ/zVjQQO1yf4XS/m3raMB9TtiD12k/5qxoKe1yP4V4/NjW StRaW1PlJ/zVjQZfysf5qyP83NaY0NpbA9tpP+asaDEdrn+b9rpfza1tKUs7Y167Sf8ANWNBJ7XI /h+1k/kjzle+YLi5juIYo1hRXUx8gak0IPItgIc3R6vxr2qmOfm0aazY70rAevf4zhHJ1/av94Pc wRT9n4h37fhhdW4H7PxDqR0/DFXBth8Q606fgcVeleWdU0Gz8v6DDqbJ9ZuppY9P5xNITL9YIHEh W4GrLuaZVPDGZsgHh+x6/sfFllpyYXwgHi3raz82HecT/wA7Nf8AxAfvR/xEdcsDznaH99L4fcGN arqP1G1MoHJixSM0qocg8Q+4+EnMnTYPFmI2A4gb0T8zbfRNHlntrfn5mnLIss6j0LWOnVAKl3b3 NPxrtZdlxMu6A+Z/Q5mnzDELAuff0ASrSvONzqF8wvpDdzTMWluKVbk3iF2p9GR1ehxcPFA0R0/H VxshkTcurIEf96UpWp+HNFKQiLPJhAGUuECyWMnzXrEnmKTSrTSTLbwTqlxemQcREaEsuyrXiagc sjjyCYscnY5dCMUf3kql3ebJRKFkKt9mux8MsdZe7vVCyFW+z2OKb3d6oWQqfs9j4YovdCX8q/Wo opLs2UDCRmnCGTdY6ovFd/iai+1a5sezsMZmVx4qr73qPZnR4888nHDjoCh7zuh9ObTbi9uIr3zE 1haxzBILhraSUyRUc+pwRqr9lBx/yvY5tMmkgAKxgn3+78fB67J2LpogGOCJNcr937fkhb64WFeV rrQuj6IkYenJGfULlTEK1qQlHrsO3XJR0eM84V8ft5s4diaU88MRv3/bz+Ctol9cSTyLM5dONd96 GuYHammhjETEU817VdnYNPCBxxEbJtN2jDuaNTptmneLIt3psiMC3wnFNU0Lc7EN8jijhTGy8uaz qh5Wls8i9PUpxSv+uxC/jgtvx6bJk+kJl/yr/wAzxoeUSBTtvLGNz/ssBmBzcgdmZu5Y/wCXvmSM BnjjQVoCZYxv9LYbUdl5jyCI1v8AL7UtL0OXWL66iWG3iWSaNFkdxUgUoqmpq3bG2WTsyYjxEhgo 8w6LEpMt2IYz1edHhQf7OQKv44bcQYJphCkcsaSwyq8bgMjruCD3BGLTwL3jLMoLfFT78VIbSJkr 8W3cYpApYsHIAhtsUcK+RC3FWbfeh8cUkM9/KKIpqGob1rCn/EsEuTuOyBXF8P0rfzaNNZsdwKwH r3+M4jk19q/3g9zBFY/D8Q6nC6twJ+H4h1I/sxVwJoPiHWn9mKvQtE13y1puh+WrfVwrXeoXMkGl lojKRObgqKNQ8PiZd8lDFKVkdOb1PZk5DAKJHO/mWLecif8AE1/uB+9H/ER1yAdF2h/fS+H3BIri JZ4JIXIKSVQ1FeoOSjIg2HDt5Nq/kbzNcXaxxQmURAxtKWAViHYggse4OZ2rkMvDISHLr7y7fSaz Hjib72Ufl95W1fQLi4l1JY0inUIlG5fHUdM1ufPGERCMhKZmNhfLkfdzv4N2Th1AM+GXBGJ9XLfp 775fFmjP+w32XYhjT9kU+H6a5j5Y+JkET9MRZ/R9xcPTZPBxSyD65Hhj5bXI/aB8XLIFkKEfDXb2 zLddxb7tiUCQq3SuxxW93eqFkKt9nsfDFb3WCaQ3Yt44Xmd/sJGOTfQBuemZun0M8sDMEenvUHel FtH1bWb+G2s7GWZ42LmHialVID8tqKKim+bbT6LwISlOYjxCvc7fsntKen8SMIkyyRoEbcPmhbrT Vsrwi4sRDIVVxBJVlCuoZSF2G4Ncy8einOFeKSPIfpRm9oNbwDHKchXwl8+bcC2jTBXtYODeEa7b Zia/Ryw4uMZJk33uJHtfVE/3uT/Ty/WjY47a3lb0okRWpUooH6s5+eWUvqJPva8+sy5f7ycp13kn 725TSWqnwpkHGPNeZQ8TdmA3GKbsMx8n+VK6c+tahA1xCoL2liOslP2m/wAnwHf9cJyoO10OjuPH IWOgZle6vpsejQy38n6O9RQwh6OKfshR28Mw8+Dx8fDZjbvcWqjiAnKh70h1Xzp5R1O1+qTm6aNG D8o1UElQR+0ffwyWp0Uc0BCV0GnB25jwz4onf3IbzF5r8l6/aQ2l8LxYoZluEMSop5qrKK1LbUc5 mRsLpO34YJGUeZFbhNvMPnXytqPlu5tGd5PXhH7kFVYmoIFTyoQR4ZAxvYtGXXQ4CYy3r4vML6xS 24PZzM8U0Xqwh9gy1KlWUluLBkYbH36ZA4yN4/Lp+x135qMyI5aMZfxAASHnt9VdQbvpXNjx017Y m/0PjbXDfHLaH4bec91kQbI5/wB+KOQPXkNstjISFhxcl45nHk3rr+kd46+5M7XUYdQtYrqEMnKq vG+zxyIeLo4FaMrAg5Jx8seE0jI5eQoftfrxQCoxyFD7dxixBpUnYMEIO2+KZM+/KCQvf6gD1EKb /wCywS5O57IP1fD9LX5tf8dmx6f3B2P+ucRya+1f7we5gg/Z3G5P04XVuB+zuOpxVwOw3HX/ADGK vQtD13QNN0Py3b6nH6lzqFzJBpzekJOMpuCoNT9jdl3yzHhnMSMeURu9Bo88YYoA/wAV/exbzl/y k1/uP70df9UdcqDq+0P76Xw+4JMT7j7VP17HC4bizBfh48mYgMRULTxHc77ZiZjOcuCJoVZP6nYa UY4QOWY4t6jHz6k+QsKYZVd2cGSQVo53Y+wr0/VluLBDGPSGrPrcmc1M+nu/hHw/BYV5p/M/T9Bu oLK5ZTNMS8oiXk0MVCQTWtSxAUD6dsxoTnKRkPIfK/1vean2f0GmEMWSU5HcmiOoHl/RFC/eWGQ/ mf55164k/QskFlbRMikzRiZy8jMFFEjkNKd+NBSpIzIOQx5uth2Hhzy/dR4Yjbck7n3D9FMWvPzW /MUTPDLq9GjZlb0orbjUGhoyJRh4GuWCThHs7FEkcPLzv9L0D8lvOuu6zd6hYavdfW1ijWaGSQD1 FJbiwqKVXphBdb2lp4QAMRT0i81G6026F7ayvBNEp9OWJijio4mjChGzZ0nYvDLHOMhYsbOo4pCQ MTRZJpmi6tr3k698zzaxIfqyzD6q5aRmCMJWUuXHHm/xUod8zJ6zHizRxDH9Vb/Z3OZHTTyY5ZDP l/agfy80DTvND3w1G8Ni1qqGIVWrg1qfjpslB08cnrtfPCAYxuyw0ukhkJEpVSQ2aX8d4r3Ns8dq WZYrgqwR6Aj4XPwt9GQ7UycWCY7q+8OMIcNFNTIqyEEDiaUOcim92jIqykEDiaYovdH6VYC/1K1t BsJ5FRiOyk/EfuxbsOPjmI95erXdzf6W11cyekuj28A+rQqPjDKAAO2TPh+GKvjekJlAkmvDAeS6 rq1zf373F23Nn3Ff2R4DKwHnNRqJZJ3JDSvEiFiVWoPEmg7ZIAnk1V3NQSxyrUUJ9qUOAhARVpZt cTsWKxWkShrm4YfDGtfxY9FUdcWcIWfLqv1G6guGQW6FLaCP0rcNQtxBLVYjuzMWPzxTkkDy5BLL Jl5zRkCofko9mAJ/4auVY9jIef3/ALbcrVS44Y59eGj/AJpI/wBzwoCKll5kuoVAEF/Cl0E2/voz 6UrfSnpfd75a40zcAe7b8fanI4FagD54tanE6tsQOX68UAulYIV2FN6jFSaZ/wDlKVN/flehiT/i WCXJ3PZP8Xw/Sp/m1/x2bHp/cHY/65xHJq7V/vB7mCKT8O6mtfpwurcK/Dup3P04q4E0G69f8xir 0/ypqNja+XNFiuULyXMssduQobi/rsK79OoyzHhlMSI/hG7v9JmjDFAH+ImvmwnzlX/E1/0/vR1/ 1RlQdZ2h/fS+H3BJqnxX7VP17YXDaPOpKuBuRSgI+moOUZMAkbsg+RcvBrDCPCYxnG79Q5fd3NB5 C5VnCmuzKiD9YbK/yl85S+bcO0Ig7YsYPuv9L5l8w+U9aGnz+Zru7hnjnmbmvKRpq+s8O5KCPZoy KB+mXAVsHo5ZZZDxyNyluh7aztktVi5NFzMb+qXt0astmz0L8mPH1F2B7daNkCd/x3uwhijw1y5f zesL7+V/gFCawLeSA3AlV52aCoEkZPFrZCfgjVR8LCh8Dsd6nDFp1AiRxXv6eo/mjoB+OR3ev/l5 Z6BpvmyG30y+gvI5NNnjcxG3Zv3U0JRpDAW+Jw7fb32yyIp0nbE+LFHYek1sPfz73rnl0Rv5u0qO S3S6jM3EwOFKtyAG/Lbbrm47PJGLLRr0h0On/vY7Xu9Tu9OEdr5hSDSLRCY/UjqVBYmADosZ6FTT frlcMtyx3OX4Pvd5PHQyVGP4HuTSl8muW/GG2iElpJurszVSSOoFET4fjzG9JxHeR9Q+4+bf6vEG w+k/oYb54W5byNp5uZrYiC6RfTjDDdC8XwEua0HbjmWOHjyUJbw/Ud9nXay/AjZGx/WHnpdFkIIH E0oc1jp73aeLm54kClNsVItPvI6OvmaxBIK8m/4g2AuZoB++j+OjJNas/Nlt5X1b9OahFemW4jNi YkVPTh5/YbikdT9+W5pYzXAK73aaqOQYZ8RvlXzefPGzv1AYDcZW8+Rbz/8AMj80v8LRyaTpiBtd mWv1lhVIImAIYBhRmJrQdO58MzMWr8LGRH6yXZ6HRcY4pfS8nHnrzDq5s9P1fVri20YD0bt4KlmQ uJJJJNyzszUJO/sD0NP5mU6jI+l235aMbMRclDzDqB025ig0PWryS34VlT15SscnIgqsnC35/DQ/ 3Y8MqyiIPpP4+xljjxD1xH4+aM8lecvOH+KNKtl1a6minuoYZIJ5ZJozHI4RgUckfZPbKwWrU6fH 4cjwjkX0ZDCxuJSrDYLv9BORj9Z+Dpcsf3GP/O/QgmVrnzMRUf6FZ8Se3K6kqR8wLcE/MZa0kej3 n7v7U1jjdK7gr3GLUBSxYGIBDD2OLHhXSIzcQSOW/wBOKSGfflDGyahqFTUGJP8AiWCXJ3PZAri+ H6Vv5tf8dmx6f3B2P+ucRya+1f7we5gi/s/ZPX6cLq3D9n7JqT9OKuHQfZNT9+KvTfKer2dn5U08 zI0n76SEGNQ3FzIzitSKbHKcmTg+L0GiyAYY33n72H+d4Xi8z3nIAc3V1r3DIMtDrO0RWY/D7kiP +x+1/XbC4TvH7P2v8wcVcrr6hVgOuxxW93z15s8ped5FlWDTpJNL/Sd4lv6HqM7c52Cs8dSFjrG3 AhQOp774R1OMTIMtx+P0vaYblhgAOncb37zy6bV8ea/T/wAuvOWma2tlcQmHT4mW5u9QHw26rbwy MSZGTktEdhuOvXscpOtxSjYO/d73KwSnjPXhuz8L7/eVIflX5vuhOuoNHbTRgW+mJNKlbuWFWVIY astKrH8PKm1Pofz+Pp7z5MJY5y+rnyHw+LLPyx8iz6B5htrq5voG1E28i6lpSPE8lukoDRM3B360 Wu3cZbg1YnOgDR5F1famGsNnoQ9Qv7m4tnWe2kMM8JLQzKaMrAVBBHhTOo7EoznE9YvLGRBsd6fe TfzC0u30vVV80XFzf3d98EUhLykqEI4Hkw40LbfPM3VaORMDi4YiJ93d5OywamIEvEsk/jvZz5g8 w6T5atdG1m80asElu0AEfpF1eRY3UdSCKId+Wa7Fhnl44Ce/FfXzc3Jkjj4JGHTy8ni11f2155on vYFMNvcztNFBQcY0duYTbb4V8Bm8ywIwGJNng/3rpMhBJIFC/wBKel0WQqQOO1DnGsb3U5SVlqu1 KYsTzZL5BRrjzLaFR/dB3k9gEI/WQMBc/s4XlCc6xY+ZdM8taqPMGqLqX1m8jNhxQJ6UVa8DRV3y zJKBrhFO67SkPBPw+9gUzESAg9tjkHl5c3i3n3WPLv1/zPJf20U9+8y2dnURvMp+pKFdQWWRESUE lgOpA33wGO1vS6A1iiPK/tebW4it7N/UKu95ABCF9Nyh+sAHny3Q8YjTvQ+ByrmXaxqMTf8AFHbl /O693JbcIsthFLEg4wJxuHCqpEkssjKKhqt8Cjem3T3xHNEhcAR05+8k/PZ6R5Gs/LMl55XtNOuV mvluDe3qUUsrizZ5OTGJXASRFVQHK9T13y0SNU6zXUMUj5U9g+vw2UF3dzmlvFykkPUhY0Fafccr x85Hz/QHTZwaxQHPg/3UpH7iFLSLaeG0FzcArfXzG6ugTUq8gAWOv/FSKsf+xy1xs8gTtyCaxyh1 oftYsAbUYpSh/wAnuMWINL7hgQhB8aHFMmf/AJQyc7+/B6iJP+JYJcnc9kG+L4fpW/m0K6zY9P7g 7H/XOI5Nfav94PcwRR9n7PU/T+HXC6twH2fs9T9P4dcVcBsNlNT9/wCHXFWcflrrUcMs2lzMoEzG W195AKMvzKj8MjJ2/ZecAmB68k181+Wp9etheQQiHULclBG9KSxg9KnoR2PTMTR6iWSJMomG7sO1 NAJ0YG5APN7q0ubWVobmH0ZQ26SKVPfxGZrzU4GJoilKnX7P2v8AOu2LFpWT1CrKOuxpii91gVPr LuPgkYIvqKF5ERszICxFaKZGoOm58cwcnZ2KciTe/n3u0w9sZoREARt5Lk9NHZAojqzNVBwqzkly eNPtFiT74/ybg/m/af1o/ljU39X2D9Tk4rMaluVdmLsT9NTlg0OEfwhql2nqDzmXD0RO3JF5N1eg r9Jy6GKEfpAHwcfJqJz2nIy95tQvYvWBiAXrWp22oRTYe+bPs7VRwZOKVkVTRJLH0soAi2wNDWhY dT71Ob+Xa+mHKz8G3BjjI+ufB8CfuR2o6l5lv7eGyvne4treghhlkDItBQbHwGUQ7S0sSTGNE89n aDBppACeolt/QP8AxSXvZ6gKp6CKSONQRsCPnlp7ZwkfsbsOn7OhMGWaZo39H9qK0m1ubaaT6yPh YAAEht/Hvml1+oxZAOAfZTle0PaOkziAwjcXfppOrSzuby7Fva27Tu1KKi8iPnToM1rzUIGUqAt6 HoXlEW2k39pDerba3cxCOWeGjPbq24UUINT3Nfl0rlUc0TIgEEjmHquzNJ+WMck48V/L3JH5vvZI rOx0Ka7N9cWaBry5c1Lynx+X3+OWdbcLtvVRnMxiOEXdd3ckFnbW0ate3qA2cZ4xxdDNL14Cn7I6 uew9yMLpYRA9UuX3n8c3nXmj8rPLmu3lxczK8F3cXT3st7FUs/rEloSvERpGlVCBa0A7VOabLm1E Zmo2PxX4/Y9VptRgOKNzANDuG/X8ftQMX5R6Rb6xFfWl7NBpTNbyNpIjj5rJGp4lppJWFEZizfTS u2VHVZhGpQN9+/8AxLnYNTjifRkj0NbdPik7fkpYOl7Dfa0vriCmkyrEqRIYXCKk5SrFm59Qu9GP WmWR7QNWRw19vuZjBLKaj6jXToAmP5fflrbaHrkWoR3Ms9zZwSxagssE0MfrSbIbdpI0WRaK4JVm 7HatMytJqjkkdtq8vt3/AFdXS9rx4MVd5ZhNw1C8s9LC/u1Y398R04JKTBGf9eUV+SMO+ZeH6fn9 7q9XtMnqIxj8oAH8eaeSFEcAqOJ9stdadl4VKVAHsaYppTiaNtio5fIb4sRTcpRCvwjia1FMUnZn /wCUgT6/flQKGFOn+tglydz2T/F8P0qf5tf8dmx6f3B6/wCuemI5NXav94PcwQD7Oy9/p/DC6twH 2fs9T/n064q4DYfZNT9/4dcVXRu8ciSRkLIr8kcbEEbgg9iMUgkGwzvT/PEOpaa2narcNY3L0Rb+ IVVqH9oDdSe9NvlmNqsByQMQTG+r0XZ3a8YyByAEj5H9X3J/qs19LoEcehy2uo3y+moe5ZXRgPts d+u2Tww4YgE3Q5u4wSwZcl5P7s3yUfMlrri6AjaBaWD63WPmlwq+j0/edx9G+X4uDi9V8LjHFj4j Q2XeZbXWV0eNvL9pYPqvNPVW4VfT4cTzp035UpksHh8Xrvh8nGz4zXoAtH6pZ0hQ6dbWrTeoPU9V Ep6dDWnTetMGHgv13VfaubGa9Ajdu1KzAWL6hbWrNzHreoifY7098xpmX8LOeMdAFa5s7WsfoW9s Ry/eckT7PtlOoOW4+HXPe+5vx4sW/EPcoahaET2n1K2tWhMg+uF1SojqPs+9K45zm4o8FcN+r3M8 OLBUuMb16feh9XtL4ahpo0y1smsTIf0o0qpzEdV4+n03pyzLFdWWDFp+CXGPVXprv8/sQ2uWuujW tJGj2mnvpDP/ALmGmVfVCclp6W4348ssx8HCeK+Lo44xQ7gv1W11ga9py6baWDaKa/pN5VX1Rvt6 fTt7ZLH4fAeK+Lo488Z4xwiPD1R81n/uTgEVtanTuJ+sMVTmGoacfppkY8HAbvj6JljPGKEeDq09 mf0ogW2tP0bw+Niiepzoent0zGuXF/RZHH6uQ4Vd7iGznJaaCCyVd0qqnl8hlFZvGux4VfG3K/dx x90vsYfrnm3SbGa6l0SMNfXO015vxH+qPfrlmPSQhMzA9Uubgaztk8AgDxcPLuH62L+W9Fn1vXY4 p5DwYmW5kBqxUdfvJpmSXRabCc2Xc+ZTP8xXtjqltp1oqJFYQhSq7EM+9PoULiG/tIjjEY/whiyp IqMDTjQ/RhdeAVqwygggjFHCUHrsMktjIQKsgDEDwB3P3ZhdoQ4sJp6H2YzDHr4WaErHzBr7adod xLPp9WNeBKE99gD+o46DMZ4t+Y2T7T6GOm1ZEfpmOL3Xd/aGI+bL/wAw+V4o/MWmWg1CxmiiXU4G qDEsQPGRGBqOXOjfCQKV75fh+iPuDj58UcuoyQkaPHKvmjfJn5kaL5u/cQg2epRrV7OZhVh1LRMP tgd9gfbLQXB1Winj35jvZhGkiVBoVwuIAQpiB9iCPY4seFfIjtxBpy3+nFJDPfyhjdNQ1CvQxJT/ AILBLk7nsgVxfD9LX5tD/czY7A/uD1/1z0xHJr7V/vB7mCKPs7DvhdW4D7Oy9fvxVwGw2U1P3/24 q6nTZd2+/wDtxV1Omymrff8A24q2Cw6UFW8aV64qCQ3zk33/AGvE4p4i0s1XKsTWuxrivGbcs1ZC rE1rsa4rxm2xN+8KsTWuxrivGbaE37wqxPXY1xXjNu9b94VYn2NcV4zbvW/eFWJ9jXFeM24zUlKs TTahr7Yrxm3GakpViabUNfbFeM24zUkKsTTahrivGbcZqSFWJptQ1xXjNrJZHEtQTt0BxYykbXtI HhYjrTcYpuwnHlrzDHotneSx0a/uAsNuT/uterOdqHem3tgIcvS6gYok/wAZ2H60luppHuDKzFpG +JnJqSSaknC4c5Em1wkDxN40NRim7CnDNx+Fvs/qxYguuD8Y+WLIyINhC2lu1rHNHbKGWQlhyanE kU6U6ZiYsBxWIDY/Y7zV9pQ1vDPOanCNGh9Q8jfP37dfJWg4JCIHHOLjwIYVBFKbjMmEeGIHc6fN nOTJKZ24pE/M2xDU/wAp/Kb6jBqGnLNpN3E6yrJYvwFVauysGVf9jTDTkx7QyAVL1R82eSz28srm BDHGd1RjyI28cLiylEn07BCRSlDQ/ZxagaX3B+wQfGhxTJn/AOUMnO/vweoiSv8AwWCXJ3PZBvi+ H6Weat5Y0PV5o5tRtRPJEvGNi7rQVr+wy5ESIdll0uPIbkLQP/KvPJ3/AFbh4/3s3/NeHiLV/J+H +b9p/W7/AJV55O/6tw8f72b/AJrx4iv8n4f5v2n9bv8AlXnk7/q3Dx/vZv8AmvHiK/yfh/m/af1t f8q88nf9W4eP97N/zXjxFf5Pw/zftP63f8q78nf9W4eP97N/zXjxFf5Pw/zftP63f8q88nf9W4b7 /wB7N/zXjxFP8n4f5v2l3/Ku/J2/+44b9f3s3/NePEV/k/D/ADftLj+Xfk0mp04V/wCMs3/NePEV /k/D/N+0uP5deTTudOH/ACNm/wCa8eIr/J+H+b97j+XXk0mp04V/4yzf8148RX+T8P8AN+9x/Lry aTU6cP8AkbN/zXjxFf5Pw/zfvcfy68mnrpw/5Gzf8148RX+T8P8AN+9x/LryaeunD/kbN/zXjxFf 5Pw/zfvcfy68mnrpw/5Gzf8ANePEV/IYf5v3tf8AKuvJp/6Vw/5Gzf8ANePEV/IYf5v3uP5deTT1 04f8jZv+a8eIr+Qw/wA373H8uvJp/wClcP8AkbN/zXjxFfyGH+b97j+XPk0/9K4f8jZ/+a8eIr+Q w/zfvcPy58mj/pXf8lZ/+a8eIr+Qw/zXf8q58mf9W4f8jZ/+a8eIr+Qw/wA1x/LnyYf+ld/yWn/5 rx4in8hh/muH5c+TB007/ktP/wA148RX8hh/mu/5Vx5M/wCrd/yWn/5rx4iv5DD/ADXH8ufJh/6V 3T/i6f8A5rx4iv5HD/NcPy58mDpp3/Jaf/mvHiK/kcP813/KuPJn/Vu/5LT/APNePEV/I4f5rv8A lXPkz/q3dP8Ai6f/AJrx4iv5HD/NcPy58mA1Gnf8lp/+a8eIr+Rw/wA1r/lXHkz/AKt3/Jaf/mvH iK/kcP8ANDf/ACrnyZSn6O2/4zT/APNePEV/I4f5oTDR/LGhaNJJJptr6DzALIecj1ANR9tmwE23 YsEMf0irTTA2uxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2 KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2K uxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2Ku xV2KuxV2KuxV2KuxV2KuxV//2Q== + + + + proof:pdf + uuid:65E6390686CF11DBA6E2D887CEACB407 + xmp.did:5768d99c-a9ed-41a4-9aad-da4127e60438 + uuid:0a8a504b-2887-4f46-b0d1-2dd3e6eac36a + + uuid:357b99bf-0568-7a44-864e-9fa618945959 + xmp.did:4dedc7d7-33be-4ed2-a141-c9be17d90f85 + uuid:65E6390686CF11DBA6E2D887CEACB407 + proof:pdf + + + + + saved + xmp.iid:5dee8c19-d41e-4561-a65a-4970cb2dbe92 + 2018-03-21T13:16:38-07:00 + Adobe Illustrator CC 22.0 (Macintosh) + / + + + saved + xmp.iid:5768d99c-a9ed-41a4-9aad-da4127e60438 + 2018-10-25T11:19:39-07:00 + Adobe Illustrator CC 22.0 (Macintosh) + / + + + + Web + Document + Adobe PDF library 15.00 + 21.0.0 + 1 + True + False + + 2828.000000 + 777.000000 + Pixels + + + + + MonacoBSemi-Bold + MonacoBSemi + Bold + Open Type + 7.0d1e1 + False + Monaco-Bold.otf + + + SegoeUI + Segoe UI + Regular + Open Type + Version 5.28 + False + segoeui.ttf + + + + + + Cyan + Magenta + Yellow + Black + + + + + + Default Swatch Group + 0 + + + + White + RGB + PROCESS + 255 + 255 + 255 + + + Black + RGB + PROCESS + 0 + 0 + 0 + + + RGB Red + RGB + PROCESS + 255 + 0 + 0 + + + RGB Yellow + RGB + PROCESS + 255 + 255 + 0 + + + RGB Green + RGB + PROCESS + 0 + 255 + 0 + + + RGB Cyan + RGB + PROCESS + 0 + 255 + 255 + + + RGB Blue + RGB + PROCESS + 0 + 0 + 255 + + + RGB Magenta + RGB + PROCESS + 255 + 0 + 255 + + + R=193 G=39 B=45 + RGB + PROCESS + 193 + 39 + 45 + + + R=237 G=28 B=36 + RGB + PROCESS + 237 + 28 + 36 + + + R=241 G=90 B=36 + RGB + PROCESS + 241 + 90 + 36 + + + R=247 G=147 B=30 + RGB + PROCESS + 247 + 147 + 30 + + + R=251 G=176 B=59 + RGB + PROCESS + 251 + 176 + 59 + + + R=252 G=238 B=33 + RGB + PROCESS + 252 + 238 + 33 + + + R=217 G=224 B=33 + RGB + PROCESS + 217 + 224 + 33 + + + R=140 G=198 B=63 + RGB + PROCESS + 140 + 198 + 63 + + + R=57 G=181 B=74 + RGB + PROCESS + 57 + 181 + 74 + + + R=0 G=146 B=69 + RGB + PROCESS + 0 + 146 + 69 + + + R=0 G=104 B=55 + RGB + PROCESS + 0 + 104 + 55 + + + R=34 G=181 B=115 + RGB + PROCESS + 34 + 181 + 115 + + + R=0 G=169 B=157 + RGB + PROCESS + 0 + 169 + 157 + + + R=41 G=171 B=226 + RGB + PROCESS + 41 + 171 + 226 + + + R=0 G=113 B=188 + RGB + PROCESS + 0 + 113 + 188 + + + R=46 G=49 B=146 + RGB + PROCESS + 46 + 49 + 146 + + + R=27 G=20 B=100 + RGB + PROCESS + 27 + 20 + 100 + + + R=102 G=45 B=145 + RGB + PROCESS + 102 + 45 + 145 + + + R=147 G=39 B=143 + RGB + PROCESS + 147 + 39 + 143 + + + R=158 G=0 B=93 + RGB + PROCESS + 158 + 0 + 93 + + + R=212 G=20 B=90 + RGB + PROCESS + 212 + 20 + 90 + + + R=237 G=30 B=121 + RGB + PROCESS + 237 + 30 + 121 + + + R=199 G=178 B=153 + RGB + PROCESS + 199 + 178 + 153 + + + R=153 G=134 B=117 + RGB + PROCESS + 153 + 134 + 117 + + + R=115 G=99 B=87 + RGB + PROCESS + 115 + 99 + 87 + + + R=83 G=71 B=65 + RGB + PROCESS + 83 + 71 + 65 + + + R=198 G=156 B=109 + RGB + PROCESS + 198 + 156 + 109 + + + R=166 G=124 B=82 + RGB + PROCESS + 166 + 124 + 82 + + + R=140 G=98 B=57 + RGB + PROCESS + 140 + 98 + 57 + + + R=117 G=76 B=36 + RGB + PROCESS + 117 + 76 + 36 + + + R=96 G=56 B=19 + RGB + PROCESS + 96 + 56 + 19 + + + R=66 G=33 B=11 + RGB + PROCESS + 66 + 33 + 11 + + + Illus Gray 1 243-243-243 + PROCESS + 100.000000 + RGB + 243 + 243 + 243 + + + Illus Gray 2 230-230-230 + PROCESS + 100.000000 + RGB + 230 + 230 + 230 + + + Illus Gray 3 210-210-210 + PROCESS + 100.000000 + RGB + 210 + 210 + 210 + + + Illus Gray 4 194-194-194 + PROCESS + 100.000000 + RGB + 194 + 194 + 194 + + + Illus Gray 5 178-178-178 + PROCESS + 100.000000 + RGB + 178 + 178 + 178 + + + Illus Gray 6 147-147-147 + PROCESS + 100.000000 + RGB + 147 + 147 + 147 + + + Illus Gray 7 115-115-115 + PROCESS + 100.000000 + RGB + 115 + 115 + 115 + + + Illus Gray 8 80-80-80 + PROCESS + 100.000000 + RGB + 80 + 80 + 80 + + + Illus Gray 9 40-40-40 + PROCESS + 100.000000 + RGB + 40 + 40 + 40 + + + Orange 216-59-1 + PROCESS + 100.000000 + RGB + 216 + 59 + 1 + + + Orange-HL 226-108-65 + PROCESS + 100.000000 + RGB + 226 + 108 + 65 + + + Skintone7 142-86-46 + PROCESS + 100.000000 + RGB + 142 + 86 + 46 + + + Skin7 MT 112-67-34 + PROCESS + 100.000000 + RGB + 112 + 67 + 34 + + + Skin7 HL 180-143-117 + PROCESS + 100.000000 + RGB + 180 + 143 + 117 + + + Skin7 SD 84-50-23 + PROCESS + 100.000000 + RGB + 84 + 50 + 23 + + + Skin9 SD 48-29-25 + PROCESS + 100.000000 + RGB + 48 + 29 + 25 + + + Dk Red-MT 128-24-24 + PROCESS + 100.000000 + RGB + 135 + 25 + 25 + + + Yellow-HL 255-203-64 + PROCESS + 100.000000 + RGB + 255 + 203 + 64 + + + Blue-HL 64-154-225 + PROCESS + 100.000000 + RGB + 64 + 154 + 225 + + + Lt Teal 0-178-148 + PROCESS + 100.000000 + RGB + 0 + 178 + 148 + + + Lt Green 186-216-10 + PROCESS + 100.000000 + RGB + 186 + 216 + 10 + + + Skin5 HL 216-176-127 + PROCESS + 100.000000 + RGB + 216 + 176 + 127 + + + Skintone4 216-176-148 + PROCESS + 100.000000 + RGB + 216 + 176 + 148 + + + Skin4 MT 184-151-124 + PROCESS + 100.000000 + RGB + 184 + 151 + 124 + + + Skintone5 206-156-95 + PROCESS + 100.000000 + RGB + 206 + 156 + 95 + + + Skin5 MT 186-140-87 + PROCESS + 100.000000 + RGB + 186 + 140 + 87 + + + Yellow-SD 199-142-0 + PROCESS + 100.000000 + RGB + 196 + 140 + 0 + + + Yellow-MT 240-174-0 + PROCESS + 100.000000 + RGB + 229 + 166 + 0 + + + Lt Blue 0-188-242 + PROCESS + 100.000000 + RGB + 0 + 188 + 242 + + + Purple-HL 165-121-214 + PROCESS + 100.000000 + RGB + 164 + 121 + 214 + + + Lt Magenta-HL 234-64-169 + PROCESS + 100.000000 + RGB + 234 + 64 + 169 + + + Red-HL 238-77-90 + PROCESS + 100.000000 + RGB + 238 + 77 + 90 + + + Lt Blue-HL 64-205-245 + PROCESS + 100.000000 + RGB + 64 + 205 + 245 + + + Green-MT 56-161-56 + PROCESS + 100.000000 + RGB + 56 + 161 + 56 + + + Green-HL 120-197-120 + PROCESS + 100.000000 + RGB + 120 + 196 + 120 + + + Lt Green-HL 215-240-75 + PROCESS + 100.000000 + RGB + 215 + 239 + 75 + + + Magenta-HL 199-64-182 + PROCESS + 100.000000 + RGB + 199 + 64 + 182 + + + Lt Orange 255-140-0 + PROCESS + 100.000000 + RGB + 255 + 140 + 0 + + + Teal 0-130-114 + PROCESS + 100.000000 + RGB + 0 + 130 + 114 + + + Green 16-124-16 + PROCESS + 100.000000 + RGB + 16 + 124 + 16 + + + Dk Green-HL 34-153-78 + PROCESS + 100.000000 + RGB + 33 + 153 + 78 + + + Magenta-MT 158-0-139 + PROCESS + 100.000000 + RGB + 158 + 0 + 138 + + + White + PROCESS + 100.000000 + RGB + 255 + 255 + 255 + + + Lt Orange-HL 255-169-64 + PROCESS + 100.000000 + RGB + 255 + 169 + 64 + + + Lt Yellow-HL 255-248-128 + PROCESS + 100.000000 + RGB + 255 + 248 + 128 + + + Lt Teal-HL 64-197-175 + PROCESS + 100.000000 + RGB + 64 + 197 + 175 + + + Lt Orange-MT 240-132-0 + PROCESS + 100.000000 + RGB + 240 + 132 + 0 + + + Yellow 255-185-0 + PROCESS + 100.000000 + RGB + 255 + 185 + 0 + + + Lt Teal-MT 0-140-116 + PROCESS + 100.000000 + RGB + 0 + 140 + 116 + + + Teal-MT 0-82-72 + PROCESS + 100.000000 + RGB + 0 + 81 + 71 + + + Lt Teal-SD 0-110-91 + PROCESS + 100.000000 + RGB + 0 + 110 + 90 + + + Red 232-17-35 + PROCESS + 100.000000 + RGB + 232 + 17 + 35 + + + Red-MT 217-16-33 + PROCESS + 100.000000 + RGB + 186 + 13 + 28 + + + Teal-HL 64-161-149 + PROCESS + 100.000000 + RGB + 64 + 161 + 149 + + + Blue 0-120-215 + PROCESS + 100.000000 + RGB + 0 + 120 + 215 + + + Lt Yellow 255-241-0 + PROCESS + 100.000000 + RGB + 255 + 241 + 0 + + + Blue-MT 0-100-181 + PROCESS + 100.000000 + RGB + 0 + 100 + 181 + + + Mid Blue-MT 33-57-181 + PROCESS + 100.000000 + RGB + 32 + 56 + 181 + + + Mid Blue-HL 47-96-224 + PROCESS + 100.000000 + RGB + 47 + 95 + 224 + + + Dk Blue-HL 57-99-163 + PROCESS + 100.000000 + RGB + 57 + 99 + 163 + + + Dk Teal-MT 35-107-112 + PROCESS + 100.000000 + RGB + 34 + 107 + 112 + + + Purple 92-45-145 + PROCESS + 100.000000 + RGB + 92 + 45 + 145 + + + Dk Blue-MT 45-61-135 + PROCESS + 100.000000 + RGB + 44 + 61 + 135 + + + Blue-SD 0-72-128 + PROCESS + 100.000000 + RGB + 0 + 71 + 127 + + + Orange-MT 189-54-4 + PROCESS + 100.000000 + RGB + 188 + 53 + 3 + + + + + + Grays + 1 + + + + R=0 G=0 B=0 + RGB + PROCESS + 0 + 0 + 0 + + + R=26 G=26 B=26 + RGB + PROCESS + 26 + 26 + 26 + + + R=51 G=51 B=51 + RGB + PROCESS + 51 + 51 + 51 + + + R=77 G=77 B=77 + RGB + PROCESS + 77 + 77 + 77 + + + R=102 G=102 B=102 + RGB + PROCESS + 102 + 102 + 102 + + + R=128 G=128 B=128 + RGB + PROCESS + 128 + 128 + 128 + + + R=153 G=153 B=153 + RGB + PROCESS + 153 + 153 + 153 + + + R=179 G=179 B=179 + RGB + PROCESS + 179 + 179 + 179 + + + R=204 G=204 B=204 + RGB + PROCESS + 204 + 204 + 204 + + + R=230 G=230 B=230 + RGB + PROCESS + 230 + 230 + 230 + + + R=242 G=242 B=242 + RGB + PROCESS + 242 + 242 + 242 + + + + + + Web Color Group + 1 + + + + R=63 G=169 B=245 + RGB + PROCESS + 63 + 169 + 245 + + + R=122 G=201 B=67 + RGB + PROCESS + 122 + 201 + 67 + + + R=255 G=147 B=30 + RGB + PROCESS + 255 + 147 + 30 + + + R=255 G=29 B=37 + RGB + PROCESS + 255 + 29 + 37 + + + R=255 G=123 B=172 + RGB + PROCESS + 255 + 123 + 172 + + + R=189 G=204 B=212 + RGB + PROCESS + 189 + 204 + 212 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + endstream endobj 3 0 obj <> endobj 14 0 obj <>/Resources<>/ExtGState<>/Font<>/Pattern<>/ProcSet[/PDF/Text]/Properties<>/Shading<>/XObject<>>>/Thumb 918 0 R/TrimBox[9.0 9.0 2837.0 786.0]/Type/Page>> endobj 893 0 obj <>stream +H͒$]?WE Ffpop5ϣ*ga=]ٕ>w};vλsumww??X)fBme0-//~pO?{gWa:Wwzx{,ݹ__A~7np +Y~n JӠ'`vꯙ>CqicӂU'}Χեha~9*s]bisc-l'oBa;pb;p|9ߖJ^RJqE{h:-9ysKȍ#TNޖɬoe/`3~ӪR.^n%/_m 1Hiso2r8`k_Zu!'բ0W@?e7̉d8/i\2:gq&)ˎ \.!¯ a- |9Bo3gbƏi(QhZsl+(;wņBYF?&IuI$|,#!k&st-cӚ.M$q1R_),R{>g='z" xFUN'z5amk*Ik8 qݨBFm45>9㔖}acuuX:og0?Ϋͅ]u9ͅkyn=ۿg$ՠ77/ޫv7whTclp p<&['q8#f <*x$">dI hR|^Eȷc#n=b^KRnrm7sF̏pqh144^FOb5a~2j$9MUL-3)gM˯s.U0TLCDTTzYî{\ y&[jbto+ECYո%\pTg"E%SGrP4ZDԓg_P-@TM@?r|y_D+saǩ"ye}e,[H؃CdaeEUÑnrYk>bv guDW>W|8x{oOMPUoB6{bƳ@&?ݾ۾Ps*է(K~g{U2 =Ͻ=w[op[b4Fu3w2LA"+jU+pcV՗+7?鹙LM!M: !$EIJQyqDU>-ށ<\]%'&̗^p&;8EF /vFJUb] QcTP/<;R9aͱW4>=#z:^`Zm"DfEIznjnr)NL/fH[Š1ՙN5MO׳JUsc<5A4vm {Px.=[[ff''zٳcх*Lb"+I)I>`no#8; ' B'$T G'Q0ْZe*hʖ#qhF6CJHUժ|Q؉BUzQij%)Y:>EK0#ٲt@*a\&t+KkVoFUHUB?h7$ɽ3^5!ˀf:zN>w}%O]:(5o$ A)'7XwwZ+V dX>pKufܖUߓTԣ?Vnu=gȪ6< +|r-[ ~:xn(a&(HfqLU4ǭ]qǀYf8J> A!)չ6zauBJfČb[z0R( +$kix4WT/8#ubk#FZ{eD5z(Ȗf"32~D9f2Ks_Z8@`Q`XgPq}>Z42+!&tʨfCM$w_gږW_"l֘q*ӶRo3=5ơH6 i-kv(cE#z5oPֵF1/W`LN/먽Q,A4*GkF2Ma{5"BL{{uuoV?u>l<SJzGp}:#qgҍ&([>Ik&2YިlPz t0~Jِ;Prm g% +ӛNkY?|z$q" VA+0TV 5혞k(lB 9('$É?G8@gZTvDɄp|>zx{Ag̔=m>aH5\q>@d<]""ݎyG눗/Ij$j4[R*ss mY;.ooR +|o<ˊU9\5K,ѮC$S8*=@jC.ɩv0D y9+Ej2|:X7bӻ]ؔ$9=R++K Y.]C;J-@AbS#ڎɡ( 5h 7 ]O+pj"s=D׳c a?kX~8B־ɷ;!ka1tP*g]D:ǵS4hB)urG3,xG*KA?7Dl }Mq4cRl"vl{ǯP۰Мд6<G 1wVI6jaՠePѢ c WK\Otzn{/$J.#Yl{%P6ζ3VX ԕcnc9 5]ktvij+0_6'rrYlFi=30t'/NSa{ǥ)c?[W}ZUuaXt5V2NV*o>˧ϗ>;tPS?iS9 _($&4g Qi3@#=Koua׽IA|Ĵ^ASoWf2jM8jA,# *U_-n격q kjթDQtAh"[ȺrV*JX6>D7 `N0ɍ !Cu1L^$s9<.5S +lg(!/o|r=qp?웒옼Q2]irg{.n +w;jԉ[ĝ Ȯu&|)#K8y һHӄXap+aNsxV+\dOK@=ɘ.z8}r'"97+O(8ө0рlB>T-"zHmo;N(x o +-WCjkM]Ͼ]KҬzTpqcTW8gO:?lBdja7*;x' + +^: +6nƭ]ǭjP22x@kЯ`%:>HdeۮvVyV 6VyX<&fjGx*8:ڹ%=C!b:QޜJ8v +峫PYqҀۃ}|j +$EW*fXD?vFUGS-2N=IA. cǸerjdBLclI!-"nP&a6Kp(S=9)X>Y`HȱL;e.%Tȵ3nۚ򆆄}k"XIyڪM_8:+/{US׉#~;5kLpȅ9,H&ܳsCl6NKҿ{]ӭ$|2A{-;#Gajَ6(ʫ5mK;k`dм/ҙ62"ᣲ +/M54 +ſOdR|lEE=W,xb +0_2r &%3k +ݕJVIn)>Ѭ(ƱҚ㽕Rxb گJzϷ˰H 6>nFFh5J;3m5DY3f<'ZW >HO9uM 3r&0 +ATo&hB!PEOc9M?ZGK~\-1.&=P/^[RIBGDrA㪋!ܾ 9R1cZZSxҫ̨*Ȏ_g!y^V1PF?@d6$2VJ\Ai,:ؐ K +CL+mKUU@ɤtޢFj2Eba{b|2]Ըw/t7M:O~~Ax-:KV:!2D&FUT9F)fp] ;&pI62L5+gP597(S;P m#  +r`<۔Lc[󲆹 ͝Z!){ǧd~}Sz̬L-uufoӎL.0p_;oߎlTS"jР\"cxq s [So4U@W U^y\A{B=}2]”aL˟лd7[k2FpwEE|r:*pEYq5 lVKV w( +kZ&0rh]CP.(n-lU|ܷr@$}q%j%|58{%L=|{4K6ggl 6Yr ]`[醸Z1YȺ3M/xoEKԽ=etGE& +V b?MĜ&o77gH6(ToZ" +niЍ::*(|ZvS(p{S,jL=y^9J"A^/0<İ#,ͷ3R_y͛pExe:O;Ȳ%i\ u JΖFZ[y[cL9]g5U) Z mATksrAiqaKFaȉEBqʖnjJ=+~:r ߋXQՑYsfr! [b#6,e$>bˊ27y~*?y1B֪cgΕ"1rGongXD||5W[yR#b- aKɤ'Wp ^zEdJ]*YT)K7Bk󜸚jbZ ݱ̘u!'4żi{p_F 1܎?2-:XHF[qA)lsA)AQ\ĂM'T[Fċ9t;!#Ws}DBY %𤼜{ 6by%bA'[7y>iR+"-`@\3B+klk%X ǽ _o? 9m@ gOix=doMYi2s4K +{mޟ`U )ܤ0-TiaTL=2tBݮpFàyMcC S7:Hhk("&2 +CRۑwn>`ItU"bq"Ft)MLDt4B(N0A"eT3F}`ȡ_[xKJીwhvg^m.y_x%b\4>1+b/}U5ڃy웽^6Y8 +lKp|ѯ+H'ԛC)UT Go_Lwz׈7UIR%;55 !œlȰi04I]fo<1˥;tӬ굍kxCH99T"?E űS>pGc "QH|1+49k0E!n׃uB۽4bÿOu'q)nTMrYXMvT'aL:@6t(q1T $"#t\GO|gݳ5FQs]YD@-sQfɬX_iJx,a0M|dv}obӓoOO&Qz㞆͍"yӘzJe-5}"m^ e dI q/7fJ (SP`jYACshrh!VEݹ&2&խRN!VɩfŒ [)Hm&ǯ)Nf8hX#F9'(<[u"IFGϢhKeU~iiI4zI 31j_6#l$l.8渽\j^٭2avzݣq`#zldwt0|XBÜ~C +3ylb"D}@KOCOs~EoK CR|1o]ZO /$N#2Jxߨ@d" +Eq ^po#EU-NNn|70Ìkpn ( @]:G8;ZЅ˫WiMM=Ů1)-xDyi^"eTD"PF3G00u)' ۝7uפ9Z5}(GĨ$wHлoFmÅyGu0#GBur90PTlAk7x(Du@kwB*`~Il9f16&Tf&LSa>4H)dSFS>dFUr=t$)RE9EnfHy0h?K*ʥ֧2QDq7*C9]1$t%?ִTn/@q>J)|N}:SRo n&KiʼnEݳSw՛밼v_lswwkټk8(mwǏuZ>|{G,DOc]P$CуL=F"k`O)]YiMyg$p.sMNޕTUzsCqJ˵`vpdLݿ) jx&eE r֯iy?7l}^9fc!$pz`RĞ|yE|3m`XkAyz4ʳAZߕciȬ0&wLê{Py#ȫ,˛'$xDNYZ*ۊz4$=qgrn~k 8߿re>-R\ClO5"# FmKnaƋ7O8r<(!iXS3yXr񈜲s 1I.S E6fh~1G.G8bk,Z}~es‘K5en͔M}#wwitI|ߏ!C$ +O8Hߝ8 +#pkW b ͺ)Ί9`ӧA>_ɵRvcb"5>PTtP$sn+nQ|YhॉA[|&N5B^ j3lqX:J!U;0Zqly& (nP} 4Hs'fhcr; 6УxQP~C"n%` +&52O=gܣZHwZVF!OdGTM&?r$x͜n5:{05$pT2) #NSیj3y~Do@uO]ɠij-!; i?3A:qXMU'Mu@>PKUuG ;K -w˼BvP&լyW@DZ1T ^^\ٙW*nCa: KAiPʀgY>xHPF;* Q,J|62An% MJG;d +xVSQX?$$ {*m zѵעo=! + Fȟ?c|LifأqY,> +*i**!qvw^fJPlWC=DIElft!i+a1;@:%[nǎdEh$Z둩n~O%થzi?z0}r җL0",,YbxFbkR5JtD?((2Un ;W8ҼFs#0H$.eWA4h7[ڣ.eʤ1-(Dҽ$IV]z)(?<[DU闲uT^T^'[9lHi>J\N\\k d8dcyO+OK-S񳮜LPSfs~r%= e2eF6xS-pS~xE`TZ&i1NW[փ N=fX\XˡNÜ_ޫ#*“m`@++h"}|.V1\hSf#- +s BlomOm}'ŀk|bvEZs6ǣGZ(s`&@P0|;j4 pߐ>Oi5QMu!O}"1X񁫏>vZYuRw p4ôyr. :>C#iq6ٳ_ϻ|߻ÿ<]#B37Ŧ2ꁑ`u: =kq H M̪ 7ݻO(8H3P' x|~k_h}v;Qūs$y KN[,E&vm'j1}3`3Z/م!`,KU8gs'?_*%]S0@~Ċ@׭HMP+d atȩk:UO UnX**ݪFV Mư>=ge^?/՗b-F*ނ*BD_2k](Z*$Q蔴2`.1`e05ŐTK\RR U1TuJ}PQ)v/+"QUq]}Y2ң$D"I'iX0;#gݖ v.ymHQbԺd&ՃwOh_U%اMJXz~zV=搑e'ƆmKz@җɀV&^$$}IfA`.}ϔ2U)\=Lm*2H;WU6TqM*jM'l$ZGh !.=.Ԯ\kܧ1!fd>\׀\>'P卵!ćJo*F#Y1D=4tRaҮ K6EJw'[t]uEN +ʖ(HLp20C*JQHL{?1ƒW5[`:Vk'EX }Uڰvg,CW%o&r(QT%:ۢQ\L=̵ttӑy}zg7E.SV1(1es0$u^MאxβҬ=dL%n3po#gBK9Lš09we!&mUjᄒL=SALrp@ [_m׷*hi;~yŝ_܆J;Í+Lq7BX[R9i +td$k X7*dNv5F"$%.Ӭ<:Xי/ـ:w75g]P:k-:]Z.4iâu:_1mU϶/tfBso)V/7щe,B +T"+aѺ\9JeQ HiNjЈ;-eiullQQH;Az/cm*6mHO_~G8Ql1@Կ_/!)j^TŅMP$/= +fN2+jb_dA~Xn$/3d@SciEaJ0r@*>d-,]*rүZ7eRKaz$s-NS\| tN0xXsҫ| lXIu WDz.lx3~J}lOPIY4D"P Z:^P~#AI}bX)?fɘ7`21*X"H㔾}hWB!J|58[I) E=zHS1nzt/uot7wT4~һW ԎI^J`|5%}(qژ^5Jho , 7{6\mM{5~*f:f:$W<nY-b<5a< /Oʥ:1FN^<)]BygpKsCn5JUY)HzEh"ZDRi]0ǰţ09NXVJG)czSzQxsԩA:Oʒ!| +kȄ!S^Iy%k)>*5%s-n ,JJ-s(hJWŐMDX$UQTiNY +n$1?u7ߨ6VpUIYŞuՏ\XZ꧌StfAMlqMMrd[` t";m#!*bOq,B-؈D\&m! U+nC-gg7ҿ)M_(]UJ?}I endstream endobj 894 0 obj <> endobj 918 0 obj <>stream +8;Wj;Z*N(E&66iQaFB"Mf`d++TQ3C7?Y1L\1QsbFJ=A7e#Ae9)Y+1Bs-eno(:ka(B +-YHMd/.K<'.q;)OOKl56(\b+KA +A?tt&im.KcT.)f77!q.d@3-oXB:Wm(Dn"S\BVb'Ap(s>k7$\\;B_6j(q'Z-V?EJ>I +c@QhE#[2U[g`>Dc9_>F7ro^?$IkjW[FKBTlQ4I0bR-F"I/N:OrX8qof8K4U@XqAA8 +?U^`#S8*i?cj\LuH+V^Tl]hG`QO=KSN'LBA_5Gco;5=2qa3&P!\\Zl-<(^b:.Mg\" +n%S3D&JQR2,3h)UX2dicI$2+?)Zc#JNG8F[SkWX'0Ug:`Vbo:5h0gR7HYLY).b.I* +RRU.6NEN&>IgUJN*nn"^>d6D4,0X-[GnMQ!N6'$!(fTC#%%,)kee +MZ(rVO?4N26%/tJ:jGHbGtd5m'@hu>k<[t]4JTeIGCldWe/dZ`7pSsTdN8*E_+?G0 +-SV,]fb/=X&0]!D0<<@_A_$>+i43kiA2[9J>,*`.\e7,aCT/1K1f=#TI#g]>`hV1> +k?Er*4MmPifIenm;b8WBLcUU-7uK>Hcc-rHes>>fO(a\P"Ar'b4F+`YehD!nna#in5S\=qfrG2aSj:d-;Si9o,g<2-aW%=f2e^pCm7Lnt^f^3^uFBFSj +omcpsd_pJmX^3t"0 endstream endobj 920 0 obj [/Indexed/DeviceRGB 255 921 0 R] endobj 921 0 obj <>stream +8;X]O>EqN@%''O_@%e@?J;%+8(9e>X=MR6S?i^YgA3=].HDXF.R$lIL@"pJ+EP(%0 +b]6ajmNZn*!='OQZeQ^Y*,=]?C.B+\Ulg9dhD*"iC[;*=3`oP1[!S^)?1)IZ4dup` +E1r!/,*0[*9.aFIR2&b-C#soRZ7Dl%MLY\.?d>Mn +6%Q2oYfNRF$$+ON<+]RUJmC0InDZ4OTs0S!saG>GGKUlQ*Q?45:CI&4J'_2j$XKrcYp0n+Xl_nU*O( +l[$6Nn+Z_Nq0]s7hs]`XX1nZ8&94a\~> endstream endobj 904 0 obj <>/ExtGState<>>>/Subtype/Form>>stream +/CS0 cs 0.953 0.953 0.953 scn +/GS0 gs +q 1 0 0 1 2610.2649 280.5333 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2610.2649 140.4879 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2610.2649 0.4423 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2610.2649 420.5788 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2610.2649 560.6243 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2610.2649 700.6697 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2470.5969 280.5333 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2470.5969 140.4879 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2470.5969 0.4423 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2470.5969 420.5788 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2470.5969 560.6243 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2470.5969 700.6697 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2330.929 280.5333 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2330.929 140.4879 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2330.929 0.4423 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2330.929 420.5788 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2330.929 560.6243 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2330.929 700.6697 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2191.2605 280.5333 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2191.2605 140.4879 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2191.2605 0.4423 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2191.2605 420.5788 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2191.2605 560.6243 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2191.2605 700.6697 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2051.5925 280.5333 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2051.5925 140.4879 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2051.5925 0.4423 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2051.5925 420.5788 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2051.5925 560.6243 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2051.5925 700.6697 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 1911.9244 280.5333 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 1911.9244 140.4879 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 1911.9244 0.4423 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 1911.9244 420.5788 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 1911.9244 560.6243 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 1911.9244 700.6697 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 1772.2565 280.5333 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 1772.2565 140.4879 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 1772.2565 0.4423 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 1772.2565 420.5788 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 1772.2565 560.6243 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 1772.2565 700.6697 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2891.1687 280.5333 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2891.1687 140.4879 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2891.1687 0.4423 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2891.1687 420.5788 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2891.1687 560.6243 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2891.1687 700.6697 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2751.5002 280.5333 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2751.5002 140.4879 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2751.5002 0.4423 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2751.5002 420.5788 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2751.5002 560.6243 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 2751.5002 700.6697 cm +0 0 m +0 139.668 l +-139.668 139.668 l +h +f +Q +q 1 0 0 1 1632.7433 467.2005 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1632.7433 373.8532 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1632.7433 280.506 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1632.7433 560.5477 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1632.7433 653.895 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1632.7433 747.2422 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1540.1378 467.2005 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1540.1378 373.8532 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1540.1378 280.506 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1540.1378 560.5477 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1540.1378 653.895 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1540.1378 747.2422 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1447.0421 467.2005 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1447.0421 373.8532 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1447.0421 280.506 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1447.0421 560.5477 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1447.0421 653.895 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1447.0421 747.2422 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1353.9464 467.2005 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1353.9464 373.8532 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1353.9464 280.506 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1353.9464 560.5477 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1353.9464 653.895 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1353.9464 747.2422 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1260.8507 467.2005 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1260.8507 373.8532 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1260.8507 280.506 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1260.8507 560.5477 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1260.8507 653.895 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1260.8507 747.2422 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1167.2179 467.2005 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1167.2179 373.8532 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1167.2179 280.506 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1167.2179 560.5477 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1167.2179 653.895 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1167.2179 747.2422 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1074.1222 467.2005 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1074.1222 373.8532 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1074.1222 280.506 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1074.1222 560.5477 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1074.1222 653.895 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1074.1222 747.2422 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 981.0266 467.2005 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 981.0266 373.8532 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 981.0266 280.506 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 981.0266 560.5477 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 981.0266 653.895 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 981.0266 747.2422 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 887.9308 467.2005 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 887.9308 373.8532 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 887.9308 280.506 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 887.9308 560.5477 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 887.9308 653.895 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 887.9308 747.2422 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 794.8351 467.2005 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 794.8351 373.8532 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 794.8351 280.506 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 794.8351 560.5477 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 794.8351 653.895 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 794.8351 747.2422 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1632.7433 1.0757 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1632.7433 94.4229 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1632.7433 187.7701 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1540.1378 1.0757 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1540.1378 94.4229 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1540.1378 187.7701 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1447.0421 1.0757 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1447.0421 94.4229 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1447.0421 187.7701 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1353.9464 1.0757 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1353.9464 94.4229 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1353.9464 187.7701 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1260.8507 1.0757 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1260.8507 94.4229 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1260.8507 187.7701 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1167.2179 1.0757 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1167.2179 94.4229 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1167.2179 187.7701 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1074.1222 1.0757 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1074.1222 94.4229 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 1074.1222 187.7701 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 981.0266 1.0757 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 981.0266 94.4229 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 981.0266 187.7701 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 887.9308 1.0757 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 887.9308 94.4229 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 887.9308 187.7701 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 794.8351 1.0757 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 794.8351 94.4229 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 794.8351 187.7701 cm +0 0 m +0 93.096 l +-93.096 93.096 l +h +f +Q +q 1 0 0 1 701.7436 653.748 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 701.7436 607.0692 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 701.7436 560.3902 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 701.7436 700.4269 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 701.7436 747.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 701.7436 793.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 655.4355 653.748 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 655.4355 607.0692 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 655.4355 560.3902 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 655.4355 700.4269 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 655.4355 747.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 655.4355 793.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 608.8825 653.748 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 608.8825 607.0692 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 608.8825 560.3902 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 608.8825 700.4269 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 608.8825 747.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 608.8825 793.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 562.3293 653.748 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 562.3293 607.0692 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 562.3293 560.3902 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 562.3293 700.4269 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 562.3293 747.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 562.3293 793.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 515.7763 653.748 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 515.7763 607.0692 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 515.7763 560.3902 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 515.7763 700.4269 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 515.7763 747.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 515.7763 793.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 468.9545 653.748 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 468.9545 607.0692 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 468.9545 560.3902 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 468.9545 700.4269 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 468.9545 747.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 468.9545 793.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 422.4013 653.748 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 422.4013 607.0692 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 422.4013 560.3902 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 422.4013 700.4269 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 422.4013 747.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 422.4013 793.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 375.8481 653.748 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 375.8481 607.0692 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 375.8481 560.3902 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 375.8481 700.4269 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 375.8481 747.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 375.8481 793.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 329.2951 653.748 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 329.2951 607.0692 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 329.2951 560.3902 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 329.2951 700.4269 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 329.2951 747.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 329.2951 793.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 282.7419 653.748 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 282.7419 607.0692 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 282.7419 560.3902 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 282.7419 700.4269 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 282.7419 747.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 282.7419 793.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 701.7436 467.3381 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 701.7436 514.017 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 655.4355 467.3381 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 655.4355 514.017 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 608.8825 467.3381 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 608.8825 514.017 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 562.3293 467.3381 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 562.3293 514.017 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 515.7763 467.3381 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 515.7763 514.017 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 468.9545 467.3381 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 468.9545 514.017 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 422.4013 467.3381 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 422.4013 514.017 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 375.8481 467.3381 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 375.8481 514.017 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 329.2951 467.3381 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 329.2951 514.017 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 282.7419 467.3381 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 282.7419 514.017 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 701.7436 280.748 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 701.7436 234.0692 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 701.7436 187.3902 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 701.7436 327.4269 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 701.7436 374.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 701.7436 420.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 655.4355 280.748 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 655.4355 234.0692 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 655.4355 187.3902 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 655.4355 327.4269 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 655.4355 374.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 655.4355 420.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 608.8825 280.748 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 608.8825 234.0692 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 608.8825 187.3902 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 608.8825 327.4269 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 608.8825 374.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 608.8825 420.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 562.3293 280.748 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 562.3293 234.0692 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 562.3293 187.3902 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 562.3293 327.4269 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 562.3293 374.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 562.3293 420.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 515.7763 280.748 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 515.7763 234.0692 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 515.7763 187.3902 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 515.7763 327.4269 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 515.7763 374.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 515.7763 420.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 468.9545 280.748 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 468.9545 234.0692 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 468.9545 187.3902 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 468.9545 327.4269 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 468.9545 374.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 468.9545 420.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 422.4013 280.748 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 422.4013 234.0692 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 422.4013 187.3902 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 422.4013 327.4269 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 422.4013 374.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 422.4013 420.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 375.8481 280.748 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 375.8481 234.0692 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 375.8481 187.3902 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 375.8481 327.4269 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 375.8481 374.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 375.8481 420.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 329.2951 280.748 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 329.2951 234.0692 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 329.2951 187.3902 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 329.2951 327.4269 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 329.2951 374.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 329.2951 420.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 282.7419 280.748 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 282.7419 234.0692 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 282.7419 187.3902 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 282.7419 327.4269 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 282.7419 374.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 282.7419 420.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 701.7436 94.3381 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 701.7436 141.017 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 655.4355 94.3381 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 655.4355 141.017 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 608.8825 94.3381 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 608.8825 141.017 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 562.3293 94.3381 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 562.3293 141.017 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 515.7763 94.3381 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 515.7763 141.017 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 468.9545 94.3381 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 468.9545 141.017 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 422.4013 94.3381 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 422.4013 141.017 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 375.8481 94.3381 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 375.8481 141.017 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 329.2951 94.3381 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 329.2951 141.017 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 282.7419 94.3381 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 282.7419 141.017 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 701.7436 1.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 701.7436 47.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 655.4355 1.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 655.4355 47.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 608.8825 1.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 608.8825 47.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 562.3293 1.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 562.3293 47.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 515.7763 1.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 515.7763 47.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 468.9545 1.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 468.9545 47.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 422.4013 1.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 422.4013 47.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 375.8481 1.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 375.8481 47.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 329.2951 1.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 329.2951 47.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 282.7419 1.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 282.7419 47.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 235.267 653.748 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 235.267 607.0692 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 235.267 560.3902 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 235.267 700.4269 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 235.267 747.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 235.267 793.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 188.9589 653.748 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 188.9589 607.0692 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 188.9589 560.3902 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 188.9589 700.4269 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 188.9589 747.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 188.9589 793.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 142.4057 653.748 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 142.4057 607.0692 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 142.4057 560.3902 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 142.4057 700.4269 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 142.4057 747.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 142.4057 793.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 95.8527 653.748 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 95.8527 607.0692 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 95.8527 560.3902 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 95.8527 700.4269 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 95.8527 747.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 95.8527 793.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 49.2995 653.748 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 49.2995 607.0692 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 49.2995 560.3902 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 49.2995 700.4269 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 49.2995 747.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 49.2995 793.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 2.4777 653.748 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 2.4777 607.0692 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 2.4777 560.3902 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 2.4777 700.4269 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 2.4777 747.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 2.4777 793.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 235.267 467.3381 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 235.267 514.017 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 188.9589 467.3381 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 188.9589 514.017 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 142.4057 467.3381 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 142.4057 514.017 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 95.8527 467.3381 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 95.8527 514.017 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 49.2995 467.3381 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 49.2995 514.017 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 2.4777 467.3381 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 2.4777 514.017 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 235.267 280.748 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 235.267 234.0692 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 235.267 187.3902 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 235.267 327.4269 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 235.267 374.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 235.267 420.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 188.9589 280.748 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 188.9589 234.0692 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 188.9589 187.3902 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 188.9589 327.4269 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 188.9589 374.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 188.9589 420.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 142.4057 280.748 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 142.4057 234.0692 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 142.4057 187.3902 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 142.4057 327.4269 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 142.4057 374.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 142.4057 420.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 95.8527 280.748 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 95.8527 234.0692 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 95.8527 187.3902 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 95.8527 327.4269 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 95.8527 374.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 95.8527 420.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 49.2995 280.748 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 49.2995 234.0692 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 49.2995 187.3902 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 49.2995 327.4269 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 49.2995 374.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 49.2995 420.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 2.4777 280.748 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 2.4777 234.0692 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 2.4777 187.3902 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 2.4777 327.4269 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 2.4777 374.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 2.4777 420.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 235.267 94.3381 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 235.267 141.017 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 188.9589 94.3381 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 188.9589 141.017 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 142.4057 94.3381 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 142.4057 141.017 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 95.8527 94.3381 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 95.8527 141.017 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 49.2995 94.3381 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 49.2995 141.017 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 2.4777 94.3381 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 2.4777 141.017 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 235.267 1.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 235.267 47.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 188.9589 1.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 188.9589 47.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 142.4057 1.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 142.4057 47.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 95.8527 1.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 95.8527 47.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 49.2995 1.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 49.2995 47.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 2.4777 1.1058 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q +q 1 0 0 1 2.4777 47.7847 cm +0 0 m +0 46.553 l +-46.553 46.553 l +h +f +Q + endstream endobj 905 0 obj <>/ExtGState<>/Font<>/ProcSet[/PDF/Text]>>/Subtype/Form>>stream +BT +/CS0 cs 1 1 1 scn +/GS0 gs +/T1_0 1 Tf +0 Tc 0 Tw 0 Ts 100 Tz 0 Tr 26 0 0 26 1310.2639 682.0497 Tm +(on)Tj +ET + endstream endobj 906 0 obj <>/ExtGState<>>>/Subtype/Form>>stream +/CS0 cs 0 0 0 scn +/GS0 gs +q 1 0 0 1 1401.5856 323.8414 cm +0 0 m +25.188 1.677 l +29.825 1.986 33.834 -1.523 34.143 -6.16 c +35.82 -31.349 l +36.129 -35.986 32.62 -39.995 27.983 -40.304 c +2.794 -41.981 l +-1.843 -42.289 -5.852 -38.781 -6.161 -34.143 c +-7.837 -8.955 l +-8.146 -4.318 -4.637 -0.309 0 0 c +f +Q + endstream endobj 907 0 obj <>/ExtGState<>>>/Subtype/Form>>stream +/CS0 cs 0 0 0 scn +/GS0 gs +q 1 0 0 1 1441.9059 528.9256 cm +0 0 m +25.188 1.677 l +29.826 1.986 33.835 -1.523 34.144 -6.16 c +35.82 -31.349 l +36.129 -35.986 32.62 -39.995 27.983 -40.304 c +2.795 -41.981 l +-1.842 -42.289 -5.852 -38.78 -6.16 -34.143 c +-7.837 -8.955 l +-8.146 -4.318 -4.637 -0.309 0 0 c +f +Q + endstream endobj 908 0 obj <>/ExtGState<>>>/Subtype/Form>>stream +/CS0 cs 0 0 0 scn +/GS0 gs +q 1 0 0 1 1451.9669 377.7953 cm +0 0 m +25.188 1.677 l +29.825 1.986 33.835 -1.523 34.144 -6.16 c +35.82 -31.349 l +36.129 -35.986 32.62 -39.995 27.983 -40.304 c +2.795 -41.981 l +-1.842 -42.289 -5.852 -38.781 -6.16 -34.143 c +-7.837 -8.955 l +-8.146 -4.318 -4.637 -0.309 0 0 c +f +Q + endstream endobj 909 0 obj <>/ExtGState<>>>/Subtype/Form>>stream +/CS0 cs 0 0 0 scn +/GS0 gs +q 1 0 0 1 1455.3204 327.4186 cm +0 0 m +25.188 1.677 l +29.826 1.985 33.835 -1.523 34.144 -6.16 c +35.82 -31.349 l +36.129 -35.986 32.62 -39.995 27.983 -40.304 c +2.795 -41.981 l +-1.842 -42.289 -5.852 -38.781 -6.16 -34.143 c +-7.837 -8.955 l +-8.146 -4.318 -4.637 -0.309 0 0 c +f +Q + endstream endobj 910 0 obj <>/ExtGState<>/Font<>/ProcSet[/PDF/Text]>>/Subtype/Form>>stream +BT +/CS0 cs 1 1 1 scn +/GS0 gs +/T1_0 1 Tf +0 Tc 0 Tw 0 Ts 100 Tz 0 Tr 26 0 0 26 1379.1553 682.0497 Tm +(shake)Tj +ET + endstream endobj 911 0 obj <>/ExtGState<>>>/Subtype/Form>>stream +/CS0 cs 0.137 0.122 0.125 scn +/GS0 gs +q 1 0 0 1 1492.5216 692.3195 cm +0 0 m +0.005 -0.954 -0.374 -1.87 -1.049 -2.543 c +-6.845 -8.338 l +-8.257 -9.738 -10.533 -9.738 -11.945 -8.338 c +-17.726 -2.543 l +-18.406 -1.871 -18.789 -0.956 -18.79 0 c +-18.787 0.957 -18.411 1.875 -17.74 2.558 c +-17.312 2.912 -16.676 3.607 -9.388 3.607 c +-2.099 3.607 -1.419 2.927 -1.049 2.558 c +-0.374 1.878 0.004 0.958 0 0 c +f +Q + endstream endobj 912 0 obj <>/ExtGState<>/Font<>/ProcSet[/PDF/Text]>>/Subtype/Form>>stream +BT +/CS0 cs 1 1 1 scn +/GS0 gs +/T1_0 1 Tf +0 Tc 0 Tw 0 Ts 100 Tz 0 Tr 25.9425 1.7269 -1.7269 25.9425 1218.8367 556.2019 Tm +(show\037leds)Tj +ET + endstream endobj 913 0 obj <>/ExtGState<>>>/Subtype/Form>>stream +/CS0 cs 0 0 0 scn +/GS0 gs +q 1 0 0 1 1226.965 514.6168 cm +0 0 m +25.188 1.677 l +29.826 1.985 33.835 -1.523 34.144 -6.16 c +35.82 -31.349 l +36.129 -35.986 32.62 -39.995 27.983 -40.304 c +2.795 -41.981 l +-1.842 -42.289 -5.852 -38.781 -6.16 -34.143 c +-7.837 -8.955 l +-8.146 -4.318 -4.637 -0.309 0 0 c +f +Q + endstream endobj 914 0 obj <>/ExtGState<>>>/Subtype/Form>>stream +/CS0 cs 0 0 0 scn +/GS0 gs +q 1 0 0 1 1237.026 363.4865 cm +0 0 m +25.188 1.677 l +29.826 1.985 33.835 -1.523 34.144 -6.16 c +35.82 -31.349 l +36.129 -35.986 32.62 -39.995 27.983 -40.304 c +2.795 -41.981 l +-1.842 -42.289 -5.852 -38.781 -6.16 -34.143 c +-7.837 -8.955 l +-8.146 -4.318 -4.637 -0.309 0 0 c +f +Q + endstream endobj 915 0 obj <>/ExtGState<>>>/Subtype/Form>>stream +/CS0 cs 0 0 0 scn +/GS0 gs +q 1 0 0 1 1240.3795 313.1097 cm +0 0 m +25.188 1.677 l +29.826 1.986 33.835 -1.523 34.144 -6.16 c +35.82 -31.349 l +36.129 -35.986 32.62 -39.995 27.983 -40.304 c +2.795 -41.981 l +-1.842 -42.289 -5.852 -38.78 -6.16 -34.143 c +-7.837 -8.955 l +-8.146 -4.318 -4.637 -0.309 0 0 c +f +Q + endstream endobj 916 0 obj <>/ExtGState<>>>/Subtype/Form>>stream +/CS0 cs 0 0 0 scn +/GS0 gs +q 1 0 0 1 1294.1149 316.687 cm +0 0 m +25.188 1.677 l +29.826 1.985 33.835 -1.523 34.144 -6.16 c +35.82 -31.349 l +36.129 -35.986 32.62 -39.995 27.983 -40.304 c +2.795 -41.981 l +-1.842 -42.289 -5.852 -38.781 -6.16 -34.143 c +-7.837 -8.955 l +-8.146 -4.318 -4.637 -0.309 0 0 c +f +Q + endstream endobj 917 0 obj <>/ExtGState<>>>/Subtype/Form>>stream +/CS0 cs 0 0 0 scn +/GS0 gs +q 1 0 0 1 1334.4357 521.7712 cm +0 0 m +25.188 1.677 l +29.825 1.986 33.834 -1.523 34.144 -6.16 c +35.82 -31.349 l +36.129 -35.986 32.62 -39.995 27.983 -40.304 c +2.794 -41.981 l +-1.842 -42.289 -5.852 -38.781 -6.161 -34.143 c +-7.837 -8.955 l +-8.146 -4.318 -4.637 -0.309 0 0 c +f +Q + endstream endobj 935 0 obj <> endobj 898 0 obj <> endobj 896 0 obj [/ICCBased 936 0 R] endobj 936 0 obj <>stream +HyTSwoɞc [5laQIBHADED2mtFOE.c}08׎8GNg9w߽'0 ֠Jb  + 2y.-;!KZ ^i"L0- @8(r;q7Ly&Qq4j|9 +V)gB0iW8#8wթ8_٥ʨQQj@&A)/g>'Kt;\ ӥ$պFZUn(4T%)뫔0C&Zi8bxEB;Pӓ̹A om?W= +x-[0}y)7ta>jT7@tܛ`q2ʀ&6ZLĄ?_yxg)˔zçLU*uSkSeO4?׸c. R ߁-25 S>ӣVd`rn~Y&+`;A4 A9=-tl`;~p Gp| [`L`< "A YA+Cb(R,*T2B- +ꇆnQt}MA0alSx k&^>0|>_',G!"F$H:R!zFQd?r 9\A&G rQ hE]a4zBgE#H *B=0HIpp0MxJ$D1D, VĭKĻYdE"EI2EBGt4MzNr!YK ?%_&#(0J:EAiQ(()ӔWT6U@P+!~mD eԴ!hӦh/']B/ҏӿ?a0nhF!X8܌kc&5S6lIa2cKMA!E#ƒdV(kel }}Cq9 +N')].uJr + wG xR^[oƜchg`>b$*~ :Eb~,m,-ݖ,Y¬*6X[ݱF=3뭷Y~dó ti zf6~`{v.Ng#{}}jc1X6fm;'_9 r:8q:˜O:ϸ8uJqnv=MmR 4 +n3ܣkGݯz=[==<=GTB(/S,]6*-W:#7*e^YDY}UjAyT`#D="b{ų+ʯ:!kJ4Gmt}uC%K7YVfFY .=b?SƕƩȺy چ k5%4m7lqlioZlG+Zz͹mzy]?uuw|"űNwW&e֥ﺱ*|j5kyݭǯg^ykEklD_p߶7Dmo꿻1ml{Mś nLl<9O[$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! +zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Km endstream endobj 934 0 obj <> endobj 933 0 obj <> endobj 932 0 obj <> endobj 931 0 obj <> endobj 930 0 obj <> endobj 884 0 obj <> endobj 937 0 obj <> endobj 938 0 obj <> endobj 939 0 obj <>stream +H{PW7}1( +A#bK5J!c(IAR;u|uvt2N{6Q uW_w~|L.$Iٚ)Q'h&A% +"}y[5/+*69~R L&PkLElan|llبnfQA%#\Zi97S]yKuWe.Ģ!ߨr<#rfb5WEYí)䛸ya9ܬxOx[ĸDMoӉb\L< ,K’la$۱qw**^>i[\*?.WU߽C.?.۬>lmIX.zIT@ +)=@Zwt=޾;%cgmHN̊ZAiË)f4f:5O C+3t{tTPȌ]`q&dZtLaFY<~Uϟu^S:k+f_oq5;})^OG.N/%w'ggP^Ύ 00[ Zk\+b`i-{x4k8|>l*|Š{-豯6:>:DC3G0V4d9͞2%`aO{~_"1h6nib|V$zyH将H5ZbA0u"PQUQU^>Ly|6Co>aδ9Ϋ]3 +6!&%!ށ.tPϟ9xsmTmB9J~ע`Qrcb.e'774;rNi>cɵILtx6לg(,{ȥ&EW_M(M{ <)$y^pB؇1Ch"q} +ZOvtMOw-p^׻<4RY%usޜ ^t_`MMPσ:M+`c^dmA(,ĠIHApv f")Q\;"NCh>vVK+ApBu9cmKnJ&hթR̛拢AU|BDh|LyjP'1q'KF7Z:j+H],hD}HƠ4d'ƎRڿȽLݼehݶ[=o:i(nzˮ%M%6c}v$f"[~zĮ7˄UBs%v|8(N#3wN:qTIx``VSat+o$U+ 0 endstream endobj 929 0 obj <> endobj 928 0 obj <> endobj 927 0 obj <> endobj 926 0 obj <> endobj 925 0 obj <> endobj 924 0 obj <> endobj 923 0 obj <> endobj 922 0 obj <> endobj 902 0 obj <> endobj 903 0 obj <> endobj 941 0 obj <> endobj 942 0 obj <> endobj 943 0 obj <> endobj 944 0 obj <> endobj 940 0 obj <> endobj 945 0 obj <> endobj 886 0 obj <> endobj 887 0 obj <> endobj 888 0 obj <> endobj 889 0 obj <> endobj 890 0 obj <> endobj 891 0 obj <> endobj 956 0 obj [/View/Design] endobj 957 0 obj <>>> endobj 954 0 obj [/View/Design] endobj 955 0 obj <>>> endobj 952 0 obj [/View/Design] endobj 953 0 obj <>>> endobj 950 0 obj [/View/Design] endobj 951 0 obj <>>> endobj 948 0 obj [/View/Design] endobj 949 0 obj <>>> endobj 946 0 obj [/View/Design] endobj 947 0 obj <>>> endobj 901 0 obj <> endobj 885 0 obj <> endobj 958 0 obj <> endobj 959 0 obj <>stream +HiTTG}<lu ~[Pc5(hܐEZdAqP%4cqL FpØAA38qkj ̙zު{om{n+c@𰙯 3ȘWGHA1RptYoN^i\$;Z\ +S`wtw\R.K (H:ۅIQk;5\ˢb}qԖlY>qƓv%D@o};k.Tp Za|s|LU`pw g\ ȹ!5@zpv8D3 > +E\)fybW >&$,"'tLvzGLd}CʔθZ\[efqkX4s=w믝ݥ===m:<{{yuuU:>S~gJ/EWB9\ePYQ*JҪa{p;o/C\'|&zab.p}bxpI6>u:Fѭ]zV cz)\p56f֤1k͜mGu7U-Жtֶ{zU@[lKPz+2I bHRPN*WC +:Dl#d5U-PK^}maa>g[QH%/Vq8H6]l8R4t]gztam-6v-=jlǯ~:p[:xS#_5?LH~b@m\ 4d;<Ԥ6p֛֟z~_7BG? S }6Q.܍p^s#K8l5Xo.)m\s'E +Ft|])\#xv},&perg9Eky ߤz Or`0vȇ`?DȆB.E a .Ű?+| 8A4{B,*<\`.Z} .Ï-pB<,HDX%`HVB*wS3tHW2!߷8')2hvp2N;8PBtE8 Cq:a8t'xOq&?lo\~#pFbF3qbE3.Aq{`O Oh&b.C &c +F/8_EQT\  `E h~ +WLt\p=z }30pnl?MCC0;9BA _פ|Co?;Re'9IN "g9r^Ɛ "&2DNnc܄ṾD}/::Fb}o@G:#[(!H\8HGQ4RC:B=H't +JP:pi,aRd&tWjZ{wr|L^>.W')|FxNCw<:. ipA+Ul5[X:[ֱ,e,md,mbl3¶<\:ٻl +{}]l7܀w A-}>b{Kq}\q}}>|/M6Yٻn{e=3KRBY#8i){t?H*?x޼Wj^É?u7FNMmbf66-lKʶmllG45—~ap@806!pX8< _G1p\8>|%|5N _'ooo)}v]lWv/ll/ Vȃx0</(cx|%_qZA+ii-6RU 6&L[%xmAFA;)*.M{(>O *tPUFGS>/K:F_tԡtS :E54tHl_cvLW*]&ntI-0))gʛ +)a*l&T3յ0r6fS4f[vf`1Yfgrv0999ƹ87Ἔss6GQ rx6/̗\s .ɥ4?]nr\rW৸"W\r55&\ ?9nNpCnč 7f͹V޳ rJN9+ܑ;qg]w^ܛy RavѮM C{5%u@u}d{ %!Y-6V:B _EM}qX8EvG9C.FE>GD!<((l-J$J4DE9G<ʨꨁ:xoI;i/d70JFUw]p%w]qW5wPD sxǏ4{x=0 s0Q aV`5֢!֣ ؊m؎H" @D&v# ppsp)94y\e\u$&n?G_qwpm\VI $%YIIz4_Phdt\Bbjfnhsфh+{a?Cc.p䌋eo͢4< /?2 202(282$242,2<2"22GEFGD?+W#h>-0Md6-&Yc hDCͦV;#h3 RVl: +҃0- R +ZJKZFj9-R=zڱwik▸En[>v +ҭrR[ֻ nKrf%nR{ʞg؞種=o/؋Re/+f.&ǦdȞK4`i `]@>M5:A֓F|l|'?Q~U~rGj#mM.!Oy(i3MB[O@=9Y:[\|] u.#]Ku~uUZh&Vݦ5EwhifM? s梨4|cu,`=a߀S> q&.s ̸ѕXߏ+m~vlsb_~zh5~;$,4{?Q?>8?W:p ^K qu5K5!Ioѿ[pJve,]FA Dt复dF6I'}}Ah +=&$~$ah¤I;Mڸ%'ZH CڦX깻6M#ݻs!oyxrcK.A +RQy!;e\!eAe\){eLYb߳)C, +!JᗘKy$ _,~ED +zQ&˄Qׅ_b4ik3o +d8++}bY%AFwd5YVGΓ8#D6E +?.npU\D c>)b|\xq|B' _HFDPA\->Q9\lO'ؘɾV/oCɏ\xőTWTs6BVI V_,-SRsS\gR}gY}tpk-d0e VVexk9[ &3aM^q+|?jpBtt8;OVn%vA۞m#hX'$0<͝-XfVPc9[p~3g} v=e~(;#SxzЯ7?|ΧA7$P_XR(~P~)BoNJ{]v:u35zuw?=B'WQ|& ++o}{/]|_/d#[-MD7i޸w]U+C+/]8H_w,?O[3Jf# + +sSԈкhz.vmkBJ5+H:Ikڍ$4a6"}/3T͔AJkaIy îPUkl!z?l=F<'ċuѺ [hq&b&"#aR~JCy4m=۲R%T-ct,l#+uVvthMP~N#SS>jl+c8NO9?1QKOv^+wn; #kuԯ8'ҦՄ63ݽ*f5U+9ğThb(Et[FfLyj.c'f] +*;r)YU͋IQ, cVPfal30,:.\aH]%7彎74C aszc viF)Sj12ebyZG[]Sٔ*u]ҿnt0%sWG —F`#OW2`4%]=S)H]QcDiJCA5EOr,wBD&fx\jtǜ0'GwMVn#x=旫tv׬Vԁ%E9ZS|LUCybhj\1cS5@J.KXCRrkmNwJлid@]ZmVJQjaWNb_6/{!hHO~AVޠ2urK UnaJOXCFl摯*Myߑpz8s|4)_4 +<2$lIw; r"ۢ:-5 e}ü8qNp5 Y7\;nts'8\. ѪuQ|4Z(kr@gy?>yن;W:AHp@TsUcc\h 7[+*kVW]ۨ:$M9n~yO|Vak3/Ӿs8qώ?1"u/oN &'ݜOlăIgEu]s߽o ._*AݖVu n5~`!ER 1N$D8bQǪVX8M;NXqa"w4v}νxi-*>ϯɟڜu- Z\wo|7︞HiHHjEw&)~⻙zg +s8#w𿪘egk"*\Ў.]4D+.RM]X=3jV}v5&izkJ޺%/ƫ5L W;6ZTs^Xix?HҲ@arKzS2%!cӅ7]vN|*3)iu!p4ؑz9Ha6sx-JhEwv/9ݝ&>ʐ6\ll+ /-ܳJh_}॒%7, @EaesiKQ*%KN0v2_1mhAR8~l?~p'yb` 4OB|'#x<'4U PrK/ ^Ѫ= +=:ٟE5|Z:ZkEpiΪ-uIӯƊF%bpt +,-5 WR4i6P)).FTMͮ3,@\F`dͺNwQ=ń@ +NGG,CO08f8.LqdgqWXtCCb^_(2j +7j^b(K`h ta̜rDG8&6ib6)kf:逗[BW12F$"oq +g*NNפa5xsfp{SóbFSM0x=AG9ǃ`Н-rr]lO$r>=pi8cB8vv{H5xy<~w>>8?oM6b|d(IGDGʴ~VatX42d+kfդl\d>)B"b \'N$~RHo|<ςЃ:&39|bgR2^Z0xEfI_G0!7>Oj^os_5y88" >e~ҧ݄p)MsVtJ喟PFi,SHD/J 3_ar&X< "V [y({N۬]tDJɪzZ^yzx^ NTKV/Ɔb*.@[C5HFJWg`uv8 _n +`L*1nyiTdwPށ,|Eܯcxևkhv<-RG˿Qo~Jmbnd13c!6S؅I|OR|u釪xg$1: R6vrڬ7- X--Taiİ3j?{Ü^~}UȍK?TggO!8U(WMFX@\V/:X=Sιǽه}kTŦ6 0o*1=Tnsl&}xw8WQcmh ֚Dbi%T!ȧuP@p Bn`OfͲnXj`j>nbYgD[] +.X53kԣ }z?} U10~Xsk@#.5f=P\hE#uV[Qjyz>lK7"ͺF}FQGף>CEZfzeͦ2%-/O,O5|޲6|E_>ieO 7t'@ ;@YfBMỹyO5S;p*tBܯ>Xr1<@QEe0.EKai};n83ϒNVX%+07i~8rw`5z+%{~U}P=Ƚ6x0my ig6k ~I6*Wѩ*&gI/Ъ;޽hJqUs*I(Y` )6JWlfqu.8 Y&KSmK$XA?RE$Ijs{K1e=s~}n7jURhT$.8>i)I]d?s({ǺEnZy->oMEG٧G%ab;t9v@uM2$9=\AnyKژ;ΈgYCV.l">".G_}o%mPN;G[I875s-I伅8p':k6 Av!k b;S6_6τ&[=_k G,5V'̓XOoI؜rg(g,o΃p#u&F08sQ~>`TfwwhǙw=(Th\0o 0Oϴ<="#!3 +΀rb.2~eY_Exu>nF쳛?k0g-x.[X$ì;7cI{(̗sП +N;(gcl~ObT-p\V W,)՝<8@YL-S` G)sOjgѢ|.25FE7y~-1@{lfTɂ5+#y.P~5οq7i3}o|S}٭boEsNbGkTu%MCuF :λ)= Cat|?+p1x=)Q4]B%<C'#&=Q\?4sa^w[ǴϱEt߯YՂ6kӏZ")[7bMs;DqPȯu!}Ԣ#ʢ?U}D&MޢCw5bQq/f^yo$1wD[!QT{s x>\bN#o:qO,;Xv6>s~:䍫7aL[ɞAA,W1rjXse4cPqk81l"je?%KB|Ik<^jVGA-k+9,> P8[4,KܯŚMK65Zɥxl(\V[aeܳO1!l`}h${w|w:$rr 1>om`kTwR~ ?^eXER[[z.mƵbkIL\;,_ᅭ]ڦ׈uo^|.xSw;am ?{<f>5${1leMY1#+)./0d=K,x4å}UgXztNrv*|\c߯GT]3ws}J9K}/^)i" ΂ZCEk +\bQ® +mKHISBk +93M543Nڼ9cSUn&NcZTEm_fKЫ(].Y1/q;VK?uIy)!Eph]aDߵK/޴ss#M?4'inBa@7朑qr.jWdt38ij{ + tiײ1ͦ< DV sYZbj &nY O5\^|fō:q<_>D3sجgzhmJ:J)0i൒k]{m`ZQ:QvN=FZ>SJݺ+Mu:ؗԼh5L-7u'hi`>xǜ:Pҝwb'hC靠Cc RcQ؏d;~ob9 ԧԃQRJJ/ɼ\DLYȻ ^(͉cVu$YVM}]VA,}OV,zcRþj' +ZyLLMs6H_/T"38'k-㩷ԯsך\0Y5x,]="wT4vػYzjT~̛RUIT +ݷV3S^vn}΋Rh>3W6h[@1A*dYIT٬nBVyewLfVO;~3\y 2ɡw#'B2*WQ8TX*zD\03O+q^ f?_l?%xWџQ1#el ]SeZ  zi>"p!D4>#߅:}dO33a;Y)e"V#+m!PiJ\'O4XY*JfI. G@"[Ǜ'%d24B=qVϑC:"yr Ѱ3 <&3Tץ2w8Gצ6+[F1Tfo $q2o>48cc9C#x"݊̓Aگʷrǃ^v.F.Qo/ΞG0/ꏧq,V x8#۰I?ɴ#geyZmgmA}dY_}gKeK[' (9/x.TyGU'ᗅ/wx_]ovH-gn Ă1%#'UmsOݐ%U'ArG6Rs.7MGF<s?+?-ПljG`6w`80Qyywi^FAuye`k&7+r` 0,/ݓ.0v5Rx`ܢsk'?)). 9 +I:eY| +t$xytZ=ĺ\##[Euo%{-bp뾊b2;%:fpZP&=S u1} ݷA튌rݯ9~q|xQho@YdrX{i -{y*;8bug=xc\mOZՌezFyVM~ߝ2bR 2B=Rݑ'"Q|3lh_| +iא>fcJ;AN0p7zطP}mY}*4ǩt/yH:QZx$Oa_$ּ>зkN7=hۣ;]2+콿N&j)C?*yZ26LtWqc܃8ۻgO4D(jL̥@1irU֦(R##(W PQD%$h&&Ө1:FTl2Dh$8*jblMݕ+Q0|ys~ wP4U|̎R'3b<|mǜ7AS=p^y[j2r\R%lC2y]ݹE~!7j;~RVjz^cm|6>M[gi"c۾Mپ9Oqe9yX# iie5z"4o~:Zmk;us=`ޖkmݚjuDgZ'u"ݶ ?ӷ[ Wuvi^Ϯs~Yϱ,9?D[ḀٶqOgmsc1Ͳ]ɣ>t;YA Z]|L&JQ0k0{áܬ!`R V sʰEXӢYߺأ"ށOR0y.bB"q9;p2I%+a`7݈o-e F2.y4ĝeܻ؛4gk}%SLzwǴXVkח^CGZjM`9 怽%G0T>#%_Nõ(~~T"gN2|`Y-ߢr %Q@z%;b&8m=U MP~~TJT>VσoPe2kDٟ(Js9'Q32~8Z▧ZG;z"m׾E;-alݐП.ֱ*: XhC*tH +_@ Az :\"7@O`Caw~ F8c FjloT֏jCL5l oK5'qWX韰(]O̧rc\?ҵowf}֡`$?|]7p8~=~Lrc`6XHxLA}أ26;}:5:fF6ߚQ+| 4H3>3On_pg_]$<'yUƳg +JՅWt]u:Q kRN \o1ݽ#P@C0KKD|tƂ`*xlr{_wE>msM}RRvK{l*ͻ|,x3ek-#p;9("jm5G(%gEjx@<1bPm.3.ڌȻցF6|#Vۖ綾 +'D  +m%E9}qķk* S)TOVC>;ԣCi*pV~ uo0-LQk /ód]Y~SI|ۖ/i՞zk+0-b15 gW}@Ki?b:QmrL>&^ 1vmf!,X?so7tԯ:cI!o"%rG{wpw>B"H$D"H$D"H$D"H$D"H$D"H$D"H$D"H$D"H$ZO($'9(bK.?GRHPg{X/ +G*|K,߁:-_Eg[Tt{*51eD+śUMQ6PQ, ANET@` o$"*xᔇ,FYHya]Dͧ()F`]MѢv [֖83@M&rgsgKE;EHb5ag"53N?i*;%~_eLe{#*Nb.@BZ#9sV #tdIB{pi`_<?zdve`_VY+-WRGY@f@}B_pq଑ς'ܯ&f(FSɡu}Jhk.nǽǮԇĝ0;ʗkXK1ݣ"52 { 5a~u M+a#M;anbL0O@\4EE=M!Ȟa~ؿsr#(+6 ܙgp v\_UB}A>br|USJI6)JT)R%֤KZ:g7*j*];337;xi AVϮ ܸB;:AmiW/_Y=4. aPh|8O.QWVioِ_}hώ{*\| +YJ V5k{(fs7(yJT>g)&]D%ݝC; 6Ҍ+͚3oڭNש,7Q*0+ Ysk_˖*p[ C\jj>=˞灳uuҲ/[By>uUnnHN,g,&-h ңzD VnURݝԡ*kS8Leix }tR1?$~!^H>$ \dI%2K~R^܍xɿ/A9K}a'D3a+@Mʑ;p+WbxL +:鳝v:/&t0E`:F|*~ܥnW+dU&3F@TQE<&}&(h=$*J1pyO |AW=zެ7qAU=+[tQgz{̑{?<1`ws ]ܴh1b؈Z,4_ʌڙ^lP%m/1yQ{vrjǘiwhGbmQ{y1eNڭLd<ɓdž +PQI 5$sYUE=+ړLϼLj4GFߘy;G*Z}*snӮ&&F) R@ #9$2~28LtDJȄ 0^]wg>į.x o [9^+\% agqV6]8CB endstream endobj 899 0 obj <> endobj 900 0 obj <> endobj 897 0 obj [/Pattern] endobj 895 0 obj <> endobj 960 0 obj <> endobj 961 0 obj <>stream +%!PS-Adobe-3.0 %%Creator: Adobe Illustrator(R) 17.0 %%AI8_CreatorVersion: 22.1.0 %%For: (Danny Schlitz) () %%Title: (Microbit_Hero_Illustration_07_revised.ai) %%CreationDate: 11/8/18 4:48 PM %%Canvassize: 16383 %%BoundingBox: -4203 5607 -1267 6846 %%HiResBoundingBox: -4202.2640275724 5607.51919553277 -1267.0201384211 6845.00846103516 %%DocumentProcessColors: Cyan Magenta Yellow Black %AI5_FileFormat 13.0 %AI12_BuildNumber: 312 %AI3_ColorUsage: Color %AI7_ImageSettings: 0 %%RGBProcessColor: 0 0.470588237047195 0.843137264251709 (Blue 0-120-215) %%+ 0.250980406999588 0.603921592235565 0.882352948188782 (Blue-HL 64-154-225) %%+ 0 0.394050002098084 0.709999978542328 (Blue-MT 0-100-181) %%+ 0 0.28125 0.5 (Blue-SD 0-72-128) %%+ 0.224209159612656 0.389239758253098 0.639999985694885 (Dk Blue-HL 57-99-163) %%+ 0.17501437664032 0.239994987845421 0.529999971389771 (Dk Blue-MT 45-61-135) %%+ 0.131999999284744 0.600000023841858 0.307500004768372 (Dk Green-HL 34-153-78) %%+ 0.529999971389771 0.100699998438358 0.100699998438358 (Dk Red-MT 128-24-24) %%+ 0.136399999260902 0.421316921710968 0.439999997615814 (Dk Teal-MT 35-107-112) %%+ 0.062745101749897 0.486274510622025 0.062745101749897 (Green 16-124-16) %%+ 0.470588237047195 0.772458553314209 0.470588237047195 (Green-HL 120-197-120) %%+ 0.219607844948769 0.631806135177612 0.219607844948769 (Green-MT 56-161-56) %%+ 0.952941179275513 0.952941179275513 0.952941179275513 (Illus Gray 1 243-243-243) %%+ 0.901960790157318 0.901960790157318 0.901960790157318 (Illus Gray 2 230-230-230) %%+ 0.823529422283173 0.823529422283173 0.823529422283173 (Illus Gray 3 210-210-210) %%+ 0.760784327983856 0.760784327983856 0.760784327983856 (Illus Gray 4 194-194-194) %%+ 0.69803923368454 0.69803923368454 0.69803923368454 (Illus Gray 5 178-178-178) %%+ 0.576470613479614 0.576470613479614 0.576470613479614 (Illus Gray 6 147-147-147) %%+ 0.450980395078659 0.450980395078659 0.450980395078659 (Illus Gray 7 115-115-115) %%+ 0.313725501298904 0.313725501298904 0.313725501298904 (Illus Gray 8 80-80-80) %%+ 0.156862750649452 0.156862750649452 0.156862750649452 (Illus Gray 9 40-40-40) %%+ 0 0.737254917621613 0.949019610881805 (Lt Blue 0-188-242) %%+ 0.250980406999588 0.803921580314636 0.960784316062927 (Lt Blue-HL 64-205-245) %%+ 0.729411780834198 0.847058832645416 0.039215687662363 (Lt Green 186-216-10) %%+ 0.844336271286011 0.939999997615814 0.295309752225876 (Lt Green-HL 215-240-75) %%+ 0.917647063732147 0.250980406999588 0.662745118141174 (Lt Magenta-HL 234-64-169) %%+ 1 0.549019634723663 0 (Lt Orange 255-140-0) %%+ 1 0.662745118141174 0.250980406999588 (Lt Orange-HL 255-169-64) %%+ 0.941176474094391 0.517647087574005 0 (Lt Orange-MT 240-132-0) %%+ 0 0.69803923368454 0.580392181873322 (Lt Teal 0-178-148) %%+ 0.250980406999588 0.772549033164978 0.686274528503418 (Lt Teal-HL 64-197-175) %%+ 0 0.550000011920929 0.455521494150162 (Lt Teal-MT 0-140-116) %%+ 0 0.431372553110123 0.356740713119507 (Lt Teal-SD 0-110-91) %%+ 1 0.945098042488098 0 (Lt Yellow 255-241-0) %%+ 1 0.972549021244049 0.501960813999176 (Lt Yellow-HL 255-248-128) %%+ 0.780392169952393 0.250980406999588 0.713725507259369 (Magenta-HL 199-64-182) %%+ 0.620000004768372 0 0.544848501682282 (Magenta-MT 158-0-139) %%+ 0.184799998998642 0.375029444694519 0.879999995231628 (Mid Blue-HL 47-96-224) %%+ 0.127800017595291 0.223317205905914 0.709999978542328 (Mid Blue-MT 33-57-181) %%+ 0.847058832645416 0.23137255012989 0.003921568859369 (Orange 216-59-1) %%+ 0.886274516582489 0.423529416322708 0.254901975393295 (Orange-HL 226-108-65) %%+ 0.740000009536743 0.210603997111321 0.014800000935793 (Orange-MT 189-54-4) %%+ 0.360784322023392 0.176470592617989 0.5686274766922 (Purple 92-45-145) %%+ 0.645780384540558 0.475838124752045 0.839999973773956 (Purple-HL 165-121-214) %%+ 0.909803926944733 0.066666670143604 0.137254908680916 (Red 232-17-35) %%+ 0.933333337306976 0.301960796117783 0.352941185235977 (Red-HL 238-77-90) %%+ 0.730000019073486 0.053824886679649 0.111013829708099 (Red-MT 217-16-33) %%+ 0.721568644046784 0.592156887054443 0.486274510622025 (Skin4 MT 184-151-124) %%+ 0.847058832645416 0.690196096897125 0.498039215803146 (Skin5 HL 216-176-127) %%+ 0.729411780834198 0.549019634723663 0.341176480054855 (Skin5 MT 186-140-87) %%+ 0.705882370471954 0.560784339904785 0.458823531866074 (Skin7 HL 180-143-117) %%+ 0.439215689897537 0.26274511218071 0.133333340287209 (Skin7 MT 112-67-34) %%+ 0.329411774873734 0.196078434586525 0.090196080505848 (Skin7 SD 84-50-23) %%+ 0.18823529779911 0.113725490868092 0.098039217293262 (Skin9 SD 48-29-25) %%+ 0.847058832645416 0.690196096897125 0.580392181873322 (Skintone4 216-176-148) %%+ 0.807843148708344 0.61176472902298 0.372549027204514 (Skintone5 206-156-95) %%+ 0.556862771511078 0.337254911661148 0.180392161011696 (Skintone7 142-86-46) %%+ 0 0.509803950786591 0.447058826684952 (Teal 0-130-114) %%+ 0.250980406999588 0.631372570991516 0.584313750267029 (Teal-HL 64-161-149) %%+ 0 0.319999992847443 0.281043469905853 (Teal-MT 0-82-72) %%+ 1 1 1 (White) %%+ 1 0.725490212440491 0 (Yellow 255-185-0) %%+ 1 0.796078443527222 0.250980406999588 (Yellow-HL 255-203-64) %%+ 0.899999976158142 0.652500033378601 0 (Yellow-MT 240-174-0) %%+ 0.769999980926514 0.549447238445282 0 (Yellow-SD 199-142-0) %%+ 0 0 0 ([Registration]) %AI3_Cropmarks: -4149.18863874597 5919.49432762729 -1321.18863874597 6696.49432762729 %AI3_TemplateBox: 960.5 -540.5 960.5 -540.5 %AI3_TileBox: -3113.18863874597 6019.99432762729 -2379.18863874597 6595.99432762729 %AI3_DocumentPreview: None %AI5_ArtSize: 14400 14400 %AI5_RulerUnits: 6 %AI9_ColorModel: 1 %AI5_ArtFlags: 0 0 0 1 0 0 1 0 0 %AI5_TargetResolution: 800 %AI5_NumLayers: 6 %AI17_Begin_Content_if_version_gt:17 1 %AI9_OpenToView: -4239.70087008701 7236.95859585959 0.3333 1428 851 18 1 0 6 43 0 0 0 0 1 0 1 1 0 1 %AI17_Alternate_Content %AI9_OpenToView: -4239.70087008701 7236.95859585959 0.3333 1428 851 18 1 0 6 43 0 0 0 0 1 0 1 1 0 1 %AI17_End_Versioned_Content %AI5_OpenViewLayers: 733333 %%PageOrigin:0 0 %AI7_GridSettings: 20 1 20 1 0 0 0.800000011920929 0.800000011920929 0.800000011920929 0.899999976158142 0.899999976158142 0.899999976158142 %AI9_Flatten: 1 %AI12_CMSettings: 00.MS %%EndComments endstream endobj 962 0 obj <>stream +%%BoundingBox: -4203 5607 -1267 6846 %%HiResBoundingBox: -4202.2640275724 5607.51919553277 -1267.0201384211 6845.00846103516 %AI7_Thumbnail: 128 56 8 %%BeginData: 11564 Hex Bytes %0000330000660000990000CC0033000033330033660033990033CC0033FF %0066000066330066660066990066CC0066FF009900009933009966009999 %0099CC0099FF00CC0000CC3300CC6600CC9900CCCC00CCFF00FF3300FF66 %00FF9900FFCC3300003300333300663300993300CC3300FF333300333333 %3333663333993333CC3333FF3366003366333366663366993366CC3366FF %3399003399333399663399993399CC3399FF33CC0033CC3333CC6633CC99 %33CCCC33CCFF33FF0033FF3333FF6633FF9933FFCC33FFFF660000660033 %6600666600996600CC6600FF6633006633336633666633996633CC6633FF %6666006666336666666666996666CC6666FF669900669933669966669999 %6699CC6699FF66CC0066CC3366CC6666CC9966CCCC66CCFF66FF0066FF33 %66FF6666FF9966FFCC66FFFF9900009900339900669900999900CC9900FF %9933009933339933669933999933CC9933FF996600996633996666996699 %9966CC9966FF9999009999339999669999999999CC9999FF99CC0099CC33 %99CC6699CC9999CCCC99CCFF99FF0099FF3399FF6699FF9999FFCC99FFFF %CC0000CC0033CC0066CC0099CC00CCCC00FFCC3300CC3333CC3366CC3399 %CC33CCCC33FFCC6600CC6633CC6666CC6699CC66CCCC66FFCC9900CC9933 %CC9966CC9999CC99CCCC99FFCCCC00CCCC33CCCC66CCCC99CCCCCCCCCCFF %CCFF00CCFF33CCFF66CCFF99CCFFCCCCFFFFFF0033FF0066FF0099FF00CC %FF3300FF3333FF3366FF3399FF33CCFF33FFFF6600FF6633FF6666FF6699 %FF66CCFF66FFFF9900FF9933FF9966FF9999FF99CCFF99FFFFCC00FFCC33 %FFCC66FFCC99FFCCCCFFCCFFFFFF33FFFF66FFFF99FFFFCC110000001100 %000011111111220000002200000022222222440000004400000044444444 %550000005500000055555555770000007700000077777777880000008800 %000088888888AA000000AA000000AAAAAAAABB000000BB000000BBBBBBBB %DD000000DD000000DDDDDDDDEE000000EE000000EEEEEEEE0000000000FF %00FF0000FFFFFF0000FF00FFFFFF00FFFFFF %524C45FD92FFA8FFA8FDFCFFFFA8FFA8FDEDFFA8AFA8AFA8FFA8AFA8AFA8 %AFA8AFA8FFA8FFA8AFA8AFA8AFA8AFA8AFA8AFA8AFA8FFA8AFA8FFA8AFA8 %FFA8AFA8FFA8AFA8FFA8AFA8FFA8AFA8FFA8AFA8FFA8AFA8FFA8AFA8FFA8 %AFA8FFA8AFA8FFA8AFA8FFA8AFA8FFA8AFA8FFA8AFA8FFA8AFA8FFA8AFA8 %FFA8AFA8FFA8AFA8FFA8AFA8FFA8FFA8FFA8FFA8FFA8FFA9FFFFA85F5960 %595F5960595F5960595F3560FD04FF595F5960595F5960595F355F355F59 %60355F5960355F5960355F5960355F5960355F5960355F5960355F596059 %5F5960595F5960595F5960595F355F595F5960595F5960595F595F595F59 %60595F5960595F595F595F5960595F3560595F595F595F5960595F355F59 %FFFFFFAF355F345F355F345F355F345F355935FFA0C9A85F355F345F3559 %345F355F835F3459355F345F355F3459355F3459355F3459355F3459355F %343B355F343B355F343B355F3435355F3435355F3559345F355F355F3435 %355F355F345F355F355F3435355F355F345F355F355F3535345F355F345F %355F355F3535345FA8FFFFA85F595F595F595F595F595F595F3560FFC8C9 %FF595F5960595F595F3584FFFF5F5F595F595F5960595F595F595F596059 %5F595F595F5960595F595F595F595F595F595F595F5960595F355F595F35 %5F355F5960595F355F595F595F355F5960595F355F595F595F355F356059 %5F355F595F595F355F35605F5F355F59FFFFFFAF355F355F355F355F355F %355F355F35FFFFFFA85F355F355F35593560FFA92F36595F355F595F355F %595F355F595F355F595F355F595F355F7796719C717271967172719C595F %355F3559355F355F355F3559355F3559345F355F345F3535355F3435355F %355F355F3559355F3559355F355F355F3559355F3559345FA8FFFFA85F59 %5F355F595F355F595F355F595FA8FFFFFF595F595F35602F3085A90D3030 %36595F355F5F592D272E60355F595F355F595F355F595F359CC59D96C5A3 %C59C9C969696595F5F355F595F355F595F355F595F355F355F355F595F35 %5F355F5F845F5F35605F5F355F595F355F595F355F595F355F595F595F59 %5F35FFFFFFAE345F355F355F355F355F355F355F35FF9BCAA85F355F355F %2F300D300D300D2F07363535355F512005593535345F3559345F3559345F %353571BF96969CC59C9C969690962F5F355F355F355F355F355F355F355F %59A8A8A884AFA8A884AEA8FFFF592E342E59355F355F595F355F355F355F %355F355F595F355F355FA8FFFFA85F595F595F595F595F595F595F5960A8 %BDC4FF595F595F595F2F30072F28280636595F355F7C7C34605F5F595F59 %5F595F595F595F595F359CFD04967296719C7296725A3B5F355F5F5F5960 %595F595F5984A8FFCFFFFFCFC2FFFFCBBDFFFFFF7C5852592E2E2E605F5F %595F595F5960595F35605F5F595F595F59FFFFFFAF355F355F355F355F35 %5F355F355F59FFA8FFA85F355F355F35590728F82720272E5F355F7C7D35 %5F355F355F355F355F355F355F595F595F71785977535F5959355F595935 %5F595F355F595F355F353559AFFFFFA7C8CAFFA7C1CAFFA1BDFFFFFF8458 %7C525F352E2759595F355F355F355F3559355F595F355F355FA8FFFFA85F %355F595F355F595F355F595F355FFD04FF595F355F595F352F0627002706 %597C60587C355F355F595F355F595F355F595F3560595F3578543C363636 %5B365A595F355F595F355F355F595F355F59FFA8AEFFFFCAFFFFFFCAFFFF %FFA8FFFFFF84845F59765F3B59275F5F5F355F595F595F355F3560595F35 %5F59FFFFFFAF355F355F355F355F355F355F355F35FF77A8A85F355F355F %355F2F2F2E2F2F35587C357C585F355F355F355F355F355F355F34363036 %303737615B37313730373659355F3559355F3559345F355934AEFF8358FF %A8A85983595F595F595F7DA8845F59843559523B3534055F3559345F355F %345F3535355F35593459A8FFFFA85F355F595F595F595F595F595F3560FF %777EFF595F355F595F355F59603B837C7C59607C5F35603B5F5F605F605F %605F5F355F355BA9A95B85A9855B37375B375B355F595F355F595F355F35 %5F3584FFFFAEFFA884355F355F355F355F355F595F3560845F357C595F5F %582E5F355F595F595F595F355F595F355F59FFFFFFAF355F355F355F355F %355F355F355F35FFCBFFA85F355F355F355F355F597C757D355F35835959 %58592E342E2E2D2E052E595F355A37615B5B3737313731373037365F355F %595F355F595F355F355FA8FFA8FFA85F355F355F595F355F595F355F355F %5F84355F587D355F352E355F355F595F355F595F355F355F355FA8FFFFA8 %5F595F355F595F355F595F355F595FA8FFFFFF355F595F355F595F35A07C %5F3560597C949A946F20FD08F8595F5F35FD043785373730A98537305B59 %5F355F595F355F595F595F84FF5BAFCA83355F595F5960595F5960595F35 %5F5FAE595F5959586059602E595F5F5960595F5960595F595F595F59FFFF %FFAE355F355F355F355F355F355F355F59FF5AA9A85F355F355F355F357C %525F35353559B5B6204BF8F8446F20FD05F82E5F353530300DA9FF850730 %A9FF300E0E5F5959345F3559345F355F35A8CBA9A8A8355F345F355F355F %3459355F595F59A8595F355F347C355F59342E5F355F355F3559355F355F %345F355FA8FFFFA85F595F595F595F595F595F595F595FA85A7EFF595F59 %5F355F59607C5F3B5F356059BC20FD04F86F6F4BFD05F8345F5F355B3036 %85FF5B5B36AFAF858561355F355F355F355F355F5960A8FFFFFF5F5F355F %355F59605A5A596059595984595F5F605F5F585F5F6034345F5F5960595F %355F595F595F355F59FFFFFFAE355F355F355F355F355F355F355F59FFA8 %FFA85F355F355F355F357D7BFD047CA020FD04F82020F82020F8F820442D %60355F30AFA985AFAFFFFFA9FFA9FF8536595F355F355F355F355F59FFA8 %A9A85F355F355F355A5B5A285A05FD04F805F80505593558345F59592E5F %355F355F3559355F595F355F3559A8FFFFA85F355F595F355F595F355F59 %5F355FAFFFFFFF595F355F595F355F3559587D587D5805F8F8F827204B20 %272027F852272E5F5F3537A9FF85FF85FFA9A9A985AF85355F355F595F35 %5F355F355FA85A30FF355F595F355F605BF800F8F8052F05FD05F8056058 %5F355F3434355F355F595F355F355F595F355F35FFFFFFAF355F355F355F %355F355F355F355F35FF84A9A85F355F355F355F355F355F353B355F0552 %27F820272021204B20F85252275F355F3085A885A985A8AF85FF84FFA936 %355F355F355F355F355F35AFA8A9A85F355F355F3559FD05F82E2F2EFD05 %F82D357C595F352E345F355F355F355F355F355F355F355FA8FFFFA85F59 %5F595F595F595F595F595F3560AF8585FF595F595F595F355F595F596035 %5F352E5252F827204B204B2027F827272E5F603537A9FFA9FFA9FFAFAFFF %AFAFA9355F595F3560595F5960595FA8FFFFFF5960595F596005FD06F827 %FD06F82E607C5F59602E5F59605F5F595F5F5F59605F5F596059FFFFFFAF %355F355F355F355F355F355F355F35FFA9FFA85F355F355F355F355F355F %355F355F056F20F8F82020212021FD04F8055F355F365B7E61A98585AF85 %FF5A303036355F355F355F355F355F59AFA8A9A85F355F355F35272727F8 %F82020F827F8F8F828002E347C355F2E2E355F355F595F355F595F355F35 %5F355FA8FFFFA85F595F355F595F355F595F355F595FA8FFFFFF595F595F %355F595F355F595F35605F2D20FD05F82020F820F8F8F8275F5F355B3030 %5AFFAFFFFFAFFF850E37365F355F595F355F355F5960AE774DFF5F5F355F %3559277D27F8F84B202120F8F8275227345F52605F2E345F355F5960595F %355F595F595F355F59FFFFFFAE355F355F355F355F355F355F355F35AFA7 %AEA85F355F355F355F355F355F3535356005F8F8F826F8F875F8F85127F8 %7B2D5F355936370E37848585AF5A5B36300E5A5959345F3559345F355F59 %FFA8A8A85F355F345F2E272EF8F820F8F8F820F8F8277D2735585835352E %5F345F355F355F3559345F355F345F3559A8FFFFA85F595F595F595F595F %595F595F595FA8AE83FF5F5F595F595F595F595F595F355F5F58757551A0 %517B7B7B757B7B9F4A7C595F35603736303630AFFF850D363036365F355F %355F355F355F3584FFFFFFAF355F355F3B340027F8202005F8F8F84BF827 %F827357D58602E59595F355F355F595F355F355F595F355F35FFFFFFAF35 %5F355F355F355F355F355F355F3584CAFFFFA8345F355F355F355F355F35 %5F355F587B7BA07B9F7B7C7B7C517C5858345F355F35373036303661AF36 %3730370E5B7178355F355F355F353584CAA2FF835F355F35602E20FD04F8 %204B2020FD05F85F5859342E355F355F355F355F355F355F355F355F3559 %A8FFFFA85F595F595F595F595F595F595F595F5FFD04FF84355F595F355F %595F355F595F595F587D585F595F595F595F35605F60595F595A31FD0737 %315B555B4EB9967E5F5F595F595F84FF95BDFF843560595F847D7B51267C %F8265127F851F8F826273B7D59343460595F5960595F595F595F5960595F %595F59FFFFFFAF355F355F355F355F355F355F355F355FA8FFA5CEA85F34 %5F355F355F355F355F355F353B355F355F355F355F355F355F355F355F35 %36303754784D787172717271967172595F355F355959FFFFCAA8A8355F35 %5F8384589F7B9F7B9F757B51757C7C4A7B2D5F52592D5F355F355F355F35 %5F345F355F355F355F355FA8FFFFA85F595F595F595F595F595F595F595F %5984CFCECAFFAF8A5F5F355F595F355F355F355F355F355F355F355F355F %355F355F355F355F35603559595F5959355F5959355F355F355F355F84FF %C9FFFFFF5F5F595F5F84355F587C587C7C7C7BA67B7CA07B5183597D2E59 %5F60595F35605F5F595F355F59605F5F355F59FFFFFFAF355F355F355F35 %5F355F355F355F355F3584FFFFA8C9CAFFA88A84A884AE84A884A884A884 %A884A884A884A8848484A8848484A8848484AE848484AE848484AE848484 %AE848484AFA8FFA7C1C9FF7D5F355F83AF3535355F355F355F355F595F52 %92525F5959522E355F355F3559355F595F355F355F355F3559345FA8FFFF %A85F595F595F595F595F595F595F595F595F3584FFFFC1C9FFFFC4FFFFFF %7EFFFFFF84FFFFFFA9FFFFFFA8FFFFCFCFFFFFCACAFFFFCACAFFCBA2A8FF %A885A9FFA9AFFFFFA8CFFFFFC9CFFFFFC9FF845F355F5FFFA85F355F355F %595F355F355F355992993560597D0B343560595F355F355F595F355F355F %595F355F35FFFFFFAE345F355F355F355F355F355F355F355F355F3584A8 %CFCAFFA295A2FF7E4DA8FF7E30A8FF8461A8FF8383A9FFA6C9AFFF9FC9AF %FF94C4FFA822A2FFA807A9FFA95AFFFF8358FFA9C9A6FFCBFF7D5F355935 %AFFF84345F3559355F3559345F355F3499925835595835F8F80535355F35 %59345F3559345F355F355F3559A8FFFFA85F595F595F5F5F595F595F5960 %595F5960595F356084FFFFFFCBFFFFFFCBFFFFFFA9FD0FFFCFFD17FFA8A8 %595F595F3584FFFFFD045F5960595F59605F5F596075B57660597D5F59F8 %F8F8595F5F5960595F59605F5F595F5F5F59FFFFFFAF355F355F355F355F %355F355F355F355F355F355F355F355F5984838459848384598483845984 %83845984838459848384598483845F848384838483848384838459848384 %59848384595F355F355F355F84FF8435355F595F355F355F355F595F357D %9276355F525F5F58F8F8F834355F355F355F355F595F355F595FA8FFFFA8 %5F595F595F595F595F595F595F595F595F595F595F595F355F355F355F35 %5F355F355F355F355F355F355F355F355F355F355F355F355F355F355F35 %5F355F355F355F355F355F355F3560595F355F59FFA85F355F355F595F35 %5F595F5960595F359A7560587C355F5F5F2E05F8845F5F595F355F595F59 %5F355F59FFFFFFAF355F355F355F355F355F355F355F355F355F355F355F %355F355F355F355F355F355F355F355F355F355F355F355F355F355F355F %355F355F355F355F355F355F355F355F355F355F3559355F3559345FA85F %355F3535355F595F345F355F355F3535357C587C345F355F355F3559595F %355F345F355F355F3559345FA8FFFFA85F595F595F595F595F595F595F59 %5F595F595F595F5960595F595F595F595F355F595F355F5960355F596035 %5F5960355F5960355F5960355F5960355F5960355F5960355F5960595F35 %5F595F355F5F5F3560595F355F595F355F355F3560595F355F597D595F35 %5F3560595F355F355F595F355F35605F5F355F35FFFFFFAF3435345F3535 %345F3535345F3535345F3535345F3535345F3535345FFD04353435343534 %35353534353535343535353435353534353535343535353435355F343534 %5F3435345F34353435353534353435345F34353435353534353435345F34 %353435353534353435345F34353435355934353435345F34353435A8FFFF %AFAF84AE84AF84AE84AF84AE84AF84AE84AF84AE84AF84AE84AF84AE84AF %84AE84AF84AE84AF84AE84AF84AE84AF84AE84AF84A884AF84A884AF84A8 %84AF84A884AF84A884AF84A884AE84A884AE84A884AE84A884AE84A884AE %84A884AE84A884AE84A884AE84A884AE84A884AE84A884AE84A884AE84A8 %84A884A884FDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFD99FFFF %%EndData endstream endobj 963 0 obj <>stream +%AI12_CompressedDataxrG&?L53L#j, T$T=[6FC) S V?~qH$ul .D|?__~l/gfoo7t7|W٨i|yn;7->}@?^}|ulw9ww?}^I>w/oWWe8Qϕ~{}o_I3Jy. 8<|}|xNNWۗMwàMm`2C +l13oV~zqQތ0jmR +vz0XԳggZٌw}CΟ08gPzPUrVS5͈z, Y0j37hgP+`yz@anr]x6ϰps*^Y<Ѭ_}hbstC/{3e!UFIQ6X+C*?KX 4} aYw<޲ju1˃',KLc4@c.Fy{PY99^ݰ@0sR:{S +1!={ܭL: E}.] FqW|6 ׷b2X(C ǜ<@t֡}`7o^P*YN'=LH.ꇍhk?S4=IYhBӾZF'efɅ'q0ǟڍ1O.ԃXCn,?Ӟ sl(}ғPQ(PK3:tϻIOBS'*tځil>IYgߴsrvIOǍ3elUAָC=M>dR}!K&n?! 용tޡiB^8aUBH N~vq `cxpp' {XA26zp=0R牎9:]$F=(94 +v0c4pFPa٨i#,?qmU9cQi{;9 uriD%c8>1XFp5i_{Z;؁c8Hs dD+cv0-*G {Zpn5C܈h4e,r #rht`%"IZeHۘggt5&ɤfH#h9x"Vʗ6FƆ9 H)& 8LX|2` +;o;LLg>U 4x&` z$17:^FZ 8Eo_7~fIza޸{' no[+"p\\5ҴP V~ "qV. q7 3`9RR$óE7C&R$`Sz}k72ӋG.L>ֈv\Ʊ@C .?@ښx``9P z!\ނEg4PbH{,/;PuY)b8#n:qQxo{=m4a2bj),Nca# 1I~6,K{=ynv;NՁ[Xٹ@= +4N-tVIyb"GVt(ads`~bSwZsm=ll! \{,@ 8@R|V28d) Te g= Y,g_~8ΧpW +VTdBTx5zSsÂ\ a~'^.gu+XE1ʒ$SALcْkLμ wY?t`w_] mol1l0#HJ)L9LȂ#ɗYb_z8Cuz%彾3±cY?ֲX˜ǿ]pwuTb櫷7?^Sh?ܽ< ͕(%17W:y :!Ƿ~>W=>ϯ}i~oUϿx}_+bgMKr~MS[nܜۗϓI=\ K0__c~?p}xE֝i*fή^\c}{s9OJ + ?ʗ1~z,>=N^c"Vb޻{7彋MyYYSޗW}w?{g/0goo؋7ܩgy{ss|8{}uxxuu/7{(ً?`}pjHy0U{xylwqś7wӣ7o߼};gp={~5w/=#͋7%gT~{|N_\bu]W߂]߶-[ >ׯ7^vq2vi.Fn_IgW,d eo߮@AL*;i씩ם}{做^\ 2>՛@Y{K;K.qqh>?/Sc/b/r9s,OKԛ7gq"^]z(ٮ^Ȇ[:]ݿ}usg/]ͅfϿysv>^M<.n_bך|d:k7ot1W &%{d7D?xLUX۟&jQaV-`pg׷bW>Pu΄d>^qmrk_^axoO(k>ͩJGB]<ú_ + $Kݥ~Ërӏ+YVW/[^&d7o|sww3x5`z,OӨK[R&,O雵z:ί xbS}&,՛\4IT|i߀]F=Aޙ_a/﬍Lct5Jz}͞s~=D`,Υg:x2?^‰]zBo)>ك'BRwTfv?vi4Ұ䑬_kTs=ilH$TRZQ}t@#F#9$$Ov;{m; T? B. 4G fa70\j4#I|<hޙ]؍|w]_zona?nK >7v<?Ki4x;Ih 刄 +?\^\>=~V 꽒&ωԥL?sZ9`ua膀eOK!.=lO=6=zA;F[*xETFeQ9s쾝hւIM0fCC˨)AhS>R?N(>PYQڙHEb -\sH"= +Hd$I\hz4?׽sACo4MF#=Zy@{HM) ɞYr$nI-wr H9^ѣN #p ssp*+9DFӹp:q#qWAG! Ms!)Ma^8q}E!9%NpXCwC 3$LFr|:ӏ![ ƨ8keaEpec!$*xY#K"82 + Z#j{AVc bj.eh+zzq |!e de56PGyuede9;0}${\5M#RŖYmΑce7`yȢyOQ (ԣpJ4jXcxЂՙ > mSM\b@}"!.bh,(%snE63´G<$Yr >Y~IX"PJJ׉@NkdD߳ KA1uP(P`b$uB$͊fH2{_0x2Ù\s9F朳w:6C2Rx *i":Ux& +l;8A>d%?4fu}k1–rcH5`QGjIE,adt9$`{UQpˎ?a-/ʟqvM,7&$%iYRAHUre4.ҮH{I҅Du?HHvWvPHd w;s:}~;d!_:i\1Ery]KT9EiS3Wy>yMsKݨ\߱a[L^"V9!9h8Yc'jHhʠFs|1\C?D^N??^L,S!O],lIMcb&1"YJ]քÎfsxLACYA%Mîva4yX5v)J>XpFk"{.Ӱ\Y,YBCia#%mLΐ%X!NL\R@xm$lOfM%)J$iI?&H^(RNIy!^!GKj-C_Əތͩe""rRT6eiɿl-nn!؝/1NU +uҥdW vUʤWR*dҦ\u1ϻ$el?Jx2Mr}$JH٤ngjx,&ɢzD(r~>]3B>4)"b:PObϲpLI%9 Y-2/z7gJivi2e!\٥>yκYks{|geRY$ļu°F~$"cD!:rtmd^#[X$\Nǐ' 2$.Gd&[YE JBQ2I$t.?AC:Bhϖ}'P"<_m4w > FS8r"Y"\Ki#̅K_w"2$8Qt2H\b\Y6I@BBلS'*~(̥:rb(uu mr|֤ƿK +P'4v6sHZeQTOwХcH2c$-'eNR-WK]Xd"uz"-nJ~YJcvUשt^9\)<+ 3mYMI&w"iv nN#iU +嵴b-4Jn$>9u'_}Ϗϊ~fuXĔU͐R~)%hT'ӆyȔ5a3'Qgkd#Xo?!3{P5O54שQAD9Eu +Jh;ĥ$ҽPHHnQL~0< ;>~w{PZTlQٙPw-w 3Š::O3o  /2/yѐK`a2FX^EnEx^E^;%ތՋh=}go4^r>T k +o+|ߗb'm&d5Qn"3 ͤs&n +8SD o{KZWĬ+ؒtUjiQӬ-Lv{xL<}\zLZb 9laD]x_<5|,m] j 9П,<~_>IZAH[Nbc3vο8^rrޚgTz?O  +b% + bZ &\+C)Y>ph rsVqp|ѧ%Ӄ@0R.3K$X>Ń^4X /؈geX3.zQIXfz/_|7]{CghQ}BvqI{01Srje4&'6۬Dv[cΩ~k T]XV>nٗ n&BfP$yn!vE*p +=n(;"/ N% ,>ԸX"$(&raҝڮ +u(K:O,yMCg‰0I>IQOtCy"4O|tCgɌ>9/2%3cF<@(ĐJjt:\8 +39Y(p?gER4>>94gwhGy"j-[Em*;kstiCz$NɓK.s~+W?c)|M|Ɖ9Z:z;pHbN⧭o_:Ss!Z*,ꓚ`Z#$<8/2ڳrf[#94KsKCX:琂dS;IY“0  Kr)< .-:6QFِW fJnJOGh7 4"mt0E낝[gZ]vM:?Hu[$]%YݠtVifg./Cq+vYWDw8nق?F;A=HvŹq{QgeO|{PƥUcoρ+p 9; 5k9ܤP:dى^'[K1agekav j8f+l/uK}a*_Xg[~NI'o5-M~(5kNÒVLPkuvcDB ,tGp$[zp$Lt,(B,`$Xu"P+ya,ݭKqz)P/E +T YⵞBȾ,DiL]x7S4]1d%|u!RZ/d9gWH狴oҮJk?C't#1 4A]p}`]#;տۭ^ % +#L [3_J^-f(ѝAYE{nDU/e>iOwwŋ.5zD(Vx\LN-$EߺK:Rz$I$!Ř.HI%/sM^3zwyNvOOnxm0Gʰ@(O cť2*Dv >K%CB/î9eX.i;B"M9ş]7Qf̡\7 R)$rWZd$+4VuZ̜H&l_2uex==IA +AyC~ +)$#S2]Epz;9%I +iH}ZZ;DcU +LnfzQђ>]4fRqQ+]RDe,:M)˂t +ତtAN0u+4 {}P]yϻ +l/0aIn,rN=s`Ψ#\Q6Kdel~lJv&G("=.#{gryw"%L]ȕ0I +:OMrWf4ǔ7uL1mDxDR*%@R3O,mjCDKvΤsde+Yh]KuqyqqA"3!E 8p{шyц)фQ6FMި n -Mk%Hת׺l]^|dvl3u@MC@KlrɕPYL^+fSl*\fqukaު[iUZZ ֻY)s֚) ֫CONu=- MJꞞ?I)\ίW ++_W ++t_`kZħ?a>` v 5=EBwʏV3`s 4~'R~V)5*?GS4Wor~4/2حWs8wX~PhU5z +9CXA?tArKɠ +=ùtrak?iۻwZ|T}Ϡ 5>&_,oH n7ݪP޶pQO9NYԲjSQP11ðby8 9盠L9S/2P89f(ɨA#KoQ{}0ƋքGE˂j=qzUTza~nIONJo^<-ŧУ v<[톑- +.IuxV7t a`-7OXK'01zĂ:B4)&Cec80l3}Ya:#ƋQلQrr>r(cH ]yWg]?y,)P-~4Z7>fHkHRtKp`$~v$͡sgSN BMSnR''c?&ȡ FC0:,"bʧLud26D/T8.u+}jmQE䧪ASJV[NƱҍR6ԨT/ [4)ɇE)^_LneA ~4fz*H1bTFͻO#t W9>ECSD@t0?3Zʚ<|Qշ[Rծp-kx d"h1f0T@hEݽ\l6٠ jfKE尸T'UCfxxv1.xn=ߓLXyP 띶Sq "^`Kr(ܯ<^8;~ A`˰@YXUF9no@%~v)AZ4U iH΋k\Dȴ0J}F INcNb3 +#B`V^xe5 + +bk?Vx t1@m`Q}ZSMbE٭*O x8UU< [J>VEVl*& [Ko@Q]kċ+Vԃ/ 2dj[!R5 -O\U*&!LVIbƖ0C0=Ab{?>KUhGvvM kC-qz.U;B +~BX\xIIsH%M/=M_E_[͈ea;FK7u?+Mݱx `.O] ^OחA0b(]ɶuF.~|:NRk2yhSH&]-H1l7 bu[<ѭ& v5M݇#F 8+;!$2kHCܥ%6_l&kCyU\ D/O_ |Zv/`vZXܷ> +So~ub)f`'Zt;E =_@c鲍/EN/n;qfطkMNƗ*Sz]spb'b# @İ,SLw_MW͗Ʀ/BeJWUwɶr\er,_<$shmUm̉Sw}?R4[J;TDZHePztP)??%avw3S*=hn' c{(C/_`Ź⟢w݉Λeip~%ۻfyQ$r#miCZt;;aB{#v0Wyn=s?u)r$Fi*v|93IDt+OtN}s4Q,_1VO EL̡󋼟cR%֍pE]ndv Ǘ,~o-B\ +3%MyKQ4? ؚDg)ݢ PS!bT33=$ԏ1I +s/:qIUq[]2j9>Sl=~ :\+SVcgMYri?É$AZae)rڕ)|CJJh%E$Do6N,62b +`*L UIكX{E`#)[t'^`.dY"FT +T̲Of0_H%!nWJ2[-R31aƃ.K_\5vqmP@b@ H{O 3 +1W9( [Z6n J t`?^GT9=2U(mcԎu2j;UfcGܹxޏ>Ch ~|Э Z"0tuyuy5c +:W`֊YQv &M[C>qwNgtX\ ݾ,~{.o,.mCRݝ|:pd2>`aps,p\kS"ojyq%ع +Ton*eQA% {>㝊Xס?QW>ܯz|?r<`FrȄpө%ƙ/ÛۧJao/_3//vOVCUqhO5V޵FOS6┞ + -fͽW zgkםiON O=Cޱv,=fxyx 'h0\U Hjoy|W;j_?fs؂_u}V'aQK*wytC7N +ʬ|/ˋ_D+}sR@2y'un&!~識|]e]T3,V!OtkG-7w0ѥʳp1 QG{G_H[/Z RTyϥ;Bz!%G;_e +ˡ>r~ޮ@ee풑2я'+p͂Z +]?/t7S˘ݱH=g=l51VePV?%j]E ul0q氤]RHd)0IIIdqΒ1@BWd&'D5NUץRu)N%5Q~*U<׷׷={V7_^=<o!n~x +|f7V~Hf݂%t1X>mu`S(-#z+co?ȯ/<;d͟gy +6vl~+wEkVKşߊlww< wW/~W7|O=2V;ȓ/dj=x=d訬g!j+ƶ~@P}h.W+~1IFmvٰ۸ak Ipi5#$f ƍXгw +*zР AA~8U 6-(U 1>[X`q#{6vBU~hnقTڸAЄ ҄.!o=zeC; v ĺF{7@<[72dFbct_?^΢U  +`i,tP\>l E xaA]C$ m4prpF :q[^ј5bA$1lEq[ S[cQ1XhڳI~km4rXާBv%hAa;0J?P :u!hXҩ L@3ay7KɀUDCN@y W +Y 0L2* E +ıW:=V؁8W= +ۅAS^(p,h^ :6) +5a6!$'IKVhA{qIB^^Ρo,\86Sp mǼ +]J@/]P`o@x0؍MQG",Ka!l2nۖ_L[Q=:S5'-."[L>zƍd+1r/jTZiXE\_ViVꞞE5ԶXXNo`}5-NCWLZ>t|9)&Aol*/ +q89x=uQ~d.qN^EIiC +{HFL< cph g_ə{?YŶVEjX,~E%pzo[_Ҫ_UjYS_TH{`#߹-x r*Zõύ@r@Y,E< k"a_av!Y@TzqeR}iwۺ"Wi7LN8UU?.hX&OCԙ)jXpĠ2J(rB"-ŹR+RA3!9<D6' +|&`CxA[ԥ2T~ : ɜZ^B:8(Ӓ@<(2%X!L^ 1}lG,% $ȦvsOXy0q-`d-WrhP!7 i ^-2uW3^)eQ,IS^Ny/ dzbl#kK9cǑͦ1iq/:2FӞlSCc@vTܞD +I{e6^q%ƞe,aJK}K54{-7ES3*f,lk^6e\5d[Wݴ>tg\ͩa+OneJ/ dd)gF7Y 3~G{U/bѹFlL|xe&HGpX*]@sJt`He4HV΂$ +f@R T"uxh΢(&Iq +^rv/rўNŕ="(9 +1.d^㔰b#]6WJN&5QS[% ;$Op)j6fL R<LpD0!u,PX1+LŊ 8F x@plP @K +G5yYqT(MDqQ5p lrBWʩ+MirT]ZpdD P*q2BE6X+>59ְ+44Y: 3B?=ȼ:7F+!b_Q-3X_-A+fAQyر -$USG]kb:ՌR]cDnxQ 詞O+<=)8!ie{ldӃuÖٚz[QS1!RXgH@טA&OQagrpC0xFuDZɽd@A_ B/<=B#KMBBSC 1jG˚x tJ3j};PU0Yuͥ"+dX/9`C!ǧroksD$r?%9xnuDh҄6GՕXS C);X,ֵm84ՠ RE&2 P6?:%ǿ8p`EلAlu;!'e*(;a\e`ڱhb $L6vȌrR[0;ObkL*RM6M4mcZ;8D79Vam95n] A5l +xJO*dN66f5˜jLWrdLP*D^k(1Ge-V2Dyo?1mUWV"t ndO`p)N>u~ +_ͦ ʧ'Ò^b&W64hl/g4&G,FFV3"d/[1lg6 hXDg{Ac^6Bx cT 32=QkjK@~Xb2z< ZC%Փ+`Gkg]Ӕ&ǚ&}%WoR+ڑiiicÙKBM=A@F2yLs+Dđ&45A *0x)5bQ@6G>gP\8r(p)g WG"|1JVWIK Ѧ7uZ J[L3MSOAd( BtrniI-b0AD" +uo 2=ru FqxTgD"k2ZjM[1]8l@p"TEJ1 d4Xw%(Dx (VhɆIhq'& 4f-EͽwEe:_)#. l^6Aa0iv!;\l@!kh%Fc]xp +o߉V^HFѐNDH|=K s%S-QFP@$sker4t9(@sĝk[%X+(Ś\S*Qԍ=mRm[t%ZvOULiiƷicɩW/yaC\`QeZZuOEtD%/T8ub BОq`l ,%F]NO{(égsu6ހ >rzAKAQn(KEmTfD)q* *&؞)&Wp %pcҚJVJWrDIVt+X^Hh^ٷʜ-AZ +&*{)-"G$QF޽b&a?Z1#:_n!)OѣMPcj((ȇ>͎Zqm|JFFC:^+t%1J9+ gc [=Fݘގ0 %ű];.F$.1-mJptDW*~D.35h)bщs֌m) Jsq%Nבsv䇎8AlQs*lOW?M `+i0A:J Cc .Nrc T2VXKemsdzA6WUƌMҾ& * h mrEQ'wՑM$.X * Hظ^_f<`%b t}xp.eOhpA +h}J )CVc}jxɠpdp0Y" ĭ [Z>¸Q$䢈Oj?iBO8۹xVyayt4T@%VP +Չ+msY*D`VvqKuh&*?qT艺0@s#RSWc*^@dW;e."5 Rù[4D*+=sDUHf$<:#ѳ Dr""(pLA*Ic%^mQ,lWI] +'xZb(Zz rブU&Gc:yQii2+9F5`ᤇr Ab.eBH]PtގYS elqփ+912䈒2\[L1zըٌIE6YR[qiCSE85up9zk{1O|P6?WNg.GP)07rԱ*0n-G1q47Y[N4]:g(slny!c6O[2GAr\RGQ+Qwlr:MdU#.} mܹUp:9D{3đ u_^C-?vm +R_jwɕ4)&0<\@!VTw-¦)MŤ15lb-܄{35H4kr+v&7 C&J.Bg)i0F9ۆikrĚpo+TVXS->2IlӸ˃T`B~\@'V +bN8QavC]}3d`2)66QuENt4ӹR^'(NDFuh!pͰԥ4#[7zT9ǹ[ 5!"wM&j&^# ĈhA"0yM&^^$ $hB5A"rLMp&8DfWC4QM&8D[Zpk&:_%b +ӷĆhA"~e&_$"GkbCL!BBLH9_"[ 5r&C!l;MP%p5C.6e&~`¡ $zT!Wc8؂M&`6;n61'3JZo5J*pBԯ P\lcMisMe.jCWmI%PaOUXS36u9myt& Eo8[W(rG@öN6bd]-5eYOCV"wAQ^6G6 Lrk_3jvwـ}Ս Q2b +Yi VZV,E"B2U9bMy@ϛl،̋7l=(6@ZE(^nc@+2lhjCD#xp97yGkE]E"JKU"gX 4MA0ӂƯGuأj`bm[Mgl`86:3)E+ϐ[ aQAU,Sr]V(}azCONB*2J3 Uo2H=˖k1cOV) +UTDu76CeiۊE5|-|$aG׼hm&b͛v49d y+^ݴJy>窾ڡ<2ٵ#TQ!XDePm&FK uuNNCQ*YT9e[5ʽ.C +2EU'S]Fvrԡ )R(t*Njd)ɦǧCWhlY:|/&&Q!j$v=Yj5~ qX-ua47>{^JiX|sC.j +myPzA>$:[F mbZ}[75DN%Ɗ1Z;ufz16[4}Eo?_tSba;nM%Ҵ"{,;4}UA}:V1{N@6EŃXZb2JnU?;GIHM|$E{r8GOmKS>\!WeHb]0@>U9WMSN3M[_R֔v VQJ5A[ksѸ*6 5ޘPiDU?c`~fz/8Or ~:CX~8DYZ0M |}@#T--M'B"J\X)I_dc] "O5me)ö)JE\l|㑇]l[ևҊ@r:C^˾44yQSgFú?lZˁъ{\"`%ɢU" F6Glt S4R6䨺\XvC\.ۂNY–ҧ:Nj4h˱iI6dEjd_ 2r{Z2F,G:`{ZxISTET x# \Sf=DhB:My @hbDȈ>+F@d'ekŴÜ[c8X + oy8W + o`a!UX0Q$s XºF6H:TSw\YZ?FZz0 +S.^U4z rz= +UdQxsj@$^mu=󋕈W*`\OkknJOW(TG!?Ϣ^9ZSa[+HT3k@Zr^E|QiC\HHĕY T/A˪X1|XfM߆Zm +F`)~D*Z HU:u+뜽_JzYzIU **Y<%T\&~%hp '5A`; +E"BFq>mEy _ 0&*;޷J(%>a<#^tWdAV7*«w_V6ѵa ĉ;Yt!G eT[b% +4STiQr#FSh%m$H NTԸIiu@)X_1r=MxԸHCyZN[X#ה{4 ɡP)E6XXDMpu5ZleZ(WbMM*MyQ:5?/};oξ:^- +dwׯyq}x+_n῿{17ww) +KQhO6kT/߹Sߟu7 +C" `]?ᱎp㛧to~?7S{se2?~w}v?_.%" A^@]Px:ch,O-J{/|5~ÿ6e,+c%u=?;[ZWy׻oot^v:Xnw߼B Cb{q_V[TТ7HSmH탞@ T:1^HVXGVB(Z.Gv4&"OpF .:BFv>DLi'x=(/Gs[) ˅L/^&KgRYafkl`x 0XփI-2tZeѤFO&x%`6BdE=qozF1ATRa"oeňȍ#C]1ql*nє/Nj!P MQ>%b}2R0(_TBnSyru5Nc`K ~2{!Kjb/+H.K**ϥ^ǚtlH Y2/ ՞DSC+EƑ| +D9:1a f TGPX&gRﷴRI%&h8鰏!}ZQDF4 DQ-— zH1-e_uQeE=nnQ%jvr T76{@$)\ R84q1.;%81Q렢Kg}i +ÐPDet11)*>D3Y۳;yҏ+,d5Y۞/ryY,Re=|eX%ׁO4tYH6|5V !e5OXQE|3H8y#'y}0-ސɔI$K!bS\$KI9{+K= w6KBk XU=k}f'Հpϸe]l dKl-j=HQ1V)3>WfFátUo¥#) ӥeX )]¤o;yY% fh"Xh:: +ZcV;}I'Yl@ĉ+|1v`V"a,rGLh(Bi-u4^ iZV1:$<\*7u2R"ţ^T[P]lIMh,h "'x;!)A#tg⁈- c$}LQXb,YqX{QgLJ*gImUD~E0=B=(A7p9a\,մr#ѵf@[CN!ȋ6Ay:좩WRTFSC++)b! x /UuX!?&N`By-Ddrofj]'QJR{% +v1lp]]1yƔ.+] m!Mq-Zhf5z/FcݧKI2ٖex&au=&2eC=R2F2v o%P$F$ r ϯ)[ '/ԯl MM L"J⤥CL# ז +mPr *|V88Y"GֹrFhI {*j(4EirqMqU՞{QI V"M[Z!nPX%0W= y&̙9c1`Q+]8P&VԩD]<.*߸A+x 5ը  :ܬwweeʐE oɂ :%ǁe|wȫ0-Ii`B;+3V_1"eJwS؅ DXCK n樋;gBC̡-u: +XmۯH_ ȒeQPρ;ADZg~N3bX/}NX4@ M_fzp2Y4f#_+z#j 1ѣ*XJf@hȲJ"vzzƄYF2SdSz{>{P΀<CT/@x@zL/}&/[K8 ip6JᎻv4$.XJbN Pbgv}GZz۞UeuVvUKi?Le S~ՋeBPO֘ꤕAQd~y' \5TT en [_iP䑠|z=godtayV5^ӿ 8 YtyT)RZvҽ +[0T\oCe:Mٲ/^b4 a7 +l:v y9xRh$Oh4b,T"IBjgI; +ĦwmUs`tF f{ίgm=u':XїR5kX2Z?50oT ؀id?u,bگ`> 2n 'La3jǔȟWJe ϫv$F[Es|ىr?/x >Y2,WEx. +̲0lFe^OZ'Bl4NY] !@a*d7)OY>:(!H2[g.bJøW~a$N+#7pLq=KwUޠ6ʗ"q<ꂉFR1%N84b" +-WP_B)4fi;!|Rՙ*)Fn$okMS"/fF%11iʗ]~_i6a nȼOwM #iAy 1]gM$^iN0e{K1~Aq\K+I.3ll*a8Gy|Ew\<shf i3LsC{7,K1qhĮ6ARԅP1ûJFյ-_e5`"!.;y¶_R +4W) Lt9 P{q`H0¬Ja:e[i'sؓy-Xg ͈&<8WSH΀ H0 +<uX:ӯQu$< S#\ ˜J4Ү@ G`0}uLLaI =i%^:KM<:&>#+X`qO0)kP~JE <5#k*\KzSPuv(uXI8Ma?dR1bAV!m"1ͩ9NDK2!GJɸ r&P2"QC܉?Zt4ܧKlшt)9q@ZT2KPHR.d!X[`(D:>5UHM!16ôU7,"ʂ[ > vB]E/Cx\1-j Gl|TN3Mb:ʂ#vHijT FH:QP2YC* 0 h,x(3 72F꽺6obAu7&&ZA~*1n(~.uΛ54 }a(i z!H)뮔S+Mr?`  -A*~Ktj򨚔\Ec\0); 'gS&ѷc)X۰ۺ D~;NǢ0pά߇t Oj$ݝ #[J_aAHU&Z+<&icr5h9kZ xKKĻY zQ$=n}3G$\@XT]8xLN%ɀG, e$L@ctiG;O; x:@,6) l2ZX +#ȸ/TXUH?_0GveD]qz 0J[R-2aZbvF4]&^%Ndgw;_)_ gb5VA0MlRX3TB-0jD.h^%u {o)y8UzTz0RՁ6DUv_u(  cA3ӣOQG|]!fxʴx1W栄$دJԨIC2R<\^ qYWvЂO/UNHj"7_є{gUy_&sm@Re:?[9J@d}RpG +)R(0qHBŘ{ zVE*CxA-iȨLLÌܫ +DE2u@㮽|CI!-$&aVU뾒\Zry<]\c,T3q@ hHGZ5-%f $ꚲm$i$fK2;V!r1.e<>|\-(جIrk]⽊2)]Q7{7xVZ} +#D&LlR#zC :#cRPNp.q͍R ׼V]~.uhQE۴[\Ex䯹̮BF =1ͤb!u|:K°X (FL ;4I^ ʋJ2ᯡB_׫II4di mz\l0T$4>X!m$@8:` tٗD>#]W%@oMn!ot1wm8B֡EN +b; 1J9_^6EXD=U-w u4*d@S^88K0t2r=K$+/}HWѐ8@o#P4aPn2yM +LmYoMXV8e TeLqBOvVdn|qnh$LTM!txbVa4ԿEcӉF~ߨABa *Ior*aڅȕDE%ZpHJCtuu4P%S+h|CNs:4WjD3 / +WEXv-wsz4eع'z-?nU28M<RX`Wr^,PWEMCRUWqdoh[vpR#\4u#BPew":ܞ1 +%ta!kd1QCK Иl{# +#N4N5XVJ4.THiXQ5T0 gQ?aٓY&I&7?Q9( #gl}uJX9~?!n.(xbA[PW8aTv)jDolbAV -$-[@쎇6oYyu╀=K)φ>{tacg\DpD/놮Ҧ5z' m}pelKY()ݣA_/5Zpei@4LHyʬӽm9S̄Τ 9C G(`!Ei& Nb8U2zMf"9 +$pl+v5^MZ P3Svf4ߋFo^ߜ׮# D;.];l iQO3]XqÞxMA<(Ġš˛Qim7)F[1vCoH!p 26,[#_+A@< &@9ҹt _A՝ Z uCS1~I| 6C5 +bvrmfO|g51T*<ֹEI78J :"<1?bv)MrަK:߼#%A9Ɗ)wLa^_]sbE=q22"rd@]l83 ~.;eѶIH01)N*]<{?T.r7$ TPήå #,r6vئ2la30 O1IX̵l,%g ~ m%U X6q4XUL]>/"e%Ӽܨ WIp%l2EA%$ж"5Gۚ׬f0|Q*J7h~(HAFWY@—HuR}IDEQ jz\V{f&[3 +6Y $g,{/*0^S]h&ȶίur1j(TTeaL7]KhI+F̋7\F>yV*+w2 lPQE9WR̕?!zr!Ȫ0HuI pfy-68Q;lTUD,KpeM݌B)bnT{U]4r\Fl?rBe{Qɚ*iuQUV9+. 'tEaW~_{ \@+`ޜCDѨEXqsj*%ԒW0&TWIzֿ (¥z"tu_|FnmHGt[- +YCUol~pE>6z>`E|=8X@K' "A_ Ơvrq{uўš&ݤ/\ ~J-#MF T"Э"/ #HqL}o͌Cc_gttTfgŲ>nXgmG䵔w w8ׯekiqcujoy (/IQu ab$Ǵ_Utjl'P𐭓Um|)ȅo,Ry.k~NAb͝';(H#i(;@TcA+fUnj]:2>arNs3֒?Xz{`&a w6ɨ7^ i8MM3Iy8zt+ hvqfVj1Ԩݛ(\ilOcawnu(.H(c(L4qT*Mq+ ၵ?=̡%&x7f2j0~Mm y닩L9|\U󶕳 v3%ajt@V}|׹;)$c?_o/?84%pIo:mF&Q;߼>dl :qhSfLvJ,~E!=bf&e˝Oёj L3(B!'tc +˔i+刅ra:&)&v5D+d*R bb9 rPͼK +.9abL,bWԉ=$F Ż)d^k{9LH{ƽ,L<~'L^@:OL TFƢ W\}vAjwr|=gS%͐c3ye$vBjzN |K qyVuk7W\w8""K+zsRq: +8ZnhVOuZbS/mLSH (nSu|jĚz *R emՖupذ&䇂x,L8E#2MAF.A$h&vp7 +G]߲P]G!=Z Uab>W3vW֪Z9 if4+op dBh  JcDZ._C(FȺO׽Ut~ַf0P(Y<v">gcݱ}&N)h(w)(5o$=5l]`ᨾ x}Q,R0Ub;+RMa by]Hu]l.Lb'?&ߙLEҢ|:, 4YnW3| &< 9E6^oDV+ 0A;YQ m`y0T4Pkcc%O^'v03u4[44S9]`75;P&Q!,I{'NiۺZ$]dy:C%GU>+2f :3NRqnG`.Ҏ$ĚGdꙆ6Zw"ނ&..@ckhBA** 4Ʌ4Lo]YPp',TNG{{= 3w/ q>vNQ?BOc"5@}ɂ҅b`6]OKטz-QWWUTXQV Պ 0:"훡a76ՠ@ X,+{8ֵ5T[6ЮEmäF 7QE2loE4kGC'\oc>iPTtU雭T$M?(^X.(c鬢掳¹G|͋phVdQ`/sEmiP=.hжB6pNn(gmG#]K̼Kwxkܝ09|?nNx0\@5 u% WLBGmNʁ&@la bXU_k>]k G0v;tqh#-FC,:&4떩)jx4u:B +b#E+nqT_LKA'G,(P9$hH-B@1|M{&4%*>"lu ^vW߹0d!7Km!8*ɍ0d1ݿRs_Y.N<Bsl׫8RhߎBҙF^6OX@uLl6̪l uNNeثvJ$2J - %)ӠLR4 }y'h2hANF' E 4k,ı͞|N'ЮYFGmIb(( RcXCҞ,LoxхJuE7^GqB8񅯣l4:݁lQX:ppUY gTʵmn;j؄t<"S=cs0T.5;zǢ`Ù!&/=tFbؼti-b[GK塬pjn#:@RbY),W,w pؑDʯX7Y:cVLU{C?^0y yU@6`:ۦZg= nɎ`35Ǽ  +%豥0Ё/dފHXFCV!ϛSṶ':TY'>UNq\hS?kʱG<^fe3/#?Uo&9>0MEB%Jl;Um*2@ޥ$VC*uK+Ax`m K&IVŜJ ++O}Ti'y/V/SB,@,f'/%SIR&\3TqU_4qG'Ie+%V%z?KFZ +wz7n[h1P2ˑa21E(Ͽ/q^?)6Rඈ{Q#]AE?PnV,&fZ `rXB>& `@fV%C9POi;fF~C 5#pbƭG.36g$}{|Pxy]ѕI~9;fq0[zBEsӇR`:/W #L! ΍8Vq^^M*?{IVOWeëc2v_yߔ/b ~ָo4(HBVoPM:wMJYH6=)$=aR=dG_M^HZo;-[f^ .ߥyھE幎 +>*ட;81iyX8:C/xO2S/ j2~'Q{VE8;$e̻8Vw7sٱQum}K5Vpֶ)>)˜lM)LT}쫓MxQ.ùءYh߀g:BT\'M.[Tȫ@TU_zQ?rTԹ6)Jiޚb"<)5eYXP4o6;Keݚ6`HRRyIBLi@d°Ѩ kVFwjBiV2~~ wH@u +jOK5HF#$G ]CրEP>֚G I X<6<Ul1s>ŰMFz?'h[[TS]=/yk&jTnYk~[!]đo Qb(oBsAn}j\Sm[ +FM3_)Bͭ4 +btoJ<9U3b|Pԕn4U4OiQZdM!#-ĢnUa-`3SJ.ZohB5TV,ogTw.l1.sq +H9s*I嚫UAԏ83E, M4y!кr2xO) .FmM?qB{ˇǶ+û8JiĔ4Qٲ?y9%=e٘`;2QMNS1c[Tv/-*oȀJҼ%a@iqI{7zl GX}jyU_ƀCڧ~O s(_laQ[i8LjDyO"%~cG*zkan-164Oi~AÊMh +'U?%?|p:a\ՂEUM=X&p &0ɪRF֩>(B(T]9J rUl_b,O_䗲oRGЗW]o:$vA- |XrVe}v4zae79Ҽ.ZyՖwob>Bsm]SVF/XxEvO>ںc׍"aO%s,]F腈GU rTrڱq\ڋroM\nGpYo@̤fn! qTvǮ9MM0ykڲɉتpч-81Gԩmy ѧz Z0͗?Ғ.08X)*mn{ehoUZ@{9bnhS_bѠL3!,G]VrA#%>9,s,> P!-bq%<; oYigZl*¯[|@[`ʸUhIW)ǾsBpղӃGn7Z)JBn/ZJ~h>$h9 LhԠՁ/aYh-=[!(ҢՇXzP ׷~""[x,Crx%?hl5>PՍ~hj0_%V~֢%|Qo-Z@"O-Z0R=,h:7ƁҜRG:oIZ|⅔ZYKg`[Vw"zYVR\0HVЂF})Ѫ_GKU?0 :/"گK,5c~k"2)zKW"JdnWn)H-+'HiKU)if52D\zD\Yp;Z"چ!̧%1!"z[UIY4SUI=j H>bjHR6L-hw~:E#K*ᨹ:!׭N`q&\P>b=t+oIշwoUWN c診b(yK(T2R%eTuUxGU2%LjIVuAg}ʺ( j[U GJ^uUColiɺ^A9weφe|ԭ.!,bl[CW4]zկdsƯMBYqb<' &JcG9O5k^*,%0u8>^it)¼nW5~R8\t^AgkR FK>:`=ZpUir,JҒiLD` +T"U Ţ",NUOu؛,U) ~17'}C T`S:q,^*K Vw$'?`)VW@g1X=Nv6 hR-`#gXʩ%"efگYY*>2GCU&>+=6wv>_yW=I ";W|wLw< + SzbP,L(z.1A{HOtܒ\+ .pm7Wּ%_MB~uqP7Wn +ؑ|;QzN +;*H +Xǎ䫐Aܿ^6םcT`G"q-ʟj+Ŏ/ݿ&˽*4ͧ Rx +WuX-IR9GvQFሬ-d[YOO ٝ0[̗r!z:qsFy6H.7x`!HW&z$ѳnRrr-ZV,St ¤c=Rgx!2dC4\";4OQ {[utƨrK]nEQy)iR# +'[,*7P~qIu*|hDHKIyԍ[s(yk}e|5>Hڞq%%=S<džιV"IYN&D) \||:f0?f͵~OՌu:T炲8HPҼլ&a+ G7˼mLHPqLF"Rzhb^bn)L#*y0E*fј&v PHa +2I#!.L0l<0%l0 vqV45Yn)LaƇ&[%,'fuRKrU%A WڥVwLoK;bbi}7ÞoK9"zIQ2"Mr8N% TX+ӕHn{)[.ѽi*$R0גNSi 8I!ITrh{0NZ84eKTZ/iJ, -y]wkdG0";G4JF Bï7L%0wRjг[ +S {ڲ\s38C<=Q/!2O> +X&>u0 0(早U15#MJU1Ӌ +IQ#:nKtǮL]T$X 3Q =qBlK]MR/OKemP[RK}eK%ҷ$8 TZ@QTMxio"PD8ڕdHSX&*EbDI*aWK *ѣֳ;2SY>9l[ӼW[j0$O&NeV,9v)( >#969·!1,Ӹ ) )0+M5I:y Arl O!HGQӕr>{)'tj~ ;67QGb :r(ڶ#xVp[ 7ԣӈ ݧ<#4Br*csR``ntTKw؛ˉbo.@zJ7EȓtEJO|*Bu"%`C1TQS'vmL>+nX, [*|2@X|EI]J=, §S??Go!UT8OCjcCU_׭lHEXI p2GUlbk"?9'}y +G0Q͊B[P݊y +wF +g\_O +F?Iڧ vK/qKrNZi +@KJɥIAP 2tk~9&;*@GyVh'\}~#*rd*Y};o*ł 'ůO@7ɗvBAG#^6MPQB5w\ *vٟKP=`)vp(ΫEzVԧP:GSPi$_Gwgt.[Px h{TA[()>4kicUۀYMPpyIYVT"SkJ}}?ZX[ PE_*X$]S8 ڒC +PZ}c="p{ՠ[ +PjxnoR [ +BECfK uI*(7FVG +PXjhV}d7%@Ŋ" լGpjUt%g/@CHV$wJMP|]*4=΀ +QRxSDU\Ǩlhi`Rydb\ H =x)WD}h* ЇWM0+Qdt ڄ +77zi+L_aZLkYkSJؤkcKA&.1J5iuǜMOB + I4$1HUo?*C +Ywq1h.W>:$R2a= +AQY Lҳebf"_f[Oo=źmRCXD,?$c?o,B&- 0œIP ؛R 4Wz}j?]_(q([6/dESsOv?zߍ[pH&PP[/lElЏ<@;It^b 9vD$t&2#5~#E5VVnQ?Ro]gGOJ~j<}oCDw-',p:n1?FzI30 Wf[̏{#`Ob~4 <|aMy!ra`z CzQVSȃɒO~ b}?PzDc +㍥d P#ggL>eMGTUsGaA?C-vE}*oRuJ&"GTS&(fכ=ew`+te0U +F;^izyم$THkWۗ/t(o*sC S5~?u_~mQO4~!UO?I@v+?UhQOED -6Xߔk Wtg;^"p,"²O??PAb~+:2="~Z4@/u!S6!_BwO~Yxӛ6Qxx.ߢ}DEW;Z}$7G{#cJ7\U| -1%vV2OG{D'S +JGeO~]\q:NYT]Zz$9}JQj,b_+̡.S0cT0<26ixTK6!GU2h#߰k=]£Z(܂wTKuS S5ĭjWLbvʡ7;,g\#\GVժo֫Cdj7Z 騁obtDU?*!9WR pfCWI~rrJ\V#0CsUȻ=eP3xUr04몜ogKLܒf]M߬]FY3b-e``?̄8/exT<8{ +;[U&s=RdUc(gcd԰*CtBU17u1.wbfZ}-14H=%T]f> 3LX&:`׸E;7-BR<Ƚ寮E ~I/wC f!:ͩݬ&XG̋4%jbz)vny9wo̭PhMqԸW!}Ը.!z!c  6v7-EPƇV ,Ho9-̗cg [+ LYR[+6f&VrޙE+cWxWݪ`"E+x-dj"٤b'*nUw^ l`Uœ [ܧR,ܿͲ 6]8G~ + J$Sr8bSP}:SbkכHM!S2I|G5 +y#%Lr>ͲyRT-+E `[jc13,xG"q9"Ov"Ʈw(|SiSve&Tn᥹~4mƾ8rd:?α4zh;߅(nE,?ԕα#$AZJsS>%/VNU|QN:5xt/$vo @P1U $`и[p73/#GH!5n}#"m)(3 y.:lGh-s )= (Z¢Ei$|t[5A"6`C~Zjlu IOj61M.p#-KQHo7~uO %\Ж E9!DɳXC~"e{}*gAg YJ[,Ouj*_bA"4Te5A=my)M3}ejxRs$S&!gSxC+곆_qv^;mpbAX(V`4ė@YuPL6$L̺=uhC@F/?T%;2t8@T*8h:R4<&w̴]CyF/A°xT"=$[DBz_m˸(o扁N" t;T8]'}|;_`-G*l,)UK<~axQ@̛] fZc!f{AsAaXpPiS-ˬO/ 8wG/}thվ\,Pfw:2o8k}Ii|SXL'uB}fJ{Il4dM}%4ab%\KܢX2l=tߟJNCZmZ \ 65.+(25DN4v.W34Ž=/.3SUGqQm +-Y[p9r2xr7aqcܣWRȾ< +T!?ty=rdŊ6T}Ԍ9zw!zi1\d;51nm`b^J`{>">[zD; +`Sm/ܗDޅʍ=<*+e³u:}L'aϣt?: LNPNBe>NC:`"x;"ao;ݝLok:UZ\ȴXK; ]G׹7,1ݘ˃`E̺svI=P6jXP_Y.O݉ыi.>l ~ouVD:׳iv؜QtcT?܎~P0:D\M+v׼{aS Z'`4"$* :8OXT.Id߷ǥ‚6;]rluㄋ +gzWMY!!ܟ*xFU']Q axdNW<fn3:?8Gb`qT'cWDQA31~6DIE! (,'ҸqZz@Y(Ռ w>w/uB CFu~у%|iQC)YaJpd\lYyV;VK}/'w z9A~8y28@xۖ Zz5WC1My(q m#qgo` EI_"=kE'^OC<{%ѧ9ע~ɸt;:}ܱy3#/9 Pl#-F-Cd=N.oz0AƩ9ҁGA6+2J88I%.04/˞iJS>HPSe X/uj*Zj +Ȼ2~"OB<ٱ0jjYVy( HP 2!qBA&]W(KBC.}.&ܨKm N}jFCTW.QH>a"dzR,Mh}!UБtaij˒|%;ĒKV?J@c8L@LX!uA%z 9TN >~bw +5Q\Aکto,HgE)e\F%J3Y 1) b2j@kӱ ɫnL©K7@8 lBZIn7&&nlI +alj %Iq0T! * py8DӉb,_uCe&Q>4o3gu[K*BG>@Xq=TCL\+Dv<"YS=XxøէPKT=*iU1&s!|\Hy=OmBw%N,ke]&)%-å)0Ÿ\UƷ]jWjv݊ `nҫiF## CJޱh%m\{򤯶o!c6'ApMC0˘f$/sb\^k zZ֫ >ۋ]X=5Mx)EL >\~mxvS5MuS.u5T5 JTHU` Aeeaؗ&{XԀrbJyGX ?Lz/¹lxfGIvJx&U{EaEWuG .욺l5k 5`SX lab.A֤q%c3lg.Xޥi 7H𘮳kјGIԠhr\k"Ɓ@D਌s:%4J^kеj2gj\8&vq5Z3 4\&tFiY`N P:ND@vU!l0)]r/iR%9yTU޶);e! <e7b;{j Tn`دE,ц\mzf]LN~ tǓ8X,=:x^ݞPK+v%BpR-)IjIs/hVD-% k |N9!6‰0Tk~m[… )"?t~3}Ft`3&1ҋDwOQOGLj!>^a)i:`U|@둿}0qNDEDi ZV8V! +>s,zF{=ECUKDYUqê7<ɣ\9TڻpPtQ W@S:Iתͻс.ԬCi#EL\Y M΢)VnDEU]0쑴y|e' hK!4daQd+G̀ѐ/S@_2睥v*>˽{5\z'J4aHd7@:q]Q:if-ҽhO_^}I$9= raIAGɧj8Q~c֛N!P {{~HR"$ >0i0#Ja]b Ol +uY|Wl ڬ/P,E1vRy(J5|/ŗ1d~,5BB +qL{d7")1+6bSF8=:>6oIkg[ƞ1['xuKX/fj*NMF4Ƀ٪9#QqMm>k%MC%Lapx Pt[l]i3뙟 #yod,"R2~.=bX*GpT9<#VDaѩ@UE.nn0p=lTaD\2ec#kD )|`:iFrI ;jB6Ag =d@"DXW$M3@imʅj.b I򞅩c2xJ}ݍe78n˨? u_ +Sm۽QR@:L=`iTAi~&c6&f#\t!|)a6`e$^Eh`䣢N7r@}:pbʜ„hӉu1鋹7\՟m` dTi4]OD ﮟ7Sǂ5 0z)I4ܴK_ N4Nqj7@+'ӖqqG7h~iiSdS\Xװ')R(R ƺ6bUQKV+ k\C0l"b"Յl&3ȗ%cJ +A56j><~4KZ" ur`U v! +F))SԪg,ph8c7|)ҮR1,q"eΒCHiaBꚽ-*[KK꺑dս⢬E{Yj-/ pxLX(6TǞ_DT<.!/A~ J( r[&qz%gx-KbdoUy͹_U ڐ<=DGY"KԏFJ"P0kQ*I~ *Z? +zhJJPJL@ڋJq5eSHxiO5P;J DHeHX6V_mG{C h+·Ki[n. ma,h؂1c,r1VČ9ǡ32-٩/ԠEd%?l"l,PU_usjADݑhco띡UڭߴBt'Y9=teԙޤϧgzvyRd!h +#g (*O|ua5VʵA6S6fsڈ MK ż{iQCl-PѢC Y-$ /#Q>dgp,<,T! aΤnTbopKԤ)s`V\ғ԰P6]C:vVo-!qh"CZA\Nn&N OWA#8w5 ̰HL8S'r3:+ +t)\%I9 fS90Pcl&cx(+Votɍ!"TQe5q`R1/giNnJ`^w<r1gRQ8  ŗQ}\/X ڗ]j|iI$R,+Ӣ <@CJ.`y"zŰpU(Aɠ {L3ִO3DKJ'K 2ͨ'E8k 8\x?Ǣ?)Vվxӗo:boY +!Я4aSp&4p؄[ iq/ǶބFq.sX j⋵yM{6(|КA SOl큑$1z+SY~-tq 2tO!6tkdQF?J wͻ8~L 3= pJNвM-E+5kD"7j ༐]t%f12]Š:-F>B/1Z[3QK'u^<{q5v{r~Ud>U7Dye +NC^@UAxxGK_Rgz걮AX+B{`T{ 2GfJ(`7*g@hpHem. +Hqdw<4,ԡ" 1ګLD+2ư "s^)jlH / 6,jR_Kj[V($'Bͩ.$XU7V'R+θ)7\ C+(ђ(7pڧ:Ӛh@-Ȝ( ̠ly^ +XcIN5b8DSgGfX1%DC2pFBYB[-yg'K\ϑw{aEDz|M gN +X I :!U8 ]e} 'pNV|zi"09U6+F1 )2rm@EQJU(!b\ R\:ס40>ʳ;D"WRDQtѳ6 4J΀@SA/ወĉ4a]`ǝe"B4F)oTS&n'cD89OK8ؙvцoD,1Bbh|5WNV" ahP(J-65ĀH quZMI֝⦞aI aj +~kqSPŶk>VgUBLS`V]oXBap-"* #n{&YV@VىlCeZK1;W2SL4®`#:r5OB%z +Q-$)lH  +'YQ_\ 4Xb۪om-=k Q::3EVE(:AnF/h/b,հ1)Q֝є*)Yv(j~GIh/Z;;˚!\I2`4XFroUщm&eS2_H۹|88y|y! D& N&ؒP!rKbM\62jR 8%y5TB[-[/M;OP%huT:KN7j{WQ7!wQZD,jS 8ЅxVzWAܮL$v$8@V,)!d,cRKwC[B#X*ѽZ6d^^FBĆ⛏ʇNZ)}KaKDyff{EN`29l!bO,@D<[j<tJb|^$y,4hASٙ,P?ZF̊*CtSїSY澓kCSX67/Ojq 0p$ $IQa2LС&lXa*/O~!Tv\1+y1~Vr +fOg +"Ai76o.3c &) %Tnp| ͈1BƶWFŷ!չ %LK!K@ĔB?6d9L]IV'VO:BjIYd$֐jSy0N7P4XL1Yml,b;FV +>!lCluKIzZtrPFlDE,E,.,՞9 QD ,Mts޻)6usZ*I,{2 +c{nC:0l A4]V]?=0]<-:f17Z4Ie*FË`yRb눨 +/N"MK=5ϑ)W3;{ˆnV@>1Rj=z> -BZRᴘZ~Ka&/a!i]D%żJDCDa~,E)3/O*e:'h-&_3ܕEMb͚k-D`N(@@Sű/EŦ#{։ i0㼱N9\;k5+\ku~R'3~޹G)Nf,Qђ^(}0>Щt RXO8+3۔$8luѨ9N"* ׻K;_ \UUCz%`7<5@@ +jzqdt`t\<=RD(ns 3aFLx\a Uk}ů7lOV!*"+gAY0#Q P ~b# +8Z^04=*P zjbwՃ5<4fƅ,~ye鼹l*0C$=R!沪kM/]O_A\_WIN( +@3ȖAM<Ҡ[$״v#y!`vf" #htqW ӵK%G +h~󉨋*孙Gv?XթɖW5Rhh4."NCMAA?Jݘ35 Wt1|ZEb<.Fw|AfX97`MWz KT0Yy#"Z{Jaڏ(bհ0$޴  :WH|AĨHkC;s 5TkDDNQo`ޘX$X效BRB9io #wYnUFD9 E6EG͚L)8!C5@@C\/;!L,ўYfLR&mic& +N1d /vrI]0"Hn1MHH43X*/T tz'q +鋚LF4i SiM~w,;:3R)B*z1 +xGd⑞LY OӰbY8O/rW9kK(iߙwY H`\ηnzϹBpz|F]| %8F ݭ[蜶@fWKYuH^()?Ǵ?DEDVOC\Vh .v󱤢 r5fK"q%ەݤ3G+9fXd/K6Jį[;V5%-דTz!(V,ԘŐ|',vriyע;`T`p=` : OVM# N$F@8 ne(w!t'q&("j܅3`r^"%uSy2(;IN/Ե.=%wx jlIz5~k&=IeUcjēYk.3YK@;[YYv.Cs] 㶥9c@yiٙF r  DujLSa:$U3GbɕU^` yX Ee{qBZJq#%1 ֍Y(E3MT ~G+(BZbv|7 ȫ0q Wk3:'Jz*ގ[t2<)w;"3NRm1 mh xy qFn +g#'u00=ʌ)D ~N,狢 +,KUQ"KVLL%A{Owq,0ZPFZDOSh*\t)WvN2ZHA^&EJԫb:!xk/dI0,aSwKN5tAW,˦嵭M ޷d-wr`9oQ,,X'Iqj$jԗ}5?j@`w@~j؞0T6_1yYJU-X/5 mDCFuٙi}/M'a@yU?P_g[wRT[u6D8/H{' єv. ܩ%DV=] Z<2Z D \g)]!'5LW)/ #z]x&1OKAY-jȁs@U[klh˄!OY$f*shRRȤъ$vEJ#A6%"c=ECB80ȹjfgJGG-E +ph捘&]C7wh"rJAA=&.7瑛b|:jJ R ],T8);ݸ`q4TXxb؄l=+`XYl(N`4'0aq> B-}]Ћ`[DU!b` b" +-AA N,zF QiqFH,+R!_qo*G  Xnk6P6'N_:S>M̀}*1%0=5Gk5^*s;wZT&eU%N T#;u%BCF"^%SsȠX*HW=TSZ(D1P|2 DrC,"iMR֬IÃCR04A\Y@R9M2`>j K&B"".Pu5/GT;oזuj1$!&0՛E4t1πcIB]F.}a!FU|XZg gDb).Lr%$vG6g *GPunVf DXbrYm2;l:1r1F)-*g&Q]$XRU| ]!֘k@0G_)s:ԉt5VMh!F\!ջ=YAh9vd7WBFu0h> +)ɥ.Wh!VgB5Uabn&PLҜ߬+`uXp [zw^o D&fp2eʋ0~c&dUV5-/Op+ίG&8c4d-WyAX&1wE=+FS~ (uk@txHFfBe"PX%c,-2au!1r[cuL"tYòO a"h! L\f>s`KWÃ#"4ϙpAՐ5_急{\@L$ڝ؃*-9YJ(4Hj(d4+{"Ddo&%'h'+\^K;Nlkpr଄A'5fuojB9I#FF1KG}֒>q c8.Y!E^u]s\Ft*YI&h8-T?-|: I(C9 O`%K2[AU= {ƒ~P5L ?Ǟ8/놋Mp"&>Жi-cQ_'ק3ħEؤ^d0F&\*5wE<\f4}ZƼ,}n/ȫhYR\@rFǮ-r*Nb-f*l>|BǙb jpUfp,}`LV\p1 DV>؛\f x K4޴K!4!R-Sqbilԟ=ס+m0DUu r ЖhN.*$;I|K C>m,w۵z'`Uz| OկH K_m>&(pP}ܙi %7bdO(#!,']s+a%p=ĸYG^!"2KvS:HnΚM${`bj?,\xZuY"uo'j!Z_i`AӢ0Qu endstream endobj 964 0 obj <>stream +%o 5?nɑ(}-5onhJL|G8o,F'jHS@fBo79l`oFMLjCw2NrRݤ6v9Q9v@bX 79tYM*[tz1o7%Zp\貧@bCkPN;ۇ%";)LT"Nr +;<\9.'Ċ[&fCpȏ%L4dʁgX<[WD6S҈lTQBHCj/ȏKjNjrDOENM|aV'^iS Ň@NA_1gF+= +%l< ٌK6Z%F<.a)%hvǂ({a pbD!eoWWVbi(n9 +MdV)d!(FBԍǏ(B,MP+RPkS+Ph*9€f ;sd3\f-:-F9x#5.LOP324`œqFa)gfAk.i#Ds`9-F+U@C+H~|iG( +CrU2&@*IBD97X%ȃۘ˟ϔEB;S: Fe;1seaR!tm#"f|lxmB)l!X‰e4(*r|w.Ds{}$lOuޑbuƦP듄͞Bfuݥ ;JзPU=(l˸7YZTs]vH|N;E4g,2&͝@R['w321{H-R@W +b~? BY`H&{bmaπL^@U <9\ l +_gT-ˉ[@;p@ZNYߵɮg !,Q]0 d*lMpQgu8gT0A ' +rbR R4W,BDSVm˪JzW]CT 61kIKgg!8Ȍ.S1QCUdS[K^FK.`FL+K ˄{uͿ.$G/ы^USXiKRZ7=֌ZeJI%^"մz Է^d?s1dG|SG3C\# M Qb$&.zXZ5Vpw.. Īe3bD$85,_6,_ï< &:~!'4(A92^!'K`D9扬KUKGW] W7R+<-@ʖ*BxaZ_lafK]X=΂+ׂhʕdia>+wi.{T{M:c<ĥ0nO!=f@0.")%~pnp V @J] @ R3,$Nw +v_/ %,U<;E]RŪ6)X}{~#.,0:5"N@˜$]li_g@g,}~BMo9K7-,K"̚j客SxztNۉTԛAWYiQ_  .%,D2Wׇ}+ܑl}?رTђvv 捴՝oG}|Ύ4 -V|4pβ¤#QsWX?)2[~'_V4Z$q̤Q K1;y~pą?o#;%L<.nmqLٶct u˜:VMc_s⼤xnBA5YQAT 0RC 'j6lޙ0@ڸŮbTR2av^QtH zI$>LG& g"YH/ʱLwsFřWEL^-Rw\vጿ{.eѾ;?] Kd;Wdg()jBZ1[n[M!2ЇkpAɟ!G'wG[FrY+L4RkI&iiUq6S!:d5UE[قrvN$k;KbrkTGH#mhr*%|v-= + DS!-Q-158zHg,LpXRsKNZ$#|Ԥv@Vb +=>BWdzm Ipr"`!YmDP PJ_jک>f*eOmΔw;2|=۠ +TQmP*dlЂy)ХFX +|A/]>1 +_^ryBYpriqBmU<}Jb]@ೣ\nANY|Ȉ +?'* vzL WC %W"P!9\+4 +̱))< ph}E'OZL0Iԕ$* e1iY^ uHʪ*ScvT YXCafw~J19;lt> kla.w.+{;lO +] DحqUn*/9$˲ތD4 \$?.:̉x@Yad ԐW x3<4TqH ;ҕmH+1Zv1H_J`i# H4-$j\6ChV`yo5yj C@HiCH&01L2g"?UuU%m8^KFO,;)H#KV+ 3QҥTܛCP>q(l]АHh#Z-;-YZ+I YK( mppn¼١o"&aQ ڑk!@ښ*4D ҝ[wbI,n,'X,z|ohئ eo IZYykS 8i-{`4@ Xaؓ- n4$Q} eEP(--AI< .ٰ k^/n<]ʡP#q,IxA2ˆ/9#m7G BnDgV '&( >z *WS;]5xeP9N=ۦ ڦsQ8þvOwĎ}yߋtn2bI/B\vPmD@c"ˤ5jPӤ) c;0!|)@`k F{EO!Paf`>G_E}/B"J13VwET!FFWB;dFXBovO2MQfyjٽ%v6H棢k'iBPx5eagiaY b}jv PB!^{{ +-.):>QQM3Lfj +[yIC&~"cjcvUE͢H,_$E:F ۲C.ǙnվSwrV*)@Ӡ7߉T A]rR#(ڲoJ8 ' #G8)\ QV]>L]r^mHJR4&~n²JωĿUZ#dk|/JKgRuRJR/sO@1L܅3a.EK'~!UUcD.TJ=}Cc\m+J&iU [I;J|"^uOHG!YQ!5U ]B4TZYLqFH#aҊ%+} &J9ch%0n JISg A6 )Q1DIրlW#YME;b8rEypU<>h')$dz+!aߎI!"b k*ǰdǰkiJW`!g" +.GId.P!OB>WԱo`X=zx⒴v @/ GM¨LЦo@zމ3 %,@Mz !N ƁDUoZôDg t"wC^9TBzRʏbVe {-5y9"S#(+ +b = y 6GCvGZi{R A^Ow* kyD^ +=-j))E_PO_-[Ё!@FIG ª0Pf|$g#jU3:N#` Q2b +8M,+1'ܘak]bB+t[4Fչ)(Gj!(ac;D5zr c +;Ruhk))1U?B\F %6/1M"pL {O|l2s`*E)eݽݡ9\:=EFуKehd~8Uك.)3iHz-fkл_*TDm}vJO7M)oڽ/<ƚ:P)ɭa'Iڡw 7+@N|w58ݶ'IgiwG v +Պ A{nRTM:'~nguCQZP$o#"k3MSQ}IdY +J1;Z46.jv i8kpg;!.\;xVyh6\nCBӜFfHc> ܠ|g[J+0JkP %{,EM'ZoIdzX9G{Cl=uadEk*QQa tv¹1a0+$bGuxouECaptw6T=$! v,R C#-AGTL=/m!JfJB2Z˱]h hee + N.KT}xrahnj Ȏ~vpwh/_.Lgqʋ4ϬotYaytAq~weHEIF|ElHmEx15bH"3u Q9;4pZW۹br(L/ЅEF´` Y, 3vx*,^t#SG3VRW ydaQCchlޕ`F"V xMo |di*םۤh@I˦R֥2RJ[2I22S_Ʀ[`,+7}sb_o3Xn&Q6Rxb)В>GI5P,ľ8q&caZ0M^wj%$z8U\p,槁JAAy-Bd# L[_DgBrP )sv/ %vߠ2-Z5X^H xDW|_K0D쥇JI6\ +c ǐ1pVb< үdXJ 7e2 ܽ6E\W&P^a0S}Ʈkhx + vs SXI2BjD*-g{n{!IP.B#X/8`# +p"/E X51B,hqpcHcYj8A PʊX@ 8 O*[ qDZG'(g +wal'28+39D;nÁ@Aۜ;2;i􀱐ZWH t8 + z1'z]DOȓ YdtE՗tz&4ƛ%nuc$u8=i`b* +,lJZ8@ !t\Xs'Ceͨёl&~{>~~%D`˰GG&QQTv,xF7VĈmӫ)nRCMI$&f}{!󒉎b'< 40b)abb<sۖ4 eo2|Bۃ4f9.UBZ,VjR·NkWp㧴EUf+*֬p4klwu+R)e"Ԭ+M*%wYBAu LC\rWa;̔lP O9e O$nDVM%liiUEIJZ',̞/}jdDƤWai]ΔT寪=lVy!mR-Yؽ|.ّ-Y-^'ūh+J`8cRxg"[#B KÆ̳m#g7b%_'[R/!D3+j \t A{JCf(:u2ʜ"?~hDc(ƄBK&i'$wȁM LTiӋlwsmv k-x*0tݦâu &Է; lԠ/C8a !1)|]m u`N:G:,uRʌ\#GJ-18CQf<ԩxè;'P%=КkRޡ q!P5gb3hvWhsf_퀮 (J(*z *XfcC"&xWcxљuՒr"qSJ&{j!!7k4!SEsDSlE$ΐQ!̑ .)6a*JgDep3n~%t\\aj5tMs~rXLJ(+nӕ3ZRZ,5duu+X*,qRC${uѤJy_`0CQb$M;<+ԟHLs*3Ko`~ %xih7b6$X w;QOP`hʾ6&MdtέI|[gp%Hw!fn\`\#qSBh=ےq9mH:LE"iuNʎ{Ifرa6}39WyM 5kv}U|%\%y#y%r&91K~vSb(z8$7KOΨb&`8[Nr#JY( 堚uJA<3n5;8-!&SA6zJN/! $W {Hp`%\stpKDqбd#K{vj Gr WOP-y %12!&fWv~HV<Ɍ. $@2@>VHR=7!s'5b +9paZaQ`y;뺒O&n/!ui b#o[l{6='ς ?{e <}-rŲvyd+] "ȕs hap8Y& & U,w7Eʨft~IC-?RE_yrvGDs;q&7#tkVD+dXoHNr&*2$(#n%:,RIR/,|Ʃ|b!8Oi| i dA 4-B/f 4=} +hX-AP햼Ndj&ls)rM!\`8 .""fgi#&,o7Yq|Y0A^c %bao^d/-)=$mH9pf~ĻLLM6=%el^/yytGRw) |xU%^™pU!ʥE&xG}n-Un'u%6+3[) +y1_s3tωEԣPVR5؁2'XZaD=N\CLreK2|;R8F\@[23TQ'1 ^IP; 龥fXwA}Γ`B!+Z{;g/ +)a8y,;"aҕڊu +PR~rbo$;LU$mR7"_,ҕuk,ݮNkO]A<}3:U_S"O p{bnm'ΝVMNa_{NzNj& k͕b+d6?r[zLbgw̹#/9O]Wv$#@ˬ?30,<{"Wˣcc:VUdOZ*)xc:-KT`Ҭv}eflD?SԵ +LB_Z2*Ө1Q!h4saA",;^l4W]};RszQG&B=Dk!I C5n!Kim-@)c!L$}ry$Âןy[3X~9-h>8?st K|Ĩ6sK>yO-|3ȬYb)˾|*%Q6Q|"5op1gDtL K=M̫e5Jj,w=[/p!0rct`}HY-%"\O drE9:E!j mF~N +;0ZDXqC$7bc CYYw$,4!^1$=e+d7u-Npw:m.TIM˺kY|=bGK{"2۩t}ԉ%PUuJP,H( &AL} ΋QOYL >\I`  \PalO X&Ѣjo QYIkŠLB ,w5rS|]Lqο|/K}%'a ܘ~BxְdRM(!0˔MsqiP]yb!}=,e[-CMC%L()jnE-Xw9£p%p?W|m+ZKqٚ2HW_Bw&e)vfeG$$3>@@iZiJ?ռ*(}U[93cv&G!MZ.mNv6aIL~߃"I -&9G߃ @1,YAкr:;C8cX5z*;V,GQT^CqcG`ޞD@p<0܃8 :qϗ7+dÝO+EJJuv΀&]v9;!jwz;p +& ӣ9܎Ԛa1'b8+zg0ʌ!!fuЇۉ+6i]g@CT_Pf3B5 a 8 K5_ZJH!c7&0=՞漿bV1_ [pFXR +V$C8]GPFdH<׬ +jrK`E% cR"%<"@ ZZF2FI,cmڥA!A-NٚC&tڍ>o"~+gfx N>ߡEGu~Q|5p0;JRRl-zU#ϩEeNTxv/D/$pkt^dU %eL/-& dK;%tIhr䪒#:;µcv0>M?Ԉt/PfQd:Q% +v4[Kv3㦦l\3}zZĴ#1C;aT.+;nNjc"A^hRlE!<˶FYHzo%Z ڀ_(Z8ɜ٨%B%P) +$D3BTTK*Av:&į);DBPxE1ϩTI/?_R?dzB`C6CۯA2704NNHt$[nr BK%.g(zvPIÁn*_`yIڱ ՝W`)>?u!1X͒%G:>/$DϷ Eɂ1\򃲓dLĔ!<+-ƛ/E( C mذ @ʢJ9EMHcpgQ-]};7%ӗ &zEE3S[.5UÚ k/F!30f T.ۃrS]h$wOZ[׸UWm^9\_vZ0w$\ʧ ׀ޖT' yMXKM_h//0SIJS +NJGSҭ6&@4MxHtP@!xf_R- 2 n|/F9.`A!4"l>iXȺ{$ ./q>L2CW΅PV{SYdXp0&Q. +nJr+IKJ.IpX樆0 !!:6~~:d^`fNk;}+(*LwVDlȰ%9Z_ fDÄ;I0x5 jmi3_0K*HLaK:DVJeV߼١{M zdZt?yT SȞݝ} +qR%,ɐ`↡r^'] ;]y_,؁$4{`ءJ@ X;Vh^7g,uvQ+%EQ9O6&~CoINK8*/ ItQLΗz,5WCEh{-~ )2:zWX׵p #Bٯz5SaS\^oyB$ b`69_oȄnJ~hTֵ6YgEF vZA̽f*;dCO&*y1KLs8~5;<FdoX09(VPR-jʅ`JꬆN2E"~& M:Ry.H&•Δ)V=1پvNk::ڑVbyHo%zYW;AHaA El&Eqz\FTч+z\[}:bEXa/">FdRׅ+d)kBzGaq!UZ?]ZyV~F!6ow'Eu^NfpD 7:vTo)ġX|#>SQTN`/PGYڐvL@}/$GaD%p0Rkp޵rwG 'LrҫDKq_XIvPZ|jI"dgF+ǁ+G}̭r!BnSRuZ$.*J(Ika[ OOQ)Jk8I66 <⪀+P ͎ܵ<# vzO<~ͺ(GLeCo9T?v'ײJ"1 `g'< EW6 +`1 %%A"B1Τ CSn¶adqs?{fXXxeRmvE/Z_@?q7/W?_o^~=?~C}~/om/~5߾}_Ǐ!J.gF/=O]/7?~ҟX-WFц/qX. }=|_8%ӓ7'\^$'*FV(;Tot@ +tozc'f;61{ÆaϬhrs&R.ן/X%g# xనiͽ{߼~5HDR#qžHwyrN/ql!'T8zM_ll~ңek(hJV60|w:P@>:/nf9o?)noeq8c#Bޘ}x '򿷳lnK1~F4(}Bl~:wF=N7PSF·G$5bs}ޏ`:>ރjAbvpb}xfw@~{Jpg(CF›6T^͝c8}i+fj7JUݍkVlm!Kis{ia <żҨ̥U 1~cw^ۻdlz8KwtcwG-b'7#b@Jҏ(Oq7b[_issXޘj?e>L:4dp7>c3ZKi؞6ol v p}sDw]|ӝD$FNQ)|WM6ς3yZͥ޶)){K2HjDd3Sspb9~|xxQ _[o؟{}csiOuc.w'c3Sf@4s2V!Y Hܧc[*+΄g{0<v<6LoJݶ@=&6MKھP]K7Vp~>!8n꫗=@~1Ʋ1Z׳:=N#gdaib,v H[/ 1WW3Bw3c{c5T7bρ݇ ;/'cN㹭|-Q nk{ܒb%OBMswxq}o&my_wSf~^u3#uqYuţ!Psayqh[($-̘'٬sTlˮ{smHJq]+, >˽&q=(.Obf4Rb=@Jϫbv7SiYuZN-_t{TCK1B|9c39oAa^ٖOYkp~rm7h|K [ö|K~IGͻ+ļr;!wr𚪻 X+`f{|`\y_G:M.K1 ?yH%:@xgܰɽK`VW7qkku֍'{oo,5?Y{?Mەz7S ֑(f ^sDL]n$933 E +ΏVn [i,6;H_s>en}?`d1ݹ!HK~_GX sFJxcnC٦c8D?H3"ϟ^;>3N۶[Mi=g!v1 =8 tW5#TCEy̐h[5}hpg`ϊL(egMя(3Hv$8NsdĊ{,^s^X};8n5R}ll>1[JJݎA[l۰ QA;dԍ(59AsLA~O'@4Ac Y +5%[KbX(U!.n<MȩCU`H kZ@'wȧ⛘8膡ˈ +c 4P0![$R/3rpA^y84"[pGe:d0R'`I&XyA’$F(4DumH xYYo`paf hChN1ƸFYF,2> INjZHJ8~ +zb6?k {8<n2SD!Dbҕ bbSQ -u1-DT` e!̉vQU}lV.:h˼-ܺ ڙS{`ژ20d >jM,uR )0u"4&@ Mfp=+PZ- EbAKTXcy8?d;N5B86b2W@Pf (EB/q?l,`gD;W60M%'ouaTUFrvȫ 3(\h&f9,6fÿRYh{Ayl yuN@-@>3506i"7gFbpfr> Z޳.F$-@^ۋ4'1gkgBm4 viWZ}nrg^ 2}Yʨ,">70)4pb;.YkP8e$Rd .v-Ã0`jZHh`oQ(\hpt?H赎L 3g;g0 $@Gb8ߋFn8R\&M޷.kL" c,J2\֡3cgLp*'Dz=F=$H0adcΑ9?l}QVz-"D&*/XY:٩ѴS!V+5p)6'~@ 9ˣ$0t$''`<3Pqe2. 2*ؚXSME)_Hb !eSrS,&:tRɼe +8`:If`XC@#@6+g@>L:Z8J3Μ_+Q~6D 0@_a?NѼynd)B]93-QQN8E8GI"3H>׌a`&[ب,/ UY8- tpN3_/ZC`$ Z܂M+k0*{ɵW24+}aZOTsRERm~ZS)GxC;}% 1lC4**i?1GlDxµ jY氛6`\]S96?j3|%Ms71t3j9Z}"pU4 n03^ˬ(nwVA7]Y.w]$4Sۜ + GV.2ٝaq2A.((o*,p`N;ĂL NyÌdVI-Rv ,u᧙ =fMP20G$@`"3Z+sDf4SK "p ӒvX@NF%Q:dp2!-qLTY+ar&'(ɬ'e(w6f`qFo6i +"c+@'jMkϛ$Y E͊2rJHSA[:)Qp5MRI ce`skiQiHFN"%&cYAas85f7fBDK憈\O+fR#Si%J F12f#ʛ^LG+q^DCT.9gVp,(&DY9ls-H#8 ,8X-N-^Y^͡C7TrRsV+}x;#i}1 +Ja~OSe;)uYR`$IVc#rبHM4QkPoFop/3]Xs3*x3^`xkhyzxi +;j' +4 v3VV6,g7!*p@-ђ.ZA ae;-'@:@6jtZYX B3XTC `EQ:ftҴx QJ"\+B0dPHk(碓NJ2{"[D8e|+q3 ym:7 vp8( `:i;ocY-qL%#2Uy㙆b셫4U +>SAv8&CȚ`1q!UFIZAťY4kF `%ؘX*@0A j 2EF*XSN%h 'K +JթSAcDMEo kg WzN(Ts9Ŷ"1捾inBsYHtWurPWҾ"ve*S[l++D٠7f +ؕhcD"]U NuA_cV0hP2EM3 Tv0;;#\;.,t"G=j~Q M;%9V03Ԑ,,Kpi0!6oI'`G9Hf^]bp'dp+!6%+WdY3pAtC@' Swo8Flsi ڨD1.5~8{PDpجl?uȳ48P!)vt78{0P a ڬ¡v\8}TV@C# +|1a$S4E0 I}NU:?q#S3T3Nࢎ7\KyV ,0`4-l~%n/l,"|]T_1m~ yײYA;ٕ^e}X8TrƆ󅃌+ e9E@'oIg83$7)QT7Mdx!mSF3hZW@v&U.dP\bv2 QFdb +D֫XWdja#H14Z +Jx,NV\k>RkNY׺"OpF &W&iu8:U0D"6،bYKaMl|QaA NbpOijJXMX6NdZT2!+&„܍&7l 8".6nf`1!k.D2O18"+a[7:6'i=*r<ިDbs J7ĉ4aA' g7X1b\M/)X|K<\l H4!fNG!|+Ib(4n(@Drl Jl:!UZYA3 aq,7KF'7a،L/ڙik) hWcY +~G̍/ U +G' 6(@W OM_8~f\>:Xh7E0!; fr {Xh5մtGq-TI+Ό~30F\\1A(0H'6pвm"x3lH5~isIlSKDI[Y4)NsymT(,~ڔ ,$88 HHmh +D(la*&3qsYWH(ߦkk4_dLG&~prsŬ<`oLʟm`S0@}Qhem);ص609sɌ4rSyq%`Mm@)% P1Sig)I6joR!ȚX=ߵN;gL?pp926«Bcf,ў6փ[ +*w$@4?,icIj6wsyh<ԉ`91+cVz%Q$f #+&ysa s M"ztz ,MKn8 Ul3y3ZӮBvubKn%DY Il+4g Myh|hK{x S.XMsId ]vZN3) MDvddOU*= #WV2]Zdy8E_@0؛X5I544':,an"O8dVyx1h@;oz9Y`+x= rƵNV$U|Ѳt܃3Om1<:ɺ Kl)sDZov^N}L?35Y n;nN.mlFZfg43RωwXnwlBs p0!;ط9,~xDaiIlI Σ8H +I"`޲fϬF~Bt~! +`vN4/9(v- tTbr Il^'$3'(lmFU#x'ñey 7>B-ZgID~PpҲr u$=I05Ku# +vZlA砝>]\b>} Du2_7P3Y]9(d=(vs;ۻn4f? )r48`w _f#z†h'I 8elF8%7L<׆,trl9 >,oeG8tڏ]e@Ow%Zi?twX=merk{rsLgkdbR2 d./1˶I;S"-]kVO -H9%-IY8gD44}i -%_Kp*DʪFy-V*k;m6%Lt\.PZC +v1v @,eo6M#sh3E1Z'p}KOt˙H,IlLdh-IW;c3K!5~rQ.l4N/se7^+'d\& vpghV'X )9VĢWZHV=y/#16b2Ř; O#78VIÿNͯ=j.; ) Lb'a=gfvپ"+hOh`<VL&f_6ƼS&}sY"`l^n<$Zh d&4Kфk(RGY + UEoMsH `#mY-?͗'rjp'O|q6d9ZH' (tbw'{ +f}W9PB# ^%&1-Swhc&]@|z6X[:+=[ "vQ7@JR[yگ_Ǚz;/v{Nv)w7f'}//0x`=PAMkS+ SZ{ʺhو72+{sVzV9>ޛXQN*|4 ֗lUW룥UtSJ;oKh{V6|T7}\}h}?-ce)eip/Z rl!zk;y4 R3˺) +:ȉ9ܲ-CeݔvZVuO /JIhl$.8G $#Ihy3[-B<Κ̞)Z}Zʉy,絘ipo\{nj+y~Q[ϼRbE'iaYgg~PiAP5|_^\SYP>ܛ_ m՘vx}{I-Cs[œvZ|YG2\Gr4"_QϮM'tfQeQ +:(UіC֧AK-ͮWJmu:ּ^s]0؛S[A󚻪7^hFyWz+v@$?A&wRSv涓f"^ZO/;B_h}aza$?Tt739KϬ<7Zg8޲#`w-}~j!h4y?kQ^-eq'uI@o)Ub0ptPh]5oMo%RIN( 'uXiVy_W-\W( +[ArU˪*Z?.l+/Hln~JN- |5cjH)*[F0+VH&R[1 n,n RNlLl93*HqU]nJbi'[jV]/-{c5i)z2|_RY'-seO5FMYUKOe]<)<:Zt ^ AF s; }NK- +Qo/ײWԗm{Z<2'ZOoh ,ogӳj{iE |{FGº `bpd ґ+wЫ٤WțUrLrkP*ŝ՜5u}@nyDrHbRKE Oi٫Q˺* C]rQ3WoU<:FY{&{ˢnGc{/nc˫NSK S;i-;b7V-:W}(zV_K҂6jry%{UOe].X {EZ>)PT$kNd~-=X@1ma>؜ᲯEBCz!xTHoE=NDrѣ[V^~!M!{M-\OΪꮠq=Dg-,?Vq|4/d)ؓ`ס#LGcс`;#SZ薰[@/;F'.gU4{mlFلKb~F<kr_BJrq',r7ײW 7m?q9k9{z3ʺU=Ao7 eX*t)w鶡ҭA*A@~~}f衣w}!YU}^y0'̭x0u١Zq@xG G#F)UGF)o׼(RPlMOpVR};B5yx[Z/;0RG⯞ x$RK;+*Vm =5Y@*̕=@nbZΞv<$ vZ }آHI d EH_ .nޡB>Fп,F~kK}9^^yjTEk,sx%ev%KH-ܺ>ڪc5'Vlګ ڊ^}5/O +RAzeןiHo"mg/U86 5Xo5a4 %hIG=Q^U`.5y*ﰏlcG|yfq +$WgTza?YrJk|NZ}b|/ۂGZ,+/_S7䨒ʊȕGF%[ʙ5WʺKsa2ߑ< +{bxbR-:DYujV4PNE뷠_[E@/\d+zvm_&o4?RܒI-1YAVPYP9E!:*P%10 _n"975֧?*O~K|^<6JI*e>d!}uOur͛*ʅ }强r^⦧'n/&Uuvj=GEhB_AZSNY&̗6)'!l=^uo`yQM[7'b;.=։h}=M4|A=3V+:ˀ !`W Az+'؉x#{=`7x6 :h5EEE09/{ȅu}U݂!@ oX"Hw*l${^Dx䐂ރgyVx~]ygJh|F;|C6_}=[?a Oc8s $-D :=ğJnR2ZO4ZƊsW#[v!~{B`!H#_,=p`lZ1@7+وOSW5 C)ja+OLr+VXUuqGp-٦v#3Z][2DS0oJ,ڛ+qԘ V|RF`U>Bj%ϖk/rhu?϶K/{pS·u{<;:UѷH?+rJFMրIa)E@nb0KoDņA,d$tғ;UF,*'.{ + +F6R ٦jN,d["13ߓ[E: ^6G2^h WjO=" Q9kCݷ&UGG07] {{`w}-.kY PJe16-C&Ȩ롤VwvAd +GhJI]E`ob>3`ݑ9FP2'"{on[ T.r[A2mF$?ōԥ;9}^j+Eb y_|9/dx7: ேyi-=ڛ1m`#Z=d, ; +?:=eҭuxeYl|3"W&=K>ck+Ek>?.$J恞/K+/ +H'l?7yA'ߒCb쁴G<t9Hǂ,Ӱ^C_4X: 1i+N>z{3alw`f )Eÿ>>'4`o"% tbbn{{=s|:5v9(km&rs3ZOK;)5h. Tګ˻ioc[)v1YPO:2F[~h~`"2K5җvՓ ;e[{6ex=_ +/ \Vo v=HN`<11 OyK.#ǥQ,_WJ:6@:Ǽz.Z2_>܁}SdtJZa*#^J_w|U*捻ArIYq|R<O^eҽAj^S` zPO=+mS^k0E5syݛOw܍ JΡrbmަfbǼg ݿ_LJuh'uGEV]sڢn K A~jIAE0^Sii9\Xi\sY!_I)=XYxi՗+Ib|_KbRx{l _eq| #IDauGƸs_ZzauQOc j)ھoGnx=|꒪TМGx s䖢#{AO*:T?ֲVbIԚ7i+Kj__urHxGy Cל~N?gjόlpJ!@LL-i(WƲPSm7' d=`b6aIG/:. b =?uedPC<RTJ+l'Tt2ί8޼w ~.1lb1Zfk!+խ7& K;c3{ mXrWFcל+gGz\zѳdMqoF&9+;8ҷtK7 &6ZI\C@D:UY DA mN~ +s#տoYu(ˏr{}AbRyPzA%;`A'!J:zr[ClAFZyӊ td#٥#ry?F+{=~cTOJ q+^CLAo|QCg z#"a9Y cK6 T*WO1z>Gl3ѲʺA7 2?سX6}ȶ s|=%n$?){;=zROK@{ vQkeWP+ }GvSPo9z)ۃ%d=6|p6_Zm/ jLA;jڽeѐF|"*/l90Cz䏮 v?ɥ]h-b2Hq-E->ۻFz^ \ +;1f(#W/?|w qO֖xZ-l ?U~#䇡-"rz_*u,`d&U";?>äu_JĊRV]1g8mJHIO Qq<Ni f Vt͂6؟Xu/Q)6|iviڏx6?Xqm^Rvޝ.}0M=9xƣ T's: zy 7kW$B 5  v춀y܄VzVmo% lpUX}m7@?=j{Nmە}wfz_J5o?+62VwDVrdPħ@e5o ^2C @6]:1W{gVt| -_ORk?|!Jc;x>uoYã܍ r|e Cv<t6ͶA{(; cUўc<9=lxiKώww90{5[]YhY{|P:1z9aze~~wו3<[?tLܘ&LPKv Q^?x,ZSS^=Lt7^Z}p\c9HL[M^Kzw1h~=K7m +gf 9|!S5oZߕm'*ۯLI3׼k+מ+6^qUg(EA~{6~fw<y?äЕF!5WmmiҚ0;8&|jXC#iQgOyi~O >;^WN+ &K8V %[y>tJoM~Bހ0 wE}G./h ݛkk±#-Օ'Vz[k(ĄF%WZB|H?vXlQ{-c j@h2ʻ]ו'w:&^zEM', +}"kFwhD:ֳdё}+8լM_llrcOovܙ"8JCv}W*ۂρ?nRڄ|gV=zj6ǃWO[g}ũ֋+ C=w_Q_*?X$yՉڑ2a=EdUkrw!P{*|r=}1׼3^-6fӔϨ KоK,\ȅ6h 13rgVɣ.|X?ĨE'Jn xOfj_OY}z)PP9ী͎ +OSV qY!N= F +z W@s[ui`JRbz[#!5 7 ~~[~7c63K3#Ep¢Nc9*w|yLԲ]AXO kgp}gOarW4 {ټ˵iKTs\w|gǥ=;FHzCN 'N)<r8;ⱑpԟbdپ/82Z}bU>E;GF;MVU+oc +y_ހ8*wo ?_u|R7 'yXK pnkѶGL/c):E.j ~RXĂ@O<ݡus8MhEuA^`䳐dĦq%7H_NY`m!f z9!1!~ x!_gƅ fd/!;C^lk=mA:Cl;AX^9cNX3!+1AYvlT1/OWAe酿 _<4_ +%ݪRV#YQVhg0id[ vQJwA`=]j9+ƥހ|=𷱝({]|Alx= _1Vw7},H ;u'- F$C:p^6-ِ8:=_s>A^g(\ {!&%~lųKskkk/b_}zSA Hg !c;`Z @Uo<ԝ~coOR\#6}|0Ȼx5ww}f!~\ԏיN4E90\WS/߼˻MS>!bKU4gRQē|}oU1j7xml7cu/_Qc+-_|F[ 2ĭ_D>'핽}ϔw<"o*M'5}"s;nNvݟ~eOWVVOq) [7_A~dmgz1KF?#<*kھ!kz}#7_#gȇo'{?|yϾLy}v/M~۲zеcW"7HY\s*i ҩ+ .['^~s櫥+E{?Hg~Ҥw~Kmb|y7_z5d${^uk+ofhT+F.m-\?2GDZ6C2@?ȇ~ UNQT坻s.PމŽ?M|{׃WwÔwdO!c-%Tso/ ܟH{Wկng_],|ȷ?_=v'9Ktx7evX H\G]KՎ^:usDEegoS[n?x;u%V9Gt`[}ubtġ>7w( O +Oވ~={-}7sKoS?~0^~cE}<;FK@>(Edӿʼn3ZT_&{|{*c߻}?Olgׯa?oܗwuԍ(kLϞԽC|o^X{[tat,I?q=J}Nx3<~O P>I=ZQ4ˇI{{?2&4{nϛ7UnenTDZk7v_1⵿eϓ?!Z|Rҡ_1M,ˑ] +𪰺I^'dżu6˻۩7dž4ϑgMI + ?[~^t[}|g%s4{WGnhھV4$甝?NG6np9/~'%_?QBUV(\)LO⛚Ƶ_/k^o^pĦG_׿U{Z~dcs?GUώ^񞽞׋}o݊W~tgQ~y='nLԾbK-Ӿ=mSsc~B)S̋#6]ŽSWڝ*|=T=\}|sJ'*{?_ziM 7VIJ?x>H?'nV2hڻb"};uhkE%yGWyy(nh]K^]uw?fyN&#_P}{w򨇟wlK[bh~|Ar~BՕǑʗS#}ng7.s)ƌ4f~Xz}ۦGae+vԖ"6ߛ i @w2AȻλo?ߨ^QOkbx緙5#"@bŇ'Λw;Gf\߹3-}QzM9rS_Nyȫ!M9pc- r҄;54}Y^|FG7DQOj}z}'/p ;,Oټы6 qw7xZ~ ;`q?<|A.;3Rko_I'{V9>lݥw}/nc3#~Vums}Js<o'ng+?Z k2zW'{ZȮ˶9{r~&_3n3>֞MۿYtqMWVoIټ%o^zgސvys69IBiZuY3خG3}W=<{P.,XTɶ]$ +bDl@EQ cT1"dI::̜sWk3sy}}صj]>\Mz#oi`j!k^Bd_$R9>"җ"3?Ih(7pb@} +N%]!x nrւ귫GJ>|\f}(f7^}dt+G.Wa>;)>/N{Ź5!} +eBgj~XOf^F{B(A-}MsBrwewe[ۃs?ͽw%:?%YmvSW+ +{W8yRמl!] EŶ`aLq|]A?{&(I>ؑ>@ӕYsj@7 ^moO?++8hi ʾ}48nwpмxUG<.h)HhO+r^c99sORمAOod?numJxٜ'}зWRɒ8RV/]zE~_ֈso^ԪNE&{NoI7k)srp,[9OcO JEݱe{Ve1F>S۟^ד,R˅Ǚ˸n= UlT^k(88Bl!_Y?#W;H7H +sCќujAJkJalk2#[YW֚ZFyrq|x\lJ(i+{Wyyvۡ>G:=w8'{oHoHho2'cB?V{Hމ֨]yMA9Uޝ)"y-||7_\W2;i퇊Jmm/Sp@Lw}YW})_p`ū%_m@]WgT<+؏M_SRWF(5=8s@h±.ijo_"q"ޜ,8Q}7Dq7$??Bti=>WwΙ9eپGm~ bZcaVnDZҕТfhjDX^`UyO9kȈ[I'6(&T7)&bWd?Ov{ۖ%E%-ɥU5b +n(lWcۗ95mQp|syPAg~X%RtFh.tF>dd,da!EvPU5=MAX5]4^u2n FFFڋ h޼Mhp86Ωc%o8@>_~{W Ƽ䳡u?g# Ȓ~x}K{dQbGzqɃ{qcc8.m/(,HsL>NJ#w#sV=)oK(O"ߥz]s}ne `ehl#p\dW.^>AYӌxFH]j]:QSCKK:2Uuin)Vq3M(_01_٘TP^\ٻ17E).܋ʻ|;: "jO+a~|~I&~!:YadGھ7@sq_?U򭀾JU*Mcp &&MXF:tEpEEq mcʺq"s>ͯ{cLͦ𜸶 +O2al^waBEm>˳4淾W2s"q LmacqtŸ*5Mo?[Cߍo" 6Bf)'Z;3'lzv=YCA`R]Pt6ֲxLB*'@?Wp17E6G~'ҜV#=M _AU"ƟLw,4c3Zl6Fwzْ?< 9j*|)~LEҮ'ᅷDYp1)3'_I&o{6O|wVs$hYZ!+Sp3tm{2Fr7(܋.}r/9zcBcT~ec"5/1m8+ +coOeٷp ,_c(YTϟ?'LB 8]O8&M9~֘ƩDjhȅh-) +na~[|u Qم/-innf?1&*8@M~0@` \s 8m~5{MR /+_<Io,4Isc &HWk _F/FZeHw =]s4s72qS|J8 Rߏ㎼}x=CWD@{XiKKD]qjo_q:KOMP_ýO)8LC" EHgr4`3>k?HPYVK{7žwOK[G(6F*ߏR}[# +/8Km+nBG~>##|n'sLU8qrχbūqh$?j.ҟMZ$GsF3Vnŏh|)2Dfh4g&ODTGtz8xMZ^z-5;bJqWi +WzQ-h+D;qD)hR9*UkqǡsogcO' ahYH|yHw"<"}HO{=ȷ`;20K|Í1 qۖ#]x|1&/wGhs*ǔyd9ZuUu}֯7p˨́YqssS=ګ⣈8ǵ4h /z|{?pgInr5 CQCzæ6MQ,ؚC?S5@z#xn7W)Ѵ2^fZGYQhڦ`dhuM +AsEyhaյǙ] 5W˹vPYwkލ*!I@_ =OBuH[fYK\k-Ј8{\6~c>ixDNǦ6~Q훎&6Fڣ؈#]"dx+l!tCТTMGo<Ͱ̰Y};=ԍ8Eܶw#s>{CwH@HœΰDZy._$ ِ%CZx$x>:jS޸%|_Z1&q8uM]J⌦̴Gz͑tkM3s%-yFmUVXzNSܼ3Ǯ}RsK%YtkihU4Z,DK_P]dIJQl-y $_B^\Ly3Cz71ʝqϞ뜽9\_4ɼ|~m4Kj;lPnɫCxz2IwB4Y˶Ah5OfLۀ q? @`M)@RhR)m-vNG)%Zc\&r,_qΟNm's|z9W,sH}s~Tw^Փ'>g4~e{Ƕ 3?F44K CA |CZ0B:td 77d7m5n.M9+o&턵QOƬ )}}% +&yjƨZ? +Y(fHbel3e7| +2XEs`4gkZvA}QaS\`Ē+KojJx2jUU=cV?:pӸEM'8c]nM7gI_pR~:@@vl)PBddOC~%NM?KU Ozxҝf +h1h4yL$Ks}=g&vnE;ߺVԪ-*k}iljܘLۼG͗X:¹~|kuxDZi  +g^i;ygI͙s^كՃ=AzGv>Ĺt!0ӴFLZ9j$B#c]hu0Z$G m|Ђ$ +͝kfj"MeleQSA|9b9ү?${3u}ۅǹN-PDmƼp闗iT #N.i}y\lGVY[Bgƥ*TmX{y۩=z&2e5-E&DZKu>>7wN$>'jk[˿o?|D?sr9oqNo9w{y#mf slO8o?#M_\׃Q;_/r_uΗ˜NީAX&k!dVY(=s:N4qM3AMB&5֤4[c#,9S' +w߸y'yʶETgFXCcgbs[is^ɧ?Be?uf0^%9]̜vX쭭}Du{{4䰁lw61U7'7 {r8Vak˅hؙe-?ƦYXcfbJr/!mOϜn^ 9 G8>✄=%x178["aCAջ⶿m>D/ &7v"R>3ˈ ]. e'M=+o<ϛ6:B?+MI#vqq?iiNu*4}ZLvT7Ij?Zs|6гuN6gM|uLS_㇃΍@'ۮ.0Adcc&Ξ}= &j'"g u᱿o$n'ٓ) ѠsaϾn27_x1MdZ\>mɊ}mIb^yIp3]s6u?iᜱpeRToΙ9|\]r97eBwo?Ő?}uı`5f6hey~ sl}#> +WVxP@~-hX_;$1tę nsU s^ݖ&"9P-vۧ"A.5' * u]6v+?%v *rܗ?f>4]%t?ǥڤhqMS1+x7вh+*U(NjX淞O73,@>i q7y/V2\$#:; ;ӵJZV +Q`&]N ZSg?%E$œٌe[S`xݻ/elsQf3|Jzb1pMG},voЗ硩-B=h7-{Qkt8- +8wS7ual-E]sgl LEΎ"d2}229Ǽʻ+fąS>:{w,[ڊ|kM\NUg获Mm&rn/ўl/xy[q=ZFm:4w6 8*mݏϟb`/NdgN)Ps&aۥšok8+7OX -1O$6sQ[OK \~𑵵/"^|W+IڹْT-"ltߣy㽗?ĩfk&I‡5$>4s/uoWZ}@D +-]%ڹR Hեfh6͓lB3=J.=3";FqcOj}D%~KZ0LAuJA{SqyDH$ҿH .D3BPSZ!+WU*xqXyoJ +IU y%tSWu8iC. VfM~C).9saDv|-Jr'* qPvǏOA'3+d9oB,?+{Nbbd[b@([VR)gIgHkj;La)9`Pi'կ-dŒ_, /)4'.'a.".iYA\L7'z`~M~q>m#skƛ :%I>WȉA][]`nMq؝VpOy9G:!+3'&+dvXIpfzdMdo(t"Wp>D?`ifiZTpD^ g>ړm }rA{Itg+)}ؽ_t7kQ S"|I?94A8cMt~y~s;ŭpiY&o EL,٘!+͆C,O@vVH, Kc_{LLyp6HcggڷKϾZJ uɸ#S%5_$eD@/mf3(R=8L:>)LFWH +؏\[ +Z\ZX6q]N;:A}AdOk +ah`DI@!ElZd2k.ڰt5rgKO ^D%d[;]R\7˜ؓ}b{qU2 ΝȄWNBKp-'j<$v#.~d)I\͂be>%>d&u ^:l *1nwt$Xʼy- qV:E\гpA^U.9qβ" {ܡjnj ?e9gM<3ܣ꟦#˸n%Z$lT\ΒL3" +'q5g67v֗;Z|7Fz3v}!u<'skV\|W;'22,[TNO&&y8GtT5P՚ح QBolMMhpm4MK"uz }wBSM/ݲKmMݒd3LmB3W"bIH.xLT;hFƟ.l*Ǫ OٙgrVpܻKjC28KNj ށA_\hr. 6SOŝ0L%~qPl>dāTMDpT0r$QQdq)]2`g '%lUҶ8gNXyq*܀&3&:|>;׸4ߺR[ܙ/ŢS[WZ^58E}_}íA룖pY/q΂3mBhiv0\[]YX8~n\m؈Ԟ"+XQ2D-(l["qqJvȳ Qsu1QtQt}-?3NϥO' +[V'P?@R_{o!/pN4%b ŻbG +ȝ66 D e'j&o5bc*]<Rqo1[?9g"FPQU8z@ +V Ȍ ' k+YΊ>֙iH*Kn,5 9 ea7u}U|QރE'IFRgHj?G>[o&vz6,RQ;S7Z6hŜh d2s Zt9ڼy3stFmqnޅA [{!zIr{ EI/UBcEYTo&5JIwlإkHdbwKdQ΄ŝkdcqÕԩ.⓿وo͕,V}0qh*N8>M!dKUĞ,Mюak%Sgu,&G7 /K:6W^ZZd#p +EW"ÌՇ¦ HqJ+2CIy:g5}m}XҴ3yɼɻL=?ȿ̽JhN&)>z#q3u材8͒H:k ~"}jj=Xؙ< ,{bG=X|=B'KvXWL#&k]#;;i,)]˟AξHRx-M~ݛ=+wy拸ዥ qQJR9I:5ya k=D yXmNgs9u#>:hNe^Zs7$EW?:'7/'«a]MTMY54QҹΏ?xGexyam@RbhZAlao:9:ٟ2IޔLl4|-u<]a#nE^ՀAyi={i\!.n\![)Upy,kYw'6v+-y3s9յA{3+KLsw%u#%O ׷!FMH:|cA׾1"j$LhQk `!}#f<-aٽiyA.xW xx\/<ƞ/ ?aڋ~0o3 /xڅʽTT*Y\_8VP +]&8S +%p}9ҢdO`wnj!Ə%q..pCxl*[Asx01SyVQsM/|< @BjOXV 9>*ZxK^*1~6\3M;JI9=ȿg~m#;Mx}g=>~sg$wxNup.x ŵ\HJo]#?\/XpMN|7xr?U~u^ +S;nw7i;cGWpKC!w-ܣLKJ +'uXx)<4)s-]d[T@ '!B]-ܭwIc#81^;̘Ѵ/u)Z,M+'Ih89(a$5udxOCTlςjޭ~ Eౌsm P#86R[T!J}?y͗gH}3FL!(B{5_]62GXρJu2!Skw0@j[p1)b+?27>mKU1w/f'dǺ$rZۉ6W2 +坕l3?85ӽR+;d50M@k TLsu(߄`sy&1BS4g UQ%hܱ>)\< [e1LFLf'Q;G;FHw[Zh \X"٫E9rz=v9Zԡ3) ^|6@o!ش/l)su)QcԞTM<7TpB"d3KIޭ'ml$VwA@px0]=T؅!1 +^޼G_fOH)!SҸ^^vۂͺ5uхMkMńgZq Yh=pQ9SdqӁ O=ƵNYƆ.QSK'ΐf/ ]~sދ)L'a3bJ3W%ٜ7} <+LGTNzL33򅍼Q^ԑh,DiP[5 G31Uck ll {yu]$=x./OGfO_NW6[e-xl k*t~z5InkNnM%TM>͂*adwh?Wؓ6yj)h7Y.ƯN1//7j.iv{kxIRӽ|BaMpSe=vTիz0]N=9ɲ/eBNJZnE?Z V&"cܫIk8ӳzc߮|}nd}}=Icu5 pvAd(YyI`q':ڊyc`;"jpXX`}::wo=qU`oN'FyfMX>#aGcqUY8~UuHDG׾Tb^0$NUi}F QcxOC3YD@xpgƵ + KUL{`'͆ 7,`򮮔wX.S<M8D;?}kXxy5ފ}*O wt韣ů+_H^k-ź[y&lXk=ޛ{aEy5?LM`xK8x|mbg; =Qceх+yOv+~`D2ު_njx-ӮxlpD'#|v C^<͔3\8}s5<qCϏz~X!xVX L ?T3ۭޣÙ;wwXXe{\ +9 RiT4ɶa&!qp8s C r

uDdYT!O/x${w-Sx??-Э2q/S\1fZ$M=9gOtXX+/n?CfLY9hRXD Fx6V\tXoٿՆԁC/?us&#bgUtX՝; @6g6$Mxe^2fΊbgz}:W0/.] 4\yLTgvPc$Wp ~>3@k(߱tK<6_ {YIfSG>Z# X`ǹ(嵕CGfq+ -Nb)2[Uvlg 1ξ $8E聜),B65yHk\tC]γM!$ k< 6,=P1VoYΰWqSvb,,;Re1vv F{0OCO`w&"0smdJ7UYe +| +y>ᡲTe9uGT\VZ,\򝑣݃Bq]R;W^*q=%}&$;݄ggc{<;V>6YJ`g9\2G gSYr';+f%gv_,ᔛARu;h^`G77@ Lg`+u ?}Az +4秝_?uɐљ2|-y>ρV o$}HoS$~@ F^jvR$"qM%l8@bWOU`#B .aw'PI~>*`-Avz 8G_R7Xyxc.eؠlG黂F';HWub4Jb +vmýRyH$YƱnq3|kɟ7K{gMbfa0 ]p=[fE=H*o<sZ^[^Q|n!pIeGYŵUnڴ.u!pf5 Zv/9΢xvVFki AgaCn .AČKJId'ɢ=؈:@{}績$B+ReY|OuoQ^5˻`},l{duxhu]f&W +jS=\S:ʈ2RLoQyB/x8XEB{&MԄV5 ' dN2ܫ6b>/Qr!!S=UReSم5O\4X/SY[j.*Rȃ'|bC;n ||["ŵ*0p`}s)5ġ9tjΕ~3QКX00zt8o\ Z;(s..&eB\4-yb㓩~k d],'pNOܪs*%{'_(/E^_F5v~n,:<8`" ˚לoY +T<>qp{;b/w@[qΗG( y>0[@SWWٸ݉v,*k \'Lp02-leYٲ,+xOEV_ 6XӐ$Ak5fDɽ< X|rn![p#[h +:I @:8 |d{5*4JTvQW' +4Vg]YL +T%Ӏkp;YCXÄqxq,,Pˣ*` 5-yT;["|_zb5[ebf_X'd$OC3_8OHGzm5;}~)]hSh,n4-|fM;5B FNuyߒP>Xw~3qWh>'q4(nS'cˌ{B8[KgyW%9<7ڍ##O̥>u +"'Cmu3-0IX.m]O+nN1+z-`DEY,]Ьw^ y֮/k2ߛآu/X? ؓk)ݿ܆!m{cNvXJp90S{g~i4ϭf{ac\|wg5{Pq dyFc=[w +b=]37p$MwDA =~cCh+)g&40+eQn9tnQL2꼢fBp(8pA8sX{L'EAcSn8Y7 +qozb0<HJ &>X\}t;KN۾cEGʰN5y0}0:1] B[+E@4.ŜA55Q;<<^m,=e6{t)زsրN֟$_G_Gdq''v{?tzHB#wGϛKTߏ~|?ߏ~|?ߏ~|?ߏ~|?ߏ~|??::[eٗWgզg˝l\1uZ{];[zh/Sf馵K'oq5m>|ړWm3ۜyut3מebcM{r&/ko'OZYn|WSXSXs.+;\mC~?<=Y}6}V<`Jګȃۃol/sgA|@ڣ=gmh9ڋ.D~d̅;?ϡ_7gK]ofijSpZkf>gGO9[ +y߼قǘ"ngPp d|RmCM{evFD*1]AlKWP \g3ly'MpE9-W Γ$-SQ=M[{;mp%5'ooʵ`=2.RJ F*`]4У>dƵM<#ܦλDޭΕrҀӋwKpJ, +[pw$׿ó'NKyl"6Vnj׾}[A)뾁/g|x,5u #'=v=;rʁ6"@o~ #3wTj[4RةΆƶ]L,p8ׁF!7>6JNr=2+rO\v3~UIJa{{Ik |A\ q\ufCF݄]9>n4vo"۴\]}Ǒ¹+kM[Gt `#z'jb\/95=a7{"0_=1CH<"~m{zt{e w Qr%b +xOl= +$8wrd͛{& 7spup38(X˝3^ڮAy&{q~}Пi6 +}®~oO9:=\r!6^֝E{{wl\4!!>=ȓs3{R5'^s%#EMl ۔䏡 'Ӌjmq|?C"rNJG9L: FoA+8-E"dE幊}ǧ)7DDzPHgg0gvE\Xq=Q ^Xό^qn=Xk@5/˜{^T7"B kHFpr>=(ߛ7}-'OG1= g,D{MM6䎑@hp#ȣNoG _1Z#BrΨGPP^3p# (6 endstream endobj 965 0 obj <>stream +`bKE"?Ks=x&k# +ׄ>W1tÛ|gЏ)ʽ=|a\KG'v7bDp=+‹t>ѿO>K s =SsX?zp GcR sN^>Z@H-muSά 48{z5Օ $Lyviė^S2'́uKD? x85U@$g!St|kA\F_8Nqɿ7;םI1 |;~d :~wRX%Gy=$~a )'/q-t|w`ʧDl>_Wb33MN{gw"8o<8W/WKV|."Γ!h/d`{m5d0ӊ:7<A_#gM6UڏIl \"K'G^ NY5/?:._ڀ+1(#Wۃ""scڻ!}'#urOm'Wz=;{J9^E|#WgOp 7fQKSi?䎈~W0~ߕ\|Sl?CiGu3IS;;CH8 ޅE??x(w",t#Frf&Wp[D^Fܞ'۔'}`(^N2A7l?}'d~PJ0^p/E<_-6E9;B{ Igxј9y(e٦=F WǞAw`hdCjDm.(wp G%?ϡGǁ<荖ںK ]~fΕ_<9u~ FEy~gd-~[pw=MUaGB gƜm +U1fB/SGr,qi*~ilAC1>~{e89ߌa <7w8SAW ޾11ۡLJ2m=⮄H@||Kpn-x MhmٓD2%\x'!"95$n}'Y q'$$SAlj&ip[h"rkn#yW/EH=OyZD/l~ )g!,,"s /] bOOB;>sር8mk7 3@><k3oSGȑx'N z\VjBs=N'1ۓ$֑n2w 3z$$WYtA- ƚ#oߦfۑ1^@㆐1N ?iN2:IqGJeiNpkRؠgPkWc^p|>\-vU5\`.~}7i>엄 +ɥGl>};{ʽ"# 1h@rm<֊=[[#AT9C%1 ';2O4KΡ)Qҝ\ᫍƲC͔gr8;B{b{k.Nkh] `W.Oի;!nIAqoh]M0WVw֟ s I}, rJ¦z ]bᡁ:gtQ-mxǀ^<)CbF?B#M̥cژ4F挱`ՅTvm:㥢: (y(ٕ1cQ$^Wh >wX0UH&39#qϝyg*=fY̱bIkd/WS';s(8Afާ;tW'yawKd ?QVhv|s:1¾S%|Bn!|O:9I\ rq *!)>&14>L.xA-v'׉]aNQ]SNz==7D$QA=w'<Ji 98iĻ%Sl-8 _AMTr飆ZOE]j}nAu6p#1+mX'O*<&Axr!_[gdȡrGJ{eϾr{WD}d?:Lh ^#1^|il˕\jb.E{p.li~ +rHs#8'@@̪Xf,,Q0!Lg boΗ7H9z[vh _琯#N܄|Ky$ |000_wG5Fs/M-=3M1S8UؓٺwTWf''/7ƕlvu ߢF&!9B~)9Cʉftܞ~eSo\~DOKy:ȱpn20kQCr)4o#i5D^8>QYK;M ٝ@>vw7'K:5\Isl?4Ԯ$:6V88MsI46$fM"wQtYŜk=?pyMLbWƽ\}HW "жڤuٟ:0שV#N^(/'BbH<(o Ƀǃ^;ثӡh\ ܇bsD/G' $߀1W:u໧kda'G|ݒЙ cKG&|'DLPgE:B~:H8($yjLؓ{nM-9LɥJr07q @L1r. + ԓ=WfQ'ȃF4_:8dq4_G *WhcP`|zVj驁NݏDM{e=7vN|vEFj(nz@(>>NE>|ޱJ͡InL@R>ó0g/DF y6럼% V>,Zp [žIakN.‰=ah'o9!?~]*v3ָT[];VSG!ug3Hj{CטȯZ#Tob3ԘR6:wP{hL` 1ҩ1AbՈ vcAr ;k7Z_ܑy;ſ''P~ګl~*6Zw /;j-)Orꇒ Ãn߸z%TG*r!V5C#C`C.s>|%"H7n`K72dE`F kX;+Bjz:x 1q9//q_(OhaɩȜZmhLny=̠A5OnuV5W[g +q?[f!-.3.~Nh~%_˥Y E)|vun'i0_먔1p.xᷱbA|yDbpP![ض^r1՘ <1QujLKɟB1wAg CQcB5&:5&1Ƅ[7^]&:Q5a̲%Mj2l`6m0f y +U-Q2Aȥ'.Ş/(խOri\*hXrQ'Qlu}/g-+W"a47`yطGlBHX̫)U[*N6 lig8HkV]9.Np2~M (\0,3;bt)Ĝgk~AZ/:fz|rֿկBĄkv4}AFט{FѺ:&fuw/eDNZ'hY{GkRNo[ƵfKm,<5KN+ah4!cO-[вl^ +>Bq)bؑTk^Zq;B5Ҙ 持: IV"ɜBzIMldvFT>$*?jL N`?^lي"`?4<<~BS^̭\NNޱF|t1ԏ-RSwM#vb<@QjQ1S ?@n6m࣏O'AZ:D<aRڸi`L 8J<ؠ'ړTS~X>IѠz&HIνj-3h h +~ɝ{><^Ƙ3a@a([h` +{XB{!yt_9 HN=2$"! -9jAS&$03l`.T%+!}{ThqRLiO};rb̯'&=gcAr] E*t*/̈́|͔T$_wRL=Fgt{>"M?A}&YƝҴshT;CVF_}qE䉩tOc"NiB؅It "tH00>d..~s)w{kA'| MXĚgE>Ƙރm5Z>]RNd]8$hJ<-ė| Fؼ#/]WlS8lwo9_^9[QK85Q- '{HE~mbKs30XZ=բ@뗨b/!ѺLka~KXk&\MPO:WT :|1qĬ1Е^J W@R7Lpr +ik ڶSi~ +U5s|<[v܅)ٰ? z7laZ5r! +i%B9.M!ߦ87dS'K`~7 '~Y/`5 aSg:6Irjbʬ^Iv.D,䌤Z/^)P+"s@&Ѿ4jC&<:~E_w ;ݣn {QPG;t%SKyv.9tO\lE 3#y)؛K5^ (KnS9cR|hi>O|+DCӼ:"$']5z ؒG]<\H1+pg}}rQ0/{oσ_'u2Fh)5:&5!;f?'d~b3n-V;A; bYqIAjg>\HS.Ά_e?Mc}b +ŴЭPԙ)4n()lX=<EP۴ kRl9_ e9˨_BYN$f-:*ɏ-#x@jQzވ. XF 6!hJqrcj A{.qc6'㸘SisY=35nIeؠccʲy6'y^zdzG?I|Z+;~T~Nq^vJ+g<|owo%UrϠ!I$!l>a2ˢrqKA@Y1˦y,z3byؗ!˭^-!sly+z]嵬ƺ ?~i ?I3h]: Svu| ۴݁#OMT_1|OIgiOJ _4f7n )ͫ[sD.ͮ\ +;]k]T s/o~TZu=w\,~$d]x ȃWqƜ?(4{!/6X^q9'M>`/7jejכ$G^Bm%5Ҋȳ+ +^ YSD.yDxe__l^ +gmŸ׳ fCWW9je?_A״]xL6ݐI C)I+],F^/fύĂMAq{O$06h6iإqFYW]"B诖_l%OŴ\ež#t?]oޙ+j[olkE;V6N窭 +kL)ro#Up}:bPš21e}}&rEq +;v|?At܉VC;cb _l[-V%V'ZMs-GPzɏƲ,{ݔ,K5Kv+-%ˤWJpo66z^(|Zi`vFfvB +k4 m\5 iïW=v{]_zf٩3 oe>*^mOk<".ՙ/7m/7sLPc6kYG;ɣ[Ho,e/e>w춸dlwI;z΍O?d?* +<[X-kL8%B<0Y,0.1jE/duPФ+0wQWA#wn,YHuI/~#i͗/ۏ!_J_W:̐'v6kxLvyer[:/;fٙ KϜܹayE~Lz:I΋WfjHeKPCX8l@١jJf7قu‡HŧDOqlKWNw⍡4l6,YjBzxNYok~|gf+lg.TY䮴k/ͤ7yN~k/ūVҳ_ߛp$w^+*|@})/88Յ,w2Ցpƃւ…oxbvc˩l禂,ݵYi y/O>ow&\}z ߆% 9(BᇭZ+-kF۴Hn.T5zKZ\P2 9ڻ9òjɱϭ9uk8xоry]I$I&m0/tnV7)N73|kC𶖢 bsOҢJa6R?x+WԡGcfpR%]>'Y7p2( VU ^[Je$d4 Yڲ/od۵oV+ 7P!''66766'*(36$}޲eP}b~DݾUʢ)zS#ʣbFTKsHr +u([nwF6ŝzgţ=&?d,~l2~tlkӡ<禣NMmQlgGҿ)$5K+`Xe[ް}ѡK'/voy]fq;k~ÕΕl//l4⎽,^1Zߋo9ez-աB[cAefxuto]|J\ex@Zߔe {⋫Vx'x$TV{$+=JK}/. J+t/0w7A|_m~M)}5¿rg~1.+m[ɏbBYnś8Us8e]mSy"u5]iśJ%_M7^J5F(U%X{ ϋw`WӑC֯n)Gt~6ˮTgsJFBuhڹ*_eqgzĻ =z&ިIH݁ʠςʃ+c2>=7,S FISLV ߋK(η[5ZXZ\$EH ߮5JWZlv|狕6,"@@bp_uMsI~Y]{# + n y^ʵxSL|t%);.y5dffԆ87S{=o;?16;.:36Py7)W8y棼]y?l2,4աX9Fhm 7+ʒĮӢʣC33sKB3bʣsWLMT[{?8<`qhTb_rȹ7җ4}uvj8s *Xlu1 +m_]L˽gBjcSr/`y`ʹz~vg3dvV7'=ү,]JɌܗ4$pqhOejK]^k]~CSxJˆXEӋ(ʯֲnjcXxlg3jFu_<7/UqvmӬ^Q>ر/gե5~]_D_c;/wA^DٛW~f&6dfUٶREK|k\JV%SqTV?\WT_¤_7S']Pm=Z^eQ]|.ǯ:5?<"L!-> Rw/ J>0$,of+Oxn~1cwSQksھmk:,OR)33.83yt)JGIʠXewÒ͉⏍TZevʸ茂`%{ʓ۶)ܻ|k/'6ֳCr= +TyrQPڙAw(> MyEbdרOJ|*Lи'#y_<:CǀM**7Wg7'^V^No >V Z~x4}z7U+ |oꬾbrS9x.3O% W1/gf,\^hȬuYsm#jKkYR;i'&?J˼V0T &}/;d +o^GW$om9IpIJ3> N;FpCzyX&pi?O:Xv Ig^x$iHߧC5z"3m63&3dF1Mc3kzlm0 V_e&Ōdw gk2F0új3zLddƍLY`̬W1t-ՏU*A7cEeЌ%?(N/%<8=,<32&'2!;qxi:ʬ'{3Foys])m՝}&ȧ!)=yOK>,8-" r8U`lzδ ^χw/ӽ@Mi(3ltfkfmx{7>mql>Yt?4ჀÏCR|/)".İgY+S> Pf:I~mU->) *iF[3\Cz䚆D] .Ʈ{C\6feԋNWm^VY5Lo>^Qq.&1"0y@ g)%nnSFoUL<7=U_j` $#5}#_=Ìg\T]j3o;Qig_v~pƵ‬ Oo?Jt'8Ԅ'ʠČ$*S, H- M3YjCVz͚֟`OzWv:-y;{  zڗ ԘZLёYhYN^eǕcA)q%Qiۚ"v?\`Hի&5ݾ{RN0{]GR'H̩ ʴz{QI|{bÇs^ou^w7zgz;ԋOgoGA߮'2S82KNk?!Py4Ot<|5> LNư80Qp^Ӏg~wL0(-8~Ap~YI@͇A? S\J22Di~:AL7mutzCuz4]֋ڛe3T}4ӿ&'$1~ 3XCuO}<3tfFf@f{foܢ$1!5<1],mJcR_O| 0![*SNӣ)%Mf}ˉ?*a/c_}W5ianj>x15t9h3lfHY̠3AFy*f\kfycɆm*{ۆӱNU +K&ţM +[x$gA*o.+A޵\`4]O("61Юݧ3{` ;`\>ڏ1{wR؛~P泇参K3< |(0ܓğy⟆Ӟ)״VM}-M^Գw}Gz~~G-q2N#gFig=ވ>ޔ>:v3jKd~kj-[q<ڗza`P%=< `ORk>*O%רjx:_.3tw9؋Pa^g1#P0ogͷ%GfT9N (e1djcFH_e,j[UùboD ͪ] 8{~ʗ+|3xgͩ)&]5f8;c^k}ɫnÙu}2Zf<8̿%A˘!6j3j7ˉ̷>$}ʋɫKT >y;4APF2Ԗ2s~-U-u>yI.V\gڦmv^+Clpf:ɐȼL11L?2cp>ɵe4/$ؤ3b3z33vcL3Sdj2tEj}üGQbSUES$ƕeeTfzʺǪ/۟ jm,ݯ5QV=H͟1yğ< 5̘u^뼙&)lB%/bNUh俳$/6~Jҍrn=v4 "3g>$yB3Z?ٻJgYr,J0"^]I,M|xF8Jms07DM\XfXco$S!egX23ms10 R1 jk{tZ5nMj%N[a; ƦVG~@RߔUjk{V훓[b{u:1/=h&sm1DF,:VZcF;aa6G|3r.5b5v=5ۂ9XfY }U _QB?6Y4;3,Ml4/UoyvTUԬ2_7>LaXŌDc%3|+V0ÈL2\5|3rOh̨qI,3n=3y]3SzImnsz-aY#V?TЮ2|n6ov/99v~}bxSk|n[_֗~ZQjQW]RMY[ZeIjICRnJk~%9W> L/'oܚY/kWlX2>5p&3n3c 3YLMb^:#qQO{ }cnk,kAtSu}=~}W_UX]Zjʸ&5T6Ԫ6թ$[TF`A徧:#UDs@eR!kl_̀OCqQ]"1 ==bITc>Ta+1F̤.Li83]%&2/jd|*U VW|B#hfYj%N5)y𪌟GKF_U&)P cJGoNmlPD{` 1`&iEۘ=&an̴2fu f4]W/*W>WQYJ|m=$~~_<$kVen^te*#RkRԿ7/Hj&~lak{Y;jpIȏɸoFw=aʏ4O~d~ZLaJpn~KUZomz*ݯ*FUTuY<, %"XX"~.wT6\VLްQeiҮrGKueeJsGU31>FiAJ6ѻp|{@!x7={sّؐScMhv>׈wmE0V̄3@֓fM˯e[taAg91_l3O?f0Iaٙj),=piGw˥_i+M)HoNӋMmφXOU[/_JU?f_ݹo__ >mgi:5ƈm:h `@U-o-K/ ^ֺx2k-gS,.]y~0鋾-G~tbAدK|ߛweEsk߿ksW+{?Cf>,c(' )B۳ ≿{nQ lBM@fo~ۍ~ h6t҂iF\gYk3q9D냋ܞn׹}Y*iM7ޟ2O nC?%^}petgpqa֯cD`*mTQc9h\kOzlAxT{roc`O}Tn8^*Ƶ|Z_{jO~[ocnG{~Z:L],Id6&^? +܁σw`ߙ^olw3 FLCbrlC;?$]^cOdϚlVgkJ$Z?r>v~'_':&JʹKV>tcz$>.UE2w۸[K4ͷa]a]dw[qy{X)|t/~h}LZͅAnHoq i"b$Ʉ'YGd ˫9 ~޿7߼]:pgk?/w}9|vx64RfF%[й4AW?K +$;2]۳5ݿoiw%ǭj2#3 03\U!M&{87͞~Qzzg~k^ǀu]S{t?^a~\Nx>h)cbsr_k͋q߸yx2!ؔ5 +%>XoyCWV[MĿLUj.i0:ޫ nT_1WI.Ƅ͡f6pX;'fpR:t2 ZHۼ~-_PޠprU[:&`9ivlӵ|Y̅r[0\ΌwFceǕ l/kv7Ҷ\˽KssŪsޡ} {=c1!ԝwUh{o=W:OkN+[9Ivo%w1ꠟ?'?tL#,AZ#]4!į"ߤ W*)Gmhu Ѩ~gW{uټ`%Օ RC +"R +F$4wio? .}Sf{ +W{|p ղ';JWg_gwsc]6'븿Z|Mk=:ߓ*{۠ˠA_;>7}J>{9%Z&$y{y2Lc:;3K mЄEt!)b^$[tcȯ'&؊Dz7pG$T: X 7> z[<;C_^"g%is'G8Z|N89CHmv`ޝ`P[>"k=rOL8#jݯ˧|0ԿqO G>;n uM̱O|/{^IZLcBf'^t -Xs\݉|.{.k̟c@:\cxHskoMlW_ܱS8Ew/s WW/7>'9W! ufpߞ|CK,l0Zo0ӥ0ŋqYܴmHFN0g\7negcYpr}PI׬ಁ 24Mƌ4ow(Vvc:eSٞ_]}wsGlr1~"Q.هaurWrx"_9>7Sd?NeK@e?:$hPp {ؠ))<0Z{KW+FهDz鍣r˚uy̦ek_eKϐ^=,vRw^[cY:RO? ?yq͗ EmR~$!۶ \U4C݉n)z]Nwn_~*\A>z$~?[ٔ{!ܞ+::YYAeԷK>)3E~mb$S=I 6(\Gw%o)#|ZH[W) pŐDscZu;+{.l/aWf¦plw6KꦥS ? k cFuqF*<1W؃eH.l13,=5\5p}\څ/?3Z]Z5֔#\2D=wGR{ +0Z:> @ͥ{p33tesƲ 6.>* f;՗p{ ̕wd[<[c`X%L(̷>]/t7<#:gOlvܕ{yqc0=7O|.kNva/r3 +~go$*Z;OkEw[r?)Dd-^kO?|Ə塿2诩p>Y4nn>]T>:2 4ɜ ϰS]3ܼf=cRjB]p)bnU:Pͨ,+)4\K+AxU>Sspz}ϓBw +u伆qB7;]+zVs{)BkO̠I%gf9 拕]N|eI0_7ݥ9t&jnԧrs'ª 5n팟.s +Us330F3FNf6U`ёJ3캼Xj|S`rPcNYH)4O_^)t~ҋqҟt^&(5#7][~xAa$3(>`F"#ޔx?wWbv8|/9Й4+X{q>2t,}7s? rGs/CgL6;LuAY\LMtdKmeY#xdX}qw$*$׍Bk.6w8ؑbg rOaĿ@å xHb?|&b~MxP;SG%=}uފ|V}o[c#-Шaro3_=1 (|Ffu̶ ۉ]=PS6ԖŶ|b.2ng#^]fG52sx`d""33{z?4u?,t>rƜTwbx|sW#pNԟo$(6 32g.F*蘄?kO[Η3sv@ 5CC knOx V|A?Use!s?ǝ/v\~:3^nB=\qԫdęq `h%Y:S&u#3RJHgؔRi4r.cpyx3hvmCL n` +ui`R6V껟o$qpbk{ Rϧ݅g~(?xcne}#SL'kwpG_30l\V[/ŸlYlA[ȀoCscx09n$zH.I~^1LtOc?mz 4 XRW&U EG& %$ΒB$B(e#wH}g 6Klr;`B7ꀪbf̷r=]/]JLZEIrbǃ./F"W\U?5HQ# e՞'Vqwk3Iً; X3`IПI.Jڦ oz& Rˠ&X}ll .>_gO0Ndc +ǧ"U e7{22ÅYȥ#_d , J;}DQ&\L{LW>8,ͤ,|#W̖.s7SMx'soqzJåg^GAtᅠ~4'U_nĬX%ꙇ"{g Kj6uEws2eHMIe#6$jCR}4o2bh%Sa-yFi16`EA }1q 6 qgƐ HMo/L%J:ozmos3HN21qtn\O85qu>$lng\3Kl8kd&ZƳ~~$N2X#+9H8m )d]=\F|.蠂-W ^aC`A2ǀct3,T\K:|r-e6Lb%{Z1g (YC |Zm`ՐևͳhS(隂_+3|HH(6M&9tX\+ɴr)LذK!~3L/PNV~~8w۷(}]Ej2SO,$׏@9 5qˬq2,D3/Rmג\Jֲ&`r? ~)|h4CvZșpl8RZDمemo +M +8;W]MrZs;R,|:.2K/R2$XC5UJ!$\N&6V6RL&ku.R[L$C-(jťjrAJJNlp\j!CjrHuC_o^ T7$p0ʙ'"zg-0 8r. +f?[JVm ;w2GS )jy'>KKGZCqߵK|9pZ'W\-R^+9Oc)ö?[ }u|tmޛ6DF)ᢋxS."ӒŹHHqcf-^øb 5ӛ]f iKW;y=s€D"Q:L}Sr-zc(\ۗ9&$ړaCj/ =_{o.d5 5H=ST `S8!`ySFtBaZPԾGZ,ncմ!%hQܛBϓmZqϥ|ZbJ=]L(AnރTz gpƄlD%4H .x:bCN䜎I]č=zԼB_ =z^n> yGpAkF8&pBLfÑ^B}0f׏BwZ`ݣ6\\.twUh +J|*5_ ֝Tvr&ս|kVn%JJщT\ +`ؿzZ}i_V +7 M h^Ae"{=`\m ]C}KQ=$1N2,ԔyjC#` #wWQ]I`6M.*.v$5չyb\3{ׯۡ;x}烥bv;М}:c +zGbm=rf<݉_I$ 2CoΐXb/D$X .RݬQJAjDZaݩ)E#zXjgSxOڛ$y vZC̡-Jfc +!Udʔ I(ӶȖ2w͒DzHpCgx4Vqb=-,=6+0nlP|=4U]ݳ`q+pZGqVC},a)vk3G%rnWNDS3:}S7_HUjC<C/z|^0abՌQ]=s;y~OpO߹O;o|{/^)iTOVzIäBL4| 3O"ϕs:'"Aۏ˶ A&:;1:;FP-Qj)!6]ϷAE={-soYzI5aigMG1Qodu$D">³"s QVJx09"k8|4>uމjѡ)bB=ջ V:x?OZ〼U%> }W=g+PͶiBA,n)m@fRW*Qjl PmP߂)B\h9r"1?<*w?܎^YJjhسS7ze΂^2jU2e$~P91mX9,k ugr \CɡT,{c^#vȡYèy|`G<CB5*IQtxA>#t9?#ֽ} 16A{'撺o3x③B˃3΢'pS,T;+Yf>XjT;nMjg !,ÿkg%6L2DR[$oG Srh+; +#モ8>T_wq!K8f\*q6T,*u4Cy\P Rf^ +IM7 1Tή>"722{QP-"[>".2Â*vKJUӋI4:I '*2T[J%1{Ű71u8/xwՍhs"v(㪿̰a|LJDC :R5g k;7^MiC5cֽIj3O9SIɱҋl`)b'Ϫ!214Wi֐0'Ҟ ~{;Kɕ!L1b=ȥ Si$qI6OCtHo6Ψo/!kxV:q'RԪAsHSaHPMWWA yD%kb a_f074ꐇ.."@;(./ m\m>~'sY"t?'FR#䝕#pODHȳ})ke8L`rv||H3`Y |}>΂VY>+g"YCY+Ŗ"F~+)4$~-ȇVɍsWvN˻SޫR][sIe, 4I\{v_\=;|@IĐuhg!>= Cymp_CHEk ;G31\ +ΰDGM*imH#-3-ՒntD.z(@Kuض``a1hנ99͵6Lvj>c +47c30cBL%3E+ rR-0ClI;3{|A}`JŹ;Qʻg@[$>B8G_,98tΥT/(j2kR frmM$n >ձA^T$sOk#fIwMw;iEi瞪sb[xsV'3E5j +'R/!+XIrPY,ŌVGh)kqiYeӡm$aMN5ޙC5@kAPϕ/[n:['Asڳp! SdzE9Ou[=v^^BMfO?_(:3Fz>J!Wg"5} +3s_={ݤȂJ9fn^jvMSS 'n~`eʲ$73z"!?i5 &T˓R=VؿD5.|#ДsE/JΧR#FQV!:ʸTKQ^hRMzۘ%o=+y&lP8aPnIQC[aZ=֩]ݏ^"%Q9VbH4zē_(E'AKm%kp5~3u-1yRJf(h(mw[n:J)+ ++Uc\MG#ȺOI~Nꖕ'tO$"s}cxvh[lJ/gxVTO=ĦVQ_K} { ' q+§{f{cBxd"1h^8s`<4UpoL6"9;]sƞCzW('磇{{Eb4r$7C\e5(S+ϗ2bOodBǒO%tk[w=wU{T+ځ=A{O͓*H^ }c?tlb?^ﻹ Cؐq$z?a(Gn}\4w+fqaj V!&@̾q2?e췪D\츻Yw kL*qN:Z>X +bl1ŸL+l=$3hCmU@KRQCO/M_7$fو;+rI7QiL 9G9y4jԻ8ȓpU"6+gYQۆ49gJITsUoF=-ԃس +/V2:vFIuSk#hgCJ|TO[f:fWZM_YNu^3!y(ָpyA8sXSɹ+!vFEAR9y7y9C?>RAM9stBɷ]@>]NIЮڦaυt?pY +Dhb ȹ2Oqb N> jf{..3A>G?}jlE&Z@'\7f/|ݧ +閘AGl80Gh&TMo7Ǜxs9o7Ǜxs9o7Ǜxs9o7Ǜxs9o7Ǜxs9?gLJm N vZH_3%WXyPrN͗x)BT5Ui͆dXݭT̰h3/ ƧŝG&yVO LK9~gWfˊ h0yr7" i!\ȰT m qJjF4%Yy{0U2ƨy':20׍2~t+>*RnH$X}7)WW'o$b;R|F +(! Z&r 61@P$b{ #F  S`-&bҘw`2|{%"ϊ" +OȕQ?Fͳv#$  bi02o>P?ĐQ˷a tL/s#s-m(jk{1("[\ bt83o˻g@sIV}Z9RNNGI0JNjrLJlr7N ͐fX9\s|hS?$lfN|32*Wa G˅&L>FRdސl#JL DcTohI1Õ2VM4ӫď&+6jFXCrkdZa՘U(b!cR:*dF:PhX&@ 3³-+`m bmaD5%\;BK(UF7JJ~^<N5U06Yd%A1$R jL5 JrFF\+$Gfbl%$ד=,iȜ@GQirԜijE,LRHꙭ֞[ߤV_dHr +KHc[d vh]3VY3Jl Őexcgs0h(!XCoF !H'|&%*ё+119!ScTL_R@jŪf6T6vL=yqXKq큏#@,1=s8!lkQJ|- \p"~;(o\|&XH\η^VL1B,U'~SL`tX `_41M}Q}H.gX@OIU*ϣط R:Jd : a1M 7h'Š$ >&qctt?6j\ ّ$瓜dj@ÐҿM\HꣲN#$~#53d ĚcIG*1X5ct|@24# b_K$FL X0~ON,x!dbiuqyÅPH}1YcQ{ Jbvù| 9$^a54JCtm7;6rKCYJuń*{)u&*)^1Sˍb41~EB~2䗩亦E֣spw| $/UpcB|lS5ch`%ȃ*ް &85fqN 6?((\8 +|ōWcIX?^2!%rhGϨv@4GXl:JlTl~:H9!i? + Eל )c2s$ϗT1粁Qf."XJI4iE?k FS!74Z?SJOAG qnI-DZ!-n_X!Ogfa#\V8SXuH"Ch^:Zund $?3Z<9[j1xzAFl#/>c5a]LdΘ`~&3= 9P;JJhj$V >ޠ9{rxJ,+?\>pu0O:CW܊SkHDH?(HBΏ\ h%E&~ĖDI^#&y C$(XR7d[\NS +PId&z;S\}oGg@Xs\o Ȱ:X;@#[qT 3R ,?FjX3Ԍ"wGjHPkJ!k I},Y *}|'qÇug2-P?CVvhY@HiV0b +%S8#ya@ ;s 5Vȡ&+I~' c t$u9% h> ,KC6h9]cǢo I=sh/dȑQwX=9U@Q콹b@Hj\ ij͟18HeL!웰"1rbF^䭰ǢN'HO$ޢd,l\`RSH> +~ ?D,>h pi^T->1ֿmSԒӐǢgfv4d5 a'|{&&*}^3 +LhT+p5ʍ?V*rgpsrL-b-$na%B*,5J=43q')R[ļa{O\Gn\+BR:u)EY '/Bi%x z ?v^'v5Ee8HOÑo(9I]A?AJI,9v{?C-QLsk9n$2mM.'Տ^ 5]#Mv^P~gnxu`JG"ף蒔[>kș;7O.BnX؟V1E_Hnq8WuNρ*7Cub>'@/Բ^_*z)$ :0DRILE}`nO +ؿs!|"P'(@<Τx2$\#@ cLR^>p*oSs~>iK 'gwND.8!^Z(EZTE9m2wI=Ŵ|4y$)v:PZ +m;m}Lq+r;axv .4ۀG Wo'(R,&ZI@.^G$yzi.4rmk F.,&ՌP[ꑴH|.PrٹB;K bD0JfnBstʖ DM@2葱zQ"pOP{k~ _&Uͤ=BnÀm. ﻶL8rᙑ?$!B0ABwwq@2fsܛRR%Ӂ`(N +pS={%u$z5E8Ngy>BP=|5..O[>rn-æKG~wd ƲOȴa%3ZY\!1 k%ǧ˅ǝi-Ib:0f;lX5 QR[?ߪ?qTr mN5kb3][#MQ4nkHQnj:r#9שD YqIxyRF@+"k KJEE3HT!'IZJ3R[K qtU@C:K jɴ^&:d!ȵ}犾Y^R嚁yo>-wwWk3/8ط^l$D9a$ yhƫfCSR?uT(" *3O" _YԜz}7ׁ|{:z'P? DU/Co}JZ@P:Y|g!-y$C$':=BN%!$T;5#c%!*TsABI̶ڡr#SAkCJ#W>ሡbyZ`ǀ_Jj Jrl~^BȉpN1;Kam(bg[;(˽WVJTÉ<<ަ= ZE\ܣvKQkKEN|BmrQjq#bBtp e, [ht, ߥHk!FPT_5#ÿEi8 xTi}:t=zad,‚!E^(=9@Im~s f/DG@r#m(9{z/m +Ki?"Cv§@{%'B/&첣lxFa.i +Il>*gd!@O֮@<OžQp<j"-E DqIr*F*?@ΙKWuw%`I% ߀{WPkQi'%#hoasG0ߠTg J GP\uF!pp5 ?b. غ-*BC{+$)șX3=Ϩsͱ7JF,ߒܔ^BΡqHB3j3CԏE~I\%!J$!Hn.'[BёiYG,jw #J:s:qn-Ԋ|۰N";UjGiHlc҆cjjHA +xp EiZaj_-C~9?zTkmuv u90Eˢ~%1BQ QC $f"'G@ \% z=YS! Ip&  F@PSIoiGp#7q}x ="J%2 6|dC4h~{rk#9DW⁛kgk + x{ntxz Q)rSo`qŘI|yU,vñgz+pT6Z>YG%!H>` +Y$EeۦCjJBIB. $De+Ѧ4=a煖{HI{5'К3{8\mR|ϮK+%'fy' }x@nּ@_^0E2F}YMcQZ/$;w=VZZ5kz}_j_Wy Nf]r g꙾fOJ; խ+Ni3"SM*eP!ڍIwOJ*ie@{9`g߱-[' +|M`-?mۃ=]OSėS*0{@F nW {Muz('i;+|sCt .˘}Lt +<Й7@n}/}{X&Dwjv=3b-eD] J5ƴ0c,e 5^ߐz.{ + 7n/_<@HcE[~_^T"dJ=^(!}qqw*yI\r?)!ġOw}E8/pA +ϙ*U&VOUf=@kGov]b\AB15h +qBWjB48F߯%͞=#}ZmOU@lbbM:/>9]3ԩVuw]Ebl߱';'..=]qpP;2vQPʞkCM_ jP_s bs?<9I\`GY&G@W,d7E7h=.z.$~+J'IlfrQ8)eOJX[P2"M\pyhiv ٤⛙n)K9J]_ R}uWJǯ\]5f!ЗC/7l\>،բxYQ8]tѤUt6hZ2Cp-?JԤ'¾"lv̀ {@>d^5.ԟ~Osy +/UdqB/wzu#N= Az$.qroPy`?4ԅQ\ p0C f6r.PAV$/{ipd5ZO:.zTcTș=!&uJ>ij>@]c]qǭU 4b焟crJZL>@$V JwR7-Cf@OO:"kQ(t>N37ۉМ\(ܜydf:z]A8.ڹ`9sPo r{,n.1fqApkSBmu>z.=G}c\o]%⫔!пa z}b6zVA"Ur테K"賂\][f3k \{VѳG =_u~Y/@rЏCoR{t1E|Ǹ^I)BֻF*񵘹5Y+k`9W p+9*g$i9QOcqף~q,@MhrgOř[Q1qn,qz$ЈM ?Bc8W` ~1rtP/7/ʝ3 y@+vu,c +r }&.qK1fZ)^XLpg?:H;>k9?^rz1v %{|]W=(% PQϷp5I˹ Ԅ9c_~ +[qTgP=4:0g+Pr;8MH9[ml|Z ό՜OjR'/BP۲jRf_ݢVC*Giɽ|AT6kaxni@͑x@fN#CL^Q=@ +.52G,#ҁRWB61;Kv5fG򍰯 by? ۋHuUqDbz8耞dY؏x9.b\-Vj18E9/$e[;{;_5Y? ɷL܏TC}#R>$5ɋ#ҷ$NO;%-&hS6 /kx7I +ybaPG*s좹k q%S3b[/?\̉}{&>ګG'kqjP78=آL%hB"K3~6$;4@б-*@49 gk\*/<2wS/6R%;[f5*Y[l$JnG"a?#o܉= ' dB +Pi>PE?ľ¨=DwMe/LA)˖#6ZtZ&Y(hƿFL]4P (D7~V eܫ#LiSX ׀--<(z&b2ztD՞4)+V5& wSq-&,M2kQjRWjG]մn>[w Xl(燄{<_/z8GrPG+p4rLO9-$ܲ"7—?oRw3*aa嚨 U{? NVQ,;L=S/$ 'e/N<ݪK5t|A{¼/ѱm*-ƦIqlMHmf>%y(j9]xB#}È7`d3LVya.~QD~X|$S5ɘ[]*>󰝦̯d1AQVQD]kiSI)ԡ)G$uCd dݥ)զ ZQjȦ,ݫѷj5Ʉf}L"P ?(ɽjTZuۀ'4 3>d>zG)8\1e7$OZ̙'ar̂_ Y_ )&aM_Eko.(:-ͬi-tJ lgWD|zL€&ubS&]o~JpZI^UYQVLrC,Mm#i (EWc$2sJJ^ ^I:TB 0j`7?~~e^K?H|D]7/gȖ/VtGtϲxp`烗ϴ\~='ZZ_冯z\s\RpU8U*˨55.?e&i9ɣECӶGtK ˮ=#Ȉݐ(!vA!{527 dVʗd5sKsO 3'~R/ds>`ڏӹQGҞstIYcdwLoOftyYi{MiG+RtĭOa=Џ:)IDlɵ󅑵;ٿoTgɧPOnѧFOk zU2Xw-U~%1Խ'2zf#G%>Ҏf/2gwC7C)ՈAiNYr{ٳ㢷GC$[")i2m-\k9%.nEZXe--3λ..i(}SwV$<0\Ӏ4$y&Ʒ/GngC5& ejqwMQMIO7FP73A韦D鯇_Q>^ 5zH?U~.KU~8Ow(ɐ䝏zUa7d9geY&&fv x0oZHrOK? 2O4̛ÒkGYsM2cN݉98Pp`]\VkE7eJ1-5=-rNߏ>ےy!&R]dm&Pד'@GK4CB226Kj!/:i{\Y]סΗaoD6fYU۫%|K&+-d[Xt = bSRұ'1& `ט-8XӻK0wyb3LGp,s%n^a z J?[>_s2Z!$%lK|cåU~oˮ7t5?'Sk cҮWPh }yH W\A-k<*h( QkyOQڛ.<%d"xONҕmߎ0']C5e׌~2U2e\VS ѕ.޵7]jb.~.R(+-m$䗦mfς5?2P~1da;?%x/ ++ڣGR]i%LҸv]&VL%yvʤYZVi/zk&LMM\+Xϗl$^ Һ2^F~%,u7* VZW^ m-Aշ_0(;5h\ O Wir3Ի3Ļf蕆0'Lo+U:p~5h&}xR񬴠e1a m1l ׮Zңη܎;ے{~Ɠ*|_71Ǎ޳<V({;=⢶Kš=9tk54]q$yt}Zi;cC?؜d$p +m rNpgY5]+_iXZk_Uc__WTY^ . N.s +-8ۘn2_wxJMtkBW{R\rC:Po:^\p3BKmˮWҾBC=vgFf_V^Xgh*?[Y]BShRSh\s{wSQ+GbIQiiicYGq}9a:q_],4^Qr#=D[..k?%)4ZI*jڐ_rYRX[]Cu:c&Q|=" +Ò +]CmC|Tތ=ύr0xc ->Ք_S~]YaLcUQEd'8T߫ Np ~X{-*0.HOf8k=fSe'Ӂ~vU7ãJ]B ]CUk 9v%U.-y)6K?4H[-D3<4 "|9hHMMt$dΊ{QhŔyh.5MP&+A/BF@m@KmCW+Hf ^jV$"|ִH5<]b2Evaae7cc߻?YYt=Etӿlv'*ch٢hɬhex 34GcX|L¯tHqZ6mڸ0 TTjj|fV=6x/5 {%=>^=$1U~EbHr[b{۠!X_8;%;TG\a|iA']M/y:ZbZ~0;6S%yƱ.BD4B#p>K߇!^ǣ5R &F^K`V_"G +y-,rGhO iY_PC쩃mݯ0; u^!,')s\"Se@_GoōJwU9ǖ5߲;4LW=|Uah$Npg˜w99s ?%q$|~asxo4ZuX*D@;4XMsYSB`bГ!mL J{xǫ!a~zcpjV1uNYr_HT?{?߃*qX|$nԨ?u_cí5O=мǮVZJ +Ƅ\|ǰz< q%ѵvao;a }]7J7+Kь Ӹ_n01H|͍c8uZRV\F[%1' >5޿#A[X;yNye"Cv!p8W`.r[v?-c֮?Omȝ鰿>?SB3Ifyu\li#I×Kє1Ьh#s6>. +v$7z~ +̗҈Ehp%jE~*źd!1|6j6f=>~ 5 Z +~h 7l(Aaw/}ϐG/G:E;FT8EWG;D8F<,r M}(Z&WogUlTztXNhNdo y(ǾYhxa{dab%%v!u!!xro~ +Ku=.Г90{S\c9od0  +͞͝u-_/E+wFK 4w]BY+4k>C&h|` CMH~R5Ktqs4 +J+mjm"lcjK'Jn7$G4sl4wr4{4uͫ)ۍfO݇Cӧ6o)TlZf_Ƕ͜˧*IC4g),ZfzLZMƢ/6CL_ZY\}j<'%ϰ++ m/ ﮰh-pP;{Ҝ{@߃F.cq:~~0)Y!q܆<.!ҭ'ЊVhZ*[W 6R6I9h=*.8%78哛1կ߹%:BWq)*" ׸<*ٳ7۶|8kpl-º)RX"gp9 ߧ+[f[[u#>&A3cT-Zom8o>w@ b]ou<`7*>%xv&/Oȃ׮ʷN xlA/Jm?T[|h+-u 6si:g?}xO]gk^k Ҥ\)W2`9\ElN1Ds"9Hi&Rdkm9ݿqž4vr%EMi7= +bXFZjmcm>_rהּ\\5Zh׿5oꏉx,-Z/PAc]fcN3:km}hh +_I%[UNh0m<Ź|怖{ %nf[lLڟ +W%;=*(nn5~LGq'{J=rp҄%~ڶ1wZr,ey9i͇M+|Z,܏c}9wz|ۊم}J#xoC@ێT9~SvU3b'~#-OէYv=>ՔFD컛ӢzC˯WZDhfsFrH8>#cd^Jh8ףًRe{=|@w؅/UO*?cW=iv,ʳ=+fֱƟOїBw~盢AL3]C_^ j. t-$4۪;Lߑ1rOFEl@KZ*<f_~ϒ1[]ߏxv9#2~GvEwXZ9A^ݧ|]2S=]Uj5BvV̊C5RPnD񐎁< fEh`+7rJf.@Jxh9pGh8m=qGqo}i|0xªPPݺ jj G }Db +v<)"TzA2r&EIϨu[xhe),cMZmm& +|ۧ;[/)ޯYO!F X°%KX^k!dmؓF,c\3%lTqu|d ?w<붓iC t3zzXk,.H 5yw1CʝOF:6k~-)1*c{r\c^8M=M5zh5y7*U^߰^+iJXI-I7W؜p7J6G6FF!JFg7H#K Y]Qwj˻@/FVywvCGxwfTKK,y|i` +[NJJ.At?j0'sfU:n\f(Dav9V*zYgk.3mEiSvh7#óF?79kMIj%?:U"<7xʪe :^=M젉GŒu&Tp1~>ոP, ~h̍qVSχgp-ъ\>}_r9MVvmVryS 홣] |Fi6 ?fՕLvx.:-kr80كjL=U=g74w~T6h6xN}-D&_ .Ÿ-x&`"SRkӲB7Ӣ(Ot$"J -ѻ2mӇOrz9y5ZF;?#vN/K(tYFjYSۣn)V c)bS6-WJ3OsОes>8VAj;M8m&/xMvc( %+wkҁ9[nuɽf(.l>O$~|^.?tjdZjV7K>h}GSGHy$ ӴSǡ&0z1 K1a)-s"2?}nv3,mρ}bhPۏI*+mO + +T" ydh0SCfy5in#}/F+Ι_&^ВM|gˍvou̞&qPؤ"C+mV-Q5C*ifޱr.i]kt{bcˌ&lf§1ֱ(;)^uƾ$R3Lr+,"F?*~HS3Wy3j17LԒ9nRVdQۤA[sQpgHUׂ]1N%e͜,%Ќ д8qMFH!F3{P/ɁX.ʳn|_Kn/֐Nv*HsNdD n眺*hHXoP.Q󈈲o*3s%}JqREJ +\{0(+N5*vb04x˚˽]U?WUx1D4{3=?Xko%lNtNKJd#s%9: qsUTyz^rPYfۣr|@v-_ي TB짙s,E>_ѳS"Ov^OOx/wA_7M~xVaǝݿ*7WcP63 {D&?r;?jĞlV=hcݿпnch !@/b ߰z,cXdpaYEc3:ZhHmNkdH#CxD_o~a8 6a.-qk1⑸BjDqO[%ZSQ)B 9'K_$K6SI$[-U)+*2ݔ%ŠBWx,b~ v)gSj]Κy!ucv;#{zUcLm=bǤw+#{N(G&59 dI{:&%>\E!լ k𾳜ps"a7ZO Io2,?"nJ͙]*}0c8=⢺ kd}70>Uknɚy3yn5kXoMx5zr0M;>^w1Ѱ =;z#ޭ#~T+=1-~J!2A3Ե(of7:P':Mg';)i_Ԩ'SvNvRp绚DD<~LNuLR}Xדhމd5 Cg+C9+X-ϋs +| B+yq=xmD!/yNtº1dLfg.yO*J&T[ڀ!{P-SQahפ 37o-|׶Ӣ5%ǚ: iW먛WUg"AB>ZDf铹 N8Dyd,4 +,Zid^A\rOg,}WGa?LHˊc<2aբـg e6»KnR%RZa8u +;?;*. v>uPE[΀x-^uK7}Ln"{@C|1 M86΀13=:M*;J쨜>)/eZ#h2vB8iӈH#- '])]`y`5:0ovXl屒KקrQǬ0gN]X F$QBevH+=n-5xO+QIE- +_8~du{@ 1PڝEdMoj'}Qo4 wJY*1E] };ԑmd,'l[-;-0 <W&q7ž<'뙈&Eg"DN  ds\&V*a|^KDVmd~a2zI@ d Dt^"~/}O[aemԣ6!-ӌk;D>린MCtcDPҤ2cIۤ9EeDúK, (|m}+Tڠ푹8i?8:rL<3)kO雵-KŷQw;{ oA!G4T`IJM n _OΟr$ex };.Yڎ) +-̯ 'O6rhhv5G$`KnY%-5BP(a:͆"b;+Q.1{{CzDGM2zj/{OEWj"&2=}1`v"א7. 켢uToj=81xDX?uzSQѴ]\#kV 0_:=<1<08ym4`GҮ +ws{ƕH,EYRYNѻdf0d+mj؛רwX%Byo*5wl R0X*p8-e[u;I9ƦV}v{\򑡀D-:'ڌ9?8(9#HuA3%GF#f,GȜБe{ 1Hp%#u xUS[ua+}g M⻵*/HSF>Můw*􍔥C,"!n0Own\B\J$ &+!Eۄ1/^ jvn؆4#/?b#R0?ܒ9NQ%֛tPz*CH,/:9k3N> ~QCܥ8F̥Lg, &p:mvva\싻^Hۇ$gglƐg\qx;OWqGy؇U6#a41٫E/7g] &8< EQ]p@HQ#R5-V;PIꀱCdO k"SIi33[6)$R~O axV"߀IGRK y5U4̄CQ5a8v@ך)E4 ­ѺZ"i"}=b.xNfn$-lJ%i!3+ Nڎ\η8dTL w&O1q!`rXV" + +}EƔݪѕ r-VګM>2dwkld^,7NJnΥBgᵻۧ{q{?vi5Ht`2Ow)]:/F8&zd-^ + +p p#SWp|lGyOg<*:YvZPGӯ+HSl3"~'/`guǕORƺ&XM$q|to +u*u1`x`TrZ +[U"]p<W/s"v//p3}u`P:EO$ R^b !uw}=n`=[{AH':D u/0cx9j>-힃kcɀH^2 +i1|)|!uK#d@|LWp9 +?.9>tDDJe__PnKÞ>eMiƒCף-; qp'~10tGºTMZG<@!'X`LcHF6M^39qH ,Oq8όM+p8 Fb!/qLCl{0H(s)b+.H ʀHߪӦ+T'9;G끳$wj]<ɽJ v+QaĻm`EZEg`Ja]v\c<$U63!FZ S٧v܅4 ]յyؗ>ǿ LnR'-.GH_F|S^W&2x^Hzr.v/s=ˌ}h7kz*ؙSGG- ڏ1_)C'VooC\g4eϫdd.XM@k JYMNZ^\̥ cd %1Fq /~q7 wKXֻ9m)71x8NJ~  ؀9d069 v% %$Q(sH"`2LF ==3z^3ܜ;ve +~כZߟ-JˊI!0$BzRs-Y4U .%99_|+JԃrcuVʮSP0eVK]ce#qn׬cI\"{Y::W\ Íf"yVkOZY2sfJrnbnڕ'NXm!y57yVZJ?*ʞ,sLƆ&V{Xp Wx6,뵚 4]= +qd@Bh-&hоg@/!i3(]^V\\%e } &]]"T^[/1Fh|I} I׌t➉;vuOym n&vYͲk0'ds;kZsKA9Q_L 4ߴĦeBY(QtE)gyWd#7/I[3r_V!YCh&9}B']H<4DҋFѨ-]6m6hE.cD܄79xd⮉r_%ז +QbCbrxhiZU\\(l)-ۺӆ]71KkĽͅ9~|buǎ>{cꍠx1>vX! cpw0X]>Je !#~RHHҮ{Z[uw)j^0>\\XؼZqބUBo>rmo_\=oժgkWCA>\nqul._sglnx+J/U9<ZwbĽJ82U{I̜uɷb?N5vwvPZsYfn$7u2P-\hYT7or,PB2+GL+byف'ʉU5#; ylgЭ Mjxj@phËFC,BXxA+uer)BM96 /k06zة-d*o._?ZWkL7sZܵ7ש --&_7j嬆A#-,b/Yxmz5vb=Ó8Vv{/w#%ežYDyDi-+\>ؿR~ou||_ł#nyV|1{$иd׻;J^孛S9$1l z*>1HBeuShB#]g!r$o+s :4EH99 Qw`wk=ٸX~-"Cm|ͩyGCEfy +wb8¸S|"H,Bcby|B3cm5cίزZѵVf=n#Ҕ]$MȾ8A>7gF_ub{'naLklwSENQ[Nnձ^ON6.G;x،sM'x@ŝ2K[ͭw>kX&v +-,jO,_YݿF}-:ʕ:Yq + ώ~`Sti뾄3l#;K){Fj_CvƸfe<^i9z ItKtZڲFX׻X ]fxr$AL=];@l^ ]]c=4,.Ώ|݋uv;"fB7!a 3fn ZfXox8X)6V"MǮGvV*Y,Dfޟ,5%˃Mh5ho 쳬t ,m^19t ޤ{]x~!iq4 BI5Eʻ-]R!G\r&>s7J,%Y0s88XF^^} b|E;J-4=؄v^cnp0^OvH#;!>K9}I +g՛]!_C1$e(8jdhh髡*;!>gp@#;_V3հoj@ 5nuMcfSj;}ԝfu;TGɑucNѓк}3#ƃeŌG-fx)Ws/샻[6],-e na;XqѪv' c>4u D/Zlp6i5n vtdgE1T1]k⋣Su +:|{HA=&>/GP/{]k+]X  Fު\iJr恙ril+l^7B[̳Lh^=@9⺣֍+v,-Q;MF,'3)F~dgU5jm@/#; V{B҆WvxɨҳzƵ/3ޯ;.4郑_,8s}X@z{?s^}=x%j4ه\#%jLCӇAgb&|Nj|mYcƣ׳؉_rfsR'wݻX9/1 Ld#٦VLl !\䒒GB? s[f^R띺!cAG]NlSĝS; l¾аǚԬ77v)J`giyQÃlYo/zk`~`4J{CٝOO&5+Xv]值a#0*[kc9OT1 ,,%.Gmo\ncu(S=-؜vr"~I%XJnXT< ĈMl&bg'R׃vXm9/壡 rT6>F@gu^oUw +9qcK:u&(Zn}Oo9sU_q{V:ͷ'gkuFYcɱ!cjXHCGDAEi=Š>ӏLlM봚Mۂ?9+)MS򥼒m $\VHz+]}JigfbgA#5?Y|{鉝o}z0Jk6JՐJƞֱ}oMxHc/x,KCZj*#|/14J3/֊aoFV 'u9. nL|!Ǖ~ltp#sb -pŒӋ+_9w#d%kQFRrx_]< +5F¶^V_hݴNXXn"wWUCFy,f7!dUl /z'G,ԩ]ͭt1ǚ{K!_Rdq8y /4糾b\|ws!P +FlGhRJ2UA)>Cb(ԜS ~C@L0xX.\N}a`!͑ +./AyEG91llPE[+`b Sj[66ޕD?33?р8бUc 0{{Ƽ{v.W|mYGcYB澩!5wԌ5O=sSVY>jwb쬘NvTprPWoe1_Q2rMlA>^ eP=VKƉJީbůk9A>/yJZ7\9{c'%,5sP7= e=y6V~XD|'VcQrtTӷRȓ,m5ޯh=+?8ʶުPjĒ \c9׵̶yUѠA9qNC{%B'ETsCk=&g5^[<0̖1Aw~}C'"Վ[`>l!\WԣFYM\r./$^PP1Pψ P)mV!' j#]{ bߓL~bi(*;z*ڽR`5_ 7an1}/,!|ۢJFI'"V4/Au e9P: 49O'8#~dgVHĘ*>Gu%f@ 8iM3 -SB=]SĆgv>6pY-_Ӽ\qmU\5vsWRO̢ulO\uq<~G} *V9)ٽd߁]ډX&:)D5sɅrP0+rjbXG%0kg֚V+Kw ߋ/q!aS˓}X;|+_"&QکY\`)GX-^jqr~d:zтsx/ e̡&z*zK&e_9+b H81M3j5o %Ijꑙ{7]%zRm1߳D~sH/a{·fBɝكq*#]VIlLLs0oYG9kځX_ GK(8=ٶZWre!w1L{]cPLJ7 ~;򔰂/Ԙ +#b+PWl\pQ[nWSyX2A,ƽosVG>a)2P)kτ `r[^&_%ԍZOeC^~ЬaYcؽK.zW+Oi[{c!dN`ҺR8L|'̍.L7VHۙ]`9 sH',9uTP1QOL,#]sПSOs?Ú-%{/'e=)].hlGg 2D>Bj0dz;/'Oŵ`5TVev [k<9*!fմT\=(y1w'pkV\˿0tX17.IG`ph9rXGB8AghUwE-nr0ᄐ,gK,*i?*}+_\yz.EŲz#]x cQ1cL3MUTWryE\C{)'kHI.,EQ U(Q1aꋹ7dϠ>)Qc5uFKmXX4ȣQuGV٬ԋliv/Gr } +xZfKW8EP;#$no`Zs|@PdžR1(ozRbv+}E68yKWLX1.fG`2G+bggcLg.OY 4;;9!_zvރ}O≁ +0<$ R&?0>:>XKϮ[I` t!)CQ']M!tZwֻ! b|Q-Q%ťC3 ξT54aOǧt|:>Oǧt|:>Oǧt|:>Oǧt|:>Oǧ8q[~†~Wn\h~ϴD+}88{z-şͺkMlm=zT8w5{שF3S̚hє75bldhegԯ٣~5kŋ/Z8gy ?ϛ?kŋ\9 ;=?]v'}?o:sfqssXm"n2LLg]y h.Eݶz>.ßWF ا#lN`K]hq?ac y&&ʾ9dLg®c $ͺ5MRÎu u nighx]iYlf:Qcmb20n3Xg,h֬lXgagW[ToK\o3 M-ZYt: š>BeaY|#i 7oX]8iQ>>K`/ Ffnڴ=u6b3UcS2hѓMo-m8<N9Nr MKJpe +U[zJۻc}SCl CAݭYwvZhoe͒-:xwNl]ޙQs9y8mVZ.VҖ.[ $FԌ&k Ź ok Ul ^q=8Sxh9a^_`"f"zZ]!H+zKb aEwD""&-l `Yoʉ6~4W i3 .斶]6+IYaӅJB&e @ lݺj5eCsl`-[[%ff5h.]!iljpa{ ;&fz3 6v>ؾZ O׍yWCtئ Dp[ƫxǀKDmG_7~ux6ln= s0*a#j#4iC!Tr ocɈ>Mp2l/~}óTa[x#7!M.10omp T"ǐW_I%7a){ERٽ`@}=ccq\8D=7m FV}.=i 6F ] Ъ[ts` +c#i,y6TngWKn:\ LL%&ΣwJb8lu15AVE[|_ }u],x.$;6c~CD^VwW|7Zt\ s84r]bhϮV +d>J@gw`--6҇vxL1 endstream endobj 966 0 obj <>stream +ӛ>P@P'y06UH_gtBGH&Nl2&[9]Wk0ߋ0j)jyjҞ +TORC?/@?;7$3|&6h-W¶PQcaS.mƦqشDo}1Q|^${Nbi{Ήj쮉kJ\wun\lObk(;FADH0> ^;J6r׎Y^>?#ac& (&<),{55ùrzv/a؈|!6AveLcRq*lq1٬h%z8;oChC +N=`?Z[[7ldXCpwyG/!l c hÖG4;Gl_/m 1'}0 7Y)269Exu KG(ۂzCAU%6[* U!%mc'mQ<C(,:$a4,ڼkD}SB +? *(uX~0bIJbD% &%q"?q0DGOCڐr y{lUS> ? A04&aSl ~a#9v.awX†[9 L{a>6ac6p!!FfZ #;a#l1~Djhh [g\f~ +oO1=08 +ήGpolB$|-)tm%c::olxKxo>-A!?El2!)Bu~=AX?y6uX.s0BTKL:4Y?<| EKi+ . -x H4IːS:wA\u%p *s7r;C cy\`0%!a'fQ`#|,PX紹Z 誱Jt6&M6^1.! 7IK' @x!hSfd1mmsm)rx +!j IE2f46Pfkŀ(:d:ژ/gׂ~ +1kbыj,9rq|6V 9=AnR4^L +?|m.ov q9du-.,)'U%J'Є>nM<> ôq7 vGY~L9DJ;QH?9bBXs +;ʿ '`0 F/x%Ra;@!'k +7_B}G)8c(TT9Dvue{'j#Cnj/kXDH #o0(β"?L9e M,o8rteuöޔ)wI! k0^0$-~lLF;>c Q!Dp@kjfk׮8c @>sԲ:k/hs=~r``0+:$~9 }MZVp6]KB^sQXNq1pF'@~|b2˅{ɇa|!6CVN@«#?mu9zv{ux=y9;|!hNBnM1}8nef1SnZkϮ$1\VΡ=!H#D7#i'xXx]U2vx"" }uf!*]_ f]'{ +/&9衰Zh,' xF'A= 1V`6ˑCڪ?-!r5 Yg@gkY|r=ٝBĬ%@G9/6;,IDk< &klv  +{>|%B^=(AN3 + *F6q C>cy5 $47w썱$Ƃz?Y\ظn]khgIJ-7| +3 ,R[zX]mjs+kdׅ3vBC:DuwWBs qލ[wz?D92DF +"yKP3;+mro-0u@Ў<9CIXٳφ VcdZ +=# 2{(^, ~g3XN>5z=~0Dx g +տ;F+cǢgg Sr:#ò?|9v_RXu,71pD_*'$|P{#C2fx^#q0<ęଡb _* 9{RO'ig\rA/ 1t +WBtRHB9& +~9|YWkq Yɗ,*[//&!wG\?yG),< Dp 5\Y m_XڶCuI7Qrh{\ >90ra+e\Y%#ɖN̒M =`.fF+^wܻBHb=2-1^d^RC_CB#D"M }?a\9ާ壏\wmYbj:i{`-5;QcnJavH\ qYE+C/$YCs#qRbDV;O9ݿNq!c@_ojz) Db!l! ?l:f akPDta]9+q9Bɼgz4ewV{G+E6BZtgli_]%Wy욢^'h66݂{@(R9rLU5!Bԯp)|!>XMu _[V/=2P_g.fxo1Vu/;@x}XG֍S"FQnu/ؽs|7Rʮ)$܄>.&JwMͥm:Fmŕ%pfܞ,ϑ=rwNQWV3s:r*ԏ$!.3Ob )읪D^Ϡzb8GCD=:>a fCo}JX^J:k*%|!Wq{)y\Urt.XNqJ=[׈>:.].FBje3vOe~8$k8`gpD~_]e-+ʶ~?G ĽWNJY~z${yV0R=c6ېbBBO_&':N tYiD"U(-pm‹ >Mt`2ȥ)F6qq}-0?s6Ujp]B{B,WgdNI0N?9 3ߥ0Hr戾MP]]$VvEz'x%?.DV"70S8 ¯5~ChK0'GNSN_!1$}D0@54OV<4c|)|'?rVYnCo4X6bbƹԏp<#]nHu.F M7SB՘+)lyH/)I  |7G؅chNγ ؽeA葲=ϘqI= 5BـvSNL7/SȻr4U4ǀ3Rf>Y67mjXmK¸, )| +`X+>j~#߬:Y9v1^ˣi7 bcgcPJfy/&B;DQ,J,SO"f|ٍu+ueXն}< KsoH -խ.0wejj,6d,V/G̝6VaɨA"C &5M ,͕uԄI$Y_OOك/K#?[3ޝk+D)ZXGߙiuݰ6`ۣvQݼZ)vt%A2$3]( +]G +f7@V9S!j jG*q;忱&y$VWr_|%sq.}p;_8}#a W!?;;, +zb jj@9W{oCLc\.s0?z~` y͚4٠V+g@ʊH>ȁI4+GpQH +7PBׅK}vaB]E !M c^y*5'y ;wCik%@Ghɏ-K..#NrO +/,B HSyB#h5$<{|m̡/O ٠65럯ӕ`l{'J//`~zMS'ч"w\X@dv Pvv۝q.bNyb%";gw +՜Õkĝ+їG$G5/DQ/a}{;v  u9GQN=4180.}B8ϻP 9JO@اl~f-4f ͇"-.òVNDƉyXvY-T\/PazACik9" H[kjF{`Yfft] b,AYa 5հ*B!ot +^N[\)Y>\Ok%Rj#OŀOQ+AY[|jLٶ ,7M-;kFփ@5eT1gv!RKcÌkz^u8s<ڭu.1>.e +T)2RGQ|gL7C9@I90`,vqˤ;ꛫ[+p{str.M3 zd*`BʞI(7<} b&7wW n|=nلTx+edz]OOʇكuީ1aeBb56^Il|"3cN0jY)ٞ25Ȑ+n.ͧ @Ϲ^@CPn.`JP #}lX5vvl6tt4U>_ 걇~zz@s<GoE-m^+_fg;;NS&gOLNbž\mSnZY1eFo1v3U^_]p|Y,G@jaڔGn瓕].֎霟m|v.҇P0=/%l .b;arEZ /,TKf.V])ִm%L$QվXu?|(:3#c]>%W5sq`;4'hRQxj$y g{ꢇzr |YB`pDD/ xjػ1l&p;{X=|{iXEBϘ;2aqQHtjdX !%(1%֊ ?P@d5 zQXc5+r:SOp c-L&24w'k-~X$'*5'X0sG'x9]p~y؊1ЖX `[Ї(!DQ@[-R@z3s ո>WMn$__T]'W]'f}V؇u4?bH{Ԋ;\Pq{cbhp3 fB}z1udS6X0  >r5Ĝb9(urEt"#%sڌ~&};תQP3O`Rxn)YAkt1Lh}0TzXTѺr)0Z2ˣ2n>=h kH>5#a#CV왆șauj.5 +1}kTXvg)z&'ߎ+adZz6PV{`JD(ff] +9gjՕX'|5%;/ (RXp@ +B&TB]7#?L=:s5y4ZӇuXx`"WjD;: ,i"PC `VW ̣DR4Zӟ亀(yO Nqy׀5jhQp>:J: T ˥#k wHa(6{Dxյ+a!}IKP>u+z'S~l:AY$bq A>sc3qo1gzbK }qœ)4^ 1 aQ0 :1@c+f<௳O-sEO,XW۶pJ/cowalmS]w`}&s qtTlX_xjB؝cĘ:#BGW~k~a.z=۔훂bϗX/cb~i`=_pyje>s)b]J<8EIЙ10rh %H5oJ(E-GZkQGZtޒGWuuNAHE-d_Z E^|Yh0@.E:?|J5HigK0Sh;n"1'yGPW}[BóOr,+y/sOSc10S)@ S)7<ߠo].$4s?V/Üuy.]Y)jWh} qf1k0QY}=o9n%t1l9W~{)0 UR* +!B\GGar + +!#='6ߩ߈}]A0|F*{);` Adc,83rFb̾qBڱBYJ|sqa#ct7jka]Ú;&]kk/mN^PjX n!}Зfd)u~ζ鶼ζ榥\ru9}3*-CF<72{5bBMB۵BՓU7 &syNkھߤlOZ}ΔӨJEMO1~D>l"]U\m*mf&5< 78GopKa'k +w6[-~}󭶬c3϶?>wSδ; G;i?{窇ZŃmZ`{]N>j#}!p7r??ʲ//DL6=;2zc%j%@@(D)F:!_iK;ǫWp^IPwU˭ܵ>tρ}~唳.W`9i%}7AQ9W!RRx+9L>0k_mDJH82O#|1K5?a?܅?Tݏnn-Tz,Qxk8絗x+hNKt#̟y(Ow>|N_b5U+l05+uzPٱBna'W>Y'Z&|1 \'C|>5=c%-N'~Wkmާ'{3ݡM}Xp[VDz|]Qۜ]>qF{N[}JX;_;1_+5=mwp}w$eWӶOem9,tϖ^~ۍ&7s1b&|N/y+;*^|U>b|}CO8Cr}x~aM~7՝ /^I.I7;|wCm.gs'w]Dh|&^ZX@qG_T+UyNd`˞k6bՖ[ܺZv\s??{S>Z:F*M!/նˍLņWbwO-"@j_D6γ-˵65V[5R[neX6ctmi_G~E7@/1?ԟeڿ>d_AYL>9_>Ǯ+`GǪ`[n[.\ +=yK9rOkmc煕xVqWro KM2G=pz==MZP|=rF>E=M{u'xI^goES;'.¥_9 7^y x +W] I_m[/='7ԧד廷BlC|uUOA8OQS3/EcGGʩgvC5ѝxo)+^pT ߋԷM}y5١ +=[_-ux{X~/Yy|'^_|k#^Eڼg|Ѷ'=kK}V/-n*ThRXm\-Oe{9a Wl9뽱1|b6_ jJݓK/:Ʈl\J_]fx,ψO[]43+.Wr#6p?䨿eD~|ɦoD])l.R:/Qґ!$M#Չe. m~ku[}73XK'YW#w^m{*eߞ:ZꉱX~[Eܮ_+:ܬ܌Vo!zmmUڼku?δ̿>[wgzfggʝ^-?.?kf_kEEUQ%kO|l(:aRQ袆}wv[x;0zJAڝ€E[^_oξUL-)9,Cwc­"J\QxƎ.Owȿ}DW/[2v{vw|qH|t;X}'~vWw;2pKhG95‹^**gu5ݩ漒Ie7b +-(zXUȥ)_LWg׭Yt#E:7{nmfw[cG{SӳC[ޜ+}Hi o^E4g8=?Phd,v qz~$a..~dBScL*W5jkq2EJ[cJJE:ܟoo|L^|u,~mq_tesAdsWa\kלpEۉ K[KjWwӤ⃧!QGޏ+#*SxJD^Rϖε{ubʚ)5-O?.jevnOJKJF?H-~mO/{U@P IQ 0*3Mwԁ "IrF(HP̎a1bV9N{}֭9g{}xn:jUjU}?/Nyw+Fm5ʻ_B뭊uWj߫}9&v`kM]5쇏܃k3?Fb?{2+;.ԞQsbnK/ev])h|}_76U{jFlJi 3]ƶ~io}_5K^0@r屇im("F[eC?]|K Yqx5El<W4g esF b*S#Gߧx=ϳjN}†s% +j+ϗ5!QwےKoqQKe_KEM]{qp <ɣ,|?4o?5MwKe>) mtq]=3/dv[z|NëY /od(>_-D/|5Qp .PG? Ə)׼7㍴56n>~قsꏝk=/2C|_{9' Qq8+k5D?뭅{1)UnJeܦjq|pIba2ܫ?砾j6XoMrf34 wТ ?:?sTq^ ݼ Uj/'0aGsy]i \|FfÙK9 [rQ'^9{1 c뿲 g=uGj⟡#hd)✄*ZUm-Qk;YRTaéyMnq>jvۉ M/Ե_(ͼYS:knF޻ɷ6yP? ǯj=hb$3"hfMG9qY L,b>.fes_YS1[k;me;v#`k &߆m녫kv3qM}/|gI |hmƩJP'hݹGƣ쑑2ԙ DZ3><>i s"}5^ZzC㑸5#SNf;!JL$dyQ|dUOt/3/NfU#quG/جjA-3 w/8v-캋pkoT}^`'ˠN18D##(d52ћF;6J4y +46 +ߖ#rd6F'QhX!eLMk3 ha==@q͎?]?Ql6ctrfY3?Mkx/+Gm?h#}tzHiMD&S l #=<Bdl8[ s+?3M-A6s>[^ >K)ĩ;svӗQ/{ng?{R_%J&N"~UMΐ2cPm,~n,m8 XQq #y>)@sBżx45M)\ BUn˨}l [6\pnU2_lz֟tbvCKr9ރ2T3FƚpLq4`;92f!n;n"3#'4v<.GR\4-],<֢1iZ\foUu(y:?E_*{}1k-j~8-v;S9%Mk4]yƒdRt>~ٗX bDԱ/ӲĶ +v~,H4?F~h-+d5F|9bo,mB(4nv (MԠqe&j}=-x3cOXynɂ3pݮˮ>~=掠|xƝֶ5I_l0%0ZZx64!7C1xLVn!SQ1XlSl/26uA<4r4g~5Mu{x~^1Qz֗\.n9_\mgK>vWw3~zۛ[/3a. //?A낣)r gLƺa[c=xfn:! cgd>^,&3hhd푋fH̥U:pǣ^x/ӂ)*<[]TEs]/d7;W/%Lx < qϟc=N.o5ۆpe6EzFLGfOzh1?vLEqL)D3h,9 +L]ڜʗM]>^O|{p=U"^}̺V l}{.^MǍk7OlZPgoIC|HdL= `/ 5,p bǣ1׀%2ԵA&bIwk fzsF!#B>4dRa^Ų$ɋ~J (cvFFc=Mv]fPEh:Uf+;+.-ss;[Pv_o^tLy) Sqݩ(Oש䉁KOG98>)z9 /.n_7`-tٚ>HvMK齿 ]wz-P~PP١wʠw矬N|LP{0#M8Ac,hܴde&y"q!Xhtdm퉦ϓyTC^y7|`;>KVU/W%?"[t-mx:ψPÏqܣ{܋;~h}^yscmiAM}k7W4}7r޿/U!kñgZ<4qn @g1W_zƋEPO VKv'U@o2_x^ `|].?o[3+B+Gz/9Zrd^~YlWunY|_@؈lي4{BV S<*ۣI6Cg4ox7 OW.7oxKSȮiϫ͹SQ#t:P|q<{mo>T_){;΂.s#_O(a#ș>3[\JO}؊7?t/&8IZ_TsDLg ,cFd6Mua3_x NJ~?~-S<=åW| Nޢg6Ž7E2H>)grJY7߳{x3$gS'S1_Q(o\N}pLvU(ɝg/d˔on xvplGC-8GۡqS̀TdG~M{1'i~wIc؎9ʹ/v}:(_Z^(Pg,[.\FS]_2+{{$CTXa)ꢝwv#Еi+ rs(%$ҍCvE}kI}qHE3ȁ۠yj-3_Z!~s|l|wBf#A|FwGWW>Hhp=cn<ïE /t#>>IoY} $ +Q#:In<\YtQRЅIO qSWi/ XƙFUhkR4?LŹI~/|>T \><)`O/Iiޣ|elG8: V"X.n7/Q˕ Zxn'sDxN<+2FsԷ0>tzjH V=WzWTu;I~ upP]s49ꆦţ{Oy38\ +sty5/C?2S?yIP8qTj4I닸#61g'pb<]tV~2KNp~6P:?}OD/ƄhlKYkO㵛b~F~y`TɁ| "~eK/ݡp C<=f'cb%!2TU5I/̖4#|ޖn~tY;j;73>\FUon{>z)Yן~lYswHv~}Tz0qo~(L‹Ԧ/(Kd08%D.Fz oy9lY Ż sX#:>.hv@YQ  { "qy;BRG˄_vo1쨊̆u&˻wVr }\Q)3|ʴ]HW!MQS4p4p?\yfOlՒj_nƧ'b%O$t!/RGonLbI 8=%?XSǬ}%J444u.EZDb~TBAAi鶋 `s1K㵓ӂ*bºZ鮟=ōJ?ӻ/nMm3VcjFI:.`v}z?zUg;=ExwAo1'oyw |^Op sSqٚx85_/0u,rGB#4Uڠ ^f>tqDs2ԘfSFI-]ҕE {Ŵ e^4v}Wdn~%h`H,1GH'ץR73eC=z ?X"?H[^~n4/"/ jĺ~r y+rnhdq^xDH#yPZ4ݐ =S`o28r=CZ*?B!&l0 v}v^M%5Hʴ~wV{ǐ.k7~fjTfS:\ZJ~V7?-l%q'!^慁W^;o L?;Ї?ЁMO k7&Ud*Dkh<52ة3>eɸٞGf{ bƥV2͘lo[Lu]caw~pο _G"My+s-]~Rvid/҄ ̚B]*g=smWG6sNBƮhˬT$ <{IʏO(V4!"z 3bЉFJ_p*lXzPb⇹~oYyۉ4 VJz߸;,lAX[@'Ɍ{ZV>v\|{[vb:jGKB/^7ttF!4Z6JTodavdUOj"MMH'"TՕ.h4 +M3 q! +b4DR.W#\F#c4h\W(-\] m3uWW{DU!Mk3j/wp VHJ*?,LGL&ӂNdځԑÿz#/_${Nj v[H[FI㊴]?&#؛]rxT=Uo<+,]0_IIjLN9my ٠gD]aFEeI@+APPH5)̶^k$263]ݔǮD_>}ꐓ} ̶^;kϔwXUg18a竳:}qvSQ)+IBlܐ7 +G>KqL0I6j!c4GpUpΖqMfž<#6\ӭEESd!qb AՉ!0 +G͸#sKN84߲{KK=YfՆ]Ϡ6_@_n}Mz>kfqTCi S)-se({i$}5}#B?LH/Wd A>:g(jH:t訬!B&ێj=0Vq~[az>%'S1YèULNp ea7sCdEK6Ο)#qØ]m\A7*7*n,qGѮ_KhYp<0-5#rƾ Ǿ0S}EH&MA/GA돥U)1=T*5u ӝ]@bJwL`w{wْn+.4dI+e(=oTgjW/F7qs(˭4KYI6_e !W/qikiytQ;]cE"JU_i(,Yߤ+^03 -sE^ݔ `D6bNkeOy '஁A(P ̮6"۰u#~` YkZHл?Q=lص ^MKVhAn:6糇d\NҐ+;XtZ!Vo ~n4!:kq>cmc٬F%Z3KFk [MzԒ!5}Q%Y Aopxt|v "#Ԋ<-. Ƌd/jW"nI:L37X!qPÚyu? `?G*p\O9Ƌs}=?HΡ2;L`^MRo@axT?z)QFdsgs%C}d8D~2%lɭڔ\~X|.C8ǒ5j[@򲞩\s@[>uNX%ZWH/̕t>Zǣ#St6t~>ڷ@瞄lxM}%=ݾjiнK>ܩC9\&~4̮w$ËFN4Tiv}1*TZrh4AbQOW`#з!E;&cdʲ4偫<:Ʉ">D5wpQ\x|v}]sWJ{ﰰ/x fHq"|^vd¡n."p|st"~se?qu?a8 O܉v|-Њn h)!෕ +;xm9Wutҁtf.9U"Ց)oL)&V*"U cv[ZBt@#ZS1R" <-6ۺ 2ЛLm-]}CLk? +)~hql.)olm2B +Zܲ]A0AmAED3*t AC  <՚s!`(Ǫ62*lT!lf X2BKҒXryLluXE !:lpb$ˮ2&sұ`L$[ciD&\Y6D-':EhgVs%&}1&[y37#l >λҰgD!%xwц93ƨ-rىaO`ʄb[LIq9|UiF#KU#$H֐(|p-±4!ф-&7O~)h z*ZCRaȔ 6t身vdʝYwӉvaAXzK?ѧ_}'DwO4Z/#¾z`izE)q^}zp`sґ1ꠋIx&P"CLru* FXj6h7!8f5^Uš6*6:NtئK@poXn$𺁯A^ud;oAl`:}An/W6%pSA3I6dbk4%V&1".LZIXB"]qO_zė'Uֻ"NJf́DPV:$GoY~\m@9m=DO +9kϔu{*ɷdkρ~)7fi<7rAySh1ьS!0e_nLlӪ mi Gs](sG9cL|.~8 +A뉛 ^^R-D"mTa)q&sP*R +$7шKⓇQk4<\˅3Mτ~D%h>pفmt +#k5^O_[eN`8(KOCb1ʋY]+ Q'{w~#kh1F gg ]i p‣msiMnEްlV+N6?q?R+3[n: QRnw-Cу otYclyg;[b~ y^ev M{؆)6)DOoE.01鶇~\ϻyRЃf: +u;' ;FbXOŗPKS5l"wpbׄ`3sZEtd0*U mM>aqB_/ˮ7y.@woqW<.u8~<{/d;1i AQ(_} YS6tu'mv"sQ+43̃,-  )z7Ao Ao\A'L7]5]]\V% x~ WnZ3vܾGHZAKHuVuUG;랈xxlB.ឍ҂ tƘqNSiZM`a1t获.l]܇,!n-!f̋yq畭g^YVgph0XK +ǿ ЦWtN_z ڒ$ {_"'90.wNX4HT8з$ +UAWlGQrx:ĿR.R%Uao +X /3UH#Kب|kPъG~c3@G!dѪlJ EBYNv'_ # ۳ftEtեLILiSf7Bm{<~dxROnt 3ٵsӱm0|пv'>U1?ys<]&*N"f,V +̿At0wrAct ; ۯ^bc_Jq쬥%r1jRv*q+ +t9Z8!aIѴ&'@IE# -BE[}Bpb٨YTd$W+KB>e q4p= ^Gm$\ h>pқL%UFvYn-?EbAvV!aMB)vg{-e[~ǸUyX k+FA<-k -E'p%U B- /1 l A,]]h<2cGt穪Mwu^y*=p:[-3`X:J+ԟpqu:[AIx&"JU ^RHW<My,7}.8 +U +,(rA3V,6PKw)UVWpZlˠ>cdN$hLLMtO-nla? N4Uﱖ՜ρRl#e18fZQ%&~G3 gйg{cN%Rĥk -`~KvV g48]p xa`gv+>4(cyI۠I +ψەlJi c̩-}e:]ZWps?aп8W&n- ySםԝ9 Ϻ\Aw>(x* MEfsyNXdM.[;[S>Y*LEHHJVuc>ĹvS#jJXp?Q'#=POhL_`*D0(qes."oΒp +)q0G>Q(B1/QCK҆)S# E ,n§Ϊ1U4ZdR' |n!k6Cܪ>SKL%̶̶۞JAKgwߌk1)ʣ+b`act`֬AǩGrUyRdgdYVf2`g/r`g p%(b,"Q.h+VC 6W8֚el26p4YxŸNh<-As0 ֨=l;\s<tLXNbu,cG>}'0M?o4]_D| \ +dH(T ȑR&6m[yn6Ēb@Q( +g@%jʴR〃y9a)c s[{"hÚY]o}s7,U%e8; qO]@728&E+$:_xM6"NCO`wa,+ D`s;q-WU\ca +Y :TM[3.[#9͹d\GrtVkPfryVHJIp:7t[+oJvޕ˷?Ѡ|˞}$dEG +bϗFnqɠ +|.ZOf0&tlk?G H,Q4AF5Cp598'($ +S-7yD?pd4pM^QQFɌfKnӮiʒӁ])Ԇb0aDf38aK1E-^rq\o"k b9|>,Z[皎۳ma~\s`N% KXA+~@-d U$MrC?OTb]oiFl2q4E *f ϭ*_H)D0b)c1GbF806Xn+fQַ9: 8Ժфl~'Er7*C!N:f 7<8&;0/c`88=4KVwbEx燭:2M`ˤ_4Ir'):vߒq~N(U.2Vx\Ӈ6a2u)l<`g){2ҭOn=|p;sYe͐9S; X!0Ugq'/YئGVYM$v-3 medk{pf>5",ïǚksћwU<;|I ej != 4g$7n*'0uÜbrq˕ ^.\"jSad>Ylͩ$om2U ҨTM)f#`ɋ`qܟ쬂q6`L5$uE6.1<`6}́9Eb2gU3pbbۀ;([sۋ{n~T[#k#3Ⱥɔ=w$G./:|,>|泌LMW1-RdZu~]DX-*/3MFe :[,?ǥlTcC :cp%p>9DB)U/N+[%$*;6f`ʑ}8(vI|+ɖ7 Gљ(Ju(5tyɄBe,p`n*O5+<9LG* +vN2g%jOƖduOR~g57+y ]:b=[#NƆҐ'Uu=grBaNŶ^[ĵ\sR10́yc> s̀Kop.]L:hT{*y)z$Nɨ3UZkBؾM3gy.C /e'yDA6\ZhȳuLܾ ^^>G[pBpl9a^uv|{~ 10 'z`8ڍmG.%kXO֞\#*m7'.w^$m6==\Iƾc|f3r#`pz`<PH$+@hH nc6a?Sk, [온ȭ5#jfۮ:qg:=)䖩PK/+jI5_'k2pn51vYқv[SmW sI|L66e|։kHrw->46WKRo B9q<ʕm6t48҆ko`_7%ObWʓ dyFy>3|~b(ѐ@ $>˭HF609絍<kA<-a͖ +n#ȝ~CIk65GOh!{6K13 zfV@[][b@XM?p^aǡ0ƹMGO#+`<;c$|p? Eq491bB5 ?$י8yuX> p @> +D%p +PA`J0JOZl6e J.ҐY=4PB [,m`BVB=rN`@v)bd:4C/WUPF)6(0 TDP?ڒv%p1D1_d-EsT"UARPte Såa-Ra(-SK_ivu^`J5r)[Q>KبhK8U3%*o +q$8QQƫ3QɚeZ,m*`֛P}Z^X<=T.}!m֢k$'1[YM +%0S+e6:oH+1GWh:D<23(1@2}&f2}kV0R@1k9!.j`#a{w7GNۆL\Fs# UH@0p]"pe@2;}n"k1p~fĂ9w];8n5ٗ7wfܓeG;-`4qx$)CtϚB7tNgb_`>6 ++`YХƸF)v^a}+*~$h.Sa'0SPG !45t̓7 (dEġB0Idb `Ɓ#~EfVCYKG@Qr0}$0fy1tڂ(tsx +ww {&t20 ]&߁!w\#F6C3"ߋ Fp,1ЍȝKˀ`[%O4=a&0@'-}yf;$~ q47Y6}0.HgG,`p!76qL,Zwlucqj8trNSSȀ:BעtBG!Z? 3{{pQ6'%HeCn.ݶ1A'tA3%=en`nS<ưS l1 g>2]fA=[JXwO>Akqx|n@Ie1Q,KJvJ'B(, ~E`&`p#Ak?3JQg&B׳B3{Ĺ1:EX\LN+KqW(Z"د]"te&YNRF6 +" #7 e]qYx18G ń ؞s8Tb!`?w! !fOqEqC"fc mFakl:ca M0c + F|Mgas`?}, +6|ܵbH&A92r`ݪF9H:2v jvY/+M3s,x,496:)[4GF trhqw{Q7Qv ,ۤHP0?X Aۧ<=|>:r\GTlu] +5bP,68|̹ ˀrM^@C9LSf%rM*Hh(0`kl΍}I9I%B9᷹pe=99o`)!U #OD+L +,ȇˁco +` ~A~k<'ĉxA,!na? 09-cuhEōP Y0iE~3KZ`C[k +˘ks0®- cv`ȡa?L٦v +0/0E9qy)D]CC.+4>G0 + K[$3a"AQ >:T#9C׺*"!PK4>}!~p3gYQ,< f`mcfRƖCC6C?84^h0 nP僌~vC6A-2 :{B^4| )xnCky`ol(O-\FVO98PC6m p-b0f;ׯ)Aj`L`SfChnҗȂ]$pc6pnPCAt20J΢e w~ğSdg@-aM\(FL8->bK`rT)P$L1S1"$86G=ė7,̾1+QTN~b|fŬ.! ǂ:~! [VB]&`p@L`= p\: LXR0FϡT 0i Q61ƢA_8E  EsFMZ@іi)P?3"`$dh- V>!ʫPNk`H1&C0$>`uٮ0`|Xޅ<{qCѩx!%`'bXP˃:Ȑw _ h"p3K퇨 W=(X!1`SPb72rDo; +ĭ`*:! 'GlE%9 +.|9P`u[OZ"ti1ݓgq)!!(vdTt倬yXlDgb9lP"Rz(}(nf3|-2cׂe8(AJƿDG]A|HZ8q2l(y'fSu-k`xo)%+B42iu{J5`*d+D~3IRl@'[b,7jj e] Ȯ`MaccgG@BΉ'`=k=y@[cPPWxᧉ0 ؇h[3֡!ށ00M;c6T (9m$c85u ̎OZ4Cm;]qA< B1 a֒1o/M5E>h rUI`e8xV9 CTxi 'O ` ,3P볃Z +7P DP! +l _N*.1'Gs~f&lDsӁrB;lDRg&8V qLV1bA/ted[U*z3 E9y:{0q(ws3DǐϳCq_ +6JL.JAK6a`~cYiLtB9 XۀAr+y de-0(I)O j1X!z*^hn  ba&x<8 ks_4s"2J&RL2cE toA\l3b+8 4'Ax 52aGFž8 g25Vϛk,` ~AV;$w/5}ibSC!cNEL%vF%aoCv٫Q;cbNJ̚?YƱ(C-fB=f1 Pnh٧&|5!WBNτY(J,DEXEB63Ap5șisE6 tsi6|Ԯ(8~ȧ((D>X{:yk%A tX ^G3=_Cvb=W1A-;2|8&blu&ɨRguk-B* a)QZˋ8[AS# CL#̎LUPπz& +6K|= +u!B>y`(aP@$e׃r֡Ns5\LBQjVPB1ɠ`qBV`E i Q#$HcjcY;ΑJZ;F<~Xd6&ש1i-{`|>2G.d0*(Pv\1{\ŅԚ¼ D|//x}ƁmBl e7Qi70%,cﯣd +fL5!e/c hk0Zg=Zr^Y*0AslBcG[TRa{i#.b5dXFtl +AS " 8' hBl-1X({3*3a>ǜz5tDe|:ABX ftSV3?94ʍ &1ef1v`V~^b,`Kß+cE h =6;o<=A ]]69<PZ1 `l ]F 2Z>Y/E 5RA'o.Vb TȔmTUV? t„M5t6 UxnÞ`oP,tl@i: |F3Ǣx;S@ J@r~dX\Q>,0W10NBS԰EAK5PO3 Gz#(@N5a 9%lÕXy=32l0UM\ eiPEX Bru? T`J[GLd}ªNP4?k3wj`r 8@k ԁɞDR|o UPpvl 8J&C+ۇNZ!X-Adaj JA$@9l*syϠqXٍ@GFPfp}3}6Xq#|lw'J0GR#_~;{avca /q(F + JYgx 6PfpQV*f?6SȅDGttu탺@C' ʡޭZ POZx%(b/` ~UW3^uX}jb'1 19 y fi# j: p\$M"> 4I⠖k\O +bfƘkFM`܆=lV~qnwS&WojhA + +XA[hiI9PD@CaEl9  UK nid!/bx'˷[hwAŀ#8tS-2:{5EjPf/c\Sfy]s^`| · dN"B^#!Nƙۏ jU ̲dl40NGN,j{:1 +q'^ fjX"P{k(ynri;Q)!߆kaS,az:VlFO5jGՕϝ5DpŚbׄb8 qPk ȩ\{8̧϶01$*0P?m. .0[`~AU +cmR.q~>^=@7h2.y`2 ȿa/5 +Adrz4ټvQ}ͪ#:6\paȿ Ġ~u;Jw˘+˙kp l{+2x;Z(CfTB홌)\ {7,([]](Li&.ZM cTȭ%6I_Z1a}PJɝO'oSU!!d7~==x}@,M0T~fJ+C=ZF:(vQ!`ze4D) z Ơ (/sXQŅ+%~xTD8 +lj&`>{v0sT5A)GP} 8x\9&Z  +t 4p@g&l㸆츧=IPڊ8FM(1#;/g/=V!t%ԥCSrKPow_|-l8N9_)L+،A-[ZXG?`r6(E&&|A95{p"{TPI,jaqj^Ol;o̖b2TS10zNV3q~Ѣ{&vCNvYpG[d Rgp>'VȨ5v^*PKr$jዓ5ߩZ #ҔrMȗ> =Rg:ٶ]Ń{beQ}w%G@=n86+f}b1228",w=sĿX (a%́8m$kKȇZ_C`f]1աn"Ii[LI} #lֈ(13iK{@=lngĽNP3@̎ |F2Yj|7> +O{75 +8s{p(ɤ `rrM oP{Igq^ +!f[ͮSAN.|F8cgTp1j+L}c;İ]^C>(+ xdݕzg+{}s0f0lxe7D *RӳX55J X%X"JxA({M@=d8#cɐA \ty)>"k Dٽ{CE| (gA\ k@3 SB>uA=e&{žu }c|-]h!c"isn,vCc(Sa"JCf)c|{,ޏq  ^w oZjE8 x9p4p +Yo@E~w rg-Y^=V:&_BB'w. )^5,(ΠM8 +H 6yo5V +z:sfdQ׳ѷ@7XOL +T[MaV.Pod΄ON{FqP|e +A. ԶEOջ #<]o/G[9e2m0mB)il8gaJ&\FkA+a+ p^L|^`jp+ZOmaNMX೒PSkXLŬKL; jEh ,@ѸoGO*߸ KG2~g4}_(8u43&'Bm<Ԍ'F 8qP(=3fQQkM@y rc!.X}\"A ΥБ >S=G+Ii&Pʉ`Oqp~>aqwWбEq +qc9pua/1.xBG=[*\~=Š +:Fbdõxwh\=!w_l?!&ʨI&<݀N3g#nzlb5ĢX/jeQi C>ӂ(__}n~AN.\Y +ZÞYar&M/Jmڎ>mVnC>k#0죢x=ԼY pAV((L_jTn%sbU;dueRe9>V*:>n +:4et\o.A`axW}@(ܫyy.=ΐaP3ɀwPx59/>WRweB꘨((rMFz]-^үmp髺mыoɻi'-aާuZE urz oK[ r u |v=3P{Dtx5ѼGrAd_Ϊg볉Ż2][ +~ƐWRkC}xej9QlO=HӢթݰo(ajEhfNaB9KV~r;[VUPx3.R\KEo,dUt0nQVn2e?ߢ6GazG S]2;Uy&uUToY};[5ǽlS.+qv;\EY:Czނ_lDDQekDQoV 6Eŏ,wkM _ W$8k@Ɋp)U{ }W@%VoT[HH_LoexFU|p'+ZJ.`9c\4s ]|(Cde٠+$A=5(ܭ(Fz"/ݝ԰F.xC zM,|1Y\P Ņ}@}r#EI*˽:7i9p%縧% o֚Hr5ⴆTF^=`^ESiV= "6C yrE#b׈F'.`b`VjOاH]ԡףt6~y}pya^4D9ݪN}fE9M]'1G$ɛ=6ʉ֙=+9ޫ6;5ۅ=jR"_#wk09횰_wmjK.ԉ$W*NC٢ +Gg!Kk{¬v\sHx}Cu%>G1QnasQk=LkțPc6Wm$]ߍO2LyW^bGoNoTK w蘂 _AG1sWLgנTbDu?l%gb7'a/԰I5{א'vvB#djytn&`Yс7ҒXA4`/lZQ%NM62wA5A-vإwsØ݁º/'E_>d7/w:$p lIWcQwhdzqCzaW$ydhK߭:~ wV".Hm\6ܭ;J_k@jL^6!]Zj3+7ɬNul!kyMb>?&~d%A/{ Æ)9F=iI ]q*dFz*뵡Jן-DE^~3<ˆ>S=@qgi[]B=ykLx' ?w| 끺E:9n1}۵]{v#`ߒG6֣G^:\ cѕW;;="ѳ~ YՌ~kMWtJ{NRUoOS]u$zNJn [ YbJ51-KcMVZ75}>C5v9Q/D? uyib,Gq)WG׮п=̝.UYΊ5 ~'MK3%|8@&Hhm+$Mh|UayW>FeӺk-,ߩc} O#@1F,AR&_u%LȾܧ0CYm0kO)@ r'[daI1v]~["h[*޵;[ByZS/?? f 5[UKc^;B p\iQ[I8W¼lbKOe5nF5V;zku5WlK?2'_v5"{pE6 rz^XV?z#lG"R_42\os(٠oe ~5T} ~ta>4?DK>Uomr0j2*Q\FѥZ=I3g֒;UfM5&7jDM'g 'N)\U [_)i4)=FUԣݷ'A\[?[^@7KmZOױ}-;Xf%5&O6'Z  +"|u׿!p&Eow45w <*pԨuIGԸ(Ĭqi׋xYPX6fdCI˱WpwLL^Ȭ:5gg[K5l, F_k;9,=cP,yQuԢ+Н;%ɂBzo~(ziԥAm23fG\v̺5#^֬NE}kis4?(Oڳ};q;ծ%+۹Y_^[)^[PU|6)9!!}]Y]Vs-6+.<(Ѻ)+Hv.ĤTC^_toԽ>uQ]&[H댸%nGq*ȁw`hj)jwB4@&kw]Dzhc`ּOd ' G{n$Y+Y*-w.jrz +},hp*wz\{j/Yv,[_ TS3eK .j̭V ֨Ǩ8̸$}l##fWg"䓟1VdzJ3ۋLAhPXۮ9=x4bF%H;2YjJgbBOu[^}i$eu#٧%,ŷ1$1Sz5ծ<=p>+H|\.Q.M,;y1tKjk1V\Y[UֺڐCv" JJL+M I%y cG>W%'g\}EUC&q5H%H~UȚaۯw߉*ʊ>Q0Op=vR]{%!:-Hѯ^x X +0z0­&61:0!'.7Υ:.ަ1=ζ1#XkTUIc]sms=ߵ'ٶelO9Fᾧq3;~szo5GLK:yKGȷGn%z5^0l(8A;lmǴI:niS[U,/$F5$&z{J~O 9Xg4ԡWVoG |q?sZ^0JZjkLuˈ HͭNtjNV2͞tC3P%kmIMuNLR##֡1 aDޢx; gZ2C3=bRw%P#ܘf1w:δ&&&4z'70ZE=]D]ߜyb^[և-iE\T>P«w?ZPU-E~Oz[_kՒku9z?K7s^|2C~ny#ٷ6<+OR;d_{%}C7ެU!޸K K\fU;F~h9]|B|8}t_orO(nz,~cW?4Jj3ZOxUm׈Z5:-À#6$oIlܲXQX~b*zK6DD-h5D_:=ˣcȮ) +%ɲ|QPp9/{dSsF"ʃR2_'fz.!/<[~,ή=G!zCNGSࡋ68H'be*ܡlBP&&3Х>_:bjbn8xoN '*3触c r3iCU +%Kvt݁US?Av׼)Qik߄n1Kb +˝qM/O MLI{p ϩ4͹Ҁ}®_>/脺ƶh % {k6:/rI9T +{ywAU3a1_e1wTb,1C$Fkd"8&7}56q9r)׿FQ;(35ԲRb~o\QGLk7qcbEV'{Wy{78ˎ8׶P`戤v1:V{e/8H00tX4)&!e4mݿ{z~Tױ== ?Q BDA 9֑x)NXK,bIl=vMA +B;݊Ύvx)3;3acgJ+R +=}yReZx]bbxmw}ki9GG'NZOY$ %qCv}͚= ]{wBB'E^w<2nqpyW!.\,絖-Z {9Q}iTY!h&#L|lbb8yđˉi٭~9o2W3=5=ݕo/A󥤠BLf+3WJe{"W<o+Dx /+ՖR_/}G` h3<͜PV\OLWI\N̚KLg@LK(T'9@(/ZQ6Uۧ1Op*0Af_)3!^տ{U(=?2Bn޺ȷN89#P Q8OLFL>q1sNb +1h bzstY3̹"bB!1m1UI1c?~m~<ݽ~[~v?of|uefX㐸'I/}RJ +SO|Y&}[0P9q5=bRx՜1σ7XDBqtb1K I+6/!'@o 1}vBivbxlʋy1wD3XozS~KDD;%F#  }7+Smk\G{2zF(SX6J6In:1IeHh]MFknl845y;'ouNuMM+{f? KchF6t|MP +ϕҬ=Y+&~YM!L&f$fJs4Fhk-ool?}WVߤCb v&@4:״ .i]UnPKhulM_q?ơcB5b4Ub=+v~Lۄ03֔o'fIRR%ܵbu/b XuZkZGm}=njE}=sa=11¥~E_z ʿykFEtg^oQT (4v8A6Gpz1͓L1'j8 6 sg f!9i#glF11g9IY laJ2Xڨ13wkuxK]ߑ֫V yݷc3_$ L3wĒ\a-w.TP)߃zI#X->1g1oqb#BߏXߎXÂX^D,ZN,^A,C6~0|SYQl/;Dߜ3AVOmfzrC弮NOWƂts+˴qIs3p/łv_ԪrHߪ=iUoإdm(@ s̙MB_bȕvJ8(jV%c^as?Hs Æ/_K;Ԃ6Qbbaɀ{?rX;o+o7jBXP +xRn#o":<߯+X{cNfz?wy?7QO y?ymPFt0Ff{ '(v1n, eviR1UW-qPqoEN9O&o5 +xyebˆYĤqsPTXuȑtMc_/{mh=TiU樃5Jg˷% +#fAvsPSvt<ݝwdz6Ws7~9ڇ^Nn{bE?0[sgv +.}Su<|{XTS^usyMB>c*lj^U#/|"t}- †N&nVGlܲж>wo?æ-/ӡ%1ݴLqKg4s? +z9}^UٵV7B?wR[zMl`h+' ' =3fMۨKߴ%/Jd|&80Z!iA۸1s>ZӇKbX{MK54Wյ5|߷fVg%?2g\˨:m|v$1}_a\$g4ּ<̼aNnǔd4mA=g-7wブ |m/|>|󙿧NiiUM3 ?dùZӹv4r3 n90H~s4K aók~\ Yg[y5go~wkT&-G_oMnMz֔kٯݚ%YҶ3%hYKAe* 1ځkF9(fs.TM?m>rq)horS}LH:_ПWWZ^aZuiqrM9ȼޛK^h<\ynYi+r޾e0 .xi_>T+Nux[Up-O⓽'MqI&h(IՏGKLs;Rg˲"rY:$Lb'³h2\9sˎH!W`͙ןl =<{Sr///Pdy|_'c:'N3> .4Cw̛_|̴+}S?B6ogpˍmj[ʩ>Y~ܸlIzSjkmd6U2eS>>C2q$}HHKϒ$?"ɘ%1f[$ג*ߏْneg|kbS~|«d$Y YU^nҐ,Ǭgn{Ӵv9 ɣ)Kn?&úɲ@ [L嗶˫X˱e$ˑM57RǾ9 .tjYuJJ. #<o}@K8o֗'_{kğp$/`3 /4ղP-̋5\Z2{sOjA;ܯWsbL=uo~S`eg)?ch:\+{KR9 ;lrSbW%|7|Bvn62|Tx^܂d +`?jsOK9;zv"=/?u_so)|ONL"_fyWWtjuə6-++{;ҍE$z'Iˤ$ߜs:zf3{:ۍO(X(fJ.lp&*;9*VQ@;[qeGȕ`;E{Y70lyOאZ6R/Wy%lytxͺr'ZróéUGɍ#;a?62w%'Y@chOԉ_Pd3m &ʛ",ЊnZw>$3thdK'~2^{o\{.X$3lgcLk}acw]WS%cKݷ^ "Ne^vѿcefBz)I-Ɇzw2r&Ba +ul˩&|E>0 W g~/ gW~3w 5>o^q)0#顦I6k +44ļ 5?9㌕{zg%ʡrIRrd„ ,ɄIH!xrU29LJ˖L#ښ܃ _mȵ('l@MqX|5Ru26.L;5:U ;]jɁE{XsW?sڮ| /m>SHg,{?mK;>и=y\K/tÆׇ6\@?OU[!ll= +2ܼUeK2rG-k.2aYrj^@ȗa &'ngs.6ؐ|.]rny e{Rk 3T r"a2>ˬ5]-ŋ:ܑ Mg12Ol8 &oYbԹ?eO}1Z}r h-O?f ?9L(ۺ+0uYv2}ze>U0U%T1/#c&+Nș%ԶI?kU.f-ٶ|wFR_YvDYK˺ ڰڋ'E:s?XlesI~%0%3ηabswsѼ{ <ԁ!Gq4۳:ܶetY\sA,K\u^gjkO)h:C ;) ~ +9 e7|toR1Q/|$jvӟG?H'}4<$/eܼoתW%< Z*/,O1.8gbE2V;Nb*^ׅBc/?wZjrF !0j!)zxCgĂ$˙d5xѰf gXvOn.e' j͉0G!dA,dB|7ͨ`^˒3=޺Y9ı\ho[a#yȒŝ ӧX%S)_ċ{rZvKO ĹT}!5G_s4Լ5c!qS +{5~}8k_?/u~Aŏ)x.L;^bXWf759G$ Y˻d3j7%ۃGBy;@=oNv}kΝ6sYg%C2g>֭/!/T2yCI^|ƜE<rؓMe9Ugl=jg6旴Չ#\d!K;SHUa|rnU1\Ƃ<+> KpI4_[4?94*wʶ'RH66T{@P T/U1Řy;mFγH`d$Y)mL,j)rl3T0Y;Y4u&Sd\ =`]s|ADاn{96=8)7˽\:#֨iϛ*WηMHhKVnCP?2>ث|L'2%:qS%Fgi 仦NA4!>crܐB'h)J䗵UoE0d m켦v<5i8w}X0·.Kiͽt+ͲX>=g$; hn ")Cv5o ;6oy11^%_*h3قhU,FZZ/@"I8/38_+#.&A^.|޶oH.x݀a9pmUQ*f3f/`/}a{ (tx 3Y=`eX+aMc.sm3;`,凥dʮi>ArúrKOXzz ƛY>aLW-+HGY}dն`U|RϹH[͍4ljOr>NvyiC3}N~KGC2fkgi[/1Bo>49a<޲B2&DIș+:g,k/I0Vw03Ih%$db2oTnA>y~Y;䉇\GrM-̳ ?pt +l +b:(_ f7n`뺢0^Ss-ߤ.9nL-+<{qLk>F~Κ`?vs +ODkYf_a-ٷ^QP\OEsSm2dې+?tpOdMWĴb u)ӿL} '|#`Drz?C.ˑ>ѣ9$6`_gC0`_ í8(yO uj߇c6}޽X3ƙ~:žUg̵dȻq.n)5 +9lqWs>aAr; ]'b)^l~ؗyԾr١`+@"lGlz1!-$p`;<15Wdɵې7 +^&^~-D_X C Kܳ;B98zIaڧ1BϫV8_>p-Mo20 NG-9vU=ɘ8Y>U١0xsҥ]@{Ћ7k7#;Gh} HBUˍ:r3~N~?t15}Y'`˚&jfvwuwS6]T~  ʕpf}:0V0qʮpىAO+Y0UO brqלb>mz Mߒ0g&Oȑ8M\ {텡mgqh=D +ht6!29 0ve:T!iƶc`lD8/ч!3=;˱ C_OqU`Bs 桎liÏ@E ;Z|yO&"O0Rm0~ `95d ΃T7'B^]kͷ<8pyZyy'>˦6\ aG,[{} W'zC {oy;ulCv9ugg0p +lNW 8(L0: +ssOp0^ A:؋Ѽ rO|=cg@evJ':9cs cgQ :$X ('+Sr-Syhn΀Cz VghL~55 8[HOß+չmyao鬐{顀8q6"!dygō3乆~o9k<-ӑ1>f.Q4vֶԩϦ$9ـgRytA @9:,λ7o[^U-=3ā?cI'5wCCq^c\?wCݷ3[^@}/?rVhV|ofa&w?!2)w>8{t`h:g_|SQUؓ0͘s|c񀛕eom8jm@vm@`N#9`y㰖-cWXr kɧ#kDhDv`y$s$e:ژH;Q#'ɚh@0;^g܎N_uG[{AF7Ƨ^!A~RAc [׵ӗvH<־b}݅0fۊo+\֊=H&YLEZ^(`߅5'3{0ҙXG2Ynj>{) v[{0ms2d8쬥4vVہ~ɫx](l Υxfsvɛyf߃P}WPXqhƘ}`kxSy`yF2 +V!Cdo]O[sӪqC~ړÜ'?4n?Mr'H0~!潿YԞ?Y vV)!W7Ʀ~r~2`g-|Uq5Sȷt l^_? I Y +}[G~՟6Rpf?P05]B9>1ȁxi/^o},;iЗ<-/?հP\~ia,'ο1Ky 9z>"ߠ]isccWSL)& ۔}kO ,_lW"my\ت`?8oe>Uי; r;Y쬪0vVy}w+@zpip.{+ٌl3@R{{vD{c-{< 9ؗ9$^V@.y8XK8ImjW办.oN_g} ȗ%i,cg}2v)_d0F.ڛ}Ke` 00Ã.$9lRs#^Q9\~+ Y1Xo\|PJ|NAs¸1+IZvpE|c,C|_;{랗O-Hx c8`%5GBf)򈔚9&\ ; 9go5%P9ū뜻A<ltiө82*Ͽd5+B36ǘ& 1cم=O4/KN$7s_s1>½AVّvoҘz8THE`1Q քs' `7`ԁB"|["U;pQH<7[fECl>ZIs|2}#O˞ + zGle>  RWkr4v<`gQg>+N .<rYx; B`?kjM^ZFcgv>[w.ۚHf 䮗T-U8(ƚ_qrcj7tb."0֜f=x=vX6^xvxOɜw! 6{s[.{Go; wB>5>m{cmO= +l[bɫhguWu=Ǭ%]1rm/?|dl C9_7M:%aƀG8:9]'3&xiWؿ ,d a%# 1K$RU̾Pj{`Oľf`~l!+X..0s.[Vc1z ءHo# }cvъR +F;щi=ѺaOqs`_pןjtu-czװ͂֟m`lhޣ-eN5Jm@nZ,b>x}cs2|nz} Ͻ;ꋥ杸K0CgED4 ޯ gݬE ﵯ0{^e1oFljap(4`(_BQb4I} t~} Oc4;`,Ot/ꚁo0&eW`/ {QT=`m?Imxf僎| :2+/(8 T5ۆgl[^SA +c&̋U=X~v0P;iCIykއaVd$eDonG*?^~8C.ysԞ1f!`+rcX}j(4[daupd}񮾀E|Ii9Uy;jB?_u9zywls) !nڼYh/N + +y+7F#hS}%+O%gԉ' %_ڣC_YOIj*,m 6+e K8{ xOp.=ػ Sqlm ~/XhÙ "jZY{Ec"}AT 6Fh7uri[cԓ3^f_wn8B lF{piWt4H7C_}%UOVoDP :٫k@O>03_ڶ#X[ 7w׃g84Axy[.%=q}űG;Yx\EP{ૢy 6`@X~5ֲhyuȖ\%е.'Y|8u81X_kz'g֜f]Z7 w1,;^WN0wq@؏vm9wd[urS,k VpHxOZsjcɎ8V*A6ֺ -Imӑ.[~Ljh>,:֘uQea2y[c +E:>&U\Ѿ`gH`thΎB;`i#{ԺFD>W|){T٪=mKk:! 𥳧$FhMV+֒i3҃Y[ɼN_PxZ™-NJ+ċUz H^>sXUz!= y{E2:{{otxp^q^pnavΚ +{&5n-8sXώ֘n)g? WG ɽhlQN'? +ёUކ+ߞ<30^~`|yhkN lzqeséô}1JNǚ>z֓Ll>stream +jtT\8%ӽ!04Mt$~\@cEL*r8rWx~f咀1 y<2|珂ZuPy0_(uAoY_d.o~)Ҕ.ʽ%RNr?W(tU1irt~goxMz|h1ʃoz]:l4_I _I#ڠ11nsJAw(LWOj4P EvF? #'x cT.. 4zPt]@lPm|zA7ZLE0>`+S^q P +I ECIHV"EASwho&@W*CQEJN\uee>wIJ4Ƣ-xW^-"\wfĺP yC]٘[~0ct'GUNokjݏ>[(+=yQTժ$ +@KYד]}S-_wS%e!wp"+@&Z*'VJMO +rK(f PGAJu K-d|%hv3^^a#(URk&mq`+6'+2A=7S)x<5Lg +3[B3iB;>!D)VuBӋ!CO }9 +6}IZxN3]jxH^?ăGwQj O zG:bѿ'Id1> +VI\b%՗MxnԔqaG5,TxBzEpe*-J-Q~WO+Ղ%RO!w0*uF_O *x}@Ĭ] G/p>[ ͑Bxy&_q.=tⱙ<،peK$^D11J'ԷӒf]¦EܖĊ) +1%Kn#Q/@,H&Fb~QI4PFs-$RO.`ȑx@Lr`fKۺ3 Q4!"NDX|(Xנ/4nī&([*GV| + b9stbY?G/"Ɵ럕bY?7nnBZ!)Ɯcw7)7ĘscοiD~R}EC$d<>un^ƨת + ˼d߲,˃njWm8袠[2YHk+|74:-Kt͝H׏DūFN0aپP#|i\b?|+gg&nJfX@oD{qQV  D4A0̄7 #+R wvbU)+@%WQ̩;q3G7sq3Giz3't͜e߲͜2K)cO߭&G|uhνVqCxO!1=G$s1=[wn/5/Pb+Q8!1B_=R44٪UezXŬVMGdJp "_#S+L\ 8e ~_0hA#pBKczĺP yC2ނuIlL鿔mB NDWg\D'.n81yoq⚙$B=X(u-Ȗ0 D $ d7ÀOJ8M(Θ?ZSЈl'D9ޤ!nĒ\?폸8$$n~usNlꘒlO]ų*NYIr"Gز!ZοozIq㿅LxYO(zwx^k @ )/Pp Otnn`hMn D/0JbTB?0 +Z*<bVp'}aCL0z;B Ѫm -Bakiw,_HsCH』=3GK@ Ub,T-ˌ<^UTD˚JK*hH)v4jpr!wM,)`H %@IjcJSEY 8?O\P MsW DdGUob9(iZB׫Rrz=z>$C_:PjjhrNPzA@ENЪrN+Rʝwї TT)%ҩRS.-2J +BS$B##rXF 4IJV:Ri&reBɵDUQU\&# +BJ\AZRPFOH=jm,ܨZSht *.!T*5W2N])TD!S$Ԍ\'t2P),BnA]WX2u2%4HnJ݈P!w$"^FSpT!2UO:G лNr,P+S"f82qJGH! +\MJ += 0 ^2\ehjEJtJ4 N* RGkS40Q* +"[z)Ut;h:,E.ÀC*h$\RihZ#xQ+R"^ZFU-4B' +GcrʸvI &/f0*ri%GG%Ps'4 +5Ǡ$[cu-cA, d +FN7Ac!\hjVСJQRhЊA נRh˕* J//ZJ^ ZH!tjEsF#R ͉Xx$jÆK)2q>QJ(Pz6M`=iȂMZ|`WZt v5IxjM_]00jb0R v5Ij 0Cj8j@CI"MjjXC5lPц?Z6)pEdK. H + q|GOJCtY,<4b!=d!SXRbYZ_D}ELLl^d [ +Dp`EpK[f +!\b4fl +@FWu]_G>ןu#•;D|1{jX̠ ٨RP)xV4x~6 9ȩKFN`\R]7H)šG^*!ԅ@_O/n`\zf㔥BWyd#N'UmI.-JDD.'@񰟐Qп'D!ׁ/ZpƚBJ`Ar!"4=giVJ×Cwx=cKWb1 FZ k};"jrHw܆n(%ZU$EnvCp܂n9& 31%V\iQ]i5IL")E`_`^iY'P^+j]GGTkHXUR84<mMGMP^~`NA=;0c4z3z9y&> QjFfAdLuPTDioSC6Z"'RM `63$jj_GKv$*ӕOW"v쓇sSvﵵYE{m:I +)s;5}짉\>|bouX'ř};۝[FGUdanLRY {疪j`eX^{O4ܺk7YL TZ-+:NfV#v7CX>~bCc-EvwPX3Qf`aB\; XNZƷ;5aWkURVғ!ٷU&޹!;ԍo +*Q3G)7ZC0PZmt%܌"D0&MX((dK42+*UpLAj"|Ͻن؝t \\k)y")v5l|D6ǔ03e;kN + ^O X=o4J!(515<59#=,FL`1 O54 ^Wrޅ:a U.U@]iZf8w6%%)/6Bc } +@)ˀc\װEhBhe[-MM *!F3:v>i 4%PJ\FRTZZp5 +2gZSkpdjVM( 2IE ^58'*C2@_Ŏa ȆΎtZ- dbba;I|xqF[$pq)|," }Tk(+{&["b!`᜶KLQ5S[EڄLID04Uw)t2N%Wj +VeP!7Oh +5k_[B*) }G!I&R$_|Ϸn5 t\]] 7~ 2a@(8Ĉ-T +Nr&^V>{v+R)K.jmCuL_LF 4E 3HLZ Su*qϒKqQ6",xJ. +zꅸ{WWSHm.TEky!۹9m/(45q6v'y)JKo]Ɔ,0&S +3塀5^njp˼ +o ."W=]tedLNߗ+a@E ~&Kԩ@ܛ;Lt@3Ɨ>+rB] JWJů)+ +)d 2GJKEw)> +pYy% vYÑ$ _.C7tf^ktZOp2$[J^\Zeq 73=0K[#96^gTwA~M +/Zc +J[jZ+3:@˄WS-ӣUkW0-+$ \`ocMXbؚ "8SԖ!]snuBG_hySh*: WƱ_dg9v/e C'eX)+`L]n甈8LҫxR_fWr_2XcKSIfYwe:$Z*_)D%]$4:>˴2RsL -_jd:5b9el ̭9qTm :a"LAp^_uGUcpg%_Bpa^Ac\1~ƶޛ,r,c`t},;V-8N˷xԅle.qg1E<6Ҹv̽y05ZmG(50zWi +ߜ) ;gqv|H`1 eLKcć#2bk1.Sc[ıWD4ܜDzpy,c`k3 +N-ۍ2%1vX3p񌱮jam71cWB4Rܘ/{<1$Xy 򦖱_"n,accJcm)ౌ-x+icfgn_.f na2 +`f3g +C4e5Ð<Xck;1Eu4p X0]l 91=(8Vy̪9)abjxŘC)a,*M;'eôܕ3GLߙpaxĔ0XO7"DbJiα-aY+0m2oq!'q KkI0ropqbJrC]qa[cp,bl"Nfb XĖ,6zVZguj6a%ܱ@v[5R'$P@}@0Ǫoq돒3ėb_!ɝ} ݊:0)."GF .8[_8NH8Z'$B6!(BWSE`jFFhZwtI0.Ӆyy2S*݆_FƑ!\ڤ S*< Ҧc^Ü'HSPprFjpf&jfdNp $чlZ 'SPp0GsQ&tZDHvРPց;pa](8|}p>p4)"SP`h@azxu{"2,TPp`U CZPB"LM.:HTn"G(Gř|F,T>3q6+"Ӹd!2V320gu3R|>\ɝ T>q)8jUdAH4=ړ xF>9#*j$==NK@"Y gM.0ERBR{BpV58~_ ?T#=ơRA(Sz&W +d))hsC +.גm^uiƇPt5^l`R 2&lua8zjIe*Ze>NIH$*L&jF҄e/]R2/ h&!;4x`M҉x4̣_18i S_I8]ԑr==Gw'ye0t8å]E`Ua`ʓtt^L?)h@cӑÝgU.f԰LD8!:BNwU)"aTq`yJͥ$fkRwctYu>*؏I+:`;Z9Dd0d20z@{~Nw=eco e) Y6V>8Kg~1Txc 7ƌ2fj0SuF?ּ9 B[/$`0ƪ xWkPrK8,#'إĮ/Þʓ<ě6 q'BrM#V+n;p {kV V9=`9S\)-d!CUdWX߹OυXl5Ī; +QkU)>Uadݝ9 bfփLVkoj )S "kHT2-dK`tp^ҢC +$B-_x~iI*3ߐ82>Gn&i#N^.IuTDb=I| I+I9|55޳XLUI4,!&d4g)50e }e/{nuFe'"l"kT2%~|M'%lBKGX2#O %xGҵ󆣁̈` pMi {:_30,+á8B}٫Z3%I$qL*zEt^e xUp5A7Sz):77PM+# F%ŋGpVZ'!qqTD>607$E}~7w-H]< PS3nGP1QJ,lgiu١ˢB= $Kt |%<}pTW0y/alPEA{1?y`msP`rr+u7RU؊phTR90pD2f-b%Ahe $ ;S -7B'R!$YYga>} ktS@OZ#/C;!) jK +}`a3,`.%fZD/x' Tm"70 + P!C$FCƒ0xɌ&2YƕcQAf, =3Z<' [oUQ8ђ2zy$L.pIt4˕$nx')\P22MȤuClU*gi/W +(ٌ,LZjq?O UuZ+wNG.7@dҢV 6=UoHǣF&6),(L!O`3*쑬Ym +bo[sO  {#5B:fNcVPӭH&NИ&ԕ  + Ց1䢮"hI Tm;]u2Gv%kFO(3­&ў5O\Eraત/KąoA]Y$M|R냐t<F8OӖ4Кw5[j4hbV\-fVTp/z%Ǹ^#oM#xm jRoW^Mp &p*K<וb8P^!Ѫ.\y kA T +!ž1!0e%yMܐ蟙}ZPRyE</ 04e pxRcjc yXL/ mθVIGIar% vAAc-'F -$q>t C8bE CLTu?b 'تS,m6< O(ҭg+ɒ=YgP~ ;nv=63bM9CPѢ=sG%*>˕yݪ +]YPsi˼F6{p Hy#,q*8a QdJ~Y γ&}Ӛ7c&f0#}31r ofm0,sI&.؜*)1#F5^t5)*=F'F`d0E@!!J9NxU%z(TBGA&4Ҭ)V 4]4I'xe G(R%يʉN$y>N7Ї'[j$k 'u[UP,vۄ}ΠJ\q5WO PSE<\3sdoUƒy ){V"L>¿E@ >'B("J< UE">]q%3qD[O~5׮ ;oD +ҒQ$FvAxǹYDrS ST-$Y),9e%%)@J䟤)I```H2ĸD ?u DQzkj3ZKDZKIgOFOVLQynOYJV%^!Ju#9,P8mE+ YVZKw]syɗ+k iVaaiη\yrNsǵ'vouse&V,W_AS{Wů6q3rЅe^8w.7@" =69U +,¾~^toMiVV﵂jrU<`fOmBNH{OkO=?3|'*ߦ'R=Hd(~y)yxۏ+O+I%-[_D"WsXԾO ƤG2_Qq9\?;m9\. +>.)r~-Z<4~vV:CQjӱY*yb&Ys{:4HcԍQ4X*YѓmhMܘ1&ɝlyjOyt4<+ &sQ^^w㢯.xME] #t$7jUgSi_q纃_dO1lQw[8p1ZVMi_%`1NQu +rQؗ>,P=΅iYggyx蚓ITl|t"ȸccFHV{bo[AZZ~~g*\u ˲^ik`.U]APܔxH +'xfY4 n#  ^% Q)UUDqVU]DM02N\d@qf-r긏UÈUWps{ey45+`*?xQ8^>]P5YyA$Ak8m+fٵQ A9uѓ;*CIt@[#* +ʜF8pt7i2[upf67ϥFSQ  UE4WκlSHTw!;P +(t/HEč(  +TΑ &:&dIX){l(z!J=)7rux:TVڭʆB):qA$9fu+qWP֭Kh 4MC@԰n£n갺pE2#nS?OGeCPm8yN?B+z WX*" +H/n K" +(XdēUM4*/s.L|-0xC8xEE <9љcQL>Hov,%INChB!zxB,)HST< +; +F-(6z;(JF.!)xc08 ̉dF/d!ʨӁ0wπ@d!pt _(1+Cq}/">aN-t+K 5(JD#ANAi r4P 4S*\?xlqz +^V-UJTAxXJ:%p rNDJoYr66^ıiE\R\D*,n%D‰۠pt :@AK8Notq-6x%:vbEQ PYy*H6Ѓ!)w9 #b&8Y 4̶LEL0yz4!ARpHMTZbb`na*8-Ed`;ĆC$Ъl^pM F́-2"ꎥzuAm +jYB +,(Zl@@-Cv0t,vT0Lt)T0w$zU2#oΌ!ݮnN#O$(=-^ +6(=7wgđg4(AbN]`Cej7ɫagϴM;5Zh@3 ="dTm0` +P@H&`hRiaXٞ|4Aچ0 +ҟSlO Ȉ2?`?̡'3P0/8eƸ`e|4*F!Da0}V^*-Xڸ#DNj<҉p#,(( qEt"ԢN o?JTz|1+2O[*p" +K ;SʪMKȾ`"S-І~0_^/bF""T'4 S!) +voG(9eQ̣9 L`% <5P*)%0%~5A#ḋ3QM,5o'ctĺM P +UÍhONm`{%vU(%|1zO%8^`hZo g)̶41L=؁B3-b`AccĤy/<5Uс҈Ijx Q1N[j߀TDX0#qRl6(JT ]|*4Ў N1PQBDVq:6C5 *7MaJD#  2$Zh#\? <#B^AdKPl40 2{IA84BM)9/ Ib4F|DDޒעbD:E ސyl^AbPx&|{tU +#H 8zLZb1@HyhuAD$e EKCfDQ"s+iQ"'HăWBG&~@Lz4 BÌTyQԈ(4PftI\5$Aǣ!`UƉ @^hHxt-0: +sBP*e0Co n:s} hh$ګb |701;B@:ZD/(G,fQ` +XR,^Y@( rڣI-y, N$A~l5PgWȶ~,.5YAT@)sMThK M&T´PhuI"d7O"AVᒍJx^=,s ~[pM"< +2'+@&҈ܛ`$T>Z8 @f:5Xh0&'S%4d72)" +@4'@1XTadt9{@ejd-!, j%t .khD!Z`QV"gWfB@$b!*q%JJX(MB GEXL |'1/pe\H ' +v`.<)1E$=tЦӳUtoL<\ +@-AA[خl9eNB^ 4T`e3&ҩ&+Ha4pGDXQ@0a8\w Ƃ)"SAta֎Kz.[@+ĖXv0.d")Ѕ +Rp ĹOV0)hA[9 R}>;..p G< 4 D3ǃ(vϖ`:8T؎qeU,.5B %ڕqKO,όqQTts8^FT0h`GGOd,( wY?`!Ep*ǭ<d @(-Af _l18/&ƒ8#grK\8WVA@)b3?l"I^Vzm<]5bⲥ+L&xk$a-`JA0N1#0W&H@?-0'cRBVQ/ +fVa) btAbp2W~RWy2Y#&8[C5UE$̔?5:Rt%Oh>(ȀYE"hY}IdXP4&L \Vp.=E@TE< RsH-@!-9]xV ,|bnrᣕ&r$LtGWTTSJ'L7GK%06Jp0P=Lx.`O)[fnvy#W +L'mR*#ΠLmыp%qƐ2v%MFV0XYvEp:E:w}]Lgv5GBf@ !|QA٣N }x%sls[:ҤʒDAx+X!gL"Bb30jTz*HlC* B!R1^FWL(IiW \XY<#`Y0C#^6xϞZY 3CT* /rj=.btIG^`v +ZdDNxx.Ê`| NO qd="K/FĔ1;Pj~FǷT ^R1 v؂@x༣J.@Iѳ#i6 +~8p>X2Oc.]]CSzCaRIj2TT--cahY@tJ"p`@n*|r>F?-97&[tQJ 4wB$z$ \4hj00`OxUޢm6D"\rSPPXFEڏ!!v 0.Ý2{I)„0į08TCER-XQBѽ&穘{ +( $Qw?8lIu7 E3Ko^6OWOҽf%I '7LEYhX1/U 6.ۈ9)M퍘esZYAzLT 3mvQ6s`X\Fw5,̑mWd#OQ74`.ˢ~Ј@mn[4=l :fnsq((7z`0y qi(Ʌ2"&_gk4+DՊZL"%s,Ad8²Kc303KKI0̒)&M6. : +Og3]<yKfLjZXH_zʿ.6Dd54FQߘM#xm j1( Cw-5~.}&-Xd匉mݺU0Wer4F"fdOuk0F8:!uOe0" jj\Lzfט#OcyY0KvM^06G`Fb&/kS4>h[ + ΣIULi=iGm/;霝 TI`GYԢykl}e L1TD ը`vAlWf2p8KqIE]-bT=xz*T~llvĬÚ/xv6}02[l sU~u9bLU`M|jv>2qYY_C`?~92c~\1VBr@g:0қx1%׻ Qdz)]*-*Oz *Vf5J5c^TUss;cÇ]ЙK̷ 3mL h?% +*]i foxp౹abA [@[6 rj)݅yaI/,tmMϘ\8'od *94zƸ3j &+ڲ-Q7bj1#t2MyӤßm1jڱ ]ub޴1ٮCE{ +6ܾ,2ah˶^Y;*iK,˲:23%ˁtQOޞ.;X4e13CON2%bZb;3=%/0a+8i+ h*j_QM2& wge0t$]>X5I.WlvO ؙl^sũ/$w5JreM= Yɜmvi"[JLژÔOܴ_Ax,u\k\K4IZHН +ZJ0''AK淉,YLI+:vZsMJ3"g-QY+"lզհeY'_]l1'MXmeh:|ĕTR`0gӐ RrF'N]KVr%cr +D-pP3)X)]!xrf4 +-e%o[ZkUy̌rr*uvΧ w: d'ݚhbʺ1q !_h-a|ȶYT9{HC봱l.766 =~lO6^ݸ[l{4Vt].`{UF>#Ղhu-P23Ϣ.-O &pPiL8UOy:$2CG?48;G[*cVVk%<FF,]l1V*kJdJo?@70Y`s_m-l[MS&Mܜ^ofN#1+Y?:L羂n9o@:=C+O[@0?[z~M.d^B|t+ مKkS%fhw9~1V˟>yL1>iCmk1]CĶZBX綣]6r΅v/v&WbHѫ~Dx52GxG.'VuDXtL{TA2 +=HOQp#&cR1g3p|TӍl*d~pm x.?íQ\QNM2H2dqlv:PD<_K Oag/Ӷn_KjJ%yY>ħ(K?\%ǁd&`Nu3N.%;{}; YE3l1z A6_TM}xΜqM g + Eܚ#9=&#a(vV=EX<4{'vKj|??>)f4qvkL17n+&qCLjy>џ=6/O Qz[dFh( -L7"Ob:y~~4?t. 4#^_nO޽4;JyǧsUhy;ɼB Ʊg|eCtqҶ7 =`tXv$6CI¥Z(_P#=z4uzxB +j?މ};scD윈[e``̗jx鴟w&p(| 5Y ߸Fb7 ߞߍ~?ע敺 B6{n#g r#?H'zՊL\4|<*j7o M6zS8؊g'i<bjLXjz+MK Q}^\08k_;,w:)f^2ׇ~y>XE(C->op@*ҍh'p;, 2],r/DsB,G-徨H71%]%5y*>[qԤ"bTX: zoZ=>oN=txaj7[gSY<͝磋9Ѱ= G"8,nx44x/x&/ϝh<}3qۼm$޷Vr/ِ%_9_r87ŎJTy29M5ݴVi1M?߶y9 3Im'~&2}v}ݏٹVqλ:%]@/g<N8,u.:'wIoVΎP=XK44.NL_\i=ṇ`q|vrs=)}UHn Nu~7Gdrߓދl]$ŭ컸<~1 n#. -W?MKɥ1Բˢo/a%tc]bWr \sjVOV9>JsҨ^n|dzrzT/yȼ߆eih6o4qSN]s^m=xvaU8~ zPowcz:yRSux}6{ryP/^އK[ݹ~^_g^A^}ݵo!)?}KflOqx4__J՛M:ک^մ͆VYި+e{7!S:dt4xQko轢N#.6EA7k3x[eUnZhԖBvRO?nsNd.7{w^vPg~-vdpz"Zգ}Rm8{O7ۑq76G^1j뎚 Yktn- z$8ͼ4[^Vԕ30_Z̯E1o;+[&X-f0orcіs snfSS=v^jfA$KRIB--䰁fA5J3]k%t<ưPh#ט;`; 8+#qlmڑ}{}:gu:-j}BΝ,LH`"KX푄K r/-t +WT-&EhbC&'I\\f:I[MX <C-%ŖYW4p;%a.8ijytǓ6j>V+VYw!vq2_y}+Q;>p-S/pb Cgٔ999k5LТ=\PGi=oGFiP| iK+7D ak M6[S1?? FvdW- x*%%|pSgQ:Rv|8%ʭrG<%;!%H^gy:f{Q isͼD~mOfhc½ҽGG]!}c2C)0y;@G{N[xM>.N=+ǵi;GJu߯L6ts35w#/x^f6R-!SvhˁoBa#K"oYԳh:jY<ϦǟUTwO9%meR;aPt7`{Eh$7ܬzx_~~Z6@_M^D4kJf˻ A<fvB6OL: 5` /AL~<l80~6 Ο{D*dz?ȾN*;} gnN,Ur`Krǀ/׌a9K*`WzSC!;[p(L 68Ld!ώ?$g/W3q/_'ʓ|/.Ăl\-*4shGJІaUυ@ +sal뫄tz>-k !<g`'3ȮܸhWPws@1U~6ҍq9.=If>RϝІ (F=D1~}Mߕ~o}NT>@"3)dؿɳPvxQ .ţ70Ԋ۩V>krtٙ# 9~Ta@iUNEJ'],fww̳ ξܽw<#pBN:ozsR(en.Ӎp3ٴg(O t*^U|f_w|L&f`w+i.?'./7tn} iΪÙ<s:0/֓w/|{}(9 +3=Kv`ڗ3HK#zg@Wu9 R0vǷ3j1ַźe:Mp[^wD9Wy9 kNap*Hr qk<%_P^^ h2μj|z; rws1-'*=tOq9y>׻AcvɊŽ^Q9AIU,ɽ@{@PMByg5|G& -O#t^#$VQe3O _d1hcwq fe!> \ICռ@ )Yq&4kFwHJʖC~'f|.lJl ? iۡYI.~61'_A;!}V9ߜut Pt[WnTҍ fwp>McV%l; PMuIT +qdC=A0>D*~0;0/󆪣PLa ~+6ߩpуInz1Ӝ}&Onv;b*[lp>B^5aW"KA9+:84VJ`ge!Rd^~,y9a;2N6dWiю/dfa&}?i7NP\"usl[ +/A׮JIV,L ʃO SvŒ`6Q 3el+H7}ϒ7j̚"V60Ht-+RA{-o +V l@~ʼOj$$SM7{a1Q.b9XE +ai3ȱnEcZT~ԥdVAE`w+yv(t܉ o1߸4a&;ۓӤty}r$m5RfZ FN܏wJ|𔤮>pY{ȆK=_wtzxvQO{s /v3K%;8^7|1xO7n녷A6opRE*>;;QSM,G%6 Ĕl(r:ot [ +nPFgHK7NK87y9Wޝ]\k 9hV sVk*w1$g^Bo=]y9J \nf\L>H3^dfXd /}9D`@OP(#.򘯓Lp\}FA#>ƍܯ\H +Feii]ĠUqzNxxyp`?Õz`G +s%r)=k@/}ُoSQbAG U JĻdqk7l N9v83~Ɯj{Xodg99ɄV/|(W - +f3RdaqL^nCݿ,鵰PQ:kAm%{aWɾ@q%u^/OeSh VT'/U-mј8n;sHQ4^aOv>_X]60IiO 7׶]xtc&k&F+it8{iLmOĊ.g_wobS ԶTUoP%fw{sz&N]n%ؿ?{ҳ"pnӰOvܝlej:f +mo3ځ+_"D%Y;1G[uR+|,_cVc /Ju efȮY:RovrƖ޼'xMO/Gۊz|&FNvRJЧTJg_Ӄ9guaɒ41 1]ltn2j ):kf|֮uׅ~g] *ET15Ɠ[} +h9t""`eM12=Ӌ)=c_[f3=}O۝'#h~cg!iQrl߄4n3BA߃7b5mi>hU>dMLO;#GiY3>4fݷǞiڏ~kG'y?m M"-f tq>j4JU[83LsS2촶9â@!0 ϥb_tlAXQ#72~aޘ~1t ĎPz'QyኟHԠ =ȉ/vZ|1Q_w +O:;7_ڍ9ZC0G6* ,ɕ?Oiv 9~>;NL[:qʕZq RFYiM{վў?@ve0㡳ɪ_ݬ>* g|ܒMwO2c#s7 7ڲ]6{h]A:x)S=tN/dwCX'5c'7jF @@Bҧ L$]]T-W)Mg=xR)IX%E-}g`T~-f>;E^{c[j£{:#~96+?R<_d֑<'w7}i=;m/iC]? ~ +wʵ|W$6# +yY6G. 4sIC$I}疫XXGz +{wT?|{_Ku΋x`sѐK}!Vw#3ƞG~G'XG^+KmYSd{,Q?E;O)z'{;_^\FQ<Ěռ{^r)Q˪"*y:XTC޻G>fեW&\YEp2xLX|[! ++o*-P1*ᤲ)fI`պ{G&^UYO]鬭>&7v +ݵ|c"U2Ϋ?WJrJ}Fkx4eL$Í5rdHӟJk6PdИ1 ,Vŵ +~r5nɯwiYnYwwq#Q4J~RVQܔ6k=lu|)#z۹{9!TdDW3?K +H6{u(#ژ{H_qD)Fv%|ݝ;oDV׊mh|Xͼ,ͯ{lVK,DgkOql"N/*QFEO67eDLXzH]_+Xd9˽'FCխfFާDcNS^9Nln"NS]Iff{2B\Bd?MAyˈ6Lte6]-tl살>ޫXt"_Y>ID5!(l1+GQ-%wЮDibl[]D'h#]rDCɱI"zntJtI3JDT۶2 Ltgj'E6Q=='un׆ru֯s(1Ns*%zOȈn)緋kP;[X<H/H^lFdD_-#ʊ'ܲo ћ=)ѷ6D4!d+<% {2*%:ۼ]J3 J8(Ѹ0il~-~[D +K6Qɔ]Ȓ>p p0^U)ф8SOӑ׽cBtKZVQF;sh7jF8#v4$Dk6QBAj:yaʺ$9ۧ&klmqWO+oj޾̵O*|2K~n{ړ{#/[w?7~]}5V 3-&Mߋs Z>imz/HwItw"JJ}hvsn#'#%J\o]Ns8L/Yy;cNɼsx3œcxtD؍l∆"&޿(^ByA>ucnY/!J\SdD9~wDO<41)iKKi9s'xrTDZ+0HcJqƏ+X._ڕgn0:KPdHp]Q[jvVX$LYu=YSgjsmV1ߠZ{W ;|?-Jr( V +:DK^B}>`ɍAiw.(Z֥ƲSko]g23G[N-y⠧gm =Uz|RD5}H[1 *Mo9ssH}/1;<<|[%oinpVa-9+9+pr֋G{s(-󒪾`i0JB~@t;4tVӷdRnvxt.E-YKE7:JWmɒ|"^ͻl=w5~ulV݃=үs@vH!Wff1~ Q0*2b ;K =1`[{TW|vP)TRD豼q|R_ ^J=Fomc„/aW,"$ވY˲eh qP[U] !ft$GΡgAo=c ?άQf籠.{qGgFǼGGiΐc,w>3qXś7#>b- +o7#Lu7l`kY7q zz!Sf075A\,̆+osWsӋ.LF>} 3CN[PooKs9DG''Šߐe`Ɗ\y ~ ՟]n_MtcfD8}fPy|H!Y?hQN^<#EsW[ʑ*}.6#]_-F1yM(ipiѕa"H\i},>=v!8{`?^f`]8sd>|=-{FIbZObt<B6J\re1~5#o= +;>cqw|e#>;>j̦VXӇ/dkP}X{ﭷBY.=ns-NyzvFD, C#IBcwЙ<.ie&8ӞE}(s]'1!}U /{caW]OO%;>2R2KS&,=teKH }9%DRs׼z%KiN,I~zN&BEœ]'2K.Ҩ[2A " +%o`U6^ܒXӂ*b7,\rsFW Eջk?t yWЅ"󮠓T ]CT YC7 +VgyW9ǩtj!k+\ՂcyWOƭ$Z9|<^擇ϳfķr+vm}:>ܠD;aſ;5_Bg{zLރ"]8q~[ '7prP f8Ao2,ԹS骑sֺ*YXVfť^WY|E{>͝}_ˊݮ<*캳^vODG'w_U:q^6(`k?I +;#֔^W)/!?nvM +!'ZOܟsD]܋_ʋh{Ve7SVۅ>yX9ևj:8qQIUA~/UAoD5QP5t u3f5*j=v5Ux7Hc㬥(\M8njP5oj鸳 TAt@ȘtP-=W#TI#id d0WӉ{3B5Sd5*wj:ΧfdjI5#6F5TK7ƈIFUYw1j!1 8-zBc!7WMa ܝ(橨S~%0)tciD'dwD=~GDu+ =l(DȆ6wb,ݰHCUqYiQķ ͝77كeۺ#C(D|~C.7.-摫0D!)ך=5n(gLOUڎg0Id;4v[DEu X:z:lv& ŭ.hݡ{CzW>.eoY>=>3!{pcIa!2d:s1qݻ<ୀeÔ}y39.`(zyZP}rIBUע.W?\a+S#_֍e(t0i½#W>NYg8eo-=2p=Zl +A> ż +ZWٿ !Ýo}D:9j cwÝqi5 'Btʛ@;Ô >DGd!; w9~:F\c+ݜ|Fz3Tfcr-h>|hL_XKy/p]}Ɣlr{7d`~UrMn(d_?Pc[S뇾j~@Joʑsǒ}4<+&H+&_@ *Cu~n ]\y~}:v~]B)J]q =j_?Wvo~|z_$y Ќ{:0]]<^8I@_?kW1!&Uv|Q8'+G;*RX'ǝMti{\ctJe 0vGW?Yа}ñQ!7(Gԏotd#2ǿ۵Cߨ3V_? Ցm vs$Cqjo~|*\D?~|]͹ Q G'-g]ܞAl7OXny>~_?mIzCJt_+yws$׏gm~~.*BW?Vt~+2wA폍׏1.|,(c!G0~އ ֽ=c[[{qk ^A\&{Wuםa%UWh'ٹf׸,3uywM{ rM` 3rEi[# /V/Jao둻vYJkg7h83‹E^:9 +kœ{_[lv^h + vsPce7WVvnJ9Y^('w%Ór?rPQnv^RJ~*K~6' Nw&~-lu~woJZ_kY)墭g'][Ќb~t1?.A!b$s J5Z w^oґ׽cB8nZ@~F_YIP xAߋyK_~4w5vzQSs_nUJC|YM'Y7Y&Zt|-ӿqIsgm\7 +ں[p_Xޘfe8lm2myNn鰭^h#e~iԊ*p3mm~|v7w..nDmlmǟ]zfzaȆ~.i2״™(nƔh[ƒYKV5aZN诩erG_?._[iUIZUۣ l& +V(ЏΏv㏃ns6|[~hg :XQ +uwiRmZ'ӈv6@i~N}#|O!36^J^Rf5Q5Xu)@O?:#TrMrBo)w5Eĵ2(uJﳟ57*Ty|z1Fc*/G,+X?2 L7~dkZ.ҋӃ7O]6ڐf{ҊԐLov(:[iS^Z8U;췷jSSu=_,wgү߇ZuC'^J' TCd)wZxi9Vg>wZi$򰻧 +sTO[Qm(,QȢ~DNb}[G*nC_ e^mf`{du:kczrU's㴮>/."JLy!=N=/KBOTm5XM%jmru|cp&m)POMe/ь#Uddl}u8mX(,=O-t[Ъ ~%D + +5\b%Y%וa~1J<&u>1/7#d4" +alS߼_955Q\#^=ϩ[ժKG[Rvƴu5]-U NÍ>u }rTV,ab?40W] !U;ZmcZ،K*}uQo|lIb$\b@MF/y1U>tos_9d)/Y5!tz{K<sb[Zz+ZT֦/x.Ȱ}ܲdӏ<)Ĕty&kieD uC}xLjIrO\\Y H<-]];ӳNO)K#\Q?洰Ҟͤ1+GSBĝX}[)+^h|h3]T4ҢuQ+ma}H|ůcb^Ē5zK38)5[쎭O~#1AJ4u5օ,EV֭Fd3{15岒cbUY+ZY8Vҵ0 Aq3aK)35nRX8M%ي|EׯHvU51=wfš_@ŗA{ύ%{BjB|t39!ОCpe#zBke]MDPT=}._9R ۃ6 A3?!Qüe,lVF Xz|;_cJ_~rDmF4{p +Φ$;R1X/|^J__4t(}icc6{xl;ƚ_CA||szu#M߰ǹYׯ sn?束~}~~~:} ؜|?LO;-8K2 '.s|D҃1x:;WeYH/}b:8h/''KlfnMKZ5COy+ +G;v {i~_6|ZQ]\DvTHf+>]7cυn%6Wԭe|+v LZJo8 Km,맽#vvESvèH_]Mo#̓2Ԅc 3iGK 7;d?A#JV&[49W6: +QnY}L8/2?fę9LH.OmebByzֿ!O +kC#Ek|ThT:_V8#IWJ{f K}aH$#4pZO&6eVMg+j"IáIe[O%7c\&轄5 `O>s`Lcp]@/JQUI3iԡs_ĝI3iq +ãNT@wn';ŪvnyeW_u *4e1b1U5Qg)Pvw ]Kg7;V BDfj|d d%- }yj&"!haZ"LY*pC_'5[ od Y_[ѧM+߻ 1ҶV]nHyWYYxPo4 +,hg,ՀץȅKjct`W% D2M TUbɝc4(r1*ş jb% {\T/CgtiYӃXg& pjw1sfcl N21fVJƩUժNw[t] 25T%F>1c0 qgCMeGh_dNdg->$8?웷j=7;dE^iH 9-(\+R۠sc>\vfʰ-/ *V{{l"uL/N H&{BfkUe\*GM3FV7{"F5s\#kyIVصR`[#n8ć|;,X7_2?l2?FmՋ`50 9 8"Wvt!k+a~(P!遅|&[x\~'aAgȧ|r|nS쮟EΐOw) ;B>PĖQt[ Yȇ3FIv]CA P~[&oiFI ^Q?ICu}7I,nUc uXq=qgܧ[`܇0z4=RUӿwֵ?-Kd7v +y[-쨉2vrNx1 F]}9(ܡJGY~i9sݕrgPzeJ-ڨ|% / =hU+s.g=g}%yya𕮗na)VY j7/\M. ,YAX*ApbaY3h ެ_`ͧ]ekZ^%E:σJ6>Z٤mmmRb"O%30ڿIdMEj.όONhVyՇ:md|*VY +>bf6jd8FVǫ<Y7-z}9di&iAe"7qxt6KUQ.c/ 4U@gQk}t&Z/d(dH}q* +ˑd!/ň92^nz֪ ]|; +7 x);ooYos4evN=^=V=9dDaW0>ٲ\$X) -Jx1:>(dխ7͖`/G㺯iPς!:l:t򔪦Ck${sԔ5\`Lwȶhgg콭IŽ]@^Y]ZxNcŶnjڔY_Dݾu$~KrVt2 +ى^,jyZvL_8X!] 3c?*enAkhLeɆHu˥#“fި -<]'SKv}~&fdUmPD/P&Β7:P6jKE4DD$S XeaǮanp,#ǩDWOO t ޝ*&9I-Yi;IOPFV}W 6t>t}nj.=5Yi]׋6,I3XjI}LPT/`8*FՔjEvy*='?Wɜ>۠%:kx =nonwp.M6j'&L(E/R KSұqvKknus T6vEs7h`=ZMx [qX2_ /ƶ@;ۘ{:=KBQVA@LhJkjn<IQjeq]񩄽MUѬ쩪UÍ/ +B/.䟰TηXhexuE@ϼ0fa|rFkEEl8.Y# w=ڹQ6p~M +,_oPbilaTܸs3ḫ&T:!;DA5˞K~)mf21!RDm,m[m֮ħ[l9nivrJ|AaV n\e+YyfyeZW+;V&yDsNJuJ<d^5a#>35ͥzJSq]}(=(m[7 +rE5ji':W7]'x t0ʒ5r];{>"b^ζh6  +˼%&OUomK?Mb{$+;gG y rz=^*ORl`bKY)0Yك<+7wѼҾl4*{LuD/Cm]@mgw޲Κ͞=$~iDv* ȭkpÉ*䑧Tn4_l5sCMBvL;q8A7aQg2N]L+jpM8pQ, +8+s%OT簱.B$X;qDuh>Tɔ*>fA]y܉6&1b<ִIқ6uÑ',~kRg] WN}=XfĒ﮳Ub[tv_==a&嬪o "LF,g%ѹ؎O|͠LйLD3un& ;7n{3Aposn՝t7eV=S4.T4;bʶvFMj|4\z.,Ѷ|[od7tnZYG-g#jEsQ_/Zwse@b5 oZS7T?wi+eW-^@1/h XZAcKWM| x(b9/Ja8W+{&\ڻ);;^V:M퍚Pt]nJ7`UHacy6Byo]fcZe#mpq2v-7vS4[)M3lGq#o+w2(ίA@(>&ٖzd5 %Sǥ}QGu\RǎO|"Ԩi %k-18OFy;#:f rԊ)yx;Qf`cC;1 +~Q>l J~ύv]!$rS˽.eiqd=2:=Or~R&VإCy= uW{؝eBz؝e@z؝eܹ֓-cw1;[,Cq,2vg'[,b2팈;˰.3;˄"Iq zY-Cw+cp5 hl›Z8eajkE\r,gk&N Py|'҇ivҕ^p7цŽ/h&ђZYR&p l\yء>̎=~d,ܺ6mmOgқ'孭|~zj$S4.sH1v%k#X?-/ s푅󹢵$*=9J [t؎3Z舊ly7iRVq\zO=/m>ݭlOl47}P9uҝ37xo<]34:^=ާmݿݰy I(w+{C1j `{/>0_AϵɯWN2Iujޛ1HWÿL_s~& +12yW$ԜLPƠ y&/(tI 7'޳Afܐv,WXV;~(f{G|dk=X\ҌE眠R%^+}^'mW~[Za|=Xص#暻8D5c5pK+AKӇY\0O?}h#I1z-\睾W[1hg,ۍ?2A4qU&.jf{7 =1{%lOKHi2`c'~cͿ 6j,f]iõqmNq 6E'8kxpEn 7Ƅ'8kăh]mN8kcutmw /8k01&8f 1MX j0c1#ژ_Mq6jmcjýDMq$]hÙǸ^11pwDX1+c8+dpmcj㏖hc7۳ƳAK\ޞk'8YWݝjf7<viwg9Tɭ9aڎ{bo{Q\w[WwZon9Gss;:gRvg;NӦ2N}HpYg(i} +>tGO> xiu"vg4*N3 >1yY Oq=P2nY?3HT~}bGg-DM3犯O΃P$Br~2wn?NHQg0e233݇Pzz'3__gH٬"wN{lu3S=۪g_{x<%\*w{=USgҥwIb?_ cqk|rkz>Ϥ-Vd|pT7  /OMefoFy:%U]USY5_(t1)J(j90JjVI4EW3ɋes|>wC9C6zh? TYrk0-=QH +y{VϫY}+FJ +U# ʡXJNOiB6oh*O򮜦K㥄z,J%|~^cގͤ>_iI<>}K],6ZO>QiQk~z>{w|p?iB+k/4گ/>/-u>۝cbbbQa| ƛnhR w ;w[z}Vx:=|"2 +_oڵTѭdsZLp6Jê9$0v6朄 +ӽx} Ú%DzN XvKrOB&>ZK9Oiwr95 FN!MY"sjQIel&37#-:Y'2}|N5m&ۛ9$\>l1Ug.O5׼]w暧j3b̨>`\v+YmCe|ȩy-j.Sгt+d2ZP\Ae2Kt;SCFZ3(#7Ea +d%ɪplQ|Hj.'fJl>" Y9|ȗt&jdϨRiע:4R2d, {2 +KEh zȗ\p15khde%d 7rdCԙ T0JF2MS&1F_bEP"yn9CY2ι|8Ą,,/%ߖ\JN#~"1Nx %%7)Bhl PBKiBAS"48aJ + +48IPBAA2 PAA0 "TPP A%($C*Q(Xf Xc^#48aJ + +48IPBAA2 PAA0 "TPP A%($C*1(F gU+AFipP %CipPɓd< *C`8 *EĠ( +OJi*1((JA%TP̙lJ#s&dxOnbJaJ +40HAPBAQ2  PAQ0 TPP A%Ĵ(%C*Q(3di:dYMN PBAA2<)*Q((H04*10(`YJ + +48d(<"T0 B% +3Z2ȐdKnrJaJ + +48IPBAA2 PAA0 "TPP A%($CcZ6GJQuZ!9េfFP\)En 7|Q zȏXpڂ"3@Q +xƏTpBAI((H=G,8$ uĂ# 03_DFe'g ?Fp>A2<)Q'HA04"1'@`YDI +48d(8v:Q +L6r9pF^)dʘ!fx P ܽd|*Cx&2/mRZH?=2,`aZNI$%dlQbhy5K$(sD2!_rJFbhV2Y#h:mU%%d=_ +aɲbhy!í%A P2ONc^f5#H=K.@ g"Ȕ0X +A8Op4S3|MN),A~x$!'%AA2z P2, $!'%RxAA2z P2, $!',Q8H,of%(UE5ijF-`7ҟ~Q'Q$# +P @BV& $ +P0DA, <6b`O SFp؈==)|׌!_r 8yxDA  +DH($Chp ($CAip0 2$ +PhRLPAA2N,A F&K +yMOnrJK +58HA`AA2`AA2 K,@4`AH,% 2٬I,xȗ\~|yB%xS3FP"CK=K.@(?씌J6FA"\$ ()NQb(@4 +)]!bfԓ(dGJ^0zQ P.(AvxԓXrA@)>`4$dP +@K&CSOrJd4$$PB( % + fRӏ( ái`@S\0 (!#%48d(4 (!Da  +M +@ U3|d[o_rT"&D;< +hM-@@@P Sb%hC.H 0P FSrJd (A"N1V]QA`84 +(JPb@P %hd`4$dPgP +g z P2(e24$7s(QiQh PB8w_ +`84 (yJ Pb@P %dd(X" +MJiR@ x0h PBLޗbM +ޗapBR ái`@S\0 (!#/@QhPBLޗaxAbeg>h:=Q(e ݗ%/MJBip@ }) P +Bd(yPhPLޗ  +M|JC +'0 03J +M(;~%  P.( -DSrAJ`%R]iA@@!%~@ CӠR%E`PF{_ +%40/J!%ȴ}) PJ +}t@ }) +Yj(4 (!/@A0<%( (ʅ22R -%Ĵ})4 (!}K0P냦J|KEip@ }) P4((A@AQ.ޗ`(4 (A}KRH$Ǡip@ 2{_ +y4"PB({_ +|f= +LIK $O I +b!4@,3D!ip {_ +`( #!}KO ӃHB1K!ߗ=K.}){})3ĦY-P|R/)ѳ'  +DPP͞Ħ ! T1{_ +1E )PR!F;b Jb@=@ BSBv S!ȴ}) +0j +HCvs9P>ހT(f]5y9BvS!ȴ}) +ţB?H툱LS!Ĵ})z -BSBv@ JρdHb )PR!F;|4{_ +A.@>@(w9:{/b3߻,zȗ3Ň %r[=(yWF4InX(p[S"Ĵo ,IDSSU01wHMDi j&>g[P " sټJDPT5k1G=MP)#!v8AbǍ\0z P.%D,Q䂔 I!EdXI.@@1LJ8Da )tbjQ%?)7P0P H J r!40JBӠfJ40d(4"PB( % )T 6AB0$ypXL@D@ IDI`($ $!/ +HHg#1'A$bO +A#OBGBhp A#2 gp"D09EX$Tj6IA &QOj +"~`6mx ඼>Ԃ<Zgb]^.+i +N]DG=y.iPԦ!?O'yFBfɀԋZr +$ROb𐈀%Jԓ\A0)D@D,$d NJb;ޙ@20$7h +( (4 (a˫ H J r!407JQhPLU@)0hPLU@) B߼J +LI*!ai`0SaX$ %! ͫP0CϾy b ϾyI>8:=/H>~AJyP< tD (?qU( ?FeJy00B,U()"T"y <=x!#Ď_^ >(;>yX : +'B=)14}`2` BJ=*e0Im'C|} ~3[jn^.nZ$'KH_2݇PԞyxz|~RR/v϶*3;;3-U#_ b3;v1SNo14s5S>9v=φG$\^7eo?!%TM%Vȑԩ2AN&?ѮrXPBVɃlwwE3cFS&ȣd3ZFIYYMhC%9% 2R6 $y*J!>{ƘٛQfǡf#|d5?dsLR{ɥ|&w<J$D\򀡤4"fd]gt6دc"[܇Zi]y5Ufe/}9c#k6(jĽh"-Sփ|5]%YiɬtVkJ%MajH&Qv)Wvfqky# ]p<$g)]s}.8,mML% Z:&R͒]3K^o ]ݙO?&:c"?8#3uSccw3$8Io[ m,{!JQ̲8M@%e^0{Dzuh?OwDw |c!pYrѶcty.^n'Gp" ODОc}iNDN)0)yble*Jp1U։z^WŒ:2E)XSr9euLbL|쏉Lw[ >x^`/߮~_vufL|%/NoϿWoX}_ۿO_oGfĹY-#.Za<1Z-R.RI甚s(<2!pN`V}*;%^fLYbJ\yyMAdaZR鄨)#]VrNh6T^;b9{LNAu|1s{xLdBRRH!#\ϽLwE"M93$}/x ':>[嗿wa{pKA>M))5~~#.]}gh_}_^<u/^nv7nD߮S}u'&ڸ=Df22L1~.nNK)"`1 A$]T`3A.oN i38XWN./]D2J%eW7ʺiI\ _djGw.i7VׄT|vEMJ5{\)ҹ|{*ɜC')URKbXMn&7~zO?ڈdi"]*Y˓ٷk#[lUgIgdKD3]P[T~7u9:>#SКgUm;}2OZ9"K.yFD{%V#;E.יr> y3~_g Xv<\S<-z.Cv|5q4\ͧzͨ~ED!ltK_u]w2bS=$ +~˛_(t<)t`\Cke:eb=w 2U¤ w7Ie!|7*iYZCsIcD@ޜǎz}r~9%93wӦ.|^߿K:&zO" -_0`OD]nHJY,A:;=sJ;6Y!Yd5PqVd䫎Hݟ#"tAU|ݹ CYI<s~Bt'9=N)79yL{$u9_OKO~n2 41i[JjG!)#RF&Z*D7d4l=~ҥZY_%?EiL]NE%+m 3W~ I"YRZ%_NFf= Vd!:~Y({ &DJg%iVf{ϧuDϓ3RRP爞Dd'g&1YgghHu[šE~J8Ho_zN8Y|2,:=N j$x"!{.hA%şE)4_DcF/D,g{ʳ3$̫4dZ%|I"G[KCl8RxLsOhNezE #9@< sFDHVy}⩤ISS'Nو>Qe1 S$j"9bPI:#~/^/_$I>Yf)6hH-4&ZzϲPyJ$9/K{j +gki?ݥ=Od:xRrEV6+s!شI:Vㆴ?!=^D2^7y~ם%g ᩳ!~>13L~ Aڟ+!;\Pvֱ&hd?Iړ:H{e{7=y򚴗(^)i?oHHtt!l^}7}oDK#&ʏH!'$g^uHJi?}<^rG[KʶbynÛ9kh1AǗ;Ѫ?2t"lH$̵?WwƳ>:RPnPn "~KnqO"0Ͽ/~wի/Bn򛯾jϾ+s$WW#/W&~/N?'Fmn endstream endobj 968 0 obj <>stream +מ{C~˫o_"߇881%{1msߟz&<â.}ח_cRj㛿TwH.7N޴>*߾qܒx|vۛ7_}1ӣ?/fX9RY M O~ru_av ^Å5֣pI W35GYp.>c}JXI֋Q2ɒ ǿ哿)H'yXr+f7d0eS);yvnSB&=`97qNY%p 6&>/6'DǓV&(VcpwVQf~J<;ghN̻.9Crr-狸:cI7Q)͙8y%4w,SL%؎#I;8dܮv̷gɴL᧧_=SK{cأǾLWC[9?}%4he5υbczyjVr/Y}ً^=@A@%Z,m :)T ef;qtNu ͹ћeHO .dLqe&{9DI_56;錖l'˫ hu²{k׻n'>޸uk(It`A4tKh|wɈ-xF JR'Tŝ 頬n=Z[)s(1ǰ,,%?cvmsNDiq=-.~fN{,gwH,/P)FW:YgS?]QKxrBI^~EˀCڂKTnnx#FZty{}@u?9=w]B\#+S8gj`I[^ґ,bXurD(Y(F"SCh[r6y2X$(GT6+ٲ-uኖôILrі:=wW֜jgܵ7KU/=-lJҧRVE4i3gA'(\eDJ<DfD23VQv3Yw?ZZN#}#u'Xt&1P_i-jKj)n+ӷ {у|x {}#Ɓu8a"ԯIB4U,Be~l 6TS[>]*,eYeJRsC!Jس>H䶪GD +pa./(s{ޓ vmέ27$,y1J{VPڒGHi|-%kB.|eRG1bj, `yY5}Իir1g멆qeXXi/M %6ґ7Spyc)d(bambe*Q$kkcen@vamJMw@2Mm~~L]a~Lnsme0QOIW[W%\tBf] \ܿ׌;{4{R[@Mwqe;Dȑ}=pMբ ۣzv1-M|0~ny?x5Zhf6iBڸ*RAЬDnSkoqk{<}?~| %h娂,z=;K)N^aVI j8(su]Dtn9Q$}f̡>-I1Aᛜ"=p`䍴\[]8&: ~/#:yݿN`wNbHݷ|w_.G"Я}y9AEEkP) EYѠҠ-'!D6ȼhM.̻_Ojyiuqt5&W*4J j8 5p{R$1aM"a1QHJzDÏh:x`V_j{6 .QP3Pz70{ ʾ 0!r YL i5hNz:8{]Kz}W}Z va(VF6op/ՈWb[ +\1ؠC  gyAg$F:P'ss;\Ϲ`iJaAe*F,PDt;F)=$ +ini%uٝT"ò&e^(m4%x @Ӊhrkh->7*cM cݻ3 [p|lnb^clgaU~$#R {|iݵ7ߗ)$JX&voӵf.N&%KF݆>|<26?h s!1`70bm:Rx,X(ɚě5CKnIs uҌ^o䕧Ea*)acQޤˤ(g@'/zh+`x\-ګW>rȃQ2Nڍ: )6<9ISNZDi޻ g&2)^RzIpR롷I1u2T̷7nyg+e$|vnD9:aO7ڈ߿kKPt3xYp;9oU~O*dLVMmHe+9#v8B CV; vF^%--j,Lok#?aJ2ˡAj*+%AD[9HJ0.ֶ H1tqm#3SUILL"g .E@Y!E#Y4V]D>RdIWju[ +):pjx4dGn'IVM;,sjSiU᳻8_U,=hnfR' +}$\i}Ӛ4a[t$@uɔh#Cp0YrɕlV[1>Y[AAHyF PtG),4a쮱")biã :#.؀ +wavfym+o l3ď)$wZY0$-)$ +Vm +Ge;ۧXroAnKn4]u0QF6k^ ҄aEܜ?04Z34H!?(O0,d !#psPϖn{vhx&cO| w6>U LepyăU3]FR3Ҟ y2XHr=>El-m\9Uu 70Yb`ɢkc+7Qg0F[Qn8 +hȺ+bqt =GéSwi-꒬tQf癊Jd#D87)u radU1 T.ZWز0..kЪaH"hHdX?-~E#9N/;3V@eFȺ6 X:wxK*YO>9`_dq;wdba:r2i8] P ;rQ$V.4UHj[c ~f knd#nkzP0j|G2McRbl\S8 +w)u#4l*+e@J-'ʟirߍڪGLh[FdBuȦi 3 tk`@ipѢ6> BM/fЎ̐7[j/FD[DMU (^c̯ +KPKrtĝD9uM+~%;Rz(XGXv|5wݫ7N+̻rm!L Lvkl;Qd7=$H;w_ƭ␝&ŝKqLTS:7a2'FY H6ZH'˵3tC2{I? + H rn񛚁*Ę6Yߢss2HGM1"jM>JH_:Jפ0lFK~w<4ӏb=ǽիJB@O39)rP  FY?Od?׎u7Jv%Z`? !5 |':Jp ' 2lPz9Ong:Tn~T,z@Ws^UPo[,l)Xp64krhZu2g*;f@wˁS7JN s#KM|`_[fAUH` NU++1EP0xy:lJ^#T'/~d ph +Uq$$:/@Ov6B8x(>$} 6a%@('\ $bh/0)ize)-0Q7YFĪ))==Sip7,v6ÐJdhu6G$Ӎx yDw;,?FиCLT,Ze* a=st}Z]sw0qp7_ s[V3B0.6FdLm3)UV lSrNȭ Mwk(#c +(cFb˙a퀮9V$Y=)5u/X;I!C "u|T4כ(e# ظA:X*~Y]> C|ą )4̤_ Z"ɉ1WO +pz^ \d\k%:yIL A7H ++ k-`6шޤMГ2LgQ6_ +MFgTy$,5 _ +lƠsw8?V +DPS ,cD^=el J$q=RMv0ۂ7Xh{tX-x +C7cڗfD*N7M l(]5[ LbɾC=eY@U 41IR$؁ -grUy4SG ކ$+ :"ө (kXŶ[9Ro`^G;n&59ڨ=8 1B~8"bKVԏ}5!G@3YؠY .bLnKPnX+`(ɸ)N"6Ig}82h1fnb\c,f +}w9'ztSCn!e3%KFK5bY;2x&d$q~Au?$2VEC9Vg2#c2pR6R3N~4߄%6{D4(d$bB+7Znrr)c~]#0{J]Hy]d8F@;q3'66l37<>u&GHPZY O揀|i2L$Qw PR-ɏw`J7F:-2dSb !>d\= /O+.F#ji.4N,^nc8E`f]'kPj(8Vq: xnӍaZ` )o }]&eB_X~rTS2հMP! Uѽ "F<;tÐǔV3K̫Ih02l1) ~F +i!i#3pH3꾖dbe( 𱽉19drͻF?!`h٦JQJזuD{H&m6U uPY% 쓅8Ɗ  XssI?82҄e >3XH(+}8uO۸ڬbmF7 +%Q8lXb牂n]g9 Rwx $f{NH6YIQ:aWZJlV(Sf 3>ƥ+\&]o ̓]4QA fY<ȏN$uϴa;v\ƆC; jwaU$e .A5S\&挈 !A,lyF4"[<=!UT0L[zXw vHtɠY؄Ѣ;ZB1*Ew^*Ex&N3Ʋ +(Y0d0)UfO5 yT%͂\`R{60^a iXڌD۔1P- N |[qCShˡŗB$䇤-.h 3x1;D4P R;g$nMnfz +mBk ̃Ƨ7iz~qO-X5=g(,_Gҝp}߿Ң~H@m +!:Qq*zQ"m'kn,F1.pu'D _r0(m-"۳fd + k'|!=&{@0˞ڤWڦg2ۭ A0oYdm@lo~dk"^ۀ;_g4ĸ;mU+obB)@*ώUX%^/{} &?j;]j-:}j0FazP:`>lnlψ[&eP`V:o{LFF2O.} aER +r2 R5c?UmZY,_Fp3,"' \ηm6 B%92@(º7F".hӀK~#>yeDרrR_=Dm򔗞cjFp~GT5L +b0_m7hL3/jHEO'xMLQaz< é#INĠnp$b<6uҗبVl$a"Sd{w'Qv 8kk=jX +(r""1CBZL$r|$ƉjdH]rʹaЖEJٷ0UQ ^.nZtbJWNhw1ϭW_)1~)֔ G:2`,7۶VD7~y9a`"d$oLfiIL R1}I;Ў:j1o bH@w~-A4|_Ch)-V2CMWXE<'a6nB@EB<f 0FPJa=@f}5@u[O_t%Y'ax[Lf +{%'!myiu77wuQi7M{*̥eΨ¼G;vf- s4\fVdp7\~5fMGeU HJLY!8 &Zr sTFU)hih@s: + 4|Իq'v;ng +K#eau9yHdN' ۛZQ + oi+& ,J٪6&2]ApuHu].`{\0+_ +Dm-`*qjJ*mVX0 0gA](BAJM"0-F~=䷊(! _hCR,0\"4>>z'BhbC+XQ=eZWwȊ{:ݨ7{S_C7گVZo,4F M-f4lͧjD4c%DhA ]!9ѺuFm{S}d 5 +İuk|M9Pv>wcSPwwG> "J~eͬ@b}F^r ^h@u:a#]q'ҩuz NO ۑ?8EǠ.]/ mF" +*k]C^zjI$:56!k5 p*E'$: *Zq \F JEp xH)G$N{UDR|6A"X Ĩ4Q( +򼕺Һ|5C EmAM&*&IVH7z֯⽴ X༤ԮK@2G_D.-dG| jN2D)bGPEXH.9V'74ú@).juT {%k/*v٫oyV7ے9=qO󋈡 ,3K'J_Й( ɖQ6smh nUC-A}hx#`( , =#@ f%6e|0RQڦ+/ꔁn VXtՑs:CW +H"*jPВ K[8UmAz5ݩ3.^ _}0/1^>I@-p$!MűL&ħqVlfx2hb +vihŔ6×\96 KNvW~Cilig*㴪ٜoSeEr6Cj>;'\ 7l&vZ\F;:MҒV.D0y =uUfAsXZ܂} 1|\t?(bmv5:-o)+8nXYDnlUg++nɠ53Lp0BqmN +g- 0Т hR350NLm h휄3}hCG*(g(S(%;a5<ˠ)yzQܮՀ7&UT_$p5IdˉvHE-b<&* PtZݮURV6T{B-A$%j w=ƇkYeO,JٔR[lef:KZBtPd..qWzBBݍGt3ES^x EbdUW6X*jwt%[EmlYqNB{di_*@Ӻ HiG_rCV{XO3,龉$K x hgw'.P6LkTmd]) 7f6(;=%")җV+AbI 9 1CK$%?[eA2V f +u|Ho,&E2nD%X @qDmPzi+;2:)⾻{.׌,а/X#VhP~ ˑʑml'O}gv9 S;H|MoG6>6^9<3Pw!홌s'w#: ;v9O 6Lb&vKLdCJrx]]Ϫ kAo⨤y$a9t 5m;;F!C"~&˼6Ql:I"-`RDs?++0EMAw' MV~ߦA40\O6s>T迉yq7ʗûp?{a-N!4;öKLLI86o)Ȱf^-Nc0Kw0=$x/9I0`Y+0G%%=rLrgng( dO }0͆DҝDmV;9̆Szo\/j oo rY x&̋/nٻДH:E+edilHq[#‰ +Ny$-j֓(8݀3ftI6Ւ nn ;@N60́qFfnsC驴^/E;qwXm~Q[Q\ʹAT^A_Lȫ,DѢm'cZV4FQ1\QPnNى(!Fïרnwڣ>x)@mD}-t6E$ŋoU;6 ^$FhQy@l$ aDٚ}O'<^b:2 0b cegiP֘p=nhUY4GQK:lgeuKvzخƲ+JK kt|%v f&5>5*낇z+ 3n0BK@n.-" SŷC4 t_-̚sfdYo6G3H ``umRKhP>z:oIf!7՗=c5(F  zI05DIHfFR_17ؘF1pcDTmml@- *(F`8S )d( ;IYz$Bw=Y"lP3,r7@,HpMeAm6GmPHjx,(2iuj=cgw;09lE"sIym#S3?̭hPkNk9$fvG2ܛE{MH!eF"LN56*12KWaB%' j+P+J`X˪bd:De"$jyܛQ$5sUݷRWepomV]XXQVh8 Խ g޹o$r%1^={X[ar\''oħ-ԣmmƆz`ޙ K0/d1R ll.dNbg[$R%.N(lu$<}]/2S$fHwD)Z +kH:ba6(J\n'u]|ϛlO>^7sz(ݒPd51rz%ýÒ!za4 +'rDg|FDL^QK& +>.޹_>QL}>) - "y"S%jiY.qZ)`(!Aۉ& +z5,i +}0w }1[bN_!tY\TGR>[W M*qRm) m~Dt0'3?ulLME2nESxJq J9&{X@K"~P\E`ވE TQ#DP r粑شk!{b0#ی_\[=f~,K8[V^n4[m@2: R,n'8"U\sFqTj.A#3 +Ra梋yc+mNP/aX{5,f |#-2IK,j~@Fʨiɚ*d>"U<0D?ؒԶXk*Z^Fљ$쐘'Vﱥk; G{ayC0u\gFS<.jAZ2%ʼi@ +YjCAQ,DzS#>_(tY9Ds^b$;w᠋_w%OVPh[z ciߠhDHu([RD͢T=1m dA: ")2$\lb=#t-R{PVE"Okwe ԱI& EӀH+rhs\1'$vN7߽W}v^O ymX:,g xo (`NZ ʟюb6`T`JC9Q ﮞ$O?Ͽwt-~w'Lūzq+|;8>Gi^z]?3goB Ig5V9)Y_K߯MNQ+%]XE5^f +C@E0aIJs[4L*mF-)@vZOQmG-=ya2FX3h.Hy1mFB-٫+ȑg<BPdAU>"$IP9~J"ʼnWw-BRHyVCKd5! +"n0OD04ܝⰑsZh]O.R%ELDjE)} +\# laJ1MB 2HFL1}7wA}KN'Qk8 =X]$OzM=_IozTܰ}`^|7EH746u%`%2 +PҠ[[575%&cc \s̥7D4>L6miohȀ,Oa-p1 @؂:ɝLٳ bB2At't€E#iW6T5aԜ޴k4 UB)6ҐaPĹnnq"-0X2: x%¸Ҏ5JCYĝc\fgi!U8F+OրA=l2a~BebuTïa@ҥEd!a`<7ɔ^EM݌0UF;Ezme#Z?I3=pN>x]!B^Uv5X2hJWM^Jz8([F|#pJȯpt/p,9: +a  KF6tY+mz(Cd`K^D+I|NmP'n쓎7> +xtx"6l)'1N} ~bt>a}oGtSZd$')`ho[>ͦ3hh3*uFIyFMzT`-$Z7cg۸fYEUkS I'܈/*\Kߕ W{vɷ_hFjm]S?SML^ZɨxyÖ}R>2?2PU>|l4( vE. n}vO,O-ZIypUO4 +b[cGy?aLA3 ̢`øq_ Pi(reoy1M,kVByfGzwY=35<1 1 +F̧m%/Ô=n/^zgW=o;޸7Ov~^⣝fЀҘQZ #Z a9l1B43U6UfcT_J+cfX9c}T2%e6 Uqv.|0d#f 2k CRK(;*(l66 GCEJ4(Qgm(e@ Q ZB=@asȍ@X&?AS*4z_D;(b.ӪƔ/b N>kV.{󬵛5bGnV2{ e5}nunǣc|zorGQX>*ݦdXA!lmznDxi6CP"c;Kk|sW5VOPdM1-ӈCd6=5k'0Jۄ:>-01vӌeqZl `{8ę5%a~68A@0{*bFOx;-묩r:3cz I%;~ﺟr<=?7z'ov>:?=CPvalmI4l KIE'ZMs5eZ.:@sC-}2`kEo&ɫ[9d}YZ!`W2 GN}ţ ЬydN/4cbL lոs'>&*(ldW(y +xm%/*<:?[籫]Gu棱3v}3- o$۲u@YxOS\o$R j\d G$DݐfHq3 b1"cI}e.,TckКLJmWkD-` + I/L/X =؅%f dV~Y䖇V(tdَ+B@[~iķ/|~W7Q;H_;=&##"@af]lxjk( F>ʥ'h{>sKFjfQe(P.Yӻ6wh [͚0oh2 :S:֢A-3ǞW흱b^jԺJdrbJb4ZtSVvј[VlѲAV0;~ɻk}Ώy,Z~p~$1RXc )bI f4*MFLC0$v "{Iƶ8ߵwmV`Df;X &\~dʖ^׀/0EPЪ=2oLcT6}(VT eϾeOT7)gs0w, >ck$Ƙ{eoi]ѾQ74y^s3u:%`;nX2F5{Xd/ਬ7ȫa@>bM LXDy9GƎf3\cZ;6vĴbuta>ŵ}BK5DiIٗvm=xmuvlpꀅs"vZgJ?hΝvY l3#v@%m%/Q]7q;E1mʏOí<"MWUQ^{X̽,ͩXj!{s=[d<5R +`KF0tǒ޵3>w +oѳ^Qg`> a qLܴiZ8p9=gE:i=T6ٸ̻oy:YJ1yL<س[ ^tk?vywݏGa<(x:3PAqy'H^ B?aҌ" v:`,\^c5 fF,\ǚ޵3|&-;ho( l@#VfHk'>F> L֎Ψ$v|jp;UyCJ e-?|d文L"ұ݋ۉ<>h/y=͝K!Ώɏ%1}ݯ~_}}S3~=h7 0ugɒkj38e0JNrÛBJ z6nɆ/5mH@;-PQ Q[OBl-kRMүa<t*3>Ad&WémX=ȤQ ޢ=辝uVa:P/V,$f&[?aWyw]Ga<*~{zs~zvN \"IR9$Z}/3)ߑ,M%" ĝ9N*ϸl/%3ٛ1n̬wfhAo^ѻsB3Y=n,m +* &i: K^v_c-uCScٌ|v~`Z|T-OvdF %A{JDRoas`0cfLfʲdl0 +HfyI)%)\qIHeXX2qMn1cV3li?Y;2-7eו|T_ڿT(j]~ *¥2d~ߘkT$O$d&CWf䌽{yc4$2uyDӳo7-S fլT_kiw ؒq+Ek#@ɻ~Ɲi?xc|>krw߼8ӭѤk%7DEK 'gƨC 9B 4?> ږӷCvt%fx`5чUL^V[ٱ}=7] DR_Vu\Z{\-w)?: >&<:{9>żՉ:(H5ڄa@LNPd91dDV:. F+?̕$9kziGH<V7'KWJI4G@h (vc~J2YtFmvja]_ݼm%xut>Gg$)zWo#vjurd v6o0&eNxE.M?>rV(ٙbd]+ͩuO^KVFuyvv&v9UY ΓQݘ$HhR:Prw/L!I_oAT RզoaB%RI%F7F|3~G0|ί~||&܇Yc"ädv*(RVNO9Z J>n 8IҍYTЃ%3$6.!@sM1izmCײַ2`O 9댛^KׯL݌ېsxhQAHt]w.Vw|wPb"?;`m!=.^snߝ:;oNW#pӯp) BZTn43XrfR֜a[Z ϙRl9bPeE!Ja}k$oXI Vn idD;PRm7\{K<3]ttZז +H+OF)A\S:W~/B+Ө̆!)ŦB벉l~(# ӕ$컔:]R{!'ࢊ٨V&4{Rj͕]kvsZ99vyT: "i7`. +rSe8e ۻ\ Dp2^({*2{}2A§gFGsmok_mr87*!EmeއlHN1ِY 4},Y7c6q>ə i}{*n:Grs)ܞZ> +Y6O)*V6jZϹ?"i= +hBNny.):[jw*<^ jN˄-u(C c(ekIkBD"Xz(NEBp7:zOZHw/(6W4xSZ_jQwZ!^\"rZ3iiywR8Fc]o%`Br 3c\Km=lJ}{Go^y~'??#^?G*ChMTR%JE^kH)ڐt+&CJ-R1|bpӡ7yO~'rov(4V +R-4ZDf,Qz,lk,~ߡ{2lb?Z FΩ8> J9EusN6Cd!|lq-C"&ȕvX[ET(:[ctW9"Gn6Ÿ-_NvSʄ!4&]\SH1!|DJT#WS[i ő^Y2CkQ\ʰ/kַ;D8l B,$Bd+B8;6Lqi-QҹiuuZbm>4^އ)γX K))f+>bҤM^vOMg$7pmZ"Rn2)[Q% ]VԧϷ8<:Xs~hOPޔ{:(]%x51˕2FWBZ|\g!G= },Zk%m%Qzuf-rwv>Aۥbqw@ !fO핱u v +}4gkNRF^At5yMg1XYM 7~ +^JrjX$4tSzHm}/?dR$ 32zR#kg1siD(>"fB3QB@ŚNm46)윷p9 gp*3 cq tfzc|^eH ad i-^MFiJZS]ySHYu%z f9-yiq]Q*VЀ/  uJf +$t#k^g*@;s!ubޤ2yN/VdlP68e2b0Q*+cl7 J7^ĴzYK/|op> +V+YF+NO/tԟ;?/>>O]W )߿_._ίW+ôC$GfbrgEH.Zcg`,q3ma5yi )򴒁eGu; ^SY,7DRcmG/x~xքYĘmS#+Թu+s& +IzĮ /2<}mLӧEJ^j)Y41Y +-ܾ% xEgdl܃&ISΦ,w28F ~⡯Cg~isOGFS%fG*B.\ˊG*7x"O[ ڜ^'K843#8xo ]a›FCBl^`EDfM31cAQh + .6R}|8colIP=":#R9w*z W Ĥ!О4C}!d(&jg0KWF}E?rܾ-ŏ3=b~˿go_sa?\ػR$I@3*~S ~Pc|1>Tp?P\8g*I(g_ɫOje2WD{K2xb/ 6HDO ^{~ʜMv62xr 2E`',t (u(z?xZ|y|^XN磒} [њS[0k"p,UA_>rw"MuǼG=y^ POLڙb7))D\CWT]B@$3/^HCUI#PMXfBa}_ȟNش^n3q|ߛO_K?{&kvɃ?իNԥ +$5P'a̎U6%l;LV L'j.$vKv QʨR.)*:|-dI<"Envl0^h_ DfeOe_߻ IiQ?^חj=mx1Iq_jn j +[jE>+'j'4KfTBdQsV,`tӰDǕ_aN+vw=c`:jɀqoJW1FH^^𠼆|sW;j^OeH9^AGONHz.M_[Nˤf|J/%VenB +,_`afh{t|Fp)Af"I+tI`s+sdIf5[Q>MZ^-p"N$b؏Nv«+T겝 O$g$h:"`)z>tzJ!y8ȿQ+d,C(wXŦ$i]; `/(樬j^՟p"樼9SݾN<Ɵ 4.c"0ڞn_i@~?7~|B\vYBGC6լ{͆~2۟ =>D~:R~{jO_̤/3'ճD9G=]`>׵j# .ijadz[ufDTaAܠJhZP*O!+$`]!DK2 ?[ALǜjL,)2+e P GM3Ṇ{c,}|XO5gj~yULmrEwN- ڬq~[&h QС7BBg"8wjK1XNQhv K`lrC*k^9JN>q,‚A1pxL/g\WۣMPa<En +o;W-s3펛"[Z1yIXP漓߮R~>0Y:N=BÄa rh3Ll6< +$/XfR Hb=FIlyFƦf:kDjC/cO:1clO0q UbbHAz vJb" +Y)t<;-zR\h_zNf\uUT:lkMЭ44[RqyLR8"ܥ&!5"O51 CQ0Xީ{vhlH^ U;~ /")}J|d8) AP}np|]G +(;=$v*(]a{ԺS Gam٤P,Cҟޢ /Yb +xA]&jh*jn伞nfA#b>`Ɠ#UD'4 2Z8 /9{^B'uB1FruT "MJdJr?=14+$OyCwYiN<´@kb#DD'0rZ n0[C-/ +nй[m1yɇH0D®u}u7l]Y ܫL=rw,.S8Wsэ=Ió=2vϋ号~ҾM}ȶ|㥿־r6w@^MB΂f ʖ=G:z +ױQS0k98u>H勫PJvTEqU\V23OXٌ 3&Y֩x0'ǰ~e>峜̋f$v%McGуv{@u סMnf /Fr\(n +Ўv;0꣠q +ry'=~HAh_G' 'nptDX3M8|RV$)nˊsώ+[ŀ +mP);P+5v} =wϋ[9l ꅶtѦ^b[|C셶vXƇ{ZP8pXwnBu=h^h&mWޓ28s+:@등4LO0ya|Tu-uٚO6s>|z2VM#=ORt6z# fhpTРQ_#΃1 }5O': 繜2uMj֤Mc%@?J>%/nF})tZQЄ46VјRhozlR ʇ`NLk.?^9C Q#o6F{$5<:?7e~mH@oB.r{(HjG 9iuڷΝ8B2#%d) @Y~hbЧ,$=xa*z*l7}>J~M)%o^~QxEIȻZ圎 }л_˟PE}.GTsSMCGat(r5n-ԩ ]\I]C +RY@#10f5oiծ&s@kѳB͊rawMXQg_=Z^>x5(#X>{:O6.ǯ~\/TS e,dlH^)hZ܊p +=_pR; ɁBߴCLUKz +}u>;Bi8/޳Lrѹ;s4.󡨋~Z{B{] ~KE-r K⬄ѧpf"Y4^]f1JG7Qa4Qj,1^7_?R|8BOLJ9k9o4Iؖ*q[b9:ОB,5/µj8L`zyTYP;9:0o 3KM%9GCh;g!k1@I+KDpg w>SF3 ݝHj9Y"} ,٭w7oi*Bx{CjĞ+t{c,:|5hKg+sZ)\sDe$k +d7}qr)B&&O/mB@qu{ Ym }b=E{no&ҤʧuȇiHklf"-C h +5ŝ˸48+DHU?]~;۩>}.Q&iDѓxqra89Փ rD + zq><>9k|J^ +izCgBýҩglf=!B7{CE6u̇:^hcfvo )7[$YPEp + M-9_Rc2ILrpA)速; (e̸iiWNy("ET0ׅI#<|s9z%&v2 + +؈鐛N[ T8rMp@C!:C2 ͽP?q%G)h% ~%l~EtR(21{f.Ϝ:Z1^$6#|ŕiC >ZYjݔ|u3~P"J/㬌* ֩#_3N 6-,gP|3@)A 4Ӫ9ޣ&nF9^hGf%:^}R/éy/  +cr?ҹv>uaD']tc{oAP@霡II-;w.Y4eS}װ*::u9:%_8-|qL"4ص9]La\Үs` 9B00b hFLKemP> _cu6qJ]h_2p'| QҝeF9^4oz !M <[IGgG7h9BƄ)dS::BH)6ډ][ǝz!g-L*c#{$O(BR+8\btf8} $*UhL&xQ\=/.Ox|¡Ap:Qu{lT(4 ]+#Td dRg11g7O]?JoO-DhK8)nUYyCE1=g&AHB/yWaQdzX ˦%SiJse1!Iݣ!Ae, oq/+8|IE]Z]d7F'\_0+Pu k٫j;Ӂ 313sl' `;[#rfvQ0L8ʭM֘ D TgSNpuDh.6RdxNB7X41Ch0Oν2T@ *+uE9ϠY_]<RW Up!M޴yNl>Wv͙3?oyW ojJ2tʴq[WZ҂hu=\'yoe7,ǐ CmV޵CIP0ܛ=),%˴V?D.~MSbRLg~ +~=r1f(7OV;2P@EhE-dܱԳZ7\>ڂgl pP/g]#b(1s_#5y@lz)F{1VE gs팆N7xIsMjo:@d+r#+I6RؐTNQ|I7-!RwNMMiDg;'xit|H*w@]@MOxjKw5G,g3+n{).h锑!*; ?0g=Ø,b𛍳Up +M2R*NBDlÝ|SZQhjuWE21aֻ#ryѤ#ub=&V@dH" }YO(]ycktЂS~;6Ϗ[cT|_Q < 9}o:3rX <ĢpaP"UץFܪ+F"9vj529WaR)T3S!W ER9%W$;PtL.`)ݞH;_ HFpOjǣuFT08'27cQO0J 8b}$d{zyYz;5}= Yr +*k {: h/DzcA8)<-2+棝G\í $wG]gq) {=ό3Bfj [C9Q9YȝeZi_3-hw3>J|hIڸ Ǒ"2^N[wBHe)4 +:L R7\*3&](ɅU!ԅ{>}AkёƢEB(~(rっ !#|4[ )(WִˢGQ]W?фnCI+wbxG6SJ䤃GIhB2h.Q=l&wv3>钣]2,MOK<Mry O ;oXKi5mkuQѕ5M*D"䇋)Ź>>܆8^i'xZ>>;B&n +`i)4ac+2016j. PL[?ڥZ+ iISM=@(u3.7%5R'f]~;|a%B&FE!w~SP.yNP$-2l{f˕LOA8H,ht3vgЎ{=ӗKxuKEvվcnc !ߑ5i :"~`)hϖc;ZO1^i.(S',T̀aPsU`m@m*"P\m4lG0h8u `46BYEDd6|Ka3/LaBs"͚G%)ΗA֊ȑ.I6.B[o>ki#E(<9/nBoeofKv=З lx6uHȶƾ^dk`lYt!I L04㘮H%110@vlTc&1 0S rmUTi7r%75gә¢9M0ஸSP]:BA,QdܖE;h: i6>6)LHJJMcߘ?G Ǎ1闎I$]9^T1_.5c46sn\Qyxm(_/!#W s07aTzLfix4^!`:faf؁h8hȳVo{IS|Luoi!]a::(蝶.;%_Xe]t0d{.iqm%׍Yn ;*H#@\-bZ#:j9J7zXJ;@%͉} +HG?CLuZ+at`OKq+ >q3 П.̤?U[4GSbTü墫esr2tϷ#"oluo5C,1n1'!mTߵtmh$T +B͑xv ݜ!B:}b/?X~+,/Y!>d]Y?ᯞxg V?W>EW˟J5zm^\2 [ +u;˧W))$2*7 rTKoTD2ttLh].SFKg/Rh7@vS9jx~5Vl0 7VPR.A3 }Y17ZjņsPp ?kѳln3-|x>M_֛` + Dk{9O89ΠGsopC$frgVu}bZK/)\1ؕ氮W-3V5 $3<:Ƀf+#+s˯pYkB漷3#PS.Vvd̰‹ к4luf~RA =PQ"˄8Z@l{~ ?Hl +^m3BeW]FdR0Oi яHCc7og/GH " Y-g|߾}3X!cˮg``UyO +Xj '(j1Ѡq`/ӃWK6\2)_>3΁ЛqWZ|(`$=)ҏCnDO&vVWջR.Wr<3n$ tj.0Bׁ$D̅%'Wy}aLae9wX'g&^e Y9e?}&l^0ӂzdGb,fiIaU9Rpފ}Ϡ M1 Z1,򽎸G sth}tAqMuqׇ2 | +,V#iaJ$Gږ ¤f p"5=HaB C.I.= n21N0$PYܪc2y9G9 h +1 + bZ}~w%Q) :;p Ni6Jf +SP+agߙlzDF.Gde =-6GL6Ȱ4};:XNG'XI25&?"[lOF\T*3?=ؔ@}_1W EgY)`"#6Mfrr$Fy\-$Y).]OBt>'vk44֍z[ +cl.ك6D՝rm%CZfKsr7&[@4xhx$'XP|shJDjy +[Iǂ6zTM͠WT!KzfCRA52xP6Pi~qDav>7Z-ri7=ǎZؕo .PO&)ab^n'~+:ǂ4\GrG~53;کڋROwgPzd2OD)u@# +ر tf*>.mqX6X Otœ86t}"VR[@B%|DЊ ?çS37x1eܪ!G"Dže:-U\+Ci#])IONʬ3tAh +4̈́w܊QAV=flp@k68Qfg|w)LVZۚ׉Y=97Y9^F8$Y(܌g$`8^AH3ozƭ=y;IqSHOdk PF^e t5uth7 +:bZ# gR|pڕ@ƕKQ' im:'=wV +n":T{;3@ʌ\)!3>;V G8/Dp Zx\B(N;sʄEN_zW mJ}(`@n%=`N#C&j "_P -y32u->>ӟivR@G\4ZRM#R:LßL<@kϏ`ȓgȡe<,0x KvA<"TpL Q@3Mfr28hX98ۢo,#}pU2l|`p8293|ӜY_<iͯϿ'zwO?:v>A|%G4)6~9@{ KYb' +4dOfן& *)[ yܰ; &JD +;yAU~ɿ5wu%Y39{M2sdekxQ&[at&V;N7V? +'iy1JrXU W*rk@ 〭+߳__CY_oEv7s2 @[nx0L6A N|L]{R(h2lW /e5F5BNf‘  'Lʃ(EzSؖ*%r;>vsR<Íbwv;N.s1A6#sf.ӅI!D\>S<7j8%鴥bU+CDn +ɡYJ^TR +] uc~zѦ9{9pYVKdHxDZˆs}_?cQtxZz&MrP۸QG$f+ Ee7*5%;Sk\Ame2OVk`T _':T.}v< +6dZbD`&I̬,a@_*_\== 8㙡ڋ9C쌨n (jKc"TdH>)lQ{Z\*L5[Oꚙ,RaLgp't`ٍ)r1\WnmM⃆E8LLi{y>:D$;pӭ,"Y3NyfedjNDwu?;L`y%`ނ3 X#Q/8ݮ/&(6S$e>$Ơ=_]"'/lN x3o_n(t$9\B+lB.\GVNcxFa3ܸ󀻵ݯS2Z|Q[vv6xfW|]!l#Q@6fFdj[8KX87sq>K+8rFx0MUYշ F !T%BpBfP~ O䟢}0e޾di<=c~g=d,a R$pK̂VtSօ<2 czG!"D?b;);6uzv%F*;ظmǽH#R(|7,/DAf wq_!pfCLl*;#yT9 +@F? 0K]dv2NY6 A%$'A0:ֶb熒",T|VrF~XM9a:xo';%N"0TvRW운x4{&3SÈJ#BC%ˎ_^RW;D?n7/UW+^f ERY; O!Bpр^2eT4nH.S 4v1e{9]F*lZ@ E N,G"9gg0Iآ11DMin۶JI´DAv␷43yS}f3Txɽ1UدL!'y"^`Dr^ \;ë4lJZ'/.G y)u8yTc?N Nt"3"VpL#Dcw0N3P)@5H5Kĉ;^ъBOO}=k3 ;/tC8F +!2t(DAPYݝ U P$[F n^ƁCg7fIX-,DȔO:o_$''xB>{46ݴgi/;&LzVjۺ2Zw95|eiბ +joIF9VuLdQъ@-gql˩ez- +bm(lA~n _}99;SC\F5#S2PG$0.|%QЏ6[)ّEe|˲FypI]RΩC]dĶlFG9, )6?vSL: Si +3N.α"k=$jg3ǟ6*'ʮfSj#a+#0IBD2u +-F5br>Ӈ'.5!Dʷ b:-Ɇ(`(=|חA-SA U'>xoY敯oN{p>G3a%{eTr95^!@%)ۦf'SCh +v]+1w3nx0;{?΅b̆ۏbnnH1JOYKI'9'l3J !XL#9-h"qI25ػ>VIƿVT6k| =Hg&WrV{Mn&܂Z-c\I$Ʒe2Oy"1To~ ~_=rк9A 2@Չ~SN@ +>T>ָ +%E"v[ۿ_izA4pAU)F.?Jt4<"]vR;JӼAdx3ɹxt=&]z +% Vv l#(:Xg'ܨ1 +P`\3e,/ }; +{\E:1Tљ4CYaֳAd=goj t(焆Yon/^jDHAB2 9@4IϮ,||1 1(o!'s L9?&mRX7M2w92lEckদ|FC#@u0 +Ub32 m% +]]sJ\LfLr>a$Np@TlLqb.ot.Sck|U.#DSN>܏f]L4ng1>)RU}d3p&|{W{x5z;x1[ :{@A[Nylc9DAi2}v(dSN&LHzL7d=,-嬍#!hk}%nWXN^M.O3Pe y8igh>#ٔ[J "65*DI)>ͺJA1A[[aauDO1yEY^6e.eUo8e6%B82ʹ[g_Biy6Y\.ktwwު׮iZ^?cH<' Ѓg35Isg 5KL@,Sy6v=`GxH꣰jC4{bSesusKHJo2ChNB:hNCQx,W#Է/306par@T6H3Lc8X|,&gG +E-fd޺C|p:h$a:ޮoئ\g]dzIBqC=SgputuNb,%˄Q yq,ҰF3m83jd +&ld k?)QI [eM/,aB,jz~$ +l.us3m0\0fL;$ϑmanX,Cq[b~y]d掠&QԠxG&S-ع Aw1T1n NX;Cܢeg +=Nlƃ'/ g(wOV*ZW+G;O ]j @0m#V8HAvYa9n`+i.Pӂy|*}r?gG͜ա@i ڝ7**C;a +`82P3VM&Yφ}1yn4`+w#Rg$Db:-=ֈK2zzyi鵳{%ZyMpɏ'c)ލm2- 05'?)UBeq?2 uΈ.vxenPa -sWxR'GwY"ligԦ%!])n6yt\b&_c7V# ^ N'wKAC#lC]t~u€+ *#R]`(08DD𾧴Y_Yv + !_ H^S:1<z,lq&[Z~z{ުkxڵڵ146[>AY\U9uzZ͉X'72 rL\u _ʗ +g ^)udh;"%(r}xDg9dK7V4.`׀mݍ3Dz:5@\NdG A&n uw(C}ܠn71Qǀ@^KBLSzv$MvBy ?~Z-ȬaG&?i +Tk,$/'Eg  Nw/_~8ad0S($ˣ&YS8lj-a3G 6%Jߌ=k  d +MOՃaI]"=9mO NMLN4p9CT ؗQA H*J$"[ڀVtA|,W T[K5DuHj7zr̢e+F:P;*"c4=y*ry-kQ9jW7r11p@[1oi) D_CgÜ.R3K{kÜ dGyFJ7hGd%dB80 ty?sWҩGj qUMG/̦8@ƤS#Q(Jz*oFFKVI(DTN  t|hp)ӵ@2Si]\DLGvhۭ5y D[ftuyșon+nO_^ThygT{pbT˸L.B ~hzL1. +ܳ!$5݃gOܨŸM +"`]I*c]4trhn@XT⼞183`!DG#u{`@]ٸe"N FRY +L" LÆVud,!1iBLN xf3rQGǐ u|/GݦuƨV5ry5.1.?1o &40aݘw^iޭ?ę_ygÃ@jbgԣҙ,שMX;[R0C#Na^k>pRN T$_|]]qd *v!zx*1YAHuY8@4z$=KF 4VY_W.&BȤAG;X cp; "0lTk?`pr\$j>0țtZ2IO\Ffl.s Tzzy ktohđ2۪EwFt4Od&Zd@d]m0X~1}54I4af \E!֧j1jL Ps%:m{_|6Z=d~7mUse^ӕI}bN+&l38`$ݚ;iܻ2ɳw:]-3ּ/b*Wνz5Xm qBd7j 鈠I&2w*,Kt_WiA!\N"CvrCDmvKLg'Wۂ$B&V'q>I6;=Jm̕vc BM,;~$IG)c_)AK̳Cyƭ{y%IZBs1}0P +U2A!%@Vl4b(G$zKg'BRzN/R@$ӝ_o`$r2X59 m.;uv*N7x:{+y}v^fWPY+ni T *Q &D>9U/".dhi_\6) zpJBɁ dXsAD~3~YM|1~N^Y@MDγ$APqp7޹6Q?/> أ8\0H}01Brͬ-$/tv]m-*d j`YZtLKZ1xm ]SlukոWnt"Rތ!r#u]` U{!j< AWJ -q+=aox^H,w !F("P)8f9`_jG#W#| Ul뗌r)@9a \"? 6_HR'^q$g6rCqEfpFdC8gDu^D +ƒ YQ2d jqCuyL!!"izD\PZCxe r ZE8El;:aѰ61f55L;w@GBG?.[+Bz8#TNfb/C>}!j +f݊;QVGҿ]F6]lP(iФ{ -qrR>m֧"Xӈޠ:)3K&PNqu␝8A" +F)(h+Z(мac6У7g +*}P$Tv6ϯ۵~SuL[^x?SuT6UGvj G,bn!C z nL$?*%i5֩˖PCx^VIA/;MCȬKh!2i &߷~J%al$ZUX:Q>PabZ( LCf:i UjGԳD7!vV8 +Lyd=tjq]9rܥ 뻥E֓? I2/ 﫚d" +Z"l;;Hι$JeFrCҽ=.m.J 9G6!rz o%{lkVs1YMKlddXǥ}ټxOn}YDGwt{7-ьvZǑ'G=0]jѾ_XC6? i(;(YؤkѺHfKVuHҜ4|l 5%4v?Gtl"֛<\$K#,vpuP(ΒCcL"4ݨ<*HoZX:)'p2wZԁ,<" /2kkw2KbR:wQC@U؍ߏ,VAe "Q١Ψ3\0"jSUFY +1">v\DB*r߱Gu#fWu: H#X²T@p\+2Pa6hq03FiSq I~C-V$걠6BV09e4oo1b&7goeTw1&q|Q&fVr-'"߹ȥ5ԄbhyA=4#ͤ,6OAr:xE9@m>t2;Q׾>+Ozͷ,dvM/^8G!0']Be#rD?pشx=0D"NgrF)J2gJ}v #`n}3-[=%4&hCe_ro:̹d6 ӷ#g 'AvFH_6mk JY0!Ș@* +Y .If7{࣫cP DକC*mwtb)Y1L͍B'l\CfhC72LJEfڛ D;p>[`7/X!Y2yc#>[84M5EKzY9cEPrGty͙$e[\VE%f/x8 |~A<;^ӣ;@{_?%x󇏿g}u*w['[۶ \w>Ћ'5au +d"@!]wPAAWYqA{-H eվa[ԇy~bNAxݨj LX\΄@6A݂#vMVKk紧({z]R=B|;(y +lL _4kǭ8f^~)Q~ѳY(??~qɿ=c9{=~6p˽>ˋg9 `}'ys-"~voe7+oIZ4 +$"2!/s\X0r8x|d}M»EGPA[=,)dw7S7&O#ȍ&@ M)WMã%+UyosT,!5g)%HQpn.٢ҒD#)e{O Ȧ +^Rr;8-kBދj/v{i^KP&i.%'K[1o X!Ȝ.O݈+ly(]AЖ`Uov~;9-s 'UEIMm2)21do/֚K1Ū*Fo@$P:"RaC(XG2$4댥ӰŻ4 +xzp8&RF֦]J<`:/ +ُlY" +`z&pz"KSC2{nWoBE0Qq|WE+UN:ϭXXhydǛB_%eZ}nJX6!~{N{FP:RvF<@/:heؚOfc6~?Q%j}舒"|]:XhiUbsqs_\&*I.5"q ~oNAz {K͂c;4]ZG +.,'Rj@.,p@/ +EuidmPgN{u=ՄH{]!~yq[HěةuV[JW׬Ji:8i/n3擏?dϐAn35vcGSҀLBhNcP" ,dԹ(j#ËRobAT NyDMaf9db)R8(y֬PHKK,vYY䴬B~|A(?+AX("V@-$y0&ÐdLx"yͪ <4y4>\!"q200nT*HYMVOn8ZiB.VhǍ{W::ѡ3o0Rs@ `~F'1}d /RM $!&aBBbu{04 +Lt-TҌIkJ]b:A": /YlE~Z"ڮbhak$\ ((mg*::h*d+ؤw: gSiBrS]9a  }D3 +|BS_4ǭ0]({fǧq07ay>;[[(O=8$>w39|VtJ6̆L)URʹ<,ǖo2zE{J?T/ fO^.=`kgh`c-T*CZY=nu(p9?3p!r//".\nrA9A",!גZLOK y(gkبL+?UBC&nKpbP\a 3u @ A;&tSMC,?SQ(y+&=Ha)h O} NǁYRv!ts+X81[ ErS]5VC@x.-opӬ:˃8㖛-\\_@Vp :T3_/"#e8LfL.jlLGf,^@; +$-S'wr˺ ֭x#ޠU;gtgP IDY| oB +}y&d`6}C?aKp HBFB-#Q,GKrTG4>rŕM*$eŚLvKdӡ2k$΀˹LRn!JI:ᱴI@zA9B&pyL1"[Qhi"er `\ܡ b^LprÔͦuhOg7Qh"=$Vi*PCVUNs[3B%Ϟx]٘|qOu@LӈŌ԰iA}uV•(wקq+7W¹(3r}Md/)& M+uUvl|MG= O: Q 9\PS1!CQ[þT C0Yed{rt;t% 2dT3e蠥D.bmB FWj  Ikf(J."W[U[z@.p!HdȖLsˑOu)ڸZS }l#zG󊊖7iV{[\P8#B.R\.'gsP p5Lk3=-Lo ʵ 7Q :k%a0!ytߊvNc)Ԃ ܨ>>;JG_C7sȻǎ :'A6̓vVaE+ϭfQhQdkov5UrS]=d!gx@(?N{P640`̹0mKчgr _`N0c+h1(tQFIZ|̜MFly +CWFu@ՁMTKmk1( HsЎ9]?tqP\m}ȑMC(kl)A]M |a<+t;uqh=jXRU~$42εEӃJ8P+4!k[3viy^\Z'Y=t poCe \nseoˏw_~/>Ry@i +dX̠(x())UBR: U.V3;d>=%d:.خ9]?vAݕ}Ц<.yP_2q p-G>d%zF3i˚+waϭ]BpZԒG[]~Kע*"HQPȲNMuVbzwקq.7]ҹzקۃ/?;^tNA@IשFDza Ϟaea2m볎n%N0D]rgܥwCyu :iSO`ה V͸v>S +K4D)&i IY>Z\r)%͕q^PJB>7 +9,7!&[?G }3]յ9(F,]4V_kǍ-m(Ya s[ٗΰ\А&PHq%sXeW{ A:+I4ȑO P7p/H#2Nh_I[tڊ 1MkN\zBZ)"jJ/xK" %#GNG/$y/ +4uu[Jм>tqH%v) ~TѱOuykiĘ\STNC_4ǭ/oCO ^n v}Y~͗O.x0(MNԨ/i,A02lEGWdcRt !gc*A‰~>IKoҎ9];^!Q-:z4Q18N @3{3>ׅ0M rtػaTL{*dgbk&: +T;TzV-9TXhNh(Ŗ"#N{Ӭ;_P8×/\~nuZ5!" +e2٘X.ַ *և? F UFa ^g@#mZ<GMIJkN׏X 8Fi 7 +c5+ ^h kGhM<$F(wbIm4t@5]TV'_)/:.\qoC&#NHsZ'Y=t(fyjtw}grC\Z"1$Si/T%hb4@KmLA +D((8a잟+C~%lLH`b;t7xJ-h.gh *cCP;t|h%R*3T>k{)Pt ћhzljPs_q-UXP5z7I{;Yކ d)\<3nuERfJǘbI\mAr+|8Q }.3pK^hM]4#V\V'`R>,.%E4k<\+Ρ9TH6 28mSZ&%|mGprN12#Вj]F!4h3xH]PX&3bݡ{C<rW(ѹz!'ݵP-;. Ge~"(Y3q1P/CN`tAmAGEðл%A |ea +J mޤ +^+!āղdX-;t`: \^Թ>w{wj]_tH:m_z< 7|;_{>ͽ;I-u(CH^tX%%{׏FFG"W4TN BuW.@ j-l2zFY-q:( fInoy\T}k? vAt;U*M~(i֊]o;\ٱdQv޳ tA umAyMPBU qǐhB)FhnFE*]j>6Ms cp hN_t),!Uxh}F8SOo"@+de#Ba(+huU3ҞHtR+i[v2jmu'Qړ,"B!iʼڭߪA*OǠyCv' ȋ ̎/6ޅ\&i1r$Ce㸓9{j~MX̸@v^ԣ ኬԆ˼kƂ, +n./~ Sc{'JUN0_LwWQ8k7.h+gz6, LGM U(Z"l燜Iw7Fr"!jR5ON} +#7tkT1I-j Ǚpy f r;K#r\J'X=z}G_`w紑uh?bNrxW::Cv 4zIGe!!4H+u Ur#ת1V?eJuU ٣pH ",-u@ZرEX6fcCiDA,71OA͂(i鿡1[shď8h'hU +:pml, 86Von99mƳ栳!i@i$Z@r` ]p^Z܉Zji:PG)̹Vr')X4+[oIP~$Kz'Z+T/#{xv4E쩮uV7Zwrv-nkΓsZzBx -aJ?%A+O +! +i(L`\da{'ݧ 8aPsb}raBy +k)KL#m&ˋ ZA *KZ(R̘c(Vs,ǽ2򉂸zc>1;ۘ!*!>, wn8tzhYP: Qbƽ5:Zޯpz[)y!951t2CjB;c|rO{vu9iu|= om P*ax~@1\O*|8.4S.{d4+:M%燎@0XT$b5-K>lBJ0/NEj1/r*,^穎4Z(" Zυݪ-[H‘P[Rui:`{(ti&@k"G.Uq*M_Ag<'NSMf"ke˽-^7)db\^ٰɖď 4FQ"?~ lq g>-3 .U҅P^0"ss8^#Fz)k,p +; O0v.DCo^Z[/ru 9f. %fv!V*ԉdiU!6U6XO1D_ f!ُHx`h4GV) Ҹnfj|AZ_;!XlW2$ZG&NWgaCky(!)i@@qq] qmϩtI1HYv ѱ"6 \ Ѧ9T52r}]ch; ΐmB69:3DH$^ x%'Q+:r]BYcЃNeK&,UMvBiĺ,po]oUՠADg ML6ڲF*$a㐵1ITòqQ sH,XB +px=˛&7dDGMFM99h>RAYFD^Uqdh5,*C8g/,Hf!>O + FMNB~(4|?^뿮o;Jg6󋋯>~'}>;n?=O{xsٌH=# 62D<~Wj>_vzeXMcX;I{<$޲62n8 )-EXV˵ kcЯ"hvEkQ`)k`6dAC2Ur(o$b51[Ы1Dk&[.X[i. SS9HN隯MǢ ֧hbMڮC3]Sb[(&CE][\uLZVǒ.ǠqE2w:V:J7wI+#i~BwA&//Ud唖GCg؇$m}JdZK/5>m igu1؃U14vm#{[H 滆mG9[SB1d+u2DtGU(|fcF˩Q҆IAF@cC(w;ɻE/RmGp&;M&2U ZfJߵd[d;ķm9C7oHrjWIS*dA?ṬȏLŌ(C6I +gge+s:'xU{\KCyաރj7iiV{[DECyMZ\9g{s{|̓O$pچ|/^L9\딏eM2&fon_y()}u弅{$"WƇIϢmT ux<|9p7ҽi=5_#x9ᮍ`UW|TBZ(C"g3L7Xb#HMKʽL7+3c)oᴴVBOoLi61vylK>[uaVӬewѻ!y y`6xiC%[OsG?_ʛFݻ 1;c?ovWk"sq9hw\ʉATbhic pr^]CCҌ*Ɛ h ldR[OҨ;nM!/DȺm>[yBz 1lOЉǢUZ6;!Yc$ԲvF)OBLQLD>mgCM+ep 8͘'{kmBie\k=g?+N;v2PDRɏA4 *|e A%"-cC@NkTźF]GvdYٲ-ٲ""dtG硟:,u52)\C%A_M܄<2罖j%F!`r:PбW-s3BѬWd@'%4:J/Vu:~)v^ |z7٩~Ulxrx (WKvJzDtx^fQ9-ʼe +-aCnLeLGnqBGKGN!D\&ĺf<.OѨ6AN)6Mf +R!;̝ABMԺ%y!T)n<ٖx-gr-ɶ"QS\50l J`058!L<= Q2`n-$g,B + Ӡc׮B`j+GKy5N) @m__(׬S ֳ\bIh5=Z5y尵bN #[Q{ZMLȵ1H)PιuDtJ*6+n SLLr'qlU%䰛n +#aвh endstream endobj 969 0 obj <>stream + U-K8CHEG7}af1dF2V5<@4[ղBe9r MőCFbǔEr'{YLWcMٴMbZ^ | Lͱ|RρSOSPH%=4/!Hq--{<͟dq#V\sWgVZotĮ vLOe^L5l 9 :hk3]%X"{&4<xt.5km<Gd6L7>^ւ٫ Wަ-2r]:ch ːB~%Cok>.P#Sjsغ4-rBP?'j)Kmv-=)y˾'~avO.ʯ^o=k^cp] +>mvZH~]7~7gpG#U7xTef;bswxaّ}>{>{'m=da<{YED&kW?-h<~E![4)LAF:p^~ z{ZWN>|Lس<|&)zR*J؇i룟!7na"Onpl B|4V3Lusx!ҌK՜Je%ƫ1nLDL3-ȷ&ؚa241:UX vyAKoPuhջ9x&]?z蜭4v 9QgN]旳'㠲 09hDC8]6_ٷJl/2bj*$%tJTyZNy\fP[iĘ#f]WktR;>XǷi0ԝ:F)dٴs}횂Jyp]Xd M Dpeڍ!t +$c&h;H&ia Ϯ}5=9Ԯ=na> e*ʷxÕԢ j!Dqjb~9PAlVh7E?EkP>L'W j O6+BaB\nx4!GݸL_<,"^`pnta/G4 e. ׵SrDkjMڎppnTHx~D5u&7XiR +0`3`vf#aiSSQik Ec!bE")ɨpykP4>"dn N:}1W +N֢QsL?4%=+G-T_R5&s ԂQs~U`Uh~@ab,'W>11 c(@1:cT~Tx<Ez2cynAghɴV@*dLD%A%:h7 Q$O!3Y,!bfټo/dΐllKGL̪R kĵtbE ʶaE&ivyB +b:Q-cb| Bs `q;x%=b \XnFB + &:1|@7-uYدAB8y93@Z3/<}uE_!yq п39!߆vpH>lzmThkZ yu T& PC #8 ?$ȡds" j)m+t14Tv Aޅ_ L I *|9o1npSYEFVqprF/UP3(b`n5AЍ:OL3?jDSo6 0KoTBAВQ.,|j..HנhPupܩNԧ"Bpy< OI߸n2ML^|$x%UE ^WG +Y2rQڬz2ڵo0q˒߼\}@ ;os +gdMPH|.?; 㧏?yϋw>W~'zbS7o_D>Ow?62 endstream endobj 919 0 obj [/ICCBased 936 0 R] endobj 7 0 obj <> endobj 8 0 obj <> endobj 9 0 obj <> endobj 10 0 obj <> endobj 11 0 obj <> endobj 12 0 obj <> endobj 99 0 obj <> endobj 100 0 obj <> endobj 101 0 obj <> endobj 102 0 obj <> endobj 103 0 obj <> endobj 104 0 obj <> endobj 192 0 obj <> endobj 193 0 obj <> endobj 194 0 obj <> endobj 195 0 obj <> endobj 190 0 obj <> endobj 191 0 obj <> endobj 277 0 obj <> endobj 278 0 obj <> endobj 279 0 obj <> endobj 280 0 obj <> endobj 281 0 obj <> endobj 282 0 obj <> endobj 365 0 obj <> endobj 364 0 obj <> endobj 366 0 obj <> endobj 367 0 obj <> endobj 368 0 obj <> endobj 369 0 obj <> endobj 451 0 obj <> endobj 452 0 obj <> endobj 453 0 obj <> endobj 454 0 obj <> endobj 455 0 obj <> endobj 456 0 obj <> endobj 538 0 obj <> endobj 539 0 obj <> endobj 540 0 obj <> endobj 541 0 obj <> endobj 542 0 obj <> endobj 543 0 obj <> endobj 625 0 obj <> endobj 626 0 obj <> endobj 627 0 obj <> endobj 628 0 obj <> endobj 629 0 obj <> endobj 630 0 obj <> endobj 712 0 obj <> endobj 713 0 obj <> endobj 714 0 obj <> endobj 715 0 obj <> endobj 716 0 obj <> endobj 717 0 obj <> endobj 799 0 obj <> endobj 800 0 obj <> endobj 801 0 obj <> endobj 802 0 obj <> endobj 803 0 obj <> endobj 804 0 obj <> endobj 869 0 obj [/View/Design] endobj 870 0 obj <>>> endobj 867 0 obj [/View/Design] endobj 868 0 obj <>>> endobj 865 0 obj [/View/Design] endobj 866 0 obj <>>> endobj 863 0 obj [/View/Design] endobj 864 0 obj <>>> endobj 861 0 obj [/View/Design] endobj 862 0 obj <>>> endobj 859 0 obj [/View/Design] endobj 860 0 obj <>>> endobj 782 0 obj [/View/Design] endobj 783 0 obj <>>> endobj 780 0 obj [/View/Design] endobj 781 0 obj <>>> endobj 778 0 obj [/View/Design] endobj 779 0 obj <>>> endobj 776 0 obj [/View/Design] endobj 777 0 obj <>>> endobj 774 0 obj [/View/Design] endobj 775 0 obj <>>> endobj 772 0 obj [/View/Design] endobj 773 0 obj <>>> endobj 695 0 obj [/View/Design] endobj 696 0 obj <>>> endobj 693 0 obj [/View/Design] endobj 694 0 obj <>>> endobj 691 0 obj [/View/Design] endobj 692 0 obj <>>> endobj 689 0 obj [/View/Design] endobj 690 0 obj <>>> endobj 687 0 obj [/View/Design] endobj 688 0 obj <>>> endobj 685 0 obj [/View/Design] endobj 686 0 obj <>>> endobj 608 0 obj [/View/Design] endobj 609 0 obj <>>> endobj 606 0 obj [/View/Design] endobj 607 0 obj <>>> endobj 604 0 obj [/View/Design] endobj 605 0 obj <>>> endobj 602 0 obj [/View/Design] endobj 603 0 obj <>>> endobj 600 0 obj [/View/Design] endobj 601 0 obj <>>> endobj 598 0 obj [/View/Design] endobj 599 0 obj <>>> endobj 521 0 obj [/View/Design] endobj 522 0 obj <>>> endobj 519 0 obj [/View/Design] endobj 520 0 obj <>>> endobj 517 0 obj [/View/Design] endobj 518 0 obj <>>> endobj 515 0 obj [/View/Design] endobj 516 0 obj <>>> endobj 513 0 obj [/View/Design] endobj 514 0 obj <>>> endobj 511 0 obj [/View/Design] endobj 512 0 obj <>>> endobj 434 0 obj [/View/Design] endobj 435 0 obj <>>> endobj 432 0 obj [/View/Design] endobj 433 0 obj <>>> endobj 430 0 obj [/View/Design] endobj 431 0 obj <>>> endobj 428 0 obj [/View/Design] endobj 429 0 obj <>>> endobj 426 0 obj [/View/Design] endobj 427 0 obj <>>> endobj 424 0 obj [/View/Design] endobj 425 0 obj <>>> endobj 347 0 obj [/View/Design] endobj 348 0 obj <>>> endobj 345 0 obj [/View/Design] endobj 346 0 obj <>>> endobj 343 0 obj [/View/Design] endobj 344 0 obj <>>> endobj 341 0 obj [/View/Design] endobj 342 0 obj <>>> endobj 339 0 obj [/View/Design] endobj 340 0 obj <>>> endobj 337 0 obj [/View/Design] endobj 338 0 obj <>>> endobj 260 0 obj [/View/Design] endobj 261 0 obj <>>> endobj 258 0 obj [/View/Design] endobj 259 0 obj <>>> endobj 256 0 obj [/View/Design] endobj 257 0 obj <>>> endobj 254 0 obj [/View/Design] endobj 255 0 obj <>>> endobj 252 0 obj [/View/Design] endobj 253 0 obj <>>> endobj 250 0 obj [/View/Design] endobj 251 0 obj <>>> endobj 173 0 obj [/View/Design] endobj 174 0 obj <>>> endobj 171 0 obj [/View/Design] endobj 172 0 obj <>>> endobj 169 0 obj [/View/Design] endobj 170 0 obj <>>> endobj 167 0 obj [/View/Design] endobj 168 0 obj <>>> endobj 165 0 obj [/View/Design] endobj 166 0 obj <>>> endobj 163 0 obj [/View/Design] endobj 164 0 obj <>>> endobj 82 0 obj [/View/Design] endobj 83 0 obj <>>> endobj 80 0 obj [/View/Design] endobj 81 0 obj <>>> endobj 78 0 obj [/View/Design] endobj 79 0 obj <>>> endobj 76 0 obj [/View/Design] endobj 77 0 obj <>>> endobj 74 0 obj [/View/Design] endobj 75 0 obj <>>> endobj 72 0 obj [/View/Design] endobj 73 0 obj <>>> endobj 892 0 obj [891 0 R 890 0 R 889 0 R 888 0 R 887 0 R 886 0 R] endobj 970 0 obj <> endobj xref 0 971 0000000004 65535 f +0000000016 00000 n +0000001175 00000 n +0000081887 00000 n +0000000005 00000 f +0000000006 00000 f +0000000013 00000 f +0000580819 00000 n +0000580899 00000 n +0000580975 00000 n +0000581050 00000 n +0000581124 00000 n +0000581200 00000 n +0000000015 00000 f +0000081939 00000 n +0000000016 00000 f +0000000017 00000 f +0000000018 00000 f +0000000019 00000 f +0000000020 00000 f +0000000021 00000 f +0000000022 00000 f +0000000023 00000 f +0000000024 00000 f +0000000025 00000 f +0000000026 00000 f +0000000027 00000 f +0000000028 00000 f +0000000029 00000 f +0000000030 00000 f +0000000031 00000 f +0000000032 00000 f +0000000033 00000 f +0000000034 00000 f +0000000035 00000 f +0000000036 00000 f +0000000037 00000 f +0000000038 00000 f +0000000039 00000 f +0000000040 00000 f +0000000041 00000 f +0000000042 00000 f +0000000043 00000 f +0000000044 00000 f +0000000045 00000 f +0000000046 00000 f +0000000047 00000 f +0000000048 00000 f +0000000049 00000 f +0000000050 00000 f +0000000051 00000 f +0000000052 00000 f +0000000053 00000 f +0000000054 00000 f +0000000055 00000 f +0000000056 00000 f +0000000057 00000 f +0000000058 00000 f +0000000059 00000 f +0000000060 00000 f +0000000061 00000 f +0000000062 00000 f +0000000063 00000 f +0000000064 00000 f +0000000065 00000 f +0000000066 00000 f +0000000067 00000 f +0000000068 00000 f +0000000069 00000 f +0000000070 00000 f +0000000071 00000 f +0000000084 00000 f +0000592539 00000 n +0000592570 00000 n +0000592423 00000 n +0000592454 00000 n +0000592307 00000 n +0000592338 00000 n +0000592191 00000 n +0000592222 00000 n +0000592075 00000 n +0000592106 00000 n +0000591959 00000 n +0000591990 00000 n +0000000085 00000 f +0000000086 00000 f +0000000087 00000 f +0000000088 00000 f +0000000089 00000 f +0000000090 00000 f +0000000091 00000 f +0000000092 00000 f +0000000093 00000 f +0000000094 00000 f +0000000095 00000 f +0000000096 00000 f +0000000097 00000 f +0000000098 00000 f +0000000105 00000 f +0000581277 00000 n +0000581360 00000 n +0000581440 00000 n +0000581519 00000 n +0000581596 00000 n +0000581675 00000 n +0000000106 00000 f +0000000107 00000 f +0000000108 00000 f +0000000109 00000 f +0000000110 00000 f +0000000111 00000 f +0000000112 00000 f +0000000113 00000 f +0000000114 00000 f +0000000115 00000 f +0000000116 00000 f +0000000117 00000 f +0000000118 00000 f +0000000119 00000 f +0000000120 00000 f +0000000121 00000 f +0000000122 00000 f +0000000123 00000 f +0000000124 00000 f +0000000125 00000 f +0000000126 00000 f +0000000127 00000 f +0000000128 00000 f +0000000129 00000 f +0000000130 00000 f +0000000131 00000 f +0000000132 00000 f +0000000133 00000 f +0000000134 00000 f +0000000135 00000 f +0000000136 00000 f +0000000137 00000 f +0000000138 00000 f +0000000139 00000 f +0000000140 00000 f +0000000141 00000 f +0000000142 00000 f +0000000143 00000 f +0000000144 00000 f +0000000145 00000 f +0000000146 00000 f +0000000147 00000 f +0000000148 00000 f +0000000149 00000 f +0000000150 00000 f +0000000151 00000 f +0000000152 00000 f +0000000153 00000 f +0000000154 00000 f +0000000155 00000 f +0000000156 00000 f +0000000157 00000 f +0000000158 00000 f +0000000159 00000 f +0000000160 00000 f +0000000161 00000 f +0000000162 00000 f +0000000175 00000 f +0000591841 00000 n +0000591873 00000 n +0000591723 00000 n +0000591755 00000 n +0000591605 00000 n +0000591637 00000 n +0000591487 00000 n +0000591519 00000 n +0000591369 00000 n +0000591401 00000 n +0000591251 00000 n +0000591283 00000 n +0000000176 00000 f +0000000177 00000 f +0000000178 00000 f +0000000179 00000 f +0000000180 00000 f +0000000181 00000 f +0000000182 00000 f +0000000183 00000 f +0000000184 00000 f +0000000185 00000 f +0000000186 00000 f +0000000187 00000 f +0000000188 00000 f +0000000189 00000 f +0000000196 00000 f +0000582075 00000 n +0000582154 00000 n +0000581755 00000 n +0000581839 00000 n +0000581919 00000 n +0000581998 00000 n +0000000197 00000 f +0000000198 00000 f +0000000199 00000 f +0000000200 00000 f +0000000201 00000 f +0000000202 00000 f +0000000203 00000 f +0000000204 00000 f +0000000205 00000 f +0000000206 00000 f +0000000207 00000 f +0000000208 00000 f +0000000209 00000 f +0000000210 00000 f +0000000211 00000 f +0000000212 00000 f +0000000213 00000 f +0000000214 00000 f +0000000215 00000 f +0000000216 00000 f +0000000217 00000 f +0000000218 00000 f +0000000219 00000 f +0000000220 00000 f +0000000221 00000 f +0000000222 00000 f +0000000223 00000 f +0000000224 00000 f +0000000225 00000 f +0000000226 00000 f +0000000227 00000 f +0000000228 00000 f +0000000229 00000 f +0000000230 00000 f +0000000231 00000 f +0000000232 00000 f +0000000233 00000 f +0000000234 00000 f +0000000235 00000 f +0000000236 00000 f +0000000237 00000 f +0000000238 00000 f +0000000239 00000 f +0000000240 00000 f +0000000241 00000 f +0000000242 00000 f +0000000243 00000 f +0000000244 00000 f +0000000245 00000 f +0000000246 00000 f +0000000247 00000 f +0000000248 00000 f +0000000249 00000 f +0000000262 00000 f +0000591133 00000 n +0000591165 00000 n +0000591015 00000 n +0000591047 00000 n +0000590897 00000 n +0000590929 00000 n +0000590779 00000 n +0000590811 00000 n +0000590661 00000 n +0000590693 00000 n +0000590543 00000 n +0000590575 00000 n +0000000263 00000 f +0000000264 00000 f +0000000265 00000 f +0000000266 00000 f +0000000267 00000 f +0000000268 00000 f +0000000269 00000 f +0000000270 00000 f +0000000271 00000 f +0000000272 00000 f +0000000273 00000 f +0000000274 00000 f +0000000275 00000 f +0000000276 00000 f +0000000283 00000 f +0000582234 00000 n +0000582318 00000 n +0000582398 00000 n +0000582477 00000 n +0000582554 00000 n +0000582633 00000 n +0000000284 00000 f +0000000285 00000 f +0000000286 00000 f +0000000287 00000 f +0000000288 00000 f +0000000289 00000 f +0000000290 00000 f +0000000291 00000 f +0000000292 00000 f +0000000293 00000 f +0000000294 00000 f +0000000295 00000 f +0000000296 00000 f +0000000297 00000 f +0000000298 00000 f +0000000299 00000 f +0000000300 00000 f +0000000301 00000 f +0000000302 00000 f +0000000303 00000 f +0000000304 00000 f +0000000305 00000 f +0000000306 00000 f +0000000307 00000 f +0000000308 00000 f +0000000309 00000 f +0000000310 00000 f +0000000311 00000 f +0000000312 00000 f +0000000313 00000 f +0000000314 00000 f +0000000315 00000 f +0000000316 00000 f +0000000317 00000 f +0000000318 00000 f +0000000319 00000 f +0000000320 00000 f +0000000321 00000 f +0000000322 00000 f +0000000323 00000 f +0000000324 00000 f +0000000325 00000 f +0000000326 00000 f +0000000327 00000 f +0000000328 00000 f +0000000329 00000 f +0000000330 00000 f +0000000331 00000 f +0000000332 00000 f +0000000333 00000 f +0000000334 00000 f +0000000335 00000 f +0000000336 00000 f +0000000349 00000 f +0000590425 00000 n +0000590457 00000 n +0000590307 00000 n +0000590339 00000 n +0000590189 00000 n +0000590221 00000 n +0000590071 00000 n +0000590103 00000 n +0000589953 00000 n +0000589985 00000 n +0000589835 00000 n +0000589867 00000 n +0000000350 00000 f +0000000351 00000 f +0000000352 00000 f +0000000353 00000 f +0000000354 00000 f +0000000355 00000 f +0000000356 00000 f +0000000357 00000 f +0000000358 00000 f +0000000359 00000 f +0000000360 00000 f +0000000361 00000 f +0000000362 00000 f +0000000363 00000 f +0000000370 00000 f +0000582797 00000 n +0000582713 00000 n +0000582877 00000 n +0000582956 00000 n +0000583033 00000 n +0000583112 00000 n +0000000371 00000 f +0000000372 00000 f +0000000373 00000 f +0000000374 00000 f +0000000375 00000 f +0000000376 00000 f +0000000377 00000 f +0000000378 00000 f +0000000379 00000 f +0000000380 00000 f +0000000381 00000 f +0000000382 00000 f +0000000383 00000 f +0000000384 00000 f +0000000385 00000 f +0000000386 00000 f +0000000387 00000 f +0000000388 00000 f +0000000389 00000 f +0000000390 00000 f +0000000391 00000 f +0000000392 00000 f +0000000393 00000 f +0000000394 00000 f +0000000395 00000 f +0000000396 00000 f +0000000397 00000 f +0000000398 00000 f +0000000399 00000 f +0000000400 00000 f +0000000401 00000 f +0000000402 00000 f +0000000403 00000 f +0000000404 00000 f +0000000405 00000 f +0000000406 00000 f +0000000407 00000 f +0000000408 00000 f +0000000409 00000 f +0000000410 00000 f +0000000411 00000 f +0000000412 00000 f +0000000413 00000 f +0000000414 00000 f +0000000415 00000 f +0000000416 00000 f +0000000417 00000 f +0000000418 00000 f +0000000419 00000 f +0000000420 00000 f +0000000421 00000 f +0000000422 00000 f +0000000423 00000 f +0000000436 00000 f +0000589717 00000 n +0000589749 00000 n +0000589599 00000 n +0000589631 00000 n +0000589481 00000 n +0000589513 00000 n +0000589363 00000 n +0000589395 00000 n +0000589245 00000 n +0000589277 00000 n +0000589127 00000 n +0000589159 00000 n +0000000437 00000 f +0000000438 00000 f +0000000439 00000 f +0000000440 00000 f +0000000441 00000 f +0000000442 00000 f +0000000443 00000 f +0000000444 00000 f +0000000445 00000 f +0000000446 00000 f +0000000447 00000 f +0000000448 00000 f +0000000449 00000 f +0000000450 00000 f +0000000457 00000 f +0000583192 00000 n +0000583276 00000 n +0000583356 00000 n +0000583435 00000 n +0000583512 00000 n +0000583591 00000 n +0000000458 00000 f +0000000459 00000 f +0000000460 00000 f +0000000461 00000 f +0000000462 00000 f +0000000463 00000 f +0000000464 00000 f +0000000465 00000 f +0000000466 00000 f +0000000467 00000 f +0000000468 00000 f +0000000469 00000 f +0000000470 00000 f +0000000471 00000 f +0000000472 00000 f +0000000473 00000 f +0000000474 00000 f +0000000475 00000 f +0000000476 00000 f +0000000477 00000 f +0000000478 00000 f +0000000479 00000 f +0000000480 00000 f +0000000481 00000 f +0000000482 00000 f +0000000483 00000 f +0000000484 00000 f +0000000485 00000 f +0000000486 00000 f +0000000487 00000 f +0000000488 00000 f +0000000489 00000 f +0000000490 00000 f +0000000491 00000 f +0000000492 00000 f +0000000493 00000 f +0000000494 00000 f +0000000495 00000 f +0000000496 00000 f +0000000497 00000 f +0000000498 00000 f +0000000499 00000 f +0000000500 00000 f +0000000501 00000 f +0000000502 00000 f +0000000503 00000 f +0000000504 00000 f +0000000505 00000 f +0000000506 00000 f +0000000507 00000 f +0000000508 00000 f +0000000509 00000 f +0000000510 00000 f +0000000523 00000 f +0000589009 00000 n +0000589041 00000 n +0000588891 00000 n +0000588923 00000 n +0000588773 00000 n +0000588805 00000 n +0000588655 00000 n +0000588687 00000 n +0000588537 00000 n +0000588569 00000 n +0000588419 00000 n +0000588451 00000 n +0000000524 00000 f +0000000525 00000 f +0000000526 00000 f +0000000527 00000 f +0000000528 00000 f +0000000529 00000 f +0000000530 00000 f +0000000531 00000 f +0000000532 00000 f +0000000533 00000 f +0000000534 00000 f +0000000535 00000 f +0000000536 00000 f +0000000537 00000 f +0000000544 00000 f +0000583671 00000 n +0000583755 00000 n +0000583835 00000 n +0000583914 00000 n +0000583991 00000 n +0000584070 00000 n +0000000545 00000 f +0000000546 00000 f +0000000547 00000 f +0000000548 00000 f +0000000549 00000 f +0000000550 00000 f +0000000551 00000 f +0000000552 00000 f +0000000553 00000 f +0000000554 00000 f +0000000555 00000 f +0000000556 00000 f +0000000557 00000 f +0000000558 00000 f +0000000559 00000 f +0000000560 00000 f +0000000561 00000 f +0000000562 00000 f +0000000563 00000 f +0000000564 00000 f +0000000565 00000 f +0000000566 00000 f +0000000567 00000 f +0000000568 00000 f +0000000569 00000 f +0000000570 00000 f +0000000571 00000 f +0000000572 00000 f +0000000573 00000 f +0000000574 00000 f +0000000575 00000 f +0000000576 00000 f +0000000577 00000 f +0000000578 00000 f +0000000579 00000 f +0000000580 00000 f +0000000581 00000 f +0000000582 00000 f +0000000583 00000 f +0000000584 00000 f +0000000585 00000 f +0000000586 00000 f +0000000587 00000 f +0000000588 00000 f +0000000589 00000 f +0000000590 00000 f +0000000591 00000 f +0000000592 00000 f +0000000593 00000 f +0000000594 00000 f +0000000595 00000 f +0000000596 00000 f +0000000597 00000 f +0000000610 00000 f +0000588301 00000 n +0000588333 00000 n +0000588183 00000 n +0000588215 00000 n +0000588065 00000 n +0000588097 00000 n +0000587947 00000 n +0000587979 00000 n +0000587829 00000 n +0000587861 00000 n +0000587711 00000 n +0000587743 00000 n +0000000611 00000 f +0000000612 00000 f +0000000613 00000 f +0000000614 00000 f +0000000615 00000 f +0000000616 00000 f +0000000617 00000 f +0000000618 00000 f +0000000619 00000 f +0000000620 00000 f +0000000621 00000 f +0000000622 00000 f +0000000623 00000 f +0000000624 00000 f +0000000631 00000 f +0000584150 00000 n +0000584234 00000 n +0000584314 00000 n +0000584393 00000 n +0000584470 00000 n +0000584549 00000 n +0000000632 00000 f +0000000633 00000 f +0000000634 00000 f +0000000635 00000 f +0000000636 00000 f +0000000637 00000 f +0000000638 00000 f +0000000639 00000 f +0000000640 00000 f +0000000641 00000 f +0000000642 00000 f +0000000643 00000 f +0000000644 00000 f +0000000645 00000 f +0000000646 00000 f +0000000647 00000 f +0000000648 00000 f +0000000649 00000 f +0000000650 00000 f +0000000651 00000 f +0000000652 00000 f +0000000653 00000 f +0000000654 00000 f +0000000655 00000 f +0000000656 00000 f +0000000657 00000 f +0000000658 00000 f +0000000659 00000 f +0000000660 00000 f +0000000661 00000 f +0000000662 00000 f +0000000663 00000 f +0000000664 00000 f +0000000665 00000 f +0000000666 00000 f +0000000667 00000 f +0000000668 00000 f +0000000669 00000 f +0000000670 00000 f +0000000671 00000 f +0000000672 00000 f +0000000673 00000 f +0000000674 00000 f +0000000675 00000 f +0000000676 00000 f +0000000677 00000 f +0000000678 00000 f +0000000679 00000 f +0000000680 00000 f +0000000681 00000 f +0000000682 00000 f +0000000683 00000 f +0000000684 00000 f +0000000697 00000 f +0000587593 00000 n +0000587625 00000 n +0000587475 00000 n +0000587507 00000 n +0000587357 00000 n +0000587389 00000 n +0000587239 00000 n +0000587271 00000 n +0000587121 00000 n +0000587153 00000 n +0000587003 00000 n +0000587035 00000 n +0000000698 00000 f +0000000699 00000 f +0000000700 00000 f +0000000701 00000 f +0000000702 00000 f +0000000703 00000 f +0000000704 00000 f +0000000705 00000 f +0000000706 00000 f +0000000707 00000 f +0000000708 00000 f +0000000709 00000 f +0000000710 00000 f +0000000711 00000 f +0000000718 00000 f +0000584629 00000 n +0000584713 00000 n +0000584793 00000 n +0000584872 00000 n +0000584949 00000 n +0000585028 00000 n +0000000719 00000 f +0000000720 00000 f +0000000721 00000 f +0000000722 00000 f +0000000723 00000 f +0000000724 00000 f +0000000725 00000 f +0000000726 00000 f +0000000727 00000 f +0000000728 00000 f +0000000729 00000 f +0000000730 00000 f +0000000731 00000 f +0000000732 00000 f +0000000733 00000 f +0000000734 00000 f +0000000735 00000 f +0000000736 00000 f +0000000737 00000 f +0000000738 00000 f +0000000739 00000 f +0000000740 00000 f +0000000741 00000 f +0000000742 00000 f +0000000743 00000 f +0000000744 00000 f +0000000745 00000 f +0000000746 00000 f +0000000747 00000 f +0000000748 00000 f +0000000749 00000 f +0000000750 00000 f +0000000751 00000 f +0000000752 00000 f +0000000753 00000 f +0000000754 00000 f +0000000755 00000 f +0000000756 00000 f +0000000757 00000 f +0000000758 00000 f +0000000759 00000 f +0000000760 00000 f +0000000761 00000 f +0000000762 00000 f +0000000763 00000 f +0000000764 00000 f +0000000765 00000 f +0000000766 00000 f +0000000767 00000 f +0000000768 00000 f +0000000769 00000 f +0000000770 00000 f +0000000771 00000 f +0000000784 00000 f +0000586885 00000 n +0000586917 00000 n +0000586767 00000 n +0000586799 00000 n +0000586649 00000 n +0000586681 00000 n +0000586531 00000 n +0000586563 00000 n +0000586413 00000 n +0000586445 00000 n +0000586295 00000 n +0000586327 00000 n +0000000785 00000 f +0000000786 00000 f +0000000787 00000 f +0000000788 00000 f +0000000789 00000 f +0000000790 00000 f +0000000791 00000 f +0000000792 00000 f +0000000793 00000 f +0000000794 00000 f +0000000795 00000 f +0000000796 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000585108 00000 n +0000585192 00000 n +0000585272 00000 n +0000585351 00000 n +0000585428 00000 n +0000585507 00000 n +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000586177 00000 n +0000586209 00000 n +0000586059 00000 n +0000586091 00000 n +0000585941 00000 n +0000585973 00000 n +0000585823 00000 n +0000585855 00000 n +0000585705 00000 n +0000585737 00000 n +0000585587 00000 n +0000585619 00000 n +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000142068 00000 n +0000147139 00000 n +0000145830 00000 n +0000145914 00000 n +0000145994 00000 n +0000146073 00000 n +0000146150 00000 n +0000146229 00000 n +0000592655 00000 n +0000082724 00000 n +0000099545 00000 n +0000165300 00000 n +0000139063 00000 n +0000165272 00000 n +0000138949 00000 n +0000165024 00000 n +0000165148 00000 n +0000147017 00000 n +0000144853 00000 n +0000144999 00000 n +0000101592 00000 n +0000132509 00000 n +0000132875 00000 n +0000133391 00000 n +0000133905 00000 n +0000134420 00000 n +0000134935 00000 n +0000135304 00000 n +0000135920 00000 n +0000136315 00000 n +0000136828 00000 n +0000137342 00000 n +0000137855 00000 n +0000138369 00000 n +0000099609 00000 n +0000580782 00000 n +0000101028 00000 n +0000101078 00000 n +0000144789 00000 n +0000144726 00000 n +0000144662 00000 n +0000144598 00000 n +0000144534 00000 n +0000144470 00000 n +0000144407 00000 n +0000144343 00000 n +0000142005 00000 n +0000141941 00000 n +0000141877 00000 n +0000141813 00000 n +0000141749 00000 n +0000138885 00000 n +0000139100 00000 n +0000142421 00000 n +0000142510 00000 n +0000142812 00000 n +0000145614 00000 n +0000145145 00000 n +0000145281 00000 n +0000145402 00000 n +0000145513 00000 n +0000145711 00000 n +0000146899 00000 n +0000146931 00000 n +0000146781 00000 n +0000146813 00000 n +0000146663 00000 n +0000146695 00000 n +0000146545 00000 n +0000146577 00000 n +0000146427 00000 n +0000146459 00000 n +0000146309 00000 n +0000146341 00000 n +0000147387 00000 n +0000147639 00000 n +0000165376 00000 n +0000165692 00000 n +0000171958 00000 n +0000183764 00000 n +0000249353 00000 n +0000314942 00000 n +0000380531 00000 n +0000446120 00000 n +0000511709 00000 n +0000577298 00000 n +0000592722 00000 n +trailer <<3B4F40D76AF14513ABBFEABEBB27D411>]>> startxref 592932 %%EOF \ No newline at end of file diff --git a/sim/dalboard.ts b/sim/dalboard.ts index d123b64a..de2b9da4 100644 --- a/sim/dalboard.ts +++ b/sim/dalboard.ts @@ -19,6 +19,7 @@ namespace pxsim { fileSystem: FileSystemState; // visual + viewHost: visuals.BoardHost; view: SVGElement; constructor() { @@ -92,15 +93,15 @@ namespace pxsim { switch (msg.type || "") { case "eventbus": - let ev = msg; + const ev = msg; this.bus.queue(ev.id, ev.eventid, ev.value); break; case "serial": - let data = (msg).data || ""; + const data = (msg).data || ""; this.serialState.receiveData(data); break; case "radiopacket": - let packet = msg; + const packet = msg; this.radioState.receivePacket(packet); break; } @@ -126,19 +127,20 @@ namespace pxsim { maxHeight: "100%", highContrast: msg.highContrast }; - const viewHost = new visuals.BoardHost(pxsim.visuals.mkBoardView({ + this.viewHost = new visuals.BoardHost(pxsim.visuals.mkBoardView({ visual: boardDef.visual, + boardDef: boardDef, highContrast: msg.highContrast }), opts); document.body.innerHTML = ""; // clear children - document.body.appendChild(this.view = viewHost.getView()); + document.body.appendChild(this.view = this.viewHost.getView()); return Promise.resolve(); } - screenshot(): string { - return svg.toDataUri(new XMLSerializer().serializeToString(this.view)); + screenshotAsync(width?: number): Promise { + return this.viewHost.screenshotAsync(width); } } @@ -174,4 +176,4 @@ namespace pxsim { export function board() { return runtime.board as DalBoard; } -} \ No newline at end of file +} diff --git a/sim/instructions.ts b/sim/instructions.ts deleted file mode 100644 index 21620483..00000000 --- a/sim/instructions.ts +++ /dev/null @@ -1,92 +0,0 @@ -/// -/// -/// - -//HACK: allows instructions.html to access pxtblocks without requiring simulator.html to import blocks as well -if (!(window).pxt) (window).pxt = {}; -import pxtrunner = pxt.runner; -import pxtdocs = pxt.docs; - -namespace pxsim.instructions { - export function drawInstructions() { - pxsim.visuals.mkBoardView = (opts: pxsim.visuals.BoardViewOptions): pxsim.visuals.BoardView => { - return new visuals.MicrobitBoardSvg({ - runtime: runtime, - theme: visuals.randomTheme(), - disableTilt: false, - wireframe: opts.wireframe, - }); - } - - let getQsVal = parseQueryString(); - - //project name - let name = getQsVal("name") || "Untitled"; - - // board def - const boardDef = JSON.parse(getQsVal("board")) as pxsim.BoardDefinition; - - //parts list - let parts = (getQsVal("parts") || "").split(" "); - parts.sort(); - - // parts definitions - let partDefinitions = JSON.parse(getQsVal("partdefs") || "{}") as pxsim.Map - - //fn args - let fnArgs = JSON.parse((getQsVal("fnArgs") || "{}")); - - //project code - let tsCode = getQsVal("code"); - let tsPackage = getQsVal("package") || ""; - let codeSpinnerDiv = document.getElementById("proj-code-spinner"); - let codeContainerDiv = document.getElementById("proj-code-container"); - if (tsCode) { - //we use the docs renderer to decompile the code to blocks and render it - //TODO: render the blocks code directly - let md = - `\`\`\`blocks -${tsCode} -\`\`\` -\`\`\`package -${tsPackage} -\`\`\` -` - - pxtdocs.requireMarked = function () { return (window).marked; } - pxtrunner.renderMarkdownAsync(codeContainerDiv, md) - .done(function () { - let codeSvg = $("#proj-code-container svg"); - if (codeSvg.length > 0) { - //code rendered successfully as blocks - codeSvg.css("width", "inherit"); - codeSvg.css("height", "inherit"); - //takes the svg out of the wrapper markdown - codeContainerDiv.innerHTML = ""; - codeContainerDiv.appendChild(codeSvg[0]); - } else { - //code failed to convert to blocks, display as typescript instead - codeContainerDiv.innerText = tsCode; - } - $(codeContainerDiv).show(); - $(codeSpinnerDiv).hide(); - }); - } - - - if (name) - $("#proj-title").text(name); - - //init runtime - if (!pxsim.initCurrentRuntime) - pxsim.initCurrentRuntime = initRuntimeWithDalBoard; - - renderParts({ - name, - boardDef, - parts, - partDefinitions, - fnArgs - }) - } -} \ No newline at end of file diff --git a/sim/public/blockly/media/click.mp3 b/sim/public/blockly/media/click.mp3 new file mode 100644 index 00000000..4534b0dd Binary files /dev/null and b/sim/public/blockly/media/click.mp3 differ diff --git a/sim/public/blockly/media/click.ogg b/sim/public/blockly/media/click.ogg new file mode 100644 index 00000000..e8ae42a6 Binary files /dev/null and b/sim/public/blockly/media/click.ogg differ diff --git a/sim/public/blockly/media/click.wav b/sim/public/blockly/media/click.wav new file mode 100644 index 00000000..41a50cd7 Binary files /dev/null and b/sim/public/blockly/media/click.wav differ diff --git a/sim/public/blockly/media/delete.mp3 b/sim/public/blockly/media/delete.mp3 new file mode 100644 index 00000000..442bd9c1 Binary files /dev/null and b/sim/public/blockly/media/delete.mp3 differ diff --git a/sim/public/blockly/media/delete.ogg b/sim/public/blockly/media/delete.ogg new file mode 100644 index 00000000..67f84ac1 Binary files /dev/null and b/sim/public/blockly/media/delete.ogg differ diff --git a/sim/public/blockly/media/delete.wav b/sim/public/blockly/media/delete.wav new file mode 100644 index 00000000..18debcf9 Binary files /dev/null and b/sim/public/blockly/media/delete.wav differ diff --git a/sim/public/blockly/media/disconnect.mp3 b/sim/public/blockly/media/disconnect.mp3 new file mode 100644 index 00000000..8cfaff6c Binary files /dev/null and b/sim/public/blockly/media/disconnect.mp3 differ diff --git a/sim/public/blockly/media/disconnect.ogg b/sim/public/blockly/media/disconnect.ogg new file mode 100644 index 00000000..467b527b Binary files /dev/null and b/sim/public/blockly/media/disconnect.ogg differ diff --git a/sim/public/blockly/media/disconnect.wav b/sim/public/blockly/media/disconnect.wav new file mode 100644 index 00000000..af5c2544 Binary files /dev/null and b/sim/public/blockly/media/disconnect.wav differ diff --git a/sim/public/blocks/iconnames/angry.png b/sim/public/blocks/iconnames/angry.png deleted file mode 100644 index 6e4a02f0..00000000 Binary files a/sim/public/blocks/iconnames/angry.png and /dev/null differ diff --git a/sim/public/blocks/iconnames/asleep.png b/sim/public/blocks/iconnames/asleep.png deleted file mode 100644 index 0d965524..00000000 Binary files a/sim/public/blocks/iconnames/asleep.png and /dev/null differ diff --git a/sim/public/blocks/iconnames/butterfly.png b/sim/public/blocks/iconnames/butterfly.png deleted file mode 100644 index e9fd9055..00000000 Binary files a/sim/public/blocks/iconnames/butterfly.png and /dev/null differ diff --git a/sim/public/blocks/iconnames/chessboard.png b/sim/public/blocks/iconnames/chessboard.png deleted file mode 100644 index a9e1288d..00000000 Binary files a/sim/public/blocks/iconnames/chessboard.png and /dev/null differ diff --git a/sim/public/blocks/iconnames/confused.png b/sim/public/blocks/iconnames/confused.png deleted file mode 100644 index 9f071abd..00000000 Binary files a/sim/public/blocks/iconnames/confused.png and /dev/null differ diff --git a/sim/public/blocks/iconnames/cow.png b/sim/public/blocks/iconnames/cow.png deleted file mode 100644 index b7ebd2a7..00000000 Binary files a/sim/public/blocks/iconnames/cow.png and /dev/null differ diff --git a/sim/public/blocks/iconnames/diamond.png b/sim/public/blocks/iconnames/diamond.png deleted file mode 100644 index dfd19231..00000000 Binary files a/sim/public/blocks/iconnames/diamond.png and /dev/null differ diff --git a/sim/public/blocks/iconnames/duck.png b/sim/public/blocks/iconnames/duck.png deleted file mode 100644 index 6caf41b0..00000000 Binary files a/sim/public/blocks/iconnames/duck.png and /dev/null differ diff --git a/sim/public/blocks/iconnames/eigthnote.png b/sim/public/blocks/iconnames/eigthnote.png deleted file mode 100644 index b5e943b0..00000000 Binary files a/sim/public/blocks/iconnames/eigthnote.png and /dev/null differ diff --git a/sim/public/blocks/iconnames/fabulous.png b/sim/public/blocks/iconnames/fabulous.png deleted file mode 100644 index 917f1e94..00000000 Binary files a/sim/public/blocks/iconnames/fabulous.png and /dev/null differ diff --git a/sim/public/blocks/iconnames/ghost.png b/sim/public/blocks/iconnames/ghost.png deleted file mode 100644 index fd8be857..00000000 Binary files a/sim/public/blocks/iconnames/ghost.png and /dev/null differ diff --git a/sim/public/blocks/iconnames/giraffe.png b/sim/public/blocks/iconnames/giraffe.png deleted file mode 100644 index 9aac246f..00000000 Binary files a/sim/public/blocks/iconnames/giraffe.png and /dev/null differ diff --git a/sim/public/blocks/iconnames/happy.png b/sim/public/blocks/iconnames/happy.png deleted file mode 100644 index 66b0eaab..00000000 Binary files a/sim/public/blocks/iconnames/happy.png and /dev/null differ diff --git a/sim/public/blocks/iconnames/heart.png b/sim/public/blocks/iconnames/heart.png deleted file mode 100644 index acfcf584..00000000 Binary files a/sim/public/blocks/iconnames/heart.png and /dev/null differ diff --git a/sim/public/blocks/iconnames/house.png b/sim/public/blocks/iconnames/house.png deleted file mode 100644 index 65ff1348..00000000 Binary files a/sim/public/blocks/iconnames/house.png and /dev/null differ diff --git a/sim/public/blocks/iconnames/lefttriangle.png b/sim/public/blocks/iconnames/lefttriangle.png deleted file mode 100644 index dac569bc..00000000 Binary files a/sim/public/blocks/iconnames/lefttriangle.png and /dev/null differ diff --git a/sim/public/blocks/iconnames/meh.png b/sim/public/blocks/iconnames/meh.png deleted file mode 100644 index fc84b625..00000000 Binary files a/sim/public/blocks/iconnames/meh.png and /dev/null differ diff --git a/sim/public/blocks/iconnames/no.png b/sim/public/blocks/iconnames/no.png deleted file mode 100644 index 51cdab2f..00000000 Binary files a/sim/public/blocks/iconnames/no.png and /dev/null differ diff --git a/sim/public/blocks/iconnames/pitchfork.png b/sim/public/blocks/iconnames/pitchfork.png deleted file mode 100644 index b9f71065..00000000 Binary files a/sim/public/blocks/iconnames/pitchfork.png and /dev/null differ diff --git a/sim/public/blocks/iconnames/quarternote.png b/sim/public/blocks/iconnames/quarternote.png deleted file mode 100644 index 43dd6459..00000000 Binary files a/sim/public/blocks/iconnames/quarternote.png and /dev/null differ diff --git a/sim/public/blocks/iconnames/rabbit.png b/sim/public/blocks/iconnames/rabbit.png deleted file mode 100644 index 66f1a4e0..00000000 Binary files a/sim/public/blocks/iconnames/rabbit.png and /dev/null differ diff --git a/sim/public/blocks/iconnames/rollerskate.png b/sim/public/blocks/iconnames/rollerskate.png deleted file mode 100644 index d78e4704..00000000 Binary files a/sim/public/blocks/iconnames/rollerskate.png and /dev/null differ diff --git a/sim/public/blocks/iconnames/sad.png b/sim/public/blocks/iconnames/sad.png deleted file mode 100644 index 50af6a35..00000000 Binary files a/sim/public/blocks/iconnames/sad.png and /dev/null differ diff --git a/sim/public/blocks/iconnames/scissors.png b/sim/public/blocks/iconnames/scissors.png deleted file mode 100644 index 1bfc69f4..00000000 Binary files a/sim/public/blocks/iconnames/scissors.png and /dev/null differ diff --git a/sim/public/blocks/iconnames/silly.png b/sim/public/blocks/iconnames/silly.png deleted file mode 100644 index 6e6da715..00000000 Binary files a/sim/public/blocks/iconnames/silly.png and /dev/null differ diff --git a/sim/public/blocks/iconnames/skull.png b/sim/public/blocks/iconnames/skull.png deleted file mode 100644 index 5b7c3699..00000000 Binary files a/sim/public/blocks/iconnames/skull.png and /dev/null differ diff --git a/sim/public/blocks/iconnames/smalldiamond.png b/sim/public/blocks/iconnames/smalldiamond.png deleted file mode 100644 index 17ca5b43..00000000 Binary files a/sim/public/blocks/iconnames/smalldiamond.png and /dev/null differ diff --git a/sim/public/blocks/iconnames/smallheart.png b/sim/public/blocks/iconnames/smallheart.png deleted file mode 100644 index b952a5d4..00000000 Binary files a/sim/public/blocks/iconnames/smallheart.png and /dev/null differ diff --git a/sim/public/blocks/iconnames/smallsquare.png b/sim/public/blocks/iconnames/smallsquare.png deleted file mode 100644 index c9704a26..00000000 Binary files a/sim/public/blocks/iconnames/smallsquare.png and /dev/null differ diff --git a/sim/public/blocks/iconnames/snake.png b/sim/public/blocks/iconnames/snake.png deleted file mode 100644 index 112af5ff..00000000 Binary files a/sim/public/blocks/iconnames/snake.png and /dev/null differ diff --git a/sim/public/blocks/iconnames/square.png b/sim/public/blocks/iconnames/square.png deleted file mode 100644 index acc8a88e..00000000 Binary files a/sim/public/blocks/iconnames/square.png and /dev/null differ diff --git a/sim/public/blocks/iconnames/stickfigure.png b/sim/public/blocks/iconnames/stickfigure.png deleted file mode 100644 index 93eb314e..00000000 Binary files a/sim/public/blocks/iconnames/stickfigure.png and /dev/null differ diff --git a/sim/public/blocks/iconnames/surprised.png b/sim/public/blocks/iconnames/surprised.png deleted file mode 100644 index c753f2a8..00000000 Binary files a/sim/public/blocks/iconnames/surprised.png and /dev/null differ diff --git a/sim/public/blocks/iconnames/sword.png b/sim/public/blocks/iconnames/sword.png deleted file mode 100644 index bd5dc48c..00000000 Binary files a/sim/public/blocks/iconnames/sword.png and /dev/null differ diff --git a/sim/public/blocks/iconnames/target.png b/sim/public/blocks/iconnames/target.png deleted file mode 100644 index fba12e6b..00000000 Binary files a/sim/public/blocks/iconnames/target.png and /dev/null differ diff --git a/sim/public/blocks/iconnames/tortoise.png b/sim/public/blocks/iconnames/tortoise.png deleted file mode 100644 index c46ed912..00000000 Binary files a/sim/public/blocks/iconnames/tortoise.png and /dev/null differ diff --git a/sim/public/blocks/iconnames/triangle.png b/sim/public/blocks/iconnames/triangle.png deleted file mode 100644 index 1d9814ab..00000000 Binary files a/sim/public/blocks/iconnames/triangle.png and /dev/null differ diff --git a/sim/public/blocks/iconnames/tshirt.png b/sim/public/blocks/iconnames/tshirt.png deleted file mode 100644 index 2572430c..00000000 Binary files a/sim/public/blocks/iconnames/tshirt.png and /dev/null differ diff --git a/sim/public/blocks/iconnames/umbrella.png b/sim/public/blocks/iconnames/umbrella.png deleted file mode 100644 index 24fa7239..00000000 Binary files a/sim/public/blocks/iconnames/umbrella.png and /dev/null differ diff --git a/sim/public/blocks/iconnames/yes.png b/sim/public/blocks/iconnames/yes.png deleted file mode 100644 index 9b37df81..00000000 Binary files a/sim/public/blocks/iconnames/yes.png and /dev/null differ diff --git a/sim/public/siminstructions.html b/sim/public/siminstructions.html deleted file mode 100644 index 3d88ea16..00000000 --- a/sim/public/siminstructions.html +++ /dev/null @@ -1,203 +0,0 @@ - - - - - - Assembly Instructions - - - - - -

- - - - - - - - - - - - - - - - - - -
-

- - -
- -
-
-
-
- - \ No newline at end of file diff --git a/sim/state/accelerometer.ts b/sim/state/accelerometer.ts index 6acbf1a7..80172fd6 100644 --- a/sim/state/accelerometer.ts +++ b/sim/state/accelerometer.ts @@ -1,37 +1,53 @@ namespace pxsim.input { - export function onGesture(gesture: number, handler: RefAction) { + function accForGesture(gesture: number) { let b = board().accelerometerState; b.accelerometer.activate(); - - if (gesture == 11 && !b.useShake) { // SAKE + if (gesture == 11 && !b.useShake) { // SHAKE b.useShake = true; runtime.queueDisplayUpdate(); } + return b; + } + + export function onGesture(gesture: number, handler: RefAction) { + const b = accForGesture(gesture); pxtcore.registerWithDal(DAL.MICROBIT_ID_GESTURE, gesture, handler); } + export function isGesture(gesture: number): boolean { + const b = accForGesture(gesture); + return b.accelerometer.getGesture() == gesture; + } + export function acceleration(dimension: number): number { let b = board().accelerometerState; let acc = b.accelerometer; - acc.activate(); switch (dimension) { - case 0: return acc.getX(); - case 1: return acc.getY(); - case 2: return acc.getZ(); - default: return Math.floor(Math.sqrt(acc.instantaneousAccelerationSquared())); + case 0: + acc.activate(AccelerometerFlag.X); + return acc.getX(); + case 1: + acc.activate(AccelerometerFlag.Y); + return acc.getY(); + case 2: + acc.activate(AccelerometerFlag.Z); + return acc.getZ(); + default: + acc.activate(); + return Math.floor(Math.sqrt(acc.instantaneousAccelerationSquared())); } } export function rotation(kind: number): number { - let b = board().accelerometerState; - let acc = b.accelerometer; + const b = board().accelerometerState; + const acc = b.accelerometer; acc.activate(); - let x = acc.getX(MicroBitCoordinateSystem.NORTH_EAST_DOWN); - let y = acc.getX(MicroBitCoordinateSystem.NORTH_EAST_DOWN); - let z = acc.getX(MicroBitCoordinateSystem.NORTH_EAST_DOWN); + const x = acc.getX(MicroBitCoordinateSystem.NORTH_EAST_DOWN); + const y = acc.getY(MicroBitCoordinateSystem.NORTH_EAST_DOWN); + const z = acc.getZ(MicroBitCoordinateSystem.NORTH_EAST_DOWN); - let roll = Math.atan2(y, z); - let pitch = Math.atan(-x / (y * Math.sin(roll) + z * Math.cos(roll))); + const roll = Math.atan2(y, z); + const pitch = Math.atan(-x / (y * Math.sin(roll) + z * Math.cos(roll))); let r = 0; switch (kind) { @@ -99,6 +115,12 @@ namespace pxsim { NORTH_EAST_DOWN } + export enum AccelerometerFlag { + X = 1, + Y = 2, + Z = 4 + } + export class Accelerometer { private sigma: number = 0; // the number of ticks that the instantaneous gesture has been stable. private lastGesture: number = 0; // the last, stable gesture recorded. @@ -110,6 +132,7 @@ namespace pxsim { private id: number; public isActive = false; public sampleRange = 2; + public flags: AccelerometerFlag = 0; constructor(public runtime: Runtime) { this.id = DAL.MICROBIT_ID_ACCELEROMETER; @@ -120,11 +143,13 @@ namespace pxsim { this.sampleRange = Math.max(1, Math.min(8, range)); } - public activate() { + public activate(flags?: AccelerometerFlag) { if (!this.isActive) { this.isActive = true; this.runtime.queueDisplayUpdate(); } + if (flags) + this.flags |= flags; } /** @@ -199,9 +224,8 @@ namespace pxsim { if (force < sq(DAL.MICROBIT_ACCELEROMETER_FREEFALL_TOLERANCE)) return DAL.MICROBIT_ACCELEROMETER_EVT_FREEFALL; - // TODO: fix this - //if (force > sq(DAL.MICROBIT_ACCELEROMETER_3G_TOLERANCE)) - // return DAL.MICROBIT_ACCELEROMETER_EVT_3G; + if (force > sq(DAL.MICROBIT_ACCELEROMETER_3G_TOLERANCE)) + return DAL.MICROBIT_ACCELEROMETER_EVT_3G; if (force > sq(DAL.MICROBIT_ACCELEROMETER_6G_TOLERANCE)) return DAL.MICROBIT_ACCELEROMETER_EVT_6G; @@ -223,10 +247,10 @@ namespace pxsim { return DAL.MICROBIT_ACCELEROMETER_EVT_TILT_UP; if (this.getZ() < (-1000 + DAL.MICROBIT_ACCELEROMETER_TILT_TOLERANCE)) - return DAL.MICROBIT_ACCELEROMETER_EVT_FACE_DOWN; + return DAL.MICROBIT_ACCELEROMETER_EVT_FACE_UP; if (this.getZ() > (1000 - DAL.MICROBIT_ACCELEROMETER_TILT_TOLERANCE)) - return DAL.MICROBIT_ACCELEROMETER_EVT_FACE_UP; + return DAL.MICROBIT_ACCELEROMETER_EVT_FACE_DOWN; return 0; } @@ -236,22 +260,28 @@ namespace pxsim { let g = this.instantaneousPosture(); // Perform some low pass filtering to reduce jitter from any detected effects - if (g == this.currentGesture) { - if (this.sigma < DAL.MICROBIT_ACCELEROMETER_GESTURE_DAMPING) - this.sigma++; - } - else { + if (g != this.currentGesture) { this.currentGesture = g; this.sigma = 0; + } else if (this.sigma < DAL.MICROBIT_ACCELEROMETER_GESTURE_DAMPING) { + ++this.sigma; } - // If we've reached threshold, update our record and raise the relevant event... - if (this.currentGesture != this.lastGesture && this.sigma >= DAL.MICROBIT_ACCELEROMETER_GESTURE_DAMPING) { - this.lastGesture = this.currentGesture; - board().bus.queue(DAL.MICROBIT_ID_GESTURE, this.lastGesture); + if (this.currentGesture !== this.lastGesture && this.sigma >= DAL.MICROBIT_ACCELEROMETER_GESTURE_DAMPING) { + this.enqueueCurrentGesture(); } } + forceGesture(gesture: number) { + this.currentGesture = gesture; + this.enqueueCurrentGesture(); + } + + private enqueueCurrentGesture() { + this.lastGesture = this.currentGesture; + board().bus.queue(DAL.MICROBIT_ID_GESTURE, this.lastGesture); + } + /** * Reads the X axis value of the latest update from the accelerometer. * @param system The coordinate system to use. By default, a simple cartesian system is provided. @@ -363,6 +393,10 @@ namespace pxsim { return this.roll; } + getGesture(): number { + return this.lastGesture; + } + /** * Recalculate roll and pitch values for the current sample. * We only do this at most once per sample, as the necessary trigonemteric functions are rather @@ -384,7 +418,11 @@ namespace pxsim { useShake = false; constructor(runtime: Runtime) { - this.accelerometer = new Accelerometer(runtime); + this.accelerometer = new Accelerometer(runtime); + } + + shake() { + this.accelerometer.forceGesture(DAL.MICROBIT_ACCELEROMETER_EVT_SHAKE); // SHAKE == 11 } } } \ No newline at end of file diff --git a/sim/state/buttonpairsim.ts b/sim/state/buttonpairsim.ts new file mode 100644 index 00000000..a6db64b3 --- /dev/null +++ b/sim/state/buttonpairsim.ts @@ -0,0 +1,201 @@ +namespace pxsim.visuals { + export function mkBtnSvg(xy: Coord): SVGAndSize { + let [innerCls, outerCls] = ["sim-button", "sim-button-outer"]; + const tabSize = PIN_DIST / 2.5; + const pegR = PIN_DIST / 5; + const btnR = PIN_DIST * .8; + const pegMargin = PIN_DIST / 8; + const plateR = PIN_DIST / 12; + + const pegOffset = pegMargin + pegR; + let [x, y] = xy; + const left = x - tabSize / 2; + const top = y - tabSize / 2; + const plateH = 3 * PIN_DIST - tabSize; + const plateW = 2 * PIN_DIST + tabSize; + const plateL = left; + const plateT = top + tabSize; + const btnCX = plateL + plateW / 2; + const btnCY = plateT + plateH / 2; + + let btng = svg.elt("g"); + //tabs + const mkTab = (x: number, y: number) => { + svg.child(btng, "rect", { class: "sim-button-tab", x: x, y: y, width: tabSize, height: tabSize}) + } + mkTab(left, top); + mkTab(left + 2 * PIN_DIST, top); + mkTab(left, top + 3 * PIN_DIST); + mkTab(left + 2 * PIN_DIST, top + 3 * PIN_DIST); + + //plate + svg.child(btng, "rect", { class: outerCls, x: plateL, y: plateT, rx: plateR, ry: plateR, width: plateW, height: plateH }); + + //pegs + const mkPeg = (x: number, y: number) => { + svg.child(btng, "circle", { class: "sim-button-nut", cx: x, cy: y, r: pegR }); + } + mkPeg(plateL + pegOffset, plateT + pegOffset) + mkPeg(plateL + plateW - pegOffset, plateT + pegOffset) + mkPeg(plateL + pegOffset, plateT + plateH - pegOffset) + mkPeg(plateL + plateW - pegOffset, plateT + plateH - pegOffset) + + //inner btn + let innerBtn = svg.child(btng, "circle", { class: innerCls, cx: btnCX, cy: btnCY, r: btnR }); + + //return + return { el: btng, y: top, x: left, w: plateW, h: plateH + 2 * tabSize }; + } + export const BUTTON_PAIR_STYLE = ` + .sim-button { + pointer-events: none; + fill: #000; + } + .sim-button-outer:active ~ .sim-button, + .sim-button-virtual:active { + fill: #FFA500; + } + .sim-button-outer { + cursor: pointer; + fill: #979797; + } + .sim-button-outer:hover { + stroke:gray; + stroke-width: ${PIN_DIST / 5}px; + } + .sim-button-nut { + fill:#000; + pointer-events:none; + } + .sim-button-nut:hover { + stroke:${PIN_DIST / 15}px solid #704A4A; + } + .sim-button-tab { + fill:#FFF; + pointer-events:none; + } + .sim-button-virtual { + cursor: pointer; + fill: rgba(255, 255, 255, 0.6); + stroke: rgba(255, 255, 255, 1); + stroke-width: ${PIN_DIST / 5}px; + } + .sim-button-virtual:hover { + stroke: rgba(128, 128, 128, 1); + } + .sim-text-virtual { + fill: #000; + pointer-events:none; + } + `; + export class ButtonPairView implements IBoardPart { + public element: SVGElement; + public defs: SVGElement[]; + public style = BUTTON_PAIR_STYLE; + private state: ButtonPairState; + private bus: EventBus; + private aBtn: SVGGElement; + private bBtn: SVGGElement; + private abBtn: SVGGElement; + + public init(bus: EventBus, state: ButtonPairState) { + this.state = state; + this.bus = bus; + this.defs = []; + this.element = this.mkBtns(); + this.updateState(); + this.attachEvents(); + } + + public moveToCoord(xy: Coord) { + let btnWidth = PIN_DIST * 3; + let [x, y] = xy; + translateEl(this.aBtn, [x, y]) + translateEl(this.bBtn, [x + btnWidth, y]) + translateEl(this.abBtn, [x + PIN_DIST * 1.5, y + PIN_DIST * 4]) + } + + public updateState() { + let stateBtns = [this.state.aBtn, this.state.bBtn, this.state.abBtn]; + let svgBtns = [this.aBtn, this.bBtn, this.abBtn]; + + if (this.state.usesButtonAB && this.abBtn.style.visibility != "visible") { + this.abBtn.style.visibility = "visible"; + } + } + + public updateTheme() {} + + private mkBtns() { + this.aBtn = mkBtnSvg([0, 0]).el; + this.bBtn = mkBtnSvg([0, 0]).el; + + const mkVirtualBtn = () => { + const numPins = 2; + const w = PIN_DIST * 2.8; + const offset = (w - (numPins * PIN_DIST)) / 2; + const corner = PIN_DIST / 2; + const cx = 0 - offset + w / 2; + const cy = cx; + const txtSize = PIN_DIST * 1.3; + const x = -offset; + const y = -offset; + const txtXOff = PIN_DIST / 7; + const txtYOff = PIN_DIST / 10; + + let btng = svg.elt("g"); + let btn = svg.child(btng, "rect", { class: "sim-button-virtual", x: x, y: y, rx: corner, ry: corner, width: w, height: w}); + let btnTxt = mkTxt(cx + txtXOff, cy + txtYOff, txtSize, 0, "A+B"); + + U.addClass(btnTxt, "sim-text") + U.addClass(btnTxt, "sim-text-virtual"); + btng.appendChild(btnTxt); + + return btng; + } + + this.abBtn = mkVirtualBtn(); + this.abBtn.style.visibility = "hidden"; + + let el = svg.elt("g"); + U.addClass(el, "sim-buttonpair") + el.appendChild(this.aBtn); + el.appendChild(this.bBtn); + el.appendChild(this.abBtn); + + return el; + } + + private attachEvents() { + let btnStates = [this.state.aBtn, this.state.bBtn]; + let btnSvgs = [this.aBtn, this.bBtn]; + btnSvgs.forEach((btn, index) => { + pxsim.pointerEvents.down.forEach(evid => btn.addEventListener(evid, ev => { + btnStates[index].pressed = true; + })) + btn.addEventListener(pointerEvents.leave, ev => { + btnStates[index].pressed = false; + }) + btn.addEventListener(pointerEvents.up, ev => { + btnStates[index].pressed = false; + this.bus.queue(btnStates[index].id, this.state.props.BUTTON_EVT_UP); + this.bus.queue(btnStates[index].id, this.state.props.BUTTON_EVT_CLICK); + }) + }) + let updateBtns = (s: boolean) => { + btnStates.forEach(b => b.pressed = s) + }; + pxsim.pointerEvents.down.forEach(evid => this.abBtn.addEventListener(evid, ev => { + updateBtns(true); + })); + this.abBtn.addEventListener(pointerEvents.leave, ev => { + updateBtns(false); + }) + this.abBtn.addEventListener(pointerEvents.up, ev => { + updateBtns(false); + this.bus.queue(this.state.abBtn.id, this.state.props.BUTTON_EVT_UP); + this.bus.queue(this.state.abBtn.id, this.state.props.BUTTON_EVT_CLICK); + }) + } + } +} \ No newline at end of file diff --git a/sim/state/edgeconnector.ts b/sim/state/edgeconnector.ts index 46d1f72f..80bf91e4 100644 --- a/sim/state/edgeconnector.ts +++ b/sim/state/edgeconnector.ts @@ -3,6 +3,7 @@ namespace pxsim.input { let pin = getPin(pinId); if (!pin) return; pin.isTouched(); + runtime.queueDisplayUpdate(); pxtcore.registerWithDal(pin.id, DAL.MICROBIT_BUTTON_EVT_CLICK, handler); } @@ -10,6 +11,7 @@ namespace pxsim.input { let pin = getPin(pinId); if (!pin) return; pin.isTouched(); + runtime.queueDisplayUpdate(); pxtcore.registerWithDal(pin.id, DAL.MICROBIT_BUTTON_EVT_UP, handler); } @@ -29,7 +31,7 @@ namespace pxsim { namespace pxsim.pins { export function digitalReadPin(pinId: number): number { let pin = getPin(pinId); - if (!pin) return; + if (!pin) return -1; pin.mode = PinFlags.Digital | PinFlags.Input; return pin.value > 100 ? 1 : 0; } @@ -50,7 +52,7 @@ namespace pxsim.pins { export function analogReadPin(pinId: number): number { let pin = getPin(pinId); - if (!pin) return; + if (!pin) return -1; pin.mode = PinFlags.Analog | PinFlags.Input; return pin.value || 0; } @@ -76,7 +78,7 @@ namespace pxsim.pins { if (!pin) return; analogSetPeriod(pinId, 20000); - pin.servoAngle = Math.max(0, Math.min(180, value)); + pin.servoAngle = value; } export function servoSetPulse(pinId: number, micros: number) { diff --git a/sim/state/edgeconnectorsim.ts b/sim/state/edgeconnectorsim.ts new file mode 100644 index 00000000..055309de --- /dev/null +++ b/sim/state/edgeconnectorsim.ts @@ -0,0 +1,89 @@ +namespace pxsim { + export enum PinFlags { + Unused = 0, + Digital = 0x0001, + Analog = 0x0002, + Input = 0x0004, + Output = 0x0008, + Touch = 0x0010 + } + + export class Pin { + constructor(public id: number) { } + touched = false; + value = 0; + period = 0; + servoAngle = 0; + mode = PinFlags.Unused; + pitch = false; + pull = 0; // PullDown + + digitalReadPin(): number { + this.mode = PinFlags.Digital | PinFlags.Input; + return this.value > 100 ? 1 : 0; + } + + digitalWritePin(value: number) { + this.mode = PinFlags.Digital | PinFlags.Output; + this.value = value > 0 ? 200 : 0; + runtime.queueDisplayUpdate(); + } + + setPull(pull: number) { + this.pull = pull; + } + + analogReadPin(): number { + this.mode = PinFlags.Analog | PinFlags.Input; + return this.value || 0; + } + + analogWritePin(value: number) { + value = value >> 0; + this.mode = PinFlags.Analog | PinFlags.Output; + this.value = Math.max(0, Math.min(1023, value)); + runtime.queueDisplayUpdate(); + } + + analogSetPeriod(micros: number) { + micros = micros >> 0; + this.mode = PinFlags.Analog | PinFlags.Output; + this.period = micros; + runtime.queueDisplayUpdate(); + } + + servoWritePin(value: number) { + value = value >> 0; + this.analogSetPeriod(20000); + this.servoAngle = Math.max(0, Math.min(180, value)); + runtime.queueDisplayUpdate(); + } + + servoSetPulse(pinId: number, micros: number) { + // TODO + } + + isTouched(): boolean { + this.mode = PinFlags.Touch | PinFlags.Analog | PinFlags.Input; + return this.touched; + } + } + + export interface EdgeConnectorProps { + pins: number[]; + servos?: { [name: string]: number; } + } + + export class EdgeConnectorState { + pins: Pin[]; + + constructor(public props: EdgeConnectorProps) { + this.pins = props.pins.map(id => id != undefined ? new Pin(id) : null); + } + + public getPin(id: number) { + return this.pins.filter(p => p && p.id == id)[0] || null + } + } + +} \ No newline at end of file diff --git a/sim/state/filesystem.ts b/sim/state/filesystem.ts index 9eed2c31..79864871 100644 --- a/sim/state/filesystem.ts +++ b/sim/state/filesystem.ts @@ -15,4 +15,10 @@ namespace pxsim.files { const b = board(); b.fileSystem.remove(filename); } + export function readToSerial(filename: string) { + const b = board(); + let f = b.fileSystem.files[filename]; + if (f) + b.serialState.writeSerial(f); + } } \ No newline at end of file diff --git a/sim/state/ledmatrix.ts b/sim/state/ledmatrix.ts index 7c62600d..7fa1eaa9 100644 --- a/sim/state/ledmatrix.ts +++ b/sim/state/ledmatrix.ts @@ -28,17 +28,24 @@ namespace pxsim { this.data = data; } public print() { - // console.debug(`Image id:${this.id} refs:${this.refcnt} size:${this.width}x${Image.height}`) + console.debug(`Image id:${this.id} size:${this.width}x${Image.height}`) } public get(x: number, y: number): number { + x = x >> 0; + y = y >> 0; if (x < 0 || x >= this.width || y < 0 || y >= 5) return 0; return this.data[y * this.width + x]; } public set(x: number, y: number, v: number) { + x = x >> 0; + y = y >> 0; if (x < 0 || x >= this.width || y < 0 || y >= 5) return; this.data[y * this.width + x] = Math.max(0, Math.min(255, v)); } public copyTo(xSrcIndex: number, length: number, target: Image, xTargetIndex: number): void { + xSrcIndex = xSrcIndex >> 0; + length = length >> 0; + xTargetIndex = xTargetIndex >> 0; for (let x = 0; x < length; x++) { for (let y = 0; y < 5; y++) { let value = this.get(xSrcIndex + x, y); @@ -47,12 +54,14 @@ namespace pxsim { } } public shiftLeft(cols: number) { + cols = cols >> 0; for (let x = 0; x < this.width; ++x) for (let y = 0; y < 5; ++y) this.set(x, y, x < this.width - cols ? this.get(x + cols, y) : 0); } public shiftRight(cols: number) { + cols = cols >> 0; for (let x = this.width - 1; x >= 0; --x) for (let y = 0; y < 5; ++y) this.set(x, y, x >= cols ? this.get(x - cols, y) : 0); @@ -65,12 +74,13 @@ namespace pxsim { } export function createInternalImage(width: number): Image { + width = width >> 0; let img = createImage(width) - pxsim.noLeakTracking(img) return img } export function createImage(width: number): Image { + width = width >> 0; return new Image(width, new Array(width * 5)); } @@ -131,9 +141,12 @@ namespace pxsim.images { namespace pxsim.ImageMethods { export function showImage(leds: Image, offset: number, interval: number) { pxtrt.nullCheck(leds) + offset = offset >> 0; + interval = interval >> 0; let cb = getResume(); let first = true; + leds = clampPixelBrightness(leds); board().ledMatrixState.animationQ.enqueue({ interval, frame: () => { @@ -150,7 +163,9 @@ namespace pxsim.ImageMethods { export function plotImage(leds: Image, offset: number): void { pxtrt.nullCheck(leds) + offset = offset >> 0; + leds = clampPixelBrightness(leds); board().ledMatrixState.animationQ.enqueue({ interval: 0, frame: () => { @@ -205,12 +220,15 @@ namespace pxsim.ImageMethods { export function scrollImage(leds: Image, stride: number, interval: number): void { pxtrt.nullCheck(leds) + stride = stride >> 0; + interval = interval >> 0; if (stride == 0) stride = 1; let cb = getResume(); let off = stride > 0 ? 0 : leds.width - 1; let display = board().ledMatrixState.image; + leds = clampPixelBrightness(leds); board().ledMatrixState.animationQ.enqueue({ interval: interval, frame: () => { @@ -230,10 +248,27 @@ namespace pxsim.ImageMethods { whenDone: cb }) } + + function clampPixelBrightness(img: Image): Image { + let res = img; + if (led.displayMode() === DisplayMode.greyscale && led.brightness() < 0xff) { + res = new Image(img.width, img.data); + const b = led.brightness(); + for (let x = 0; x < res.width; ++x) { + for (let y = 0; y < 5; ++y) { + if (pixelBrightness(res, x, y) > b) { + setPixelBrightness(res, x, y, b); + } + } + } + } + return res; + } } namespace pxsim.basic { export function showNumber(x: number, interval: number) { + interval = interval >> 0; if (interval <= 0) interval = 1; let leds = createImageFromString(x.toString()); @@ -242,19 +277,21 @@ namespace pxsim.basic { } export function showString(s: string, interval: number) { + interval = interval >> 0; if (interval <= 0) interval = 1; if (s.length == 0) { clearScreen(); pause(interval * 5); + } else if (s.length > 1) { + ImageMethods.scrollImage(createImageFromString(s + " "), 1, interval); } else { - if (s.length == 1) showLeds(createImageFromString(s), 0); - else ImageMethods.scrollImage(createImageFromString(s + " "), 1, interval); + showLeds(createImageFromString(s), interval * 5); } } - export function showLeds(leds: Image, delay: number): void { - showAnimation(leds, delay); + export function showLeds(leds: Image, interval: number): void { + showAnimation(leds, interval); } export function clearScreen() { @@ -279,9 +316,10 @@ namespace pxsim.led { export function plotBrightness(x: number, y: number, brightness: number) { const state = board().ledMatrixState; - brightness = Math.max(0, Math.min(0xff, brightness)); + brightness = brightness >> 0; + brightness = Math.max(0, Math.min(led.brightness(), brightness)); if (brightness != 0 && brightness != 0xff && state.displayMode != DisplayMode.greyscale) - state.displayMode = DisplayMode.greyscale; + state.displayMode = DisplayMode.greyscale; state.image.set(x, y, brightness); runtime.queueDisplayUpdate() } @@ -300,6 +338,7 @@ namespace pxsim.led { } export function setBrightness(value: number): void { + value = value >> 0; board().ledMatrixState.brigthness = Math.max(0, Math.min(255, value)); runtime.queueDisplayUpdate() } diff --git a/sim/state/microservo.ts b/sim/state/microservo.ts new file mode 100644 index 00000000..5eb54d58 --- /dev/null +++ b/sim/state/microservo.ts @@ -0,0 +1,83 @@ +namespace pxsim.visuals { + function createMicroServoElement() { + return svg.parseString(` + + + + + + + + + + + + + + + + + `).firstElementChild as SVGGElement; + } + + export function mkMicroServoPart(xy: Coord = [0, 0]): SVGElAndSize { + return { el: createMicroServoElement(), x: xy[0], y: xy[1], w: 112.188, h: 299.674 }; + } + + export class MicroServoView implements IBoardPart { + public style: string = ""; + public overElement: SVGElement = undefined; + public element: SVGElement; + public defs: SVGElement[] = []; + public state: EdgeConnectorState; + public bus: EventBus; + private currentAngle = 0; + private targetAngle = 0; + private lastAngleTime = 0; + private pin: number; + + private crankEl: SVGGElement; + private crankTransform: string; + + public init(bus: EventBus, state: EdgeConnectorState, svgEl: SVGSVGElement, otherParams: Map) { + this.state = state; + this.pin = this.state.props.servos[ + pxsim.readPin(otherParams["name"] || otherParams["pin"]) + ]; + this.bus = bus; + this.defs = []; + this.initDom(); + this.updateState(); + } + + initDom() { + this.element = createMicroServoElement(); + this.crankEl = this.element.querySelector("#crank") as SVGGElement; + this.crankTransform = this.crankEl.getAttribute("transform"); + } + + moveToCoord(xy: visuals.Coord): void { + let [x, y] = xy; + translateEl(this.element, [x, y]) + } + updateState(): void { + this.targetAngle = 180.0 - this.state.getPin(this.pin).servoAngle; + if (this.targetAngle != this.currentAngle) { + const now = U.now(); + const cx = 56.661; + const cy = 899.475; + const speed = 300; // 0.1s/60 degree + const dt = Math.min(now - this.lastAngleTime, 50) / 1000; + const delta = this.targetAngle - this.currentAngle; + this.currentAngle += Math.min(Math.abs(delta), speed * dt) * (delta > 0 ? 1 : -1); + this.crankEl.setAttribute("transform", this.crankTransform + + ` rotate(${this.currentAngle}, ${cx}, ${cy})`) + this.lastAngleTime = now; + setTimeout(() => runtime.updateDisplay(), 20); + } + } + updateTheme(): void { + + } + } +} diff --git a/sim/state/midi.ts b/sim/state/midi.ts new file mode 100644 index 00000000..433e04ec --- /dev/null +++ b/sim/state/midi.ts @@ -0,0 +1,6 @@ +namespace pxsim.control { + export function __midiSend(data: RefBuffer) { + const b = board(); + pxsim.AudioContextManager.sendMidiMessage(data); + } +} \ No newline at end of file diff --git a/sim/state/misc.ts b/sim/state/misc.ts index c09bdfd3..c1e4a099 100644 --- a/sim/state/misc.ts +++ b/sim/state/misc.ts @@ -35,8 +35,13 @@ namespace pxsim.basic { namespace pxsim.control { export var inBackground = thread.runInBackground; + export function createBuffer(sz: number) { + return pxsim.BufferMethods.createBuffer(sz) + } + export function reset() { - U.userError("reset not implemented in simulator yet") + const cb = getResume(); + pxsim.runtime.restart(); } export function waitMicros(micros: number) { @@ -58,6 +63,13 @@ namespace pxsim.control { } export function onEvent(id: number, evid: number, handler: RefAction) { + if (id == DAL.MICROBIT_ID_BUTTON_AB) { + const b = board().buttonPairState; + if (!b.usesButtonAB) { + b.usesButtonAB = true; + runtime.queueDisplayUpdate(); + } + } pxtcore.registerWithDal(id, evid, handler) } @@ -65,6 +77,14 @@ namespace pxsim.control { // TODO mode? board().bus.queue(id, evid) } + + export function eventTimestamp() { + return board().bus.getLastEventTime() + } + + export function eventValue() { + return board().bus.getLastEventValue() + } } namespace pxsim.pxtcore { @@ -78,7 +98,12 @@ namespace pxsim.input { return runtime.runningTime(); } - export function calibrate() { + export function runningTimeMicros(): number { + return runtime.runningTimeUs(); + } + + export function calibrateCompass() { + // device calibrates... } } @@ -106,6 +131,18 @@ namespace pxsim.pins { return 0; } + export function spiFrequency(f: number): void { + // TODO + } + + export function spiFormat(bits: number, mode: number): void { + // TODO + } + + export function spiPins(mosi: number, miso: number, sck: number) { + // TODO + } + export function i2cReadBuffer(address: number, size: number, repeat?: boolean): RefBuffer { // fake reading zeros return createBuffer(size) @@ -137,7 +174,7 @@ namespace pxsim.devices { export function onSignalStrengthChanged(action: number) { // TODO } - export function signalStrength() : number { + export function signalStrength(): number { // TODO return 0; } @@ -168,25 +205,34 @@ namespace pxsim.bluetooth { export function startUartService(): void { // TODO } - export function uartWrite(s : string): void { + export function uartWriteString(s: string): void { serial.writeString(s) } + + export function uartWriteBuffer(b: RefBuffer): void { + serial.writeBuffer(b); + } + + export function uartReadBuffer(): RefBuffer { + return pins.createBuffer(0); + } + export function uartReadUntil(del: string): string { return serial.readUntil(del); } - export function onDataReceived(delimiters: string, handler: RefAction) { + export function onUartDataReceived(delimiters: string, handler: RefAction) { let b = board(); b.bus.listen(DAL.MICROBIT_ID_BLE_UART, DAL.MICROBIT_UART_S_EVT_DELIM_MATCH, handler); } - export function onBluetoothConnected(a : RefAction) { + export function onBluetoothConnected(a: RefAction) { // TODO } - export function onBluetoothDisconnected(a : RefAction) { + export function onBluetoothDisconnected(a: RefAction) { // TODO } export function advertiseUrl(url: string, power: number, connectable: boolean) { } - export function advertiseUidBuffer(nsAndInstance: Buffer, power: number, connectable: boolean) { } + export function advertiseUidBuffer(nsAndInstance: RefBuffer, power: number, connectable: boolean) { } export function stopAdvertising() { } - export function setTransmitPower(power: number) {} + export function setTransmitPower(power: number) { } } diff --git a/sim/state/neopixel.ts b/sim/state/neopixel.ts index c18d9588..e57f9a9b 100644 --- a/sim/state/neopixel.ts +++ b/sim/state/neopixel.ts @@ -1,11 +1,11 @@ namespace pxsim { - export function sendBufferAsm(buffer: Buffer, pin: DigitalPin) { + export function sendBufferAsm(buffer: RefBuffer, pin: DigitalPin) { let b = board(); if (b) { let np = b.neopixelState; if (np) { - let buf = (buffer).data; - np.updateBuffer(buf, pin); + let buf = buffer.data; + np.updateBuffer(buf as any, pin); // TODO this is wrong runtime.queueDisplayUpdate(); } } diff --git a/sim/state/radio.ts b/sim/state/radio.ts index 2b13ab4a..72edb713 100644 --- a/sim/state/radio.ts +++ b/sim/state/radio.ts @@ -6,6 +6,11 @@ namespace pxsim { time: number; } + // Extends interface in pxt-core + export interface SimulatorRadioPacketPayload { + bufferData?: Uint8Array; + } + export class RadioDatagram { datagram: PacketBuffer[] = []; lastReceived: PacketBuffer = RadioDatagram.defaultPacket(); @@ -24,8 +29,9 @@ namespace pxsim { const b = board(); Runtime.postMessage({ type: "radiopacket", - rssi: 70, // Not yet supported - serial: b.radioState.bus.transmitSerialNumber ? pxsim.control.deviceSerialNumber() : 0, + broadcast: true, + rssi: -42, // -42 is the strongest signal + serial: b.radioState.transmitSerialNumber ? pxsim.control.deviceSerialNumber() : 0, time: new Date().getTime(), payload }) @@ -42,22 +48,31 @@ namespace pxsim { rssi: -1, serial: 0, time: 0, - payload: { type: -1, groupId: 0 } + payload: { type: -1, groupId: 0, bufferData: new Uint8Array(0) } }; } } - export class RadioBus { - // uint8_t radioDefaultGroup = MICROBIT_RADIO_DEFAULT_GROUP; + export class RadioState { power = 0; transmitSerialNumber = false; datagram: RadioDatagram; + groupId: number; + band: number; - constructor(private runtime: Runtime) { + constructor(runtime: Runtime) { this.datagram = new RadioDatagram(runtime); + this.power = 6; // default value + this.groupId = 0; + this.band = 7; // https://github.com/lancaster-university/microbit-dal/blob/master/inc/core/MicroBitConfig.h#L320 + } + + public setGroup(id: number) { + this.groupId = id & 0xff; // byte only } setTransmitPower(power: number) { + power = power | 0; this.power = Math.max(0, Math.min(7, power)); } @@ -65,54 +80,33 @@ namespace pxsim { this.transmitSerialNumber = !!sn; } - broadcast(msg: number, groupId: number) { + setFrequencyBand(band: number) { + band = band | 0; + if (band < 0 || band > 83) return; + this.band = band; + } + + raiseEvent(id: number, eventid: number) { Runtime.postMessage({ type: "eventbus", - id: DAL.MES_BROADCAST_GENERAL_ID, - eventid: msg, + broadcast: true, + id, + eventid, power: this.power, - group: groupId + group: this.groupId }) } - } - export class RadioState { - bus: RadioBus; - groupId: number; - - constructor(runtime: Runtime) { - this.bus = new RadioBus(runtime); - this.groupId = 0; - } - - public setGroup(id: number) { - this.groupId = id & 0xff; // byte only - } - - public broadcast(msg: number) { - this.bus.broadcast(msg, this.groupId) - } - - public receivePacket(packet: SimulatorRadioPacketMessage) { + receivePacket(packet: SimulatorRadioPacketMessage) { if (this.groupId == packet.payload.groupId) - this.bus.datagram.queue(packet) + this.datagram.queue(packet) } } } namespace pxsim.radio { - enum PacketPayloadType { - NUMBER = 0, - VALUE = 1, - STRING = 2 - } - - export function broadcastMessage(msg: number): void { - board().radioState.broadcast(msg); - } - - export function onBroadcastMessageReceived(msg: number, handler: RefAction): void { - pxtcore.registerWithDal(DAL.MES_BROADCAST_GENERAL_ID, msg, handler); + export function raiseEvent(id: number, eventid: number): void { + board().radioState.raiseEvent(id, eventid); } export function setGroup(id: number): void { @@ -120,99 +114,34 @@ namespace pxsim.radio { } export function setTransmitPower(power: number): void { - board().radioState.bus.setTransmitPower(power); + board().radioState.setTransmitPower(power); } - export function setTransmitSerialNumber(transmit: boolean): void { - board().radioState.bus.setTransmitSerialNumber(transmit); + export function setFrequencyBand(band: number) { + board().radioState.setFrequencyBand(band); } - export function sendNumber(value: number): void { - board().radioState.bus.datagram.send({ - type: PacketPayloadType.NUMBER, + export function sendRawPacket(buf: RefBuffer) { + let cb = getResume(); + board().radioState.datagram.send({ + type: 0, groupId: board().radioState.groupId, - numberData: value, + bufferData: buf.data }); + setTimeout(cb, 1); } - export function sendString(msg: string): void { - msg = msg.substr(0, 19); - board().radioState.bus.datagram.send({ - type: PacketPayloadType.STRING, - groupId: board().radioState.groupId, - stringData: msg, - }); - } - - export function writeValueToSerial(): void { - const b = board(); - writePacketToSerial(b, b.radioState.bus.datagram.recv()) - } - - export function writeReceivedPacketToSerial(): void { - const b = board(); - writePacketToSerial(b, b.radioState.bus.datagram.lastReceived); - } - - export function sendValue(name: string, value: number) { - name = name.substr(0, 12); - const msg: number[] = []; - msg.push() - board().radioState.bus.datagram.send({ - type: PacketPayloadType.VALUE, - groupId: board().radioState.groupId, - stringData: name, - numberData: value - }); - } - - export function receiveNumber(): number { - const packet = board().radioState.bus.datagram.recv(); - return receivedNumber(); - } - - export function receiveString(): string { - const packet = board().radioState.bus.datagram.recv(); - return receivedString(); + export function readRawPacket() { + const packet = board().radioState.datagram.recv(); + return new RefBuffer(packet.payload.bufferData) } export function receivedSignalStrength(): number { - return board().radioState.bus.datagram.lastReceived.rssi; + return board().radioState.datagram.lastReceived.rssi; } export function onDataReceived(handler: RefAction): void { pxtcore.registerWithDal(DAL.MICROBIT_ID_RADIO, DAL.MICROBIT_RADIO_EVT_DATAGRAM, handler); - radio.receiveNumber(); - } - - export function receivedNumber(): number { - return board().radioState.bus.datagram.lastReceived.payload.numberData || 0; - } - - export function receivedSerial(): number { - return board().radioState.bus.datagram.lastReceived.serial; - } - - export function receivedString(): string { - return initString(board().radioState.bus.datagram.lastReceived.payload.stringData || ""); - } - - export function receivedTime(): number { - return board().radioState.bus.datagram.lastReceived.time; - } - - function writePacketToSerial(b: DalBoard, p: PacketBuffer) { - switch(p.payload.type) { - case PacketPayloadType.NUMBER: - b.writeSerial(`{"t":${p.time},"s":${p.serial},"v":${p.payload.numberData}}\r\n`) - break; - case PacketPayloadType.VALUE: - b.writeSerial(`{"t":${p.time},"s":${p.serial},"n":"${p.payload.stringData}","v":${p.payload.numberData}}\r\n`) - break; - case PacketPayloadType.STRING: - b.writeSerial(`{"t":${p.time},"s":${p.serial},"n":"${p.payload.stringData}"}\r\n`) - break; - default: - } + readRawPacket(); } } \ No newline at end of file diff --git a/sim/state/serial.ts b/sim/state/serial.ts index de7cdf6b..897436cf 100644 --- a/sim/state/serial.ts +++ b/sim/state/serial.ts @@ -28,11 +28,21 @@ namespace pxsim { } } +namespace pxsim.control { + export function __log(s: string) { + board().writeSerial(s + "\r\n"); + } +} + namespace pxsim.serial { export function writeString(s: string) { board().writeSerial(s); } + export function writeBuffer(buf: RefBuffer) { + // TODO + } + export function readUntil(del: string): string { return readString(); } @@ -53,4 +63,18 @@ namespace pxsim.serial { export function redirectToUSB() { // TODO } + + export function setRxBufferSize(size: number) { + // TODO + } + + export function setTxBufferSize(size: number) { + // TODO + } + + export function readBuffer(length: number) { + if (length <= 0) + length = 64; + return pins.createBuffer(length); + } } \ No newline at end of file diff --git a/sim/tsconfig.json b/sim/tsconfig.json index 007366f2..98cd3cb1 100644 --- a/sim/tsconfig.json +++ b/sim/tsconfig.json @@ -7,6 +7,9 @@ "out": "../built/sim.js", "rootDir": ".", "newLine": "LF", - "sourceMap": false + "sourceMap": false, + "lib": ["dom", "dom.iterable", "scripthost", "es6"], + "types": ["jquery", "bluebird"], + "typeRoots": ["../node_modules/@types"] } } diff --git a/sim/visuals/boardview.ts b/sim/visuals/boardview.ts index 3691f9db..2c09405a 100644 --- a/sim/visuals/boardview.ts +++ b/sim/visuals/boardview.ts @@ -7,4 +7,4 @@ namespace pxsim.visuals { wireframe: opts.wireframe, }); } -} \ No newline at end of file +} diff --git a/sim/visuals/ledmatrix.ts b/sim/visuals/ledmatrix.ts index 8614bb88..b58eaf98 100644 --- a/sim/visuals/ledmatrix.ts +++ b/sim/visuals/ledmatrix.ts @@ -1,4 +1,3 @@ -/// /// namespace pxsim.visuals { @@ -40,7 +39,7 @@ namespace pxsim.visuals { svg.fills(result.ledsOuter, defaultLedMatrixTheme.ledOff); //turn off LEDs - result.leds.forEach(l => (l).style.opacity = 0 + ""); + result.leds.forEach(l => (l).style.opacity = 0 + ""); return result; } @@ -103,7 +102,7 @@ namespace pxsim.visuals { public updateState() { if (this.state.disabled) { this.leds.forEach((led, i) => { - let sel = (led) + let sel = (led) sel.style.opacity = 0 + ""; }); return; @@ -112,7 +111,7 @@ namespace pxsim.visuals { const bw = this.state.displayMode == pxsim.DisplayMode.bw const img = this.state.image; this.leds.forEach((led, i) => { - let sel = (led) + let sel = (led) let dx = i % this.DRAW_SIZE; let dy = (i - dx) / this.DRAW_SIZE; if (dx < this.ACTIVE_SIZE && dy < this.ACTIVE_SIZE) { diff --git a/sim/visuals/microbit.ts b/sim/visuals/microbit.ts index 781bf0cd..f9dcb3b3 100644 --- a/sim/visuals/microbit.ts +++ b/sim/visuals/microbit.ts @@ -1059,7 +1059,7 @@ namespace pxsim.visuals { constructor(public props: IBoardProps) { this.buildDom(); if (props && props.wireframe) - svg.addClass(this.element, "sim-wireframe"); + U.addClass(this.element, "sim-wireframe"); if (props && props.theme) this.updateTheme(); @@ -1133,15 +1133,25 @@ namespace pxsim.visuals { if (state.ledMatrixState.disabled) { this.leds.forEach((led, i) => { - const sel = (led) + const sel = (led) sel.style.opacity = "0"; }) } else { const bw = state.ledMatrixState.displayMode == pxsim.DisplayMode.bw const img = state.ledMatrixState.image; + const br = state.ledMatrixState.brigthness != undefined ? state.ledMatrixState.brigthness : 255; this.leds.forEach((led, i) => { - const sel = (led) - sel.style.opacity = ((bw ? img.data[i] > 0 ? 255 : 0 : img.data[i]) / 255.0) + ""; + const sel = (led) + let imgbr = bw ? (img.data[i] > 0 ? br : 0) : img.data[i]; + // correct brightness + const opacity = imgbr > 0 ? imgbr / 255 * 155 + 100 : 0; + const transfrom = imgbr > 0 ? imgbr / 255 * 0.4 + 0.6 : 0; + sel.style.opacity = (opacity / 255) + ""; + if (transfrom > 0) { + (sel.style as any).transformBox = 'fill-box'; + sel.style.transformOrigin = '50% 50%'; + sel.style.transform = `scale(${transfrom})`; + } }) } this.updatePins(); @@ -1154,8 +1164,8 @@ namespace pxsim.visuals { this.updateRgbLed(); this.updateSpeaker(); - if (!runtime || runtime.dead) svg.addClass(this.element, "grayscale"); - else svg.removeClass(this.element, "grayscale"); + if (!runtime || runtime.dead) U.addClass(this.element, "grayscale"); + else U.removeClass(this.element, "grayscale"); } private updateRgbLed() { @@ -1445,7 +1455,7 @@ namespace pxsim.visuals { this.pins = pinNames.map(n => { let p = this.element.getElementById(n) as SVGElement; if(!p) console.log("missing "+n); - svg.addClass(p, "sim-pin"); + U.addClass(p, "sim-pin"); return p; }); @@ -1463,9 +1473,9 @@ namespace pxsim.visuals { // BTN A, B const btnids = ["BTN_A", "BTN_B"]; this.buttonsOuter = btnids.map(n => this.element.getElementById(n + "_BOX") as SVGElement); - this.buttonsOuter.forEach(b => svg.addClass(b, "sim-button-outer")); + this.buttonsOuter.forEach(b => U.addClass(b, "sim-button-outer")); this.buttons = btnids.map(n => this.element.getElementById(n) as SVGElement); - this.buttons.forEach(b => svg.addClass(b, "sim-button")); + this.buttons.forEach(b => U.addClass(b, "sim-button")); // BTN A+B const outerBtn = (left: number, top: number) => { @@ -1581,7 +1591,7 @@ namespace pxsim.visuals { let state = this.board; let pin = state.edgeConnectorState.pins[index]; let svgpin = this.pins[index]; - svg.addClass(svgpin, "touched"); + U.addClass(svgpin, "touched"); if (pin.mode & PinFlags.Input) { let cursor = svg.cursorPoint(pt, this.element, ev); let v = (400 - cursor.y) / 40 * 1023 @@ -1594,17 +1604,18 @@ namespace pxsim.visuals { let state = this.board; let pin = state.edgeConnectorState.pins[index]; let svgpin = this.pins[index]; - svg.removeClass(svgpin, "touched"); + U.removeClass(svgpin, "touched"); this.updatePin(pin, index); return false; }); }) this.pins.slice(0, 3).forEach((btn, index) => { - btn.addEventListener(pointerEvents.down, ev => { + pointerEvents.down.forEach(evid => btn.addEventListener(evid, ev => { let state = this.board; state.edgeConnectorState.pins[index].touched = true; this.updatePin(state.edgeConnectorState.pins[index], index); - }) + this.board.bus.queue(state.edgeConnectorState.pins[index].id, DAL.MICROBIT_BUTTON_EVT_DOWN); + })); btn.addEventListener(pointerEvents.leave, ev => { let state = this.board; state.edgeConnectorState.pins[index].touched = false; @@ -1622,11 +1633,12 @@ namespace pxsim.visuals { let bpState = this.board.buttonPairState; let stateButtons = [bpState.aBtn, bpState.bBtn, bpState.abBtn]; this.buttonsOuter.slice(0, 2).forEach((btn, index) => { - btn.addEventListener(pointerEvents.down, ev => { + pointerEvents.down.forEach(evid => btn.addEventListener(evid, ev => { let state = this.board; stateButtons[index].pressed = true; svg.fill(this.buttons[index], this.props.theme.buttonDown); - }) + this.board.bus.queue(stateButtons[index].id, DAL.MICROBIT_BUTTON_EVT_DOWN); + })); btn.addEventListener(pointerEvents.leave, ev => { let state = this.board; stateButtons[index].pressed = false; @@ -1640,7 +1652,7 @@ namespace pxsim.visuals { this.board.bus.queue(stateButtons[index].id, DAL.MICROBIT_BUTTON_EVT_CLICK); }) }) - this.buttonsOuter[2].addEventListener(pointerEvents.down, ev => { + pointerEvents.down.forEach(evid => this.buttonsOuter[2].addEventListener(evid, ev => { let state = this.board; stateButtons[0].pressed = true; stateButtons[1].pressed = true; @@ -1648,7 +1660,8 @@ namespace pxsim.visuals { svg.fill(this.buttons[0], this.props.theme.buttonDown); svg.fill(this.buttons[1], this.props.theme.buttonDown); svg.fill(this.buttons[2], this.props.theme.buttonDown); - }) + this.board.bus.queue(stateButtons[2].id, DAL.MICROBIT_BUTTON_EVT_DOWN); + })); this.buttonsOuter[2].addEventListener(pointerEvents.leave, ev => { let state = this.board; stateButtons[0].pressed = false; @@ -1672,4 +1685,4 @@ namespace pxsim.visuals { }) } } -} \ No newline at end of file +} diff --git a/sim/visuals/neopixel.ts b/sim/visuals/neopixel.ts index 1407359e..6e3ff3a2 100644 --- a/sim/visuals/neopixel.ts +++ b/sim/visuals/neopixel.ts @@ -1,6 +1,5 @@ /// /// -/// /// namespace pxsim.visuals { @@ -133,7 +132,7 @@ namespace pxsim.visuals { } //show the canvas if it's hidden - svg.removeClass(this.background, "hidden"); + U.removeClass(this.background, "hidden"); //resize if necessary let [first, last] = [this.pixels[0], this.pixels[this.pixels.length - 1]] @@ -179,6 +178,7 @@ namespace pxsim.visuals { .sim-neopixel-canvas-parent:hover { transform-origin: center; transform: scale(4) translateY(-60px); + -moz-transform: scale(4) translateY(-220px); } .sim-neopixel-canvas .hidden { visibility:hidden; @@ -239,4 +239,4 @@ namespace pxsim.visuals { } public updateTheme(): void { } } -} \ No newline at end of file +} diff --git a/targetconfig.json b/targetconfig.json index db4827f4..61026805 100644 --- a/targetconfig.json +++ b/targetconfig.json @@ -1,27 +1,231 @@ { "packages": { - "approvedOrgs": [ - "Microsoft", - "microbit-foundation", - "calliope-mini", - "ubirch" - ], "approvedRepos": [ - "CoderDojoOlney/pxt-olney", + "Microsoft/pxt-neopixel", + "Microsoft/pxt-microturtle", + "Microsoft/pxt-sonar", + "Microsoft/pxt-hacking-stem", + "Microsoft/pxt-bluetooth-temperature-sensor", + "Microsoft/pxt-bluetooth-midi", + "Microsoft/pxt-max6675", + "Microsoft/pxt-midi", + "Microsoft/pxt-radio-blockchain", + "Microsoft/pxt-bluetooth-max6675", + "Microsoft/pxt-filesystem", + "Microsoft/pxt-ws2812b", + "MKleinSB/pxt-foldio", + "MKleinSB/pxt-remember-int", + "MKleinSB/pxt-BME680", + "MKleinSB/pxt-automationbit-calliope", + "MKleinSB/pxt-kitronik-robotics-board-calliope", + "MKleinSB/pxt-kitronik-zip-tile-calliope", + "MKleinSB/pxt-calliope-esp", + "MKleinSB/pxt-calliope-modem", + "MKleinSB/pxt-fischertechnik-calliope", + "MKleinSB/pxt-ft-fototransistor-calliope", + "MKleinSB/pxt-thumbjoystick-calliope", + "MKleinSB/pxt-envirobit", + "MKleinSB/pxt-makerbit-ultrasonic-calliope", + "MKleinSB/pxt-makerbit-motor-calliope", + "MKleinSB/pxt-bc95", + "MKleinSB/pxt-kitronik-zip-64", + "MKleinSB/pxt-makerbit-touch", + "MKleinSB/pxt-iot-environment-kit", + "MKleinSB/pxt-serial-rb", + "MKleinSB/pxt-ds18b20-calliope", + "MKleinSB/pxt-mpr121", + "MKleinSB/pxt-graphs", + "MKleinSB/pxt-IR-Calliope", + "MKleinSB/pxt-Seeed-Temperatursensor", + "MKleinSB/pxt-MCP23017", + "MKleinSB/ScrollText", + "MKleinSB/pxt-calliope-oled96", + "KitronikLtd/pxt-kitronik-servo-lite", + "KitronikLtd/pxt-kitronik-motor-driver", + "KitronikLtd/pxt-kitronik-I2C-16-servo", + "KitronikLtd/pxt-kitronik-stopbit", + "KitronikLtd/pxt-kitronik-lampbit", + "KitronikLtd/pxt-kitronik-klimate", + "KitronikLtd/pxt-kitronik-zip-64", + "KitronikLtd/pxt-kitronik-rtc", + "KitronikLtd/pxt-kitronik-game-controller", + "KitronikLtd/pxt-kitronik-robotics-board", + "KitronikLtd/pxt-kitronik-klef-piano", + "Seeed-Studio/pxt-grove", + "Seeed-Studio/pxt-grove-zero-for-microbit", + "Tinkertanker/pxt-ir-receiver", + "Tinkertanker/pxt-iot-environment-kit", + "Tinkertanker/pxt-motorbit", + "Tinkertanker/pxt-realtimeclock-ds1307", + "Tinkertanker/pxt-tinkercademy-tinker-kit", + "Tinkertanker/pxt-rotary-encoder-ky040", + "Tinkertanker/pxt-tinkercademy-microbot", "Tinkertanker/pxt-oled-ssd1306", - "Seeed-Studio/pxt-grove" + "Tinkertanker/pxt-range-vl53l0x", + "Tinkertanker/pxt-continuous-servo", + "Tinkertanker/pxt-joystickbit", + "Tinkertanker/pxt-robit", + "Tinkertanker/pxt-smarthome", + "Tinkertanker/microDriver_SHT2x", + "Tinkertanker/pxt-ringbitcar", + "Tinkertanker/uDriver_PCA9585", + "Tinkertanker/pxt-alphanumeric-ht16k33", + "CoderDojoOlney/pxt-olney", + "PaulDFoster/pxt-microbit-GY521", + "chevyng/pxt-ucl-junkrobot", + "srs/pxt-bitbot", + "sparkfun/pxt-gamer-bit", + "sparkfun/pxt-moto-bit", + "sparkfun/pxt-weather-bit", + "sparkfun/pxt-gator-environment", + "minodekit/pxt-minode", + "LaboratoryForPlayfulComputation/pxt-BlockyTalkyBLE", + "mbitfun/pxt-katakana", + "jdarling/pxt-pca9685", + "MUSELAB/pxt-wifi-shield", + "kittenbot/pxt-robotbit", + "pizayanz/pxt-linebeacon", + "sunfounder/pxt-sloth", + "4tronix/BitBot", + "pimoroni/pxt-scrollbit", + "emwta/pxt-iBit", + "vengit/pxt-sbrick", + "pimoroni/pxt-envirobit", + "Annikken/pxt-Andee", + "1010Technologies/pxt-makerbit", + "1010Technologies/pxt-makerbit-motor", + "1010Technologies/pxt-makerbit-mp3", + "1010Technologies/pxt-makerbit-ultrasonic", + "1010Technologies/pxt-makerbit-lcd1602", + "1010Technologies/pxt-makerbit-ir-receiver", + "1010Technologies/pxt-makerbit-touch", + "1010Technologies/pxt-makerbit-pins", + "pimoroni/pxt-automationbit", + "k8robotics/pxt-k8", + "dexterind/pxt-giggle", + "dexterind/pxt-gigglebot", + "Imagimaker/pxt-imagimaker", + "sparkfun/pxt-gator-light", + "sparkfun/pxt-gator-temp", + "4tronix/Robobit", + "alsrobot-microbit-makecode-packages/ALSRobotJoyBit", + "alsrobot-microbit-makecode-packages/ALSRobotKeyboard", + "alsrobot-microbit-makecode-packages/ALSRobotElectromagnet", + "alsrobot-microbit-makecode-packages/CooCoo", + "alsrobot-microbit-makecode-packages/CruiseBit", + "makecode-extensions/i2cLCD1602", + "makecode-extensions/OLED12864_I2C", + "makecode-extensions/DS1307", + "makecode-extensions/ScrollText", + "makecode-extensions/WhaleySansFont", + "makecode-extensions/BMP280", + "makecode-extensions/TM1637", + "makecode-extensions/BMP180", + "makecode-extensions/BH1750", + "makecode-extensions/APDS9930", + "makecode-extensions/AT24XX", + "makecode-extensions/BME280", + "makecode-extensions/TM1650", + "makecode-extensions/NTC", + "makecode-extensions/DS1302", + "BirdBrainTechnologies/pxt-hummingbird-bit", + "PiSupply/pxt-iot-lora-node", + "PiSupply/pxt-tinker-kit", + "PiSupply/pxt-bitbuggy", + "PiSupply/pxt-oled-ssd1306", + "pimoroni/pxt-touchbit", + "4tronix/cubebit", + "4tronix/BitCommander", + "alankrantas/pxt-MAX7219_8x8", + "ReRoKit/pxt-reromicro", + "51bit/ColorBit", + "51bit/SFC", + "51bit/SmartTools", + "alankrantas/pxt-MAX7219_8x8", + "KitronikLtd/pxt-kitronik-zip-tile", + "lwchkg/pxt-proportional-font", + "jcubuntu/pxt-iKB1", + "KitronikLtd/pxt-kitronik-accessbit", + "kaku111/pxt-tobbieII", + "alankrantas/pxt-DHT11_DHT22", + "cgs-matthew-pham/pxt-hitechnic-irseeker-v2", + "Freenove/Makecode-Extension-Rover", + "letstalkscience/pxt-cozir", + "e-radionicacom/pxt-wifi", + "monkmakes/pxt-sensor", + "beyond-coding-tw/pxt-nexusbot", + "elecfreaks/pxt-cutebot", + "KitronikLtd/pxt-kitronik-fischertechnik", + "keigan-motor/pxt-KeiganMotor", + "KitronikLtd/pxt-kitronik-klip-motor", + "alankrantas/pxt-ESP8266_ThingSpeak", + "KitronikLtd/pxt-kitronik-viewtext32", + "plenprojectcompany/pxt-PLENbit", + "4tronix/MiniBit", + "elecfreaks/pxt-wukong", + "sparkfun/pxt-gator-particle", + "sparkfun/pxt-gator-soil", + "sparkfun/pxt-gator-microphone", + "rebeccaclavier/pxt-bmp280", + "xinabox/pxt-SW01", + "xinabox/pxt-OD01", + "51bit/dfplayermini", + "makecode-extensions/STTS751", + "makecode-extensions/LSM6DSO", + "makecode-extensions/LPS22", + "makecode-extensions/LIS2DW12", + "makecode-extensions/LIS2MDL", + "makecode-extensions/HTS221", + "assirati/pxt-inventura", + "Veilkrand/pxt-RobotCar", + "4tronix/DriveBit", + "Freenove/Makecode-Extension-Starter-Kit" ], "preferredRepos": [ "Microsoft/pxt-neopixel", + "calliope-edu/pxt-grove", + "tinysuperlab/motionkit", + "tinysuperlab/touchkit", "Microsoft/pxt-microturtle", - "calliope-mini/pxt-calliope-modem", - "calliope-mini/pxt-calliope-bc95", - "calliope-mini/pxt-calliope-esp", - "calliope-mini/pxt-calliope-bunt", - "calliope-mini/pxt-isl29125", - "ubirch/pxt-ubirch", - "Tinkertanker/pxt-oled-ssd1306", - "Seeed-Studio/pxt-grove" + "MKleinSB/pxt-OLED-SSD1306", + "MKleinSB/pxt-iot-lora-node", + "kittenbot/pxt-robotbit", + "MKleinSB/pxt-foldio" ] + }, + "languages": [ + "en", + "ar", + "cs", + "da", + "de", + "el", + "es-ES", + "fi", + "fr", + "hu", + "it", + "ja", + "ko", + "nl", + "no", + "pt-BR", + "pt-PT", + "ru", + "si-LK", + "sk", + "sv-SE", + "tr", + "uk", + "zh-CN", + "zh-TW" + ], + "galleries": { + "First Steps": "calliope/firststeps", + "Turorials": "calliope/tutorials", + "Calliope Links": "calliope/links" + }, + "electronManifest": { + "latest": "v2.0.3" } } \ No newline at end of file diff --git a/tests/hat-game.ts b/tests/hat-game.ts new file mode 100644 index 00000000..751113f2 --- /dev/null +++ b/tests/hat-game.ts @@ -0,0 +1,232 @@ +let correctBall: number +let ballRevealing: boolean +let cupSelect: string +let index: number +let score: number +let level: number +let swapSpeed: number + +initializeGame() +input.onButtonPressed(Button.A, () => { + if (ballRevealing) { + index = index + 1 + if (index > 2) { + index = 0 + } + basic.showString(cupSelect[index], 150) + } +}) +input.onButtonPressed(Button.B, () => { + if (ballRevealing) { + ballRevealing = false + if (correctBall == index) { + score = score + level + images.createImage(` + . . . . . + . . . . # + . . . # . + # . # . . + . # . . . + `).showImage(0) + basic.pause(1000) + basic.showString("+".concat(level.toString()), 150) + basic.pause(1000) + } else { + images.createImage(` + # . . . # + . # . # . + . . # . . + . # . # . + # . . . # + `).showImage(0) + basic.pause(1000) + basic.clearScreen() + revealBall(correctBall) + basic.pause(1000) + } + } + level = level + 1 + if (level == 4) { + basic.showString("FINAL SCORE:", 75) + basic.showNumber(score, 150) + } else { + playLevel(level) + } +}) +playLevel(1) + +function revealBall(p: number) { + let xCoordinate = 2 * p + for (let j = 0; j < 3; j++) { + led.plot(j * 2, 2) + } + for (let i = 0; i < 3; i++) { + led.unplot(xCoordinate, 2) + led.plot(xCoordinate, 1) + basic.pause(100) + led.unplot(xCoordinate, 1) + led.plot(xCoordinate, 0) + basic.pause(200) + led.unplot(xCoordinate, 0) + led.plot(xCoordinate, 1) + basic.pause(100) + led.unplot(xCoordinate, 1) + led.plot(xCoordinate, 2) + basic.pause(75) + } + basic.pause(1000) +} + +function initializeGame() { + ballRevealing = false + level = 1 + score = 0 + cupSelect = "LMR" +} + +function swapCups(cup_1: number, cup_2: number, pauseDifficulty: number) { + let cup_1X = 2 * cup_1 + let cup_2X = 2 * cup_2 + let cupXAverage = (cup_1X + cup_2X) / 2 + led.unplot(cup_1X, 2) + led.unplot(cup_2X, 2) + led.plot(cup_1X, 3) + led.plot(cup_2X, 1) + basic.pause(pauseDifficulty) + led.unplot(cup_1X, 3) + led.unplot(cup_2X, 1) + led.plot(cup_1X, 4) + led.plot(cup_2X, 0) + basic.pause(pauseDifficulty) + led.unplot(cup_1X, 4) + led.unplot(cup_2X, 0) + if (cupXAverage == 2) { + led.plot((cupXAverage + cup_1X) / 2, 4) + led.plot((cupXAverage + cup_2X) / 2, 0) + basic.pause(pauseDifficulty) + led.unplot((cupXAverage + cup_1X) / 2, 4) + led.unplot((cupXAverage + cup_2X) / 2, 0) + } + led.plot(cupXAverage, 4) + led.plot(cupXAverage, 0) + basic.pause(pauseDifficulty) + led.unplot(cupXAverage, 4) + led.unplot(cupXAverage, 0) + if (cupXAverage == 2) { + led.plot((cupXAverage + cup_2X) / 2, 4) + led.plot((cupXAverage + cup_1X) / 2, 0) + basic.pause(pauseDifficulty) + led.unplot((cupXAverage + cup_2X) / 2, 4) + led.unplot((cupXAverage + cup_1X) / 2, 0) + } + led.plot(cup_2X, 4) + led.plot(cup_1X, 0) + basic.pause(pauseDifficulty) + led.unplot(cup_2X, 4) + led.unplot(cup_1X, 0) + led.plot(cup_2X, 3) + led.plot(cup_1X, 1) + basic.pause(pauseDifficulty) + led.unplot(cup_2X, 3) + led.unplot(cup_1X, 1) + led.plot(cup_2X, 2) + led.plot(cup_1X, 2) + basic.pause(pauseDifficulty) + if (correctBall == cup_1) { + correctBall = cup_2 + } else if (correctBall == cup_2) { + correctBall = cup_1 + } +} + +function swapFake(cup_1: number, cup_2: number, pauseDifficulty: number) { + let cup_1X = 2 * cup_1 + let cup_2X = 2 * cup_2 + let cupXAverage = (cup_1X + cup_2X) / 2 + led.unplot(cup_1X, 2) + led.unplot(cup_2X, 2) + led.plot(cup_1X, 3) + led.plot(cup_2X, 1) + basic.pause(pauseDifficulty) + led.unplot(cup_1X, 3) + led.unplot(cup_2X, 1) + led.plot(cup_1X, 4) + led.plot(cup_2X, 0) + basic.pause(pauseDifficulty) + led.unplot(cup_1X, 4) + led.unplot(cup_2X, 0) + if (cupXAverage == 2) { + led.plot((cupXAverage + cup_1X) / 2, 4) + led.plot((cupXAverage + cup_2X) / 2, 0) + basic.pause(pauseDifficulty) + led.unplot((cupXAverage + cup_1X) / 2, 4) + led.unplot((cupXAverage + cup_2X) / 2, 0) + } + led.plot(cupXAverage, 4) + led.plot(cupXAverage, 0) + basic.pause(pauseDifficulty) + led.unplot(cupXAverage, 4) + led.unplot(cupXAverage, 0) + if (cupXAverage == 2) { + led.plot((cupXAverage + cup_1X) / 2, 4) + led.plot((cupXAverage + cup_2X) / 2, 0) + basic.pause(pauseDifficulty) + led.unplot((cupXAverage + cup_1X) / 2, 4) + led.unplot((cupXAverage + cup_2X) / 2, 0) + } + led.plot(cup_1X, 4) + led.plot(cup_2X, 0) + basic.pause(pauseDifficulty) + led.unplot(cup_1X, 4) + led.unplot(cup_2X, 0) + led.plot(cup_1X, 3) + led.plot(cup_2X, 1) + basic.pause(pauseDifficulty) + led.unplot(cup_1X, 3) + led.unplot(cup_2X, 1) + led.plot(cup_1X, 2) + led.plot(cup_2X, 2) + basic.pause(pauseDifficulty) +} + +function playLevel(level1: number) { + basic.showNumber(level, 150) + basic.pause(3000) + basic.clearScreen() + for (let i = 0; i < 3; i++) { + led.plot(2 * i, 2) + } + basic.pause(1000) + correctBall = Math.randomInt(3) + revealBall(correctBall) + basic.pause(1000) + let swaps = 5 + 10 * level1 + if (level1 == 1) { + swapSpeed = 80 + } else if (level1 == 2) { + swapSpeed = 40 + } else { + swapSpeed = 20 + } + for (let i1 = 0; i1 < swaps; i1++) { + let swapType = Math.randomInt(3) + let not = Math.randomInt(3) + if (swapType < 2) { + let swapOrientation = Math.randomInt(2) + if (swapOrientation == 0) { + swapCups((not + 1) % 3, (not + 2) % 3, swapSpeed) + } else { + swapCups((not + 2) % 3, (not + 1) % 3, swapSpeed) + } + } else { + let swapOrientation1 = Math.randomInt(2) + if (swapOrientation1 == 0) { + swapFake((not + 1) % 3, (not + 2) % 3, swapSpeed) + } else { + swapFake((not + 2) % 3, (not + 1) % 3, swapSpeed) + } + } + } + index = -1 + ballRevealing = true +} diff --git a/tests/i2c.ts b/tests/i2c.ts index d56d2d6b..f106621f 100644 --- a/tests/i2c.ts +++ b/tests/i2c.ts @@ -1,4 +1,6 @@ + let item = pins.i2cReadNumber(123, NumberFormat.Int8LE) pins.i2cWriteNumber(123, 0, NumberFormat.Int8LE) -let item = pins.i2cReadNumber(123, NumberFormat.Int8LE, true) -pins.i2cWriteNumber(123, 0, NumberFormat.Int8LE, true) \ No newline at end of file + +let item2 = pins.i2cReadNumber(123, NumberFormat.Int8LE, true) +pins.i2cWriteNumber(123, 0, NumberFormat.Int8LE, true) diff --git a/tests/import/microbit-blocks.hex b/tests/import/microbit-blocks.hex index 3e2802bf..721edc35 100644 --- a/tests/import/microbit-blocks.hex +++ b/tests/import/microbit-blocks.hex @@ -11908,62 +11908,111 @@ :10071000F19501004198010039B1010099B901003A :10072000D5C901009D26020061270200C180010099 :10073000708E3B92C615A841C49866C975EE519754 -:100740002D0CF6CB4FCF31AA3852319F38B256E537 +:100740002D0CF6CB4FCF31AA187FF87FFC58A9E9C2 :100750000000000000000000000000000000000099 -:1007600000B5002001B4002001B4002001B4002035 -:1007700000028C30024602BC01BCE8F745FC01B423 -:10078000E8F7CAFC01BCF9F731FA0098F9F72EFA3C -:1007900001B000BD00B5002001B4069801B4069870 -:1007A000014601BCF8F759FE01B4039801B405985D -:1007B000014601BCF8F751FE014601BCF8F753FEB3 -:1007C00001B4059801B40798014601BCF8F745FE4D -:1007D000014601BCF8F743FE01B40498014601BC90 -:1007E000F8F739FE0090FFE7009801B000BD00B5B2 -:1007F000002001B4002000900298002802D0FF20C1 -:100800000090FFE7059801B4F9F7C9F9059801B41C -:10081000059801B40398034604BC02BC0098F9F79C -:100820000AF901BCF9F7E2F90598F9F7DFF901B027 -:1008300000BD00B5002001B40020E8F77DFB00906A -:10084000FFE7009801B000BDFFFF000020B50D4696 -:1008500000200002A83001B40120000290300146BF -:1008600001BCE8F70FFA00200002B83001B4012003 -:1008700000029030014601BCE8F704FA20BD0000F8 -:10088000FFFF05000500000000000000010001005E -:100890000000000000000000000000010101002A2B -:1008A000FFFF050005000000000000000000000040 -:1008B0000000000000000000000000000000002A0E -:1008C00041140E2FB82FA2BB4C00A3010000000062 -:1008D0007B22636F6D7072657373696F6E223A224B -:1008E0004C5A4D41222C2268656164657253697AC5 -:1008F00065223A3133392C227465787453697A65EC -:10090000223A323439342C226E616D65223A2262E9 -:100910006C6F636B73626C696E6B227D5D0000802F -:1009200000490A000000000000003D888867041CA0 -:10093000BCC1C8A25578869B4D69261C354501422D -:100940001948E37B0692B2DBE3A99A218E18EFA542 -:100950006421FF3A50DF5CB84D25B831BC1D9BD0F7 -:10096000A3720BD23F36166C9FFADA84711D2EB338 -:100970003291D1DEB646B0BE0FFADE6FD7AD7C1134 -:10098000573353851403078AD6AEE9A5C8D021B2E0 -:100990007FFAB45E1D9AF8C10C1AEF12B167A5C2B6 -:1009A000329D2DC02570F67BAF4E1FC2923CE042B7 -:1009B00028E478417276160D1F06CE6E0CCBD84C0B -:1009C000B456FF79CC0DE99E98FE0D65BED6F7842E -:1009D000890D2B69552360DED35DCD22F579D8E4EE -:1009E000F214F5717F1C2CEF0D59E583D995AC807D -:1009F0000624B660B3E376A4C5A4C62BC0B1766066 -:100A00005B5E6DBBD94336CEF28C58753EF5E6176A -:100A10000D454E5EA91A60E7F9BAA6413CFDB93210 -:100A2000CC8DC16D25BCBA7ECF28A19D88036FAD4A -:100A30008EF21F6085E68BBD74D011870E15C5320E -:100A4000CAB0F268C6FF6A8E3DB568FF545C98A5CF -:100A5000041DFD9090BB3978F3995097661EE126EE -:100A60000993D095AB665AE4626AC471DC13A6D4CC -:100A700012F078262A98D778E53BE920E252773DB4 -:100A8000206C0C9FA0E8589826BD5F95814AC5BE92 -:100A90007BC997717460085C806C1CD9B85CCD33DD -:100AA0000016DD6FD865555605505938E15B941135 -:100AB000D2FAC2F686783310D2E2FF86A151000046 +:1007600000B5002001B401B401B401B401B401200A +:1007700001B4002001B4002001B400200002F630D2 +:10078000024602BC01BCE8F73FFC014601BC02B4D2 +:10079000F9F7B0FC01BCF9F729FA022001B40020F6 +:1007A00001B4002001B4012000021A30024602BC4C +:1007B00001BCE8F729FC014601BC02B4F9F79AFC38 +:1007C00001BCF9F713FA002001B4002001B40120A4 +:1007D00000024030024602BC01BCE8F715FC01B43F +:1007E000E8F79AFC01BCF9F701FA02209621E7F735 +:1007F00021FF01200002483001B4012000029030A6 +:10080000014601BCE8F73EFA012000025830E8F743 +:10081000CDF801B4962001460098F9F72FF901BCF4 +:10082000F9F7E4F90120E7F73FFEE7F785FDE8F780 +:1008300065FAE7F7AFFE0020E7F71CFEE7F784FD57 +:100840000020E7F7F9FD0020E7F714FE0020E7F7A6 +:1008500083FD0098F9F7CAF90298F9F7C7F90498E7 +:10086000F9F7C4F905B000BD00B5002001B4069841 +:1008700001B40698014601BCF8F7EFFD01B40398F6 +:1008800001B40598014601BCF8F7E7FD014601BC3B +:10089000F8F7E9FD01B4059801B40798014601BCD9 +:1008A000F8F7DBFD014601BCF8F7D9FD01B4049867 +:1008B000014601BCF8F7CFFD0090FFE7009801B0BA +:1008C00000BD00B5002001B400200090029800286F +:1008D00002D0FF200090FFE7059801B4F9F75FF917 +:1008E000059801B4059801B40398034604BC02BC02 +:1008F0000098F9F7A0F801BCF9F778F90598F9F72D +:1009000075F901B000BD00B5002001B40020E8F782 +:1009100013FB0090FFE7009801B000BDFFFF00004F +:1009200020B50D46002001B401B404200190002040 +:100930000090009801B40298014601BCF8F767FDE9 +:10094000002805D000980121F8F785FD0090F0E718 +:1009500000200021F8F75BFD002800D0FFE702B07F +:1009600020BD0000FFFF000020B50D46002001B4AF +:1009700001B40120002819D004200121F8F76BFDF3 +:10098000019000200090009801B40298014601BC3B +:10099000F8F73DFD002805D000980121F8F75BFD30 +:1009A0000090F0E71420E7F79BFDE2E702B020BDDE +:1009B000FFFF000020B50D466420E7F791FD20BD44 +:1009C000FFFF05000500000000000000010001001D +:1009D0000000000000010000000100010101002AE8 +:1009E000FFFF060048656C6C6F21000000000000EE +:1009F00041140E2FB82FA2BB55006F03000000005A +:100A00007B22636F6D7072657373696F6E223A2219 +:100A10004C5A4D41222C2268656164657253697A93 +:100A200065223A3133352C227465787453697A65BE +:100A3000223A343236362C226E616D65223A2261BA +:100A400077652D696E73706972696E672073637262 +:100A5000697074227D5D000080003111000000008B +:100A60000000003D888867041CBCC1C8A255788678 +:100A70009B4D69261C354501421948E37B0692B21D +:100A8000DBE3A99A218E18EFA56421FF3A50DF5CC1 +:100A9000B84D25B831BC1D9BD0A3720BD23F361682 +:100AA0006C9FFADA84711D2EC9AC893737C3C8E24E +:100AB0003144571FA844D7A3963E762405463739BC +:100AC000562C2741749E7ADF8947F2C0F16D27E6E4 +:100AD000671D21D7B68962CD4A32EB0C6D831DCEDE +:100AE000D938679D3E575063D676C5D1AD67714AF8 +:100AF000DF5E908FB74BF1BA71BE31AF0D068F211B +:100B000042E1428B1A26AEB037DFB75E85844F6F65 +:100B10007EFD07E78A8E10F0509394D2D3D10F89CF +:100B200079E24994B05EC5B4191F8F8732BA2EADF1 +:100B3000BDA33AEA6B799E8F238650EED8A213129A +:100B40004CE8DBDF1CBC54075FAB965AB71F196437 +:100B500057356BE317D9558961C31B5E7A253D8BE9 +:100B6000101FCAEA6E9334AFDEB378209D13B0B283 +:100B7000BBD03BC203BE98A78036163F9B529787D7 +:100B800047E2EBB8DB41A6C2DE8D0437572CBDC867 +:100B900070C5D57E332A3633384DAC966B5EE0F89F +:100BA0001A4FFBEE3BD5FE46C1FF358742209871B8 +:100BB000585520F96EAAEF9324E9B1252895D54719 +:100BC0006CFC464A13EB3A3899E7D46BA3C2027B1C +:100BD0008A502E8AA3F91A7AFD6DD225F44D72102F +:100BE00013FB3F888E41786D06AA9C6CBC12DB4DCE +:100BF000FCEAB9619A1C30A75D2426231876ED041F +:100C0000E1F6A1976F1202A06C6DA23FB9ED17B982 +:100C10004661EAE80727E90B820F1648E858286B77 +:100C2000C4312974DA972D1A5681A72E31DA22FFA2 +:100C3000C68CE7BBCBACAA9EBD6FF5C91D62E4B9FB +:100C40009C1B6E664633ECFCC88C169A8DF048539C +:100C50009687FAB48B5DD1A1CC7568CBA05DBDC27F +:100C6000E485A7A1BA020C34F54A5876D5793EF24C +:100C7000240921FA568D22B801545A7140A289D50F +:100C8000C96E7F553E45B8911C762CA743E18DDF98 +:100C90007FDB0D260FF7DC95B1454CB8B4A06BEEA9 +:100CA000BBAB7A21557231ADDA411E05EDAD8E7ABE +:100CB000FCE220D686E36BD35922FC6BDA31BDD43B +:100CC000FF06648ED8A908BADFF63CE91A3B5874CF +:100CD00070836F6C9461A68A19299865D6BA06B894 +:100CE00063C874A840820066F1BD40FC0816A4F8F1 +:100CF000B8505B1E18047413CFA130569896E37950 +:100D0000941201C53A972167887F1258FB9D85B3DD +:100D1000D1111EFAFB63E87B849CE3166143E8F281 +:100D2000B3EA7C8B03B40E241F13F43DD24309ECC9 +:100D30000B7F066F94CC1DFC0606F9B2284BA2BDB2 +:100D4000BBBA5A03F54A5646DB56956B1D5CEC9FC1 +:100D50005112F313C27CED0D7921A38A36C35D01D4 +:100D6000485A30A244E32C82C52EEB6C9F260F51CB +:100D700076E9E1C367F794A852FDAC99CA3B1364C6 +:100D80006F4F839EA694170E8339279977896845FC +:100D900011BD5F9646D7966E61E47FCF282FBD4C7C +:100DA0001709BFF597D59E441D6CDB5B74C44A1DC3 +:100DB000C29F9A9190DFE13600061A2252F094FF0A +:100DC000BEF48D7000000000000000000000000074 :10C00000903C002061DC030073DC030075DC03005E :10C010000000000000000000000000000000000020 :10C0200000000000000000000000000069C10300E3 diff --git a/tests/meteorite.ts b/tests/meteorite.ts new file mode 100644 index 00000000..297da4b4 --- /dev/null +++ b/tests/meteorite.ts @@ -0,0 +1,155 @@ +let oneX: number +let oneY: number +let twoX: number +let twoY: number +let pause: number +let meteoriteOneX: number +let meteoriteOneY: number +let meteoriteTwoX: number +let meteoriteTwoY: number +let counter: number + +basic.pause(2000) +oneX = 0 +oneY = 4 +twoX = 1 +twoY = 4 +counter = 0 +pause = 700 +led.plot(oneX, oneY) +led.plot(twoX, twoY) +input.onButtonPressed(Button.A, () => { + if (oneX > 0) { + led.unplot(oneX, oneY) + led.unplot(twoX, twoY) + oneX = oneX - 1 + twoX = twoX - 1 + led.plot(oneX, oneY) + led.plot(twoX, twoY) + } +}) +input.onButtonPressed(Button.B, () => { + if (twoX < 4) { + led.unplot(oneX, oneY) + led.unplot(twoX, twoY) + oneX = oneX + 1 + twoX = twoX + 1 + led.plot(oneX, oneY) + led.plot(twoX, twoY) + } +}) +meteoriteOneX = Math.randomInt(5) +meteoriteOneY = 0 +meteoriteTwoX = Math.randomInt(5) +meteoriteTwoY = -3 +basic.pause(1000) +for (let i = 0; i < 3; i++) { + led.plot(meteoriteTwoX, meteoriteTwoY) + led.plot(meteoriteOneX, meteoriteOneY) + basic.pause(pause) + led.unplot(meteoriteTwoX, meteoriteTwoY) + led.unplot(meteoriteOneX, meteoriteOneY) + meteoriteOneY = meteoriteOneY + 1 + meteoriteTwoY = meteoriteTwoY + 1 +} +basic.forever(() => { + for (let i1 = 0; i1 < 3; i1++) { + led.plot(meteoriteTwoX, meteoriteTwoY) + led.plot(meteoriteOneX, meteoriteOneY) + basic.pause(pause) + led.unplot(meteoriteOneX, meteoriteOneY) + led.unplot(meteoriteTwoX, meteoriteTwoY) + meteoriteOneY = meteoriteOneY + 1 + meteoriteTwoY = meteoriteTwoY + 1 + if (meteoriteOneY == 4) { + if (meteoriteOneX == oneX) { + for (let j = 0; j < 10; j++) { + led.plotAll() + basic.pause(200) + basic.clearScreen() + basic.pause(200) + } + basic.showNumber(counter, 150) + basic.pause(10000) + } else if (meteoriteOneX == twoX) { + for (let j1 = 0; j1 < 10; j1++) { + led.plotAll() + basic.pause(200) + basic.clearScreen() + basic.pause(200) + } + basic.showNumber(counter, 150) + basic.pause(10000) + } + } + } + while (Math.abs(meteoriteTwoX - meteoriteOneX) < 1) { + meteoriteOneX = Math.randomInt(5) + } + meteoriteOneY = 0 + counter = counter + 1 + if (counter == 3) { + pause = pause - 250 + } else if (counter == 8) { + pause = pause - 100 + } else if (counter == 12) { + pause = pause - 100 + } else if (counter == 20) { + pause = pause - 100 + } else if (counter == 30) { + pause = pause - 70 + } + if (counter == 40) { + pause = pause - 70 + } + for (let i2 = 0; i2 < 3; i2++) { + led.plot(meteoriteOneX, meteoriteOneY) + led.plot(meteoriteTwoX, meteoriteTwoY) + basic.pause(pause) + led.unplot(meteoriteOneX, meteoriteOneY) + led.unplot(meteoriteTwoX, meteoriteTwoY) + meteoriteOneY = meteoriteOneY + 1 + meteoriteTwoY = meteoriteTwoY + 1 + if (meteoriteTwoY == 4) { + if (meteoriteTwoX == oneX) { + for (let j2 = 0; j2 < 10; j2++) { + led.plotAll() + basic.pause(200) + basic.clearScreen() + basic.pause(200) + } + basic.showNumber(counter, 150) + basic.pause(10000) + } else if (meteoriteTwoX == twoX) { + for (let j3 = 0; j3 < 10; j3++) { + led.plotAll() + basic.pause(200) + basic.clearScreen() + basic.pause(200) + } + basic.showNumber(counter, 150) + basic.pause(10000) + } + } + } + + meteoriteTwoX = Math.randomInt(5) + while (Math.abs(meteoriteTwoX - meteoriteOneX) < 1) { + meteoriteTwoX = Math.randomInt(5) + } + meteoriteTwoY = 0 + counter = counter + 1 + if (counter == 3) { + pause = pause - 250 + } else if (counter == 8) { + pause = pause - 100 + } else if (counter == 12) { + pause = pause - 100 + } else if (counter == 20) { + pause = pause - 100 + } else if (counter == 30) { + pause = pause - 70 + } else if (counter == 40) { + pause = pause - 70 + } +}) diff --git a/tests/pac-man-runaway.ts b/tests/pac-man-runaway.ts new file mode 100644 index 00000000..196150c2 --- /dev/null +++ b/tests/pac-man-runaway.ts @@ -0,0 +1,230 @@ +let levelTime: number +let person: Entity +let monsters: Entity[] +let totalMonsters: number +let playing: boolean +let gameSuspended: boolean +let busyPos: Point[] + +class Entity { + public x: number + public y: number + public dirX: number + public dirY: number + public hitHorizontalWall(): boolean { + return this.y == 0 && this.dirY == -1 || this.y == 4 && this.dirY == 1 + } + + public hitVerticalWall(): boolean { + return this.x == 0 && this.dirX == -1 || this.x == 4 && this.dirX == 1 + } + + public possHorizontalDir(): number { + if (this.x == 0) { + return 1 + } else if (this.x == 4) { + return - 1 + } else { + return Math.randomInt(2) * 2 - 1 + } + } + + public possVerticalDir(): number { + if (this.y == 0) { + return 1 + } else if (this.y == 4) { + return - 1 + } else { + return Math.randomInt(2) * 2 - 1 + } + } + + public collidesX(p2: Entity): boolean { + return this.y == p2.y && this.y + this.dirY == p2.y + p2.dirY && (this.x + this.dirX == p2.x || this.x + this.dirX == p2.x + p2.dirX || p2.x + p2.dirX == this.x) + } + + public collidesY(p2: Entity): boolean { + return this.x == p2.x && this.x + this.dirX == p2.x + p2.dirX && (this.y + this.dirY == p2.y || this.y + this.dirY == p2.y + p2.dirY || p2.y + p2.dirY == this.y) + } + + public move1() { + this.x = this.x + this.dirX + this.y = this.y + this.dirY + } + + public towardsX(p2: Entity): number { + return Math.sign(p2.x - this.x) + } + + public towardsY(p2: Entity): number { + return Math.sign(p2.y - this.y) + } + + public plot() { + led.plot(this.x, this.y) + } + + public blink() { + led.plot(this.x, this.y) + basic.pause(125) + led.unplot(this.x, this.y) + basic.pause(125) + led.plot(this.x, this.y) + } + +} + +class Point { + public x: number + public y: number +} + +initializeState() +redraw() +basic.pause(1000) +basic.forever(() => { + levelTime = levelTime + 12 + basic.pause(12) + if (!playing) { + levelTime = 0 + playing = true + } + if (levelTime >= 5000) { + gameSuspended = true + game.levelUp() + levelUp() + levelTime = 0 + resetState() + redraw() + basic.pause(1000) + gameSuspended = false + } +}) +basic.forever(() => { + if (!gameSuspended) { + logic() + redraw() + basic.pause(500) + } +}) +input.onButtonPressed(Button.A, () => { + let temp = Math.abs(person.dirX) * (-1) + person.dirX = Math.abs(person.dirY) * (-1) + person.dirY = temp +}) +input.onButtonPressed(Button.B, () => { + let temp1 = Math.abs(person.dirX) + person.dirX = Math.abs(person.dirY) + person.dirY = temp1 +}) + +function redraw() { + basic.clearScreen() + person.plot() + for (let i = 0; i < totalMonsters; i++) { + monsters[i].blink() + } +} + +function initializeState() { + person = new Entity() + playing = false + busyPos = ([] as Point[]) + let busyPos1 = new Point() + busyPos1.x = 1 + busyPos1.y = 1 + let busyPos2 = new Point() + busyPos2.x = 1 + busyPos2.y = 3 + let busyPos3 = new Point() + busyPos3.x = 3 + busyPos3.y = 1 + busyPos.push(busyPos1) + busyPos.push(busyPos2) + busyPos.push(busyPos3) + monsters = ([] as Entity[]) + addMonster() + resetState() +} + +function logic() { + if (person.hitHorizontalWall()) { + person.dirY = 0 + person.dirX = person.possHorizontalDir() + } + if (person.hitVerticalWall()) { + person.dirX = 0 + person.dirY = person.possVerticalDir() + } + let lost = false + for (let i = 0; i < totalMonsters; i++) { + let m = monsters[i] + m.dirX = m.towardsX(person) + m.dirY = m.towardsY(person) + if (m.dirX != 0 && m.dirY != 0) { + let x = Math.randomInt(2) + if (x == 1) { + m.dirX = 0 + } else { + m.dirY = 0 + } + } + if (person.collidesX(m) || person.collidesY(m)) { + lost = true + } + } + if (!lost) { + moveAll() + } else { + loseLife() + } +} + +function loseLife() { + moveAll() + basic.pause(500) + basic.showLeds(` + . # . # . + . . # . . + . . . . . + . # # # . + # . . . # + `, 400) + basic.pause(1000) + basic.clearScreen() + game.removeLife(1) + playing = false + resetState() +} + +function moveAll() { + person.move1() + for (let i = 0; i < totalMonsters; i++) { + monsters[i].move1() + } +} + +function addMonster() { + let m = new Entity() + monsters.push(m) + totalMonsters = totalMonsters + 1 +} + +function levelUp() { + addMonster() +} + +function resetState() { + levelTime = 0 + game.setLife(5) + person.x = 4 + person.y = 4 + person.dirX = -1 + person.dirY = 0 + for (let i = 0; i < totalMonsters; i++) { + let busy = busyPos[i] + let m = monsters[i] + m.x = (busy.x + Math.randomInt(3)) - 1 + m.y = (busy.y + Math.randomInt(3)) - 1 + } +} diff --git a/tests/wg-canoe-polo-timer.ts b/tests/wg-canoe-polo-timer.ts new file mode 100644 index 00000000..3960be0b --- /dev/null +++ b/tests/wg-canoe-polo-timer.ts @@ -0,0 +1,222 @@ +let AWasPressed: boolean +let BWasPressed: boolean +let ABWasPressed: boolean +let wasShake: boolean +let scoreA: number +let scoreB: number + +scoreA = 0 +scoreB = 0 +startIOMonitor() +let gameTime = getGameTime() +basic.showLeds(` + . . # . . + . . # . . + . . # # # + . . . . . + . . . . . + `) +while (!BWasPressed) { + basic.pause(100) +} +BWasPressed = false +playOneGame(gameTime) +showFinalScores(scoreA, scoreB) + +function startIOMonitor() { + input.onButtonPressed(Button.A, () => { + AWasPressed = true + }) + input.onButtonPressed(Button.B, () => { + BWasPressed = true + }) + input.onButtonPressed(Button.AB, () => { + ABWasPressed = true + AWasPressed = false + BWasPressed = false + }) + input.onShake(() => { + wasShake = true + }) + AWasPressed = false + BWasPressed = false + ABWasPressed = false + wasShake = false +} + +/** + * display score for A and B on same screen as a graphic + * this shows a tug of war line, in the middle if scores the same, + * Can cope with differences +/-10 + * @param scoreA1 TODO + * @param scoreB1 TODO + */ +function showScore(scoreA1: number, scoreB1: number) { + let img = images.createImage(` + # . . . . # . . . . # . . . . # . . . . # . . . . . # . . . . # . . . . # . . . . # . . . . # . . . . . # . . . . . # . . . . # . . . . # . . . . # . . . . # . . . . . # . . . . # . . . . # . . . . # . . . . # + # . . . . # . . . . # . . . . # . . . . . # . . . . # . . . . # . . . . # . . . . # . . . . . # . . . . # . . . . # . . . . . # . . . . # . . . . # . . . . # . . . . # . . . . . # . . . . # . . . . # . . . . # + # . . . . # . . . . # . . . . . # . . . . # . . . . # . . . . # . . . . # . . . . . # . . . . # . . . . # . . . . # . . . . # . . . . . # . . . . # . . . . # . . . . # . . . . # . . . . . # . . . . # . . . . # + # . . . . # . . . . . # . . . . # . . . . # . . . . # . . . . # . . . . . # . . . . # . . . . # . . . . # . . . . # . . . . # . . . . # . . . . . # . . . . # . . . . # . . . . # . . . . # . . . . . # . . . . # + # . . . . . # . . . . # . . . . # . . . . # . . . . # . . . . . # . . . . # . . . . # . . . . # . . . . # . . . . # . . . . # . . . . # . . . . # . . . . . # . . . . # . . . . # . . . . # . . . . # . . . . . # + `) + let diff = Math.clamp(-10, 10, scoreB1 - scoreA1) + diff = diff + 10 + img.plotFrame(diff) +} + +/** + * show digits 0..10 + * @param digits TODO + */ +function showDigits(digits: number) { + digits = Math.clamp(0, 10, digits) + let img = images.createImage(` + . . # . . . . # . . . # # . . . # # . . . # . . . . # # # . . . # # . . # # # . . . # . . . . # . . # . . # . + . # . # . . # # . . . . . # . . . . # . . # . . . . # . . . . # . . . . . . # . . # . # . . # . # . # . # . # + . # . # . . . # . . . . # . . . . # . . . # # # . . . # # . . # # . . . . # . . . . # . . . . # # . # . # . # + . # . # . . . # . . . # . . . . . . # . . . # . . . . . # . . # . # . . # . . . . # . # . . . . # . # . # . # + . . # . . . # # # . . # # # . . # # . . . . # . . . # # . . . . # . . . # . . . . . # . . . # # . . # . . # . + `) + img.plotFrame(digits) +} + +/** + * show time graphic for time remaining + * @param gameTime TODO + */ +function showTime(gameTime: number) { + let minutes = Math.clamp(0, 10, gameTime / 60) + let seconds = gameTime % 60 + // divide seconds into 10 second stripes + let stripes = seconds / 10 + let img = images.createImage(` + . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + . . . . . # . . . . # # . . . # # # . . # # # # . # # # # # + . . . . . # . . . . # # . . . # # # . . # # # # . # # # # # + `) + img.plotFrame(stripes) + // leave middle row blank + // display up to 10 dots in raster on top two rows + if (minutes > 0) { + for (let i = 0; i < minutes; i++) { + let y = i / 5 + let x = i % 5 + led.plot(x, y) + } + } +} + +function getGameTime(): number { + let chosenGameTime = 7 + showDigits(chosenGameTime) + while (!BWasPressed) { + if (AWasPressed) { + if (chosenGameTime < 10) { + chosenGameTime = chosenGameTime + 1 + } else { + chosenGameTime = 1 + } + showDigits(chosenGameTime) + AWasPressed = false + } else { + basic.pause(100) + } + } + BWasPressed = false + return chosenGameTime +} + +function playOneGame(gameTime: number) { + let gameStartTime = input.runningTime() + let gameElapsedTime = 0 + let gameTimeRemaining = gameTime * 60 + let timeout = 0 + let lastDisplayedTime = 0 + showScore(scoreA, scoreB) + let state = "TIME" + while (gameTimeRemaining >= 0) { + // Tick the game time + gameElapsedTime = (input.runningTime() - gameStartTime) / 1000 + gameTimeRemaining = gameTime * 60 - gameElapsedTime + // Handle any global events such as point buttons + if (AWasPressed) { + AWasPressed = false + scoreA = scoreA + 1 + if (state != "LAST10") { + showScore(scoreA, scoreB) + state = "SCORE" + } + } else if (BWasPressed) { + BWasPressed = false + scoreB = scoreB + 1 + if (state != "LAST10") { + showScore(scoreA, scoreB) + state = "SCORE" + } + } + // Handle global transitions + if (gameTimeRemaining <= 10 && state != "LAST10") { + state = "LAST10" + } + // Handle game states + if (state == "SCORE") { + if (wasShake) { + wasShake = false + showTime(gameTimeRemaining) + lastDisplayedTime = gameTimeRemaining + timeout = input.runningTime() + 5 * 1000 + state = "TIME" + } + } else if (state == "TIME") { + if (input.runningTime() > timeout) { + showScore(scoreA, scoreB) + state = "SCORE" + } + } else if (state == "LAST10") { + if (gameTimeRemaining != lastDisplayedTime) { + showDigits(gameTimeRemaining) + lastDisplayedTime = gameTimeRemaining + } + } + basic.pause(100) + } +} + +function showFinalScores(scoreA1: number, scoreB1: number) { + basic.showLeds(` + # . . . # + . # . # . + . . # . . + . # . # . + # . . . # + `) + while (true) { + if (AWasPressed) { + basic.showString("A", 150) + basic.showNumber(scoreA1, 150) + basic.showLeds(` + # . . . # + . # . # . + . . # . . + . # . # . + # . . . # + `) + AWasPressed = false + } else if (BWasPressed) { + basic.showString("B", 150) + basic.showNumber(scoreB1, 150) + basic.showLeds(` + # . . . # + . # . # . + . . # . . + . # . # . + # . . . # + `) + BWasPressed = false + } else { + basic.pause(100) + } + } +} diff --git a/tests/wg-catching-raindrops.ts b/tests/wg-catching-raindrops.ts new file mode 100644 index 00000000..a0920f49 --- /dev/null +++ b/tests/wg-catching-raindrops.ts @@ -0,0 +1,248 @@ +let speed: number +let cupCapacity: number +let maxMisses: number +let autoEmpty: boolean +let movement: boolean +let sensitivity: number +let cupX: number +let cupInverted: boolean + +let highscore = 0 +while (true) { + // configure game settings + // ##CHALLENGE1: reconfigure game + cupCapacity = 5 + speed = 6 + maxMisses = 3 + autoEmpty = false + movement = true + sensitivity = 400 + cupX = 2 + // show the spash screen + // ##CHALLENGE 2: CHANGE SPLASH SCREEN + basic.showAnimation(` + . . . . . . . . . . + . . . . . . # . # . + . . . . . . . . . . + . # . # . . # . # . + . # # # . . # # # . + `, 400) + // Decide what to do based on which button is pressed + if (input.buttonIsPressed(Button.A)) { + let finalScore = playGame() + // ##CHALLENGE 3 ADD HIGH SCORE + if (finalScore > highscore) { + basic.showString("HIGH", 150) + highscore = finalScore + } + basic.showNumber(finalScore, 150) + } else if (input.buttonIsPressed(Button.B)) { + testMovement() + } else { + basic.pause(100) + } +} + +function playGame(): number { + let cup = images.createImage(` + . . . . . . . . . . . . . . . + . . . . . . . . . . . . . . . + . . . . . . . . . . . . . . . + . . . . . . # . # . . . . . . + . . . . . . # # # . . . . . . + `) + let score = 0 + let dropsInCup = 0 + let misses = 0 + let dropX = 0 + let dropY = 0 + let prevDropY = -1 + let cupX1 = 2 + let prevCupX = -1 + let state = "NEWDROP" + startGame() + while (true) { + if (state == "NEWDROP") { + // create a new drop at a random position + dropX = Math.randomInt(5) + dropY = 0 + state = "RAINING" + } else if (state == "RAINING") { + // calculate new positions + cupX1 = getCupPosition() + let thisDropY = dropY / speed + // Only redraw the screen if something has changed (prevent flashing) + if (cupX1 != prevCupX || thisDropY != prevDropY) { + basic.clearScreen() + // draw cup + cup.showImage(7 - cupX1) + if (dropsInCup == cupCapacity) { + // a full cup + led.plot(cupX1, 3) + } + // draw drop + led.plot(dropX, thisDropY) + prevCupX = cupX1 + prevDropY = thisDropY + } + basic.pause(100) + if (thisDropY >= 4) { + state = "ATCUP" + } else { + dropY = dropY + 1 + } + if (cupInverted && dropsInCup >= cupCapacity) { + state = "EMPTYING" + } + } else if (state == "ATCUP") { + if (dropX == cupX1) { + state = "CATCH" + } else { + state = "MISS" + } + } else if (state == "MISS") { + // ##CHALLENGE: long beep on miss + beep(500) + misses = misses + 1 + basic.showAnimation(` + . . . . . . . . . . . . . . . . . . . . + . . . . . . # . # . . . . . . . . . . . + . . . . . . # # # . . # . # . . . . . . + . # . # . . . . . . . # # # . . # . # . + . # # # . . . # . . . . . . . . # # # . + `, 400) + if (misses > maxMisses) { + state = "GAMEOVER" + } else { + state = "NEWDROP" + } + } else if (state == "CATCH") { + // ##CHALLENGE: short beep on catch + beep(200) + dropsInCup = dropsInCup + 1 + basic.showAnimation(` + . . . . . . . . . . . . . . . + . . . . . . . . . . . . . . . + . . . . . . . . . . . . . . . + . # # # . # . # . # . # . # . + . # # # . # # # # # . # # # . + `, 400) + if (dropsInCup == cupCapacity) { + state = "FULL" + score = score + 1 + } else if (dropsInCup > cupCapacity) { + state = "OVERFLOW" + } else { + score = score + 1 + state = "NEWDROP" + } + } else if (state == "FULL") { + basic.showAnimation(` + . . . . . . . . . . . . . . . + . . . . . . . . . . . . . . . + . . . . . . # # # . . . . . . + . # # # . . # # # . . # # # . + . # # # . . # # # . . # # # . + `, 400) + if (autoEmpty) { + state = "EMPTYING" + } else { + state = "NEWDROP" + } + } else if (state == "EMPTYING") { + if (cupInverted) { + basic.showAnimation(` + . . . . . . . . . . . . . . . . . # . . . . . . . + . . . . . . . . . . . . # . . . . . . . . . . . . + . . . . . . . # . . . . . . . . . . . . . . . . . + . # # # . . # . # . . # . # . . # . # . . # . # . + . # # # . . # # # . . # # # . . # # # . . # # # . + `, 400) + } else { + basic.showAnimation(` + . . . . . . . . . . . # # # . . # # # . . # # # . . # # # . . # # # . . . . . . . . . . . + . . . . . . # # . . . # # # . . # . # . . # . # . . # . # . . # . # . . # # . . . . . . . + . . . . . . # # . . . . . . . . . # . . . . . . . . . . . . . . . . . . # . . . . . . . . + . # # # . . # # . . . . . . . . . . . . . . # . . . . . . . . . . . . . # # . . . # . # . + . # # # . . . . . . . . . . . . . . . . . . . . . . . # . . . . . . . . . . . . . # # # . + `, 400) + } + dropsInCup = 0 + // ##CHALLENGE: Speed up on every level change + if (speed > 1) { + speed = speed - 1 + } + state = "NEWDROP" + } else if (state == "OVERFLOW") { + basic.showAnimation(` + . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + . . . . . . # # # . . # . # . . . . . . . . . . . . . . . . + . # # # . . # # # . # # # # # # # # # # . # # # . . # # # . + . # # # . . # # # . . # # # . . # # # . # # # # # . # # # . + `, 400) + state = "GAMEOVER" + } else if (state == "GAMEOVER") { + // ##CHALLENGE: Make a sound on game over + beep(700) + basic.showAnimation(` + . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . # # # . # # # # # . . . . . . . . . . . . . . . + . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . # # # . # # # # # . # . # . . . . . . . . . . . . # . # . . . . . . + . . . . . . . . . . . . . . . . . . . . . # # # . # # # # # . # . # . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + . # . # . . . . . . . # # # . # # # # # . # . # . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + . # # # . # # # # # . # . # . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + `, 400) + break + } + } + return score +} + +function testMovement() { + while (!input.buttonIsPressed(Button.A)) { + // ##CHALLENGE 5: Add accelerometer test mode + let x = getCupPosition() + basic.clearScreen() + led.plot(x, 2) + basic.pause(200) + } +} + +function getCupPosition(): number { + if (movement) { + let acc = input.acceleration(Dimension.X) / sensitivity + cupX = Math.clamp(0, 4, acc + 2) + return cupX + } + if (input.buttonIsPressed(Button.A)) { + if (cupX > 0) { + cupX = cupX - 1 + } + } else if (input.buttonIsPressed(Button.B)) { + if (cupX < 4) { + cupX = cupX + 1 + } + } + return cupX +} + +function startGame() { + basic.clearScreen() + // If button still held from start-game, wait until it is released + while (input.buttonIsPressed(Button.A)) { + // wait for button to be released + } + // handlers that work out if cup is turned upside down or not + input.onLogoDown(() => { + cupInverted = true + }) + input.onLogoUp(() => { + cupInverted = false + }) +} + +function beep(p: number) { + pins.digitalWritePin(DigitalPin.P0, 1) + basic.pause(p) + pins.digitalWritePin(DigitalPin.P0, 0) +} diff --git a/tests/wg-dr-who.ts b/tests/wg-dr-who.ts new file mode 100644 index 00000000..204b59f2 --- /dev/null +++ b/tests/wg-dr-who.ts @@ -0,0 +1,716 @@ +let AWasPressed: boolean +let BWasPressed: boolean +let ABWasPressed: boolean +let wasShake: boolean + +startIOMonitor() +let gameNo = 0 +while (true) { + // select a new game + if (AWasPressed) { + gameNo = (gameNo + 1) % 4 + AWasPressed = false + } + // show selected game + if (gameNo == 0) { + basic.showLeds(` + # # # # # + # . . . # + . # . # . + . . . . . + . # # # . + `) + } else if (gameNo == 1) { + basic.showLeds(` + # # # . . + # . . . . + # # # # # + # # . . . + # # # . . + `) + } else if (gameNo == 2) { + basic.showLeds(` + . . . . . + # . . . . + # # # # # + # . . . . + . . . . . + `) + } else if (gameNo == 3) { + basic.showLeds(` + # . # # # + # # # # # + . . . # # + # # # # # + # # # # # + `) + } + // start selected game + if (BWasPressed) { + // Play the selected game + basic.clearScreen() + waitBReleased() + resetButtons() + let finalScore = 0 + basic.clearScreen() + if (gameNo == 0) { + finalScore = playCybermen() + } else if (gameNo == 1) { + finalScore = playDalek() + } else if (gameNo == 2) { + finalScore = playSonicScrewdriver() + } else if (gameNo == 3) { + finalScore = playJudoonLanguage() + } + flashDigit(finalScore, 3) + resetButtons() + waitBPressed() + basic.clearScreen() + waitBReleased() + resetButtons() + } else { + basic.pause(100) + } +} + +/** + * Game parameters + * Percentage chance that cyberman will move left/right to line up with you + */ +function playCybermen(): number { + let maxGameTime = 60 + let cybermanMoveXProbability = 20 + // How long (in 100ms ticks) cyberman must line up before moving forward + let cybermanMoveYCount = 10 + // Game variables + let startTime = input.runningTime() + let gameTime = 0 + let playerX = 2 + let cybermanX = 1 + let cybermanY = 0 + let cybermanLineupCount = 0 + let redraw = true + while (gameTime < maxGameTime) { + if (redraw) { + basic.clearScreen() + led.plot(playerX, 4) + led.plot(cybermanX, cybermanY) + redraw = false + } + // Handle Player Movement + if (AWasPressed) { + if (playerX > 0) { + playerX = playerX - 1 + redraw = true + } + AWasPressed = false + } else if (BWasPressed) { + if (playerX < 4) { + playerX = playerX + 1 + redraw = true + } + BWasPressed = false + } + // Handle Cyberman line-of-sight checking + if (cybermanX == playerX) { + cybermanLineupCount = cybermanLineupCount + 1 + if (cybermanLineupCount >= cybermanMoveYCount) { + if (cybermanY == 4) { + // Cyberman caught you, game over + break + } else { + cybermanY = cybermanY + 1 + redraw = true + cybermanLineupCount = 0 + } + } + } else { + cybermanLineupCount = 0 + // Move Cyberman closer to player, slowly + if (Math.randomInt(100) < cybermanMoveXProbability) { + if (cybermanX > playerX) { + cybermanX = cybermanX - 1 + } else if (cybermanX < playerX) { + cybermanX = cybermanX + 1 + } + redraw = true + } + } + basic.pause(100) + gameTime = (input.runningTime() - startTime) / 1000 + } + return convertSurvivalTimeToScore(gameTime) +} + +/** + * Game parameters, all probabilities as a percentage + */ +function playDalek(): number { + let maxGameTime = 60 + let userMoveSensitivity = 40 + let dalekMoveSensitivity = 20 + let dalekShootChance = 10 + let dalekHitChance = 10 + // Game variables + let gameTime = 0 + let startTime = input.runningTime() + let dalekY = 2 + let userY = 1 + let redraw = true + while (gameTime < maxGameTime) { + // Redraw screen if necessary + if (redraw) { + basic.clearScreen() + led.plot(0, dalekY) + led.plot(4, userY) + redraw = false + } + // Work out if the user has moved, and move them + let tilt = getTilt() + if (tilt > 2) { + // Moving up, slowly + if (userY < 4) { + if (Math.randomInt(100) < userMoveSensitivity) { + userY = userY + 1 + redraw = true + } + } + } else if (tilt < 2) { + // Moving down (slowly) + if (userY > 0) { + if (Math.randomInt(100) < userMoveSensitivity) { + userY = userY - 1 + redraw = true + } + } + } + // Move the Dalek to line up with user + if (dalekY < userY) { + if (Math.randomInt(100) < dalekMoveSensitivity) { + dalekY = dalekY + 1 + redraw = true + } + } else if (dalekY > userY) { + if (Math.randomInt(100) < dalekMoveSensitivity) { + dalekY = dalekY - 1 + redraw = true + } + } else { + // Dalek lines up + if (Math.randomInt(100) < dalekShootChance) { + // Shoot a raygun at the user + for (let i = 0; i < 3; i++) { + led.plot(i + 1, dalekY) + basic.pause(100) + } + if (Math.randomInt(100) < dalekHitChance) { + // User has been hit, game over + break + } + redraw = true + } + } + gameTime = (input.runningTime() - startTime) / 1000 + basic.pause(100) + } + return convertSurvivalTimeToScore(gameTime) +} + +/** + * Set this in steps of 60 + */ +function playSonicScrewdriver(): number { + let maxGameTime = 120 + let gameTime = 0 + // @=0, A=1 etc + // bit0=N, bit1=E, bit2=S, bit3=W + // bit=0 means it is a wall (can not be opened) + // bit=1 means it is a door (can be opened) + let mazestr = "BLFL@GOIFIGLCJIA" + let maze = ([] as number[]) + // Locks use same number encoding (bits 0,1,2,3) + // bit=0 means door is locked (cannot be walked through) + // bit=1 means door is open (can be walked through) + let doorOpen = ([] as number[]) + for (let i = 0; i < 16; i++) { + doorOpen.push(0) + maze.push(mazestr.charCodeAt(i) - 64) + } + let redraw = true + let cellno = 0 + let direction = "N" + let startTime = input.runningTime() + while (gameTime < maxGameTime) { + // Draw the screen + if (redraw) { + basic.clearScreen() + // Always draw the maze with N at the top + drawMazeCell(doorOpen[cellno]) + // draw user standing next to selected wall + if (direction == "N") { + led.plot(2, 1) + } else if (direction == "E") { + led.plot(3, 2) + } else if (direction == "S") { + led.plot(2, 3) + } else if (direction == "W") { + led.plot(1, 2) + } + redraw = false + } + // Sense any button presses + if (AWasPressed) { + if (direction == "N") { + direction = "E" + } else if (direction == "E") { + direction = "S" + } else if (direction == "S") { + direction = "W" + } else if (direction == "W") { + direction = "N" + } + redraw = true + AWasPressed = false + } else if (BWasPressed) { + // Try to walk through an open door + if (isDoorOpen(doorOpen[cellno], direction)) { + cellno = mazeForward(cellno, 4, 4, direction) + redraw = true + } + BWasPressed = false + } else if (wasShake) { + // energise sonic screwdriver + if (isDoorOpen(maze[cellno], direction)) { + // It is a door, but is the door open or closed? + if (!(isDoorOpen(doorOpen[cellno], direction))) { + // Open the door in front of us + doorOpen[cellno] = openDoor(doorOpen[cellno], direction) + // Also open the return door for when we walk through this door + let forwardCellno = mazeForward(cellno, 4, 4, direction) + doorOpen[forwardCellno] = openDoor(doorOpen[forwardCellno], opposite(direction)) + } + } else { + // Not a door + basic.showLeds(` + . . . . . + . # . # . + . . # . . + . # . # . + . . . . . + `) + basic.pause(500) + } + redraw = true + wasShake = false + } + if (cellno == 15) { + // Have reached the exit cell + break + } + basic.pause(100) + gameTime = (input.runningTime() - startTime) / 1000 + } + return convertPenaltyTimeToScore(gameTime / maxGameTime / 60) +} + +function playJudoonLanguage(): number { + let maxGameTime = 60 + let gameTime = 0 + let startTime = input.runningTime() + let font = images.createImage(` + # . # # # # . # . # . . . . # # # . . . # # # # # # . # . # # # # . . . . . # # # . . . # # # # # # + # # # # # # # # # # . . . # # . # # # # . # . . . # # # # # # # # # # # # # # . # # # # # . . # . . + . . . . # # # # . . . . # # # . . . . # . # . . . . . . . # . . . # # . . # # # . . # . . # # # # # + # # # # # # # # # # . . # . . # # # # # # # # # # # # # # # # # # # . # # # # # # # # # # # # # . . + # # # # # # # # # # # # # # # # . . . . # . . . # # . . . . . . . # # # # # . . # # # # # # # # # # + `) + let answers = images.createImage(` + # # # # # # # # . . . # # # . . . # . . # . # . # + # . . . # # . . . . # # # # # . . . . . . . . . . + . # . # . # # # # . # . # . # . # . # . # . # . # + . . . . . # # # . . # . # . # . . . . . . . . . . + . # # # . # # # . . # . # . # # # # # # # . . . # + `) + let pages = "029 041 167 208 283" + let actualAnswer = Math.randomInt(5) + let pos = 0 + let redraw = true + while (gameTime < maxGameTime) { + // Draw the current frame from pos (0,1,2 codeword, 3,4,5,6,7 answers) + if (redraw) { + if (pos <= 2) { + // Draw codeword symbol for this choice and this position + let digit = parseInt(pages[actualAnswer * 4 + pos]) + font.plotFrame(digit) + } else { + // Draw answer + let item = pos - 3 + answers.plotFrame(item) + } + redraw = false + } + // Process button presses + if (AWasPressed) { + // Move left, unless at far left already + AWasPressed = false + if (pos > 0) { + pos = pos - 1 + redraw = true + } + } else if (BWasPressed) { + // Move right, unless already at far right + BWasPressed = false + if (pos < 7) { + pos = pos + 1 + redraw = true + } + } else if (wasShake) { + // User trying to select an answer, are we at an answer position? + wasShake = false + if (pos >= 3) { + // Is it the right answer? + let userChoice = pos - 3 + if (userChoice == actualAnswer) { + // CORRECT + basic.showAnimation(` + . . . . . . . . . . . . . . . . . . . . . . . . . + . . . . . . . . . . . . . . . . . . . . . . . . # + . . . . . . . . . . . . . . . . . . # . . . . # . + # . . . . # . . . . # . # . . # . # . . # . # . . + . . . . . . # . . . . # . . . . # . . . . # . . . + `, 400) + basic.pause(1000) + break + } else { + // WRONG + basic.showAnimation(` + . . . . . . . . . . . . . . . . . . . . . . . . # # . . . # # . . . # # . . . # # . . . # + . . . . . . . . . . . . . . . . . . # . . . . # . . . . # . . # . # . . # . # . . # . # . + . . . . . . . . . . . . # . . . . # . . . . # . . . . # . . . . # . . . . # . . . . # . . + . . . . . . # . . . . # . . . . # . . . . # . . . . # . . . . # . . . . # . # . . # . # . + # . . . . # . . . . # . . . . # . . . . # . . . . # . . . . # . . . . # . . . . # . . . # + `, 400) + basic.pause(1000) + redraw = true + } + } + } + gameTime = (input.runningTime() - startTime) / 1000 + basic.pause(100) + } + return convertPenaltyTimeToScore(gameTime) +} + +function getDirection(): string { + let bearing = input.compassHeading() + if (bearing < 45 || bearing > 315) { + return "N" + } else if (bearing < 135) { + return "E" + } else if (bearing < 225) { + return "S" + } else { + return "W" + } +} + +function calibrateCompass() { + if (input.compassHeading() == -4) { + input.calibrate() + } +} + +function waitBReleased() { + while (input.buttonIsPressed(Button.B)) { + basic.pause(100) + } +} + +function waitBPressed() { + while (!input.buttonIsPressed(Button.B)) { + basic.pause(100) + } +} + +/** + * Show the score 0..9 + * @param digit TODO + * @param times TODO + */ +function flashDigit(digit: number, times: number) { + digit = Math.clamp(0, 9, digit) + for (let i = 0; i < times; i++) { + basic.showNumber(digit, 0) + basic.pause(500) + basic.clearScreen() + basic.pause(500) + } + basic.showNumber(digit, 0) +} + +/** + * score is calculated as the amount of time you lasted + * @param gameTime TODO + */ +function convertSurvivalTimeToScore(gameTime: number): number { + if (gameTime <= 4) { + return 0 + } else if (gameTime <= 9) { + return 1 + } else if (gameTime <= 14) { + return 2 + } else if (gameTime <= 19) { + return 3 + } else if (gameTime <= 24) { + return 4 + } else if (gameTime <= 29) { + return 5 + } else if (gameTime <= 39) { + return 6 + } else if (gameTime <= 49) { + return 7 + } else if (gameTime <= 59) { + return 8 + } else { + return 9 + } +} + +function convertPenaltyTimeToScore(penaltyTime: number): number { + if (penaltyTime <= 4) { + return 9 + } else if (penaltyTime <= 9) { + return 8 + } else if (penaltyTime <= 14) { + return 7 + } else if (penaltyTime <= 19) { + return 6 + } else if (penaltyTime <= 24) { + return 5 + } else if (penaltyTime <= 29) { + return 4 + } else if (penaltyTime <= 39) { + return 3 + } else if (penaltyTime <= 49) { + return 2 + } else if (penaltyTime <= 59) { + return 1 + } else { + return 0 + } +} + +function startIOMonitor() { + input.onButtonPressed(Button.A, () => { + AWasPressed = true + }) + input.onButtonPressed(Button.B, () => { + BWasPressed = true + }) + input.onButtonPressed(Button.AB, () => { + ABWasPressed = true + }) + input.onShake(() => { + wasShake = true + }) + AWasPressed = false + BWasPressed = false + ABWasPressed = false + wasShake = false +} + +/** + * maze is always drawn with north at top + * @param cell TODO + */ +function drawMazeCell(cell: number) { + let n = !(isNorth(cell)) + let e = !(isEast(cell)) + let s = !(isSouth(cell)) + let w = !(isWest(cell)) + // Draw any visible walls + if (n) { + for (let i = 0; i < 5; i++) { + led.plot(i, 0) + } + } + if (e) { + for (let l = 0; l < 5; l++) { + led.plot(4, l) + } + } + if (s) { + for (let k = 0; k < 5; k++) { + led.plot(k, 4) + } + } + if (w) { + for (let j = 0; j < 5; j++) { + led.plot(0, j) + } + } +} + +/** + * work out the cell number in front of this cell + * given the direction N E S W (N points to button B) + * returns the forward cell number, -1 if outside of maze + * Turn cellno into an x and y based on width and height + * @param cellno TODO + * @param width TODO + * @param height TODO + * @param direction TODO + */ +function mazeForward(cellno: number, width: number, height: number, direction: string): number { + let y = cellno / width + let x = cellno % width + // Work out change in x/y and therefore change in cellno + // But bounds-check against width and height + // as user cannot walk outside of the maze + if (direction == "N") { + // sub 1 from y + if (y > 0) { + return cellno - width + } + } else if (direction == "E") { + // Add 1 to x + if (x < width - 1) { + return cellno + 1 + } + } else if (direction == "S") { + // add 1 to y + if (y < height - 1) { + return cellno + width + } + } else if (direction == "W") { + // sub 1 from x + if (x > 0) { + return cellno - 1 + } + } + // Not allowed to move in this direction, it will go outside of maze + return - 1 +} + +/** + * A door is open if the lock bit is 1 + * A door is present if the maze bit is 1 + * @param cell TODO + * @param direction TODO + */ +function isDoorOpen(cell: number, direction: string): boolean { + if (direction == "N") { + return isNorth(cell) + } else if (direction == "E") { + return isEast(cell) + } + if (direction == "S") { + return isSouth(cell) + } else if (direction == "W") { + return isWest(cell) + } + return false +} + +function getTilt(): number { + let tilt: number + tilt = input.acceleration(Dimension.Y) + tilt = Math.clamp(-1024, 1023, tilt) + tilt = (tilt + 1024) / 512 + return tilt +} + +function waitAReleased() { + while (input.buttonIsPressed(Button.A)) { + basic.pause(100) + } +} + +function waitNoButtons() { + while (input.buttonIsPressed(Button.A) || input.buttonIsPressed(Button.B) || input.buttonIsPressed(Button.AB)) { + basic.pause(100) + } +} + +function resetButtons() { + AWasPressed = false + BWasPressed = false + ABWasPressed = false +} + +/** + * The appropriate bit (0,1,2,3) is set, which unlocks the door + * @param cell TODO + * @param direction TODO + */ +function openDoor(cell: number, direction: string): number { + if (direction == "N") { + return cell | 1 + } else if (direction == "E") { + return cell | 2 + } else if (direction == "S") { + return cell | 4 + } else if (direction == "W") { + return cell | 8 + } + return cell +} + +/** + * is the north bit set in the cell? + * @param cell TODO + */ +function isNorth(cell: number): boolean { + if ((cell & 1) != 0) { + return true + } + return false +} + +/** + * is the east bit set in the cell? + * @param cell TODO + */ +function isEast(cell: number): boolean { + if ((cell & 2) != 0) { + return true + } + return false +} + +/** + * is the south bit set in the cell? + * @param cell TODO + */ +function isSouth(cell: number): boolean { + if ((cell & 4) != 0) { + return true + } + return false +} + +/** + * is the west bit set in the cell? + * @param cell TODO + */ +function isWest(cell: number): boolean { + if ((cell & 8) != 0) { + return true + } + return false +} + +function opposite(direction: string): string { + if (direction == "N") { + return "S" + } else if (direction == "E") { + return "W" + } else if (direction == "S") { + return "N" + } else if (direction == "W") { + return "E" + } + return direction +} + +function isSount() { } diff --git a/tests/wg-flood-monitor.ts b/tests/wg-flood-monitor.ts new file mode 100644 index 00000000..bf152d3a --- /dev/null +++ b/tests/wg-flood-monitor.ts @@ -0,0 +1,165 @@ +let sensorType: string + +// ANALOG or TILT +sensorType = "TILT" +while (true) { + // splash screen (flood monitor) + basic.showLeds(` + # # # . . + # . . . . + # # . # . + # . . # . + # . . # # + `) + while (true) { + if (input.buttonIsPressed(Button.A)) { + // test that the sensor works + testMode() + break + } else if (input.buttonIsPressed(Button.B)) { + // run the real flood monitor + floodMonitor() + break + } else { + basic.pause(100) + } + } +} + +/** + * test mode - test that the monitor and buzzer work + * no filtering in this mode, direct screen update + */ +function testMode() { + basic.showLeds(` + # # # # # + . . # . . + . . # . . + . . # . . + . . # . . + `) + waitNoButtons() + let img = images.createImage(` + . . . . . . . . . . . . . . . . . . . . # # # # # + . . . . . . . . . . . . . . . # # # # # . . . . . + . . . . . . . . . . # # # # # . . . . . . . . . . + . . . . . # # # # # . . . . . . . . . . . . . . . + # # # # # . . . . . . . . . . . . . . . . . . . . + `) + while (!input.buttonIsPressed(Button.A)) { + // Show live reading on display + let value = readSensor() + img.showImage(value * 5) + // Turn beeper on only if maximum value seen + if (value >= 4) { + pins.digitalWritePin(DigitalPin.P1, 1) + } else { + pins.digitalWritePin(DigitalPin.P1, 0) + } + basic.pause(50) + } + waitNoButtons() +} + +function floodMonitor() { + basic.showLeds(` + # . . . # + # # . # # + # . # . # + # . . . # + # . . . # + `) + waitNoButtons() + let line = images.createImage(` + . . . . . . . . . . . . . . . . . . . . # # # # # + . . . . . . . . . . . . . . . # # # # # . . . . . + . . . . . . . . . . # # # # # . . . . . . . . . . + . . . . . # # # # # . . . . . . . . . . . . . . . + # # # # # . . . . . . . . . . . . . . . . . . . . + `) + let state = "SAFE" + let averagedValue = 0 + while (!input.buttonIsPressed(Button.A)) { + let value = readSensor() + // Apply some 'lag' filtering to the value, so that 'bobbing' doesn't set off alarm + // i.e. to go from 0 to 4 takes 4 times round the loop + if (value > averagedValue) { + // On the way up, changes in reading are slowed down + averagedValue = averagedValue + 1 + } else if (value < averagedValue) { + // On the way down, changes in reading happen immediately + averagedValue = value + } + // Work out what to do based on the averaged value (non bobbing value) + if (state == "SAFE") { + if (averagedValue >= 4) { + pins.digitalWritePin(DigitalPin.P1, 1) + state = "ALARMING" + } else { + // Display raw value as a line + line.showImage(value * 5) + // fill in based on averaged value (long term reading) + for (let i = 0; i < averagedValue; i++) { + led.plot(2, 4 - i) + } + } + } else if (state == "ALARMING") { + if (input.buttonIsPressed(Button.B)) { + pins.digitalWritePin(DigitalPin.P1, 0) + state = "SAFE" + } else { + basic.showAnimation(` + # # # # # . . . . . + # # # # # . . . . . + # # # # # . . . . . + # # # # # . . . . . + # # # # # . . . . . + `, 400) + } + } + basic.pause(300) + } + waitNoButtons() +} + +/** + * Read a value 0,1,2,3,4 from either ANALOG or TILT + */ +function readSensor(): number { + let value = 0 + // Produce a sensor value in range 0..1023 + if (sensorType == "ANALOG") { + // Input range is 0..1023 + value = pins.analogReadPin(AnalogPin.P0) + } else if (sensorType == "TILT") { + // Input range is -1024 (pads highest)..1023 (pads lowest) + value = input.acceleration(Dimension.Y) + // Emulator sometimes returns out of range values, so clamp to expected range + value = Math.clamp(-1024, 1023, value) + // Convert to an entirely positive range from 0 pads full up to 2047 pads full down + // (hinged at the 'eyes' end) + value = value + 1024 + // Invert the direction, so that "pads up" is largest, "pads down" is smallest + value = 2047 - value + // We want the same range as the analog, so halve the range + value = value / 2 + } + // 5 possible values (0,1,2,3,4) based on sensible thresholds + // We do this by thresholds, so that we have more control over the 5 levels + if (value < 200) { + return 0 + } else if (value < 400) { + return 1 + } else if (value < 600) { + return 2 + } else if (value < 800) { + return 3 + } + return 4 +} + +function waitNoButtons() { + while (input.buttonIsPressed(Button.A) || input.buttonIsPressed(Button.B)) { + basic.pause(100) + } +} diff --git a/tests/wg-operation.ts b/tests/wg-operation.ts new file mode 100644 index 00000000..c43532ab --- /dev/null +++ b/tests/wg-operation.ts @@ -0,0 +1,529 @@ +let opMaxTime: number +let procMaxTime: number +let procsToDo: number +let recoveryTriesMax: number +let tenseTime: number +let flatlineTimeMax: number +let recoveryProbability: number +let aWasPressed: boolean +let bWasPressed: boolean +let digitsImg: Image +let tweezerCount_: number +let wasTweezers: boolean +let wasNose: boolean +let isTweezers: boolean + +// P0 blue wire, tweezers (active high) +// P1, green wire nose button/LED (active high) +// P2/red speaker (not a self toned beeper, but a piezo or a speaker) +opMaxTime = 120 * 1000 +procsToDo = 3 +procMaxTime = 60 * 1000 +tenseTime = 4000 +flatlineTimeMax = 15 * 1000 +recoveryTriesMax = 3 +recoveryProbability = 60 +let highScore = 0 +digitsImg = images.createImage(` + . . # . . . . # . . . # # . . . # # . . . # . . . . # # # . . . # # . . # # # . . . # . . . . # . . + . # . # . . # # . . . . . # . . . . # . . # . . . . # . . . . # . . . . . . . . . # . # . . # . # . + . # . # . . . # . . . . # . . . . # . . . # # # . . . # . . . # # . . . . # . . . . # . . . . # # . + . # . # . . . # . . . # . . . . . . # . . . # . . . . . # . . # . # . . # . . . . # . # . . . . # . + . . # . . . # # # . . # # # . . # # . . . . # . . . # # . . . . # . . . # . . . . . # . . . # # . . + `) +startIOMonitor() +while (true) { + splashScreen() + if (buttonB()) { + basic.showAnimation(` + . . . . . # # . . . . # . . . . # . . . . . . # . . . . . . + . . . . # . . . . # # # . . # . # . . # . . # . # . . . . # + . . . . # . . . . # . . . . # # # . . # # # . . # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # . . . # # . . . # # . . . # # . . . # # . . . # # . . . # + `, 400) + let finalScore = surgery() + if (game.score() > highScore) { + basic.showString("HI", 150) + highScore = finalScore + } + flashDigit(finalScore) + waitButtonB() + } else if (buttonA()) { + testMode() + } else { + basic.pause(100) + } +} + +function surgery(): number { + let score = 0 + let speed = 150 + let opStartTime = input.runningTime() + let procStartTime = -1 + let procNumber = -1 + let procsDone = 0 + let recoveryTry = 0 + let timer = 0 + let state = "CHOOSE PROC" + resetButtons() + while (true) { + basic.pause(10) + let event = getEvent(state) + if (event == "CUT") { + state = "ARREST" + } + // CHECK TIMERS + if (!(procStartTime == -1)) { + if (input.runningTime() - procStartTime > procMaxTime) { + state = "LOST" + } else { + // TODO add code here to speed up near end of proc + } + } + if (input.runningTime() - opStartTime > opMaxTime) { + state = "LOST" + } else { + // TODO add code here to speed up near end of op + } + // PROCESS SPECIFIC STATES + if (state == "CHOOSE PROC") { + if (procNumber == -1) { + procNumber = 1 + showDigit(procNumber) + } else if (event == "SCROLL") { + procNumber = procNumber + 1 + if (procNumber > 9) { + procNumber = 1 + } + showDigit(procNumber) + } else if (event == "SELECT") { + procStartTime = input.runningTime() + state = "HEALTHY" + speed = 100 + } + } else if (state == "HEALTHY") { + speed = 100 + ecg(speed) + if (event == "TWINGE") { + state = "TENSE" + timer = input.runningTime() + } else if (event == "DONE") { + state = "PROC DONE" + } + } else if (state == "TENSE") { + speed = 25 + ecg(speed) + if (event == "TWINGE") { + state = "ARREST" + } else if (input.runningTime() - timer > tenseTime) { + state = "HEALTHY" + } + } else if (state == "ARREST") { + timer = input.runningTime() + recoveryTry = recoveryTriesMax + state = "FLATLINE" + } else if (state == "FLATLINE") { + basic.showLeds(` + . . . . . + . # . # . + . . . . . + . . . . . + # # # # # + `) + beepOn() + if (event == "SHOCK") { + state = "SHOCKING" + } else if (input.runningTime() - timer > flatlineTimeMax) { + state = "LOST" + } + } else if (state == "SHOCKING") { + charging() + basic.showAnimation(` + . . . . # . . . . # . . . . . . . . . . + . . . # . . . . # . . . . # . . . . . . + . . . . . . . # . . . . # . . . . # . . + . . . . . . . . . . . # . . . . # . . . + . . . . . . . . . . . . . . . . # . . . + `, 150) + beepNTimesFor(15, 500) + basic.showAnimation(` + . . . . . . . . . . . . . . . # . . . # + . . . . . . . . . . # . . # . . . . . . + . . . . . # . # . . . . . . . . . . . . + . # . . . . # . . . . . . . . . . . . . + . # . . . . # . . . . # . . . . # . . . + `, 150) + state = "SHOCKED" + } else if (state == "SHOCKED") { + let recover = Math.randomInt(100) + if (recover >= recoveryProbability) { + state = "RECOVERED" + } else { + state = "FAILED" + } + } else if (state == "RECOVERED") { + beepOff() + basic.pause(500) + beep() + basic.showAnimation(` + . . . . . . . . . . . . . . . . . . . . . . . . . + . # . # . . . . . . . # . # . . . . . . . # . # . + . . . . . . . . . . . . . . . . . . . . . . . . . + # . . . # . . . . . # . . . # . . . . . # . . . # + . # # # . . . . . . . # # # . . . . . . . # # # . + `, 400) + state = "HEALTHY" + } else if (state == "FAILED") { + recoveryTry = recoveryTry - 1 + if (recoveryTry > 0) { + state = "FLATLINE" + } else { + state = "LOST" + } + } else if (state == "PROC DONE") { + basic.showAnimation(` + . . . . . . . . . . . . . . . . . . . . . . . . . + . . . . . . . . . . . . . . . . . . . . . . . . # + . . . . . . . . . . . . . . . . . . # . . . . # . + # . . . . # . . . . # . # . . # . # . . # . # . . + . . . . . . # . . . . # . . . . # . . . . # . . . + `, 400) + score = score + pointsForProc(procNumber) + procsDone = procsDone + 1 + procStartTime = -1 + if (procsDone == procsToDo) { + state = "OP DONE" + } else { + procNumber = -1 + state = "CHOOSE PROC" + } + } else if (state == "OP DONE") { + basic.showAnimation(` + . . . . . . . . # . . # . . . . . # . . . . . # . . . . . # . . # . . . . # . . . . . . . . . . . . . . . . . + . . . . # . . # . # . # . . # . . # . . . . . # . . . . . # . . # . . . . # . . . # . . . # . . . . . . . . . + # # # # # # # . . # # # . . # . # # . . . . # # . . . . # # . # # . . . . # . . . # . . . # . . . . . . . . . + # # # # # # # # # # # # # # # . # # # # . . # # # . . . # # . . . # # . . # # # . # . # # # . . # # . . . # # + # . . . # # . . . # # . . . # . # . . . . . # . . . . . # . . . . # . . . . # . . # . # . # . . # . . . . # . + `, 400) + return score + } else if (state == "LOST") { + beepOn() + basic.showLeds(` + . # . # . + . . # . . + . # . # . + . . . . . + # # # # # + `) + basic.pause(3000) + beepOff() + basic.showAnimation(` + . . . . . . . . . . # # # # . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + . . . . # # # # # # . . . . # . . . . # . . . . # # . # . # . . . . # # . # . # . . . . # + # # # # # . . . . # . . . . # . . . . # . . . . # . . . . # . . . . # . . . . # . . . . # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # . . . # # . . . # # . . . # # . . . # # . . . # # . . . # # . . . # # . . . # # . . . # + `, 400) + return score + } + } +} + +/** + * if any button pressed, terminate the animation immediately + */ +function splashScreen() { + let img = images.createImage(` + . # . # . . # . # . . # . # . . # . # . . . # . . . # # . . + # # # # # # . # . # # # # # # # . # . # . # . # . . # . # . + # # # # # # . . . # # # # # # # . . . # . # . # . . # # . . + . # # # . . # . # . . # # # . . # . # . . # . # . . # . . . + . . # . . . . # . . . . # . . . . # . . . . # . . . # . . . + `) + let x = 0 + while (!aWasPressed && !bWasPressed) { + img.showImage(x) + basic.pause(500) + x = x + 5 + if (x >= img.width()) { + x = 0 + } + } +} + +/** + * Test sensing and buzzing + * I/O at moment is (assuming self toning beeper) + * P0 is beeper and nose LED + * P1 is the tweezer sense wire + * P2 is possibly the nose button + * If we want amplification, might have to use piezo library + * which means using extra pins + */ +function testMode() { + while (!(buttonA())) { + if (pins.digitalReadPin(DigitalPin.P1) == 1) { + pins.digitalWritePin(DigitalPin.P0, 1) + basic.showLeds(` + . . . . . + . . . . # + . . . # . + # . # . . + . # . . . + `) + } else { + pins.digitalWritePin(DigitalPin.P0, 0) + basic.showLeds(` + # # # # # + . . # . . + . . # . . + . . # . . + . . # . . + `) + } + basic.pause(100) + } +} + +/** + * SENSE TWINGE/CUT FROM TWEEZERS (10ms per sample) + * @param state TODO + */ +function getEvent(state: string): string { + if (wasTweezers) { + if (tweezerCount_ > 20) { + wasTweezers = false + tweezerCount_ = 0 + return "CUT" + } else if (!isTweezers) { + wasTweezers = false + tweezerCount_ = 0 + return "TWINGE" + } + } + // SENSE A OR B BUTTON PRESSES + if (state == "CHOOSE PROC") { + if (buttonA()) { + return "SCROLL" + } else if (buttonB()) { + return "SELECT" + } + } else if (state == "FLATLINE") { + if (buttonB()) { + return "SHOCK" + } else if (nose()) { + return "SHOCK" + } + } else if (state == "HEALTHY") { + if (buttonB()) { + return "DONE" + } + } + // Clear any flags for unnecessary events in a given state to prevent latching + aWasPressed = false + bWasPressed = false + return "NONE" +} + +function flashDigit(digit: number) { + for (let i = 0; i < 4; i++) { + showDigit(digit) + basic.pause(200) + basic.clearScreen() + basic.pause(200) + } + showDigit(digit) + basic.pause(1000) +} + +/** + * Make a short beep sound + */ +function beep() { + beepOn() + basic.pause(200) + beepOff() +} + +/** + * work out score for a procedure + * @param procNumber TODO + */ +function pointsForProc(procNumber: number): number { + if (procNumber < 4) { + return 1 + } else if (procNumber < 7) { + return 2 + } else { + return 3 + } +} + +/** + * beep n times, for a total duration of m + * @param times TODO + * @param duration TODO + */ +function beepNTimesFor(times: number, duration: number) { + let halfCycle = duration / (times * 2) + for (let i = 0; i < times; i++) { + beepOn() + basic.pause(halfCycle) + beepOff() + basic.pause(halfCycle) + } +} + +function startIOMonitor() { + aWasPressed = false + input.onButtonPressed(Button.A, () => { + aWasPressed = true + }) + bWasPressed = false + input.onButtonPressed(Button.B, () => { + bWasPressed = true + }) + wasTweezers = false + isTweezers = false + tweezerCount_ = 0 + control.inBackground(() => { + let buzzCount = 0 + while (true) { + if (pins.digitalReadPin(DigitalPin.P0) == 1) { + wasTweezers = true + isTweezers = true + tweezerCount_ = tweezerCount_ + 1 + if (buzzCount == 0) { + pins.analogWritePin(AnalogPin.P2, 512) + pins.analogSetPeriod(AnalogPin.P2, 5000) + } + buzzCount = 10 + } else { + isTweezers = false + } + if (buzzCount > 0) { + buzzCount = buzzCount - 1 + if (buzzCount == 0) { + pins.analogWritePin(AnalogPin.P2, 0) + } + } + basic.pause(10) + } + }) +} + +/** + * Shows a single digit, with a nicer font than the standard micro:bit font + * @param digit TODO + */ +function showDigit(digit: number) { + digit = Math.clamp(0, 9, digit) + digitsImg.showImage(digit * 5) +} + +/** + * check to see if button A was pressed recently + */ +function buttonA(): boolean { + if (aWasPressed) { + aWasPressed = false + return true + } + return false +} + +function waitButtonA() { + while (!(buttonA())) { + basic.pause(100) + } +} + +function buttonB(): boolean { + if (bWasPressed) { + bWasPressed = false + return true + } + return false +} + +function waitButtonB() { + while (!(buttonB())) { + basic.pause(100) + } +} + +function beepOn() { + pins.analogWritePin(AnalogPin.P2, 512) + pins.analogSetPeriod(AnalogPin.P2, 2272) +} + +function beepOff() { + pins.analogWritePin(AnalogPin.P2, 0) +} + +function resetButtons() { + aWasPressed = false + bWasPressed = false +} + +function ecg(speed: number) { + beepOn() + pins.digitalWritePin(DigitalPin.P1, 1) + basic.pause(50) + beepOff() + basic.showAnimation(` + . . . . # . . . # . . . # . . . # . . . # . . . . . . . . . . . . . . + . . . . # . . . # . . . # . . . # . . . # . . . . . . . . . . . . . . + . . . . # . . . # . . . # . . . # . . . # . . . . . . . . . . . . . . + . . . . # . . . # # . . # # . . # # . . # # . . . # . . . . . . . . . + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + `, speed) + pins.digitalWritePin(DigitalPin.P1, 0) + basic.pause(speed * 10) +} + +function nose(): boolean { + if (wasNose) { + wasNose = false + return true + } + return false +} + +/** + * start period in microseconds + */ +function charging() { + let period = 2000 + let dec = 500 + pins.analogWritePin(AnalogPin.P2, 512) + pins.analogSetPeriod(AnalogPin.P2, period) + basic.showLeds(` + . # # . . + . . . # . + . . # . . + . . . # . + . # # . . + `) + basic.pause(500) + pins.analogSetPeriod(AnalogPin.P2, period - dec) + basic.showLeds(` + . # # . . + . . . # . + . . # . . + . # . . . + . # # # . + `) + basic.pause(500) + pins.analogSetPeriod(AnalogPin.P2, period - dec * 2) + basic.showLeds(` + . . # . . + . # # . . + . . # . . + . . # . . + . # # # . + `) + basic.pause(500) + beepOff() +} diff --git a/tests/wg-operator-reaction-test.ts b/tests/wg-operator-reaction-test.ts new file mode 100644 index 00000000..f262bc11 --- /dev/null +++ b/tests/wg-operator-reaction-test.ts @@ -0,0 +1,178 @@ +let wasShake: boolean + +input.onShake(() => { + wasShake = true +}) +wait_6Hours() +timeForTest() +alertnessTest() +wait_2Hours() +timeForTest() +alertnessTest() +wait_2Hours() +timeForTest() +alertnessTest() + +/** + * animate back to work + * animate take a rest + */ +function animations() { } + +/** + * wait 6 hours + * because this is a test program, we only wait for a short time + */ +function wait_6Hours() { + basic.showAnimation(` + . . # . . . . . . # . . . . . . . . . . . . . . . . . . . . . . . . . # . . . . + . . # . . . . . # . . . . . . . . . . . . . . . . . . . . . . . . . . . # . . . + . . # . . . . # . . . . # # # . . # . . . . # . . . . # . . # # # . . . . # . . + . . . . . . . . . . . . . . . . . . # . . . # . . . # . . . . . . . . . . . . . + . . . . . . . . . . . . . . . . . . . # . . # . . # . . . . . . . . . . . . . . + `, 500) +} + +/** + * wait for 2 hours + * because this is test code, we only wait a few seconds + */ +function wait_2Hours() { + basic.showAnimation(` + . . # . . . . . . # . . . . . . . . . . . . . . . . . . . . . . . . . # . . . . + . . # . . . . . # . . . . . . . . . . . . . . . . . . . . . . . . . . . # . . . + . . # . . . . # . . . . # # # . . # . . . . # . . . . # . . # # # . . . . # . . + . . . . . . . . . . . . . . . . . . # . . . # . . . # . . . . . . . . . . . . . + . . . . . . . . . . . . . . . . . . . # . . # . . # . . . . . . . . . . . . . . + `, 500) +} + +function alertnessTest() { + let goodResponse = 1000 + let threshold = 5 + let score = 0 + // Start test on button press + let x = 0 + let start = images.createImage(` + . . # . . . . # . . + . . # . . . # . # . + . . # . . . . . # . + . . . . . . . # . . + . . # . . . . # . . + `) + while (!input.buttonIsPressed(Button.B)) { + start.showImage(x) + x = x + 5 + if (x >= start.width()) { + x = 0 + } + basic.pause(300) + } + // Wait for button(s) to be released + while (input.buttonIsPressed(Button.A) || input.buttonIsPressed(Button.B)) { + basic.pause(100) + } + // Run 10 random cognition response tests + for (let i = 0; i < 9; i++) { + // Choose random delay and random outcome + let delay = Math.randomInt(5) + 5 + let outcome = Math.randomInt(2) + // Draw moving dots on screen until delay expires + basic.clearScreen() + for (let j = 0; j < delay; j++) { + led.plot(j % 5, 2) + basic.pause(200) + basic.clearScreen() + } + // Show shake or button icon + if (outcome == 0) { + // Press the button! + basic.showLeds(` + . . . . . + . # # # . + . # # # . + . # # # . + . . . . . + `) + } else { + // Shake the bit! + basic.showLeds(` + # . # . . + # . . # . + # # # # # + # . . # . + # . # . . + `) + } + // Wait up to 3 seconds for button, shake, or timeout + wasShake = false + let timer = input.runningTime() + let timeout = 3000 + while (input.runningTime() < timer + timeout) { + if (wasShake) { + break + } else if (input.buttonIsPressed(Button.B)) { + break + } else { + basic.pause(100) + } + } + // Assess the response and the response time + let response = input.runningTime() - timer + if (outcome == 0 && input.buttonIsPressed(Button.B) && response <= goodResponse) { + score = score + 1 + } else if (outcome == 1 && wasShake && response <= goodResponse) { + score = score + 1 + } + } + // Show final score flashing 5 times (0..9) + for (let k = 0; k < 5; k++) { + basic.showNumber(score, 0) + basic.pause(250) + basic.clearScreen() + basic.pause(250) + } + basic.showNumber(score, 0) + basic.pause(500) + if (score < threshold) { + // Time for a break, show coffee cup animation + for (let l = 0; l < 3; l++) { + basic.showAnimation(` + . . . . . . . . . . . # . . . . # . . . . . . . . . . # . . . . # . . . . . . . + . . . . . . # . . . . # . . . . . . . . . . # . . . . # . . . . . . . . . . . . + # . . # . # # . # . # . . # . # . . # . # . # # . # . . # . # . . # . # . . # . + # . . # # # . . # # # . . # # # . . # # # . . # # # . . # # # . . # # # . . # # + # # # # . # # # # . # # # # . # # # # . # # # # . # # # # . # # # # . # # # # . + `, 400) + } + } else { + // All ok, back to work, show digging animation + for (let m = 0; m < 3; m++) { + basic.showAnimation(` + # . # . . # . . . . # . . . . + . # # . . . # . # . . # . . . + # # # . . . . # # . . . # . # + . . . . . . # # # . . . . # # + . . . . . . . . . . . . # # # + `, 400) + } + } + // Wait for any button press to finish test + while (!input.buttonIsPressed(Button.A) && !input.buttonIsPressed(Button.B)) { + basic.pause(100) + } +} + +/** + * alert the user it is time to take the test + * in a real system, this might give them 5 1 minute warnings + */ +function timeForTest() { + basic.showAnimation(` + . # # # . . # . . . . # # . . . # # . . . . # . . + . # . . . . # . . . . . . # . . . . # . . # # . . + . . # . . . # # # . . # # . . . . # . . . . # . . + . . . # . . . # . . . . . # . . # . . . . . # . . + . # # . . . . # . . . # # . . . # # # . . # # # . + `, 700) +} diff --git a/tests/wg-paintroller.ts b/tests/wg-paintroller.ts new file mode 100644 index 00000000..1f14efbc --- /dev/null +++ b/tests/wg-paintroller.ts @@ -0,0 +1,157 @@ +let maxGameTime: number +let wasShake: boolean + +maxGameTime = 60000 +input.onShake(() => { + wasShake = true +}) +while (true) { + splashScreen() + if (input.buttonIsPressed(Button.B)) { + basic.showAnimation(` + # # # . . # # # . . # # # . . # # # . . # # # . . # # # . . # # # . . # # # . . # # # . . # # # . . # # # . . # # # . . # # # . . # # # . . # # # . . # # # # # + # # # . . # # # # . # # # # . # # # # . # # # # . # # # # . # # # # . # # # # . # # # # . # # # . . # . . . . # . . . . # . . . . # . . . . # # # # # # # # # # + # # # . . # # # . . # # # # . # # # # . # # # # . # # # # . # # # # . # # # # . # # # # . # # # # . # # # . . # # # . . # # # . . # # # # # # # # # # # # # # # + . . . . . . . . . . . . . . . . . . # . . . . # . . . . # . . . . # . . . . # . . . . # . . . . # # . . # # # . # # # # # # # # # # # # # # # # # # # # # # # # + . . . . . . . . . . . . . . . . . . . . . . . # . . . . # # . . # # # . # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + `, 400) + let score = playOneGame() + flashDigit(score, 5) + waitButtonB() + basic.showAnimation(` + # # # # # . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + # # # # # # # # # # . . . . . . . . . . . . . . . . . . . . . # . # . . . . . . . # . # . . . . . . + # # # # # # # # # # # # # # # . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + # # # # # # # # # # # # # # # # # # # # . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + # # # # # # # # # # # # # # # # # # # # # # # # # . . . . . . . . . . . . . . . . . . . . . . . . . + `, 400) + } else if (input.buttonIsPressed(Button.A)) { + calibrate() + } +} + +function playOneGame(): number { + let countDots = 0 + let x = 2 + let y = 2 + let xdir = true + let canvas = images.createImage(` + . . . . . + . . . . . + . . . . . + . . . . . + . . . . . + `) + wasShake = false + let bearing = input.compassHeading() + let startTime = input.runningTime() + while (countDots < 25 && input.runningTime() - startTime < maxGameTime) { + if (wasShake) { + basic.showAnimation(` + . . . . . . . . . . . . . . . . . . . . . # # # . . . . . . . . . . . . . . . . . . . . . . . . . . + . . . . . . . . . . . . . . . . # # # . . . # . . . # # # . . . . . . . . . . . . . . . . . . . . . + . . . . . . . . . . . # # # . . . # . . . . # . . . . # . . . # # # . . . . . . . . . . . . . . . . + . . . . . . # # # . . . # . . . . # . . . . # . . . . # . . . . # . . . # # # . . . . . . . . . . . + . # # # . . . # . . . . # . . . . # . . . . # . . . . # . . . . # . . . . # . . . # # # . . . . . . + `, 50) + let pos = Math.randomInt(5) + if (xdir) { + if (!canvas.pixel(pos, y)) { + canvas.setPixel(pos, y, true) + countDots = countDots + 1 + } + } else if (!canvas.pixel(x, pos)) { + canvas.setPixel(x, pos, true) + countDots = countDots + 1 + } + wasShake = false + canvas.showImage(0) + } else if (Math.abs(input.compassHeading() - bearing) > 60) { + xdir = !xdir + bearing = input.compassHeading() + if (xdir) { + x = Math.randomInt(5) + } else { + y = Math.randomInt(5) + } + } else { + basic.pause(100) + } + } + return dotsToScore(countDots) +} + +function splashScreen() { + let img = images.createImage(` + # # # # . # # # # . # # # # . # # # # . # # # # . # # # # . . # # # . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . # . . . # # . . # # # . # # # # . # # # # . . # # # . . . # # . . . . # . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . # # # . # # # # . # # # # . # # # # . # # # # . # # # # . + # . . . # # . . . # # . . . # # . . . # # . . . # . # # # . . . # . . . # # # . . . . . . . . . . . . . . . . . . . . . # . . . . . # . . . . . # . . . . . # . . . . . # . . . # # . . # . # . # . . # # . . . # # . . . # # . . . # # . . . # . # . . # . . # . # . . . # # . . . . # . . . # . . . # . . . # . . . # . . . . . . . . . . . . . . . . . . . . . . . . . # # # . . . # . . . # # # . # . . . # # . . . # # . . . # # . . . # + # # # # . # # # # . # # # # . # # # # . . # # # . . . # . . . . # . . . . # . . . # # # . . . . . . . . . . . . . . . . # . . . . # # . . . # # # . . # # # # . # # # # # # # # # . # # # # . # # # # . # # # # . # # # # . # # # # . # # # # . # # # # . # # # # . # # # # . # # # # # # # # # . # # # . . # # . . . # . . . . . . . . . . . . . . . . . . . . # # # . . . # . . . . # . . . . # . . . # # # . # # # # . # # # # . # # # # . + # . . . . # . . . . # . . . . . # # # . . . # . . . . # . . . . # . . . . # . . . . # . . . # # # . . . . . . . . . . . # . . . . . # . . . . . # . . . . . # . . . . . # . . . # . . . # # . . # . # . # . . # . # . . # . # . . # . # . . # . . # . # . . . # # . . . . # . . . . . # . . . # . . . # . . . # . . . # . . . . . . . . . . . . . . . # # # . . . # . . . . # . . . . # . . . . # . . . . # . . . # # # . # . . . . # . . . . + # . . . . # . . . . . # # # . . . # . . . . # . . . . # . . . . # . . . . # . . . . # . . . . # . . . # # # . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . # . . . . # . . . . # . . . . # # . . . # # . . . # . . . . # . . . . # . . . . # . . . . # . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . # # # . . . # . . . . # . . . . # . . . . # . . . . # . . . . # . . . . # . . . # # # . # . . . . + `) + let x = 0 + while (!input.buttonIsPressed(Button.A) && !input.buttonIsPressed(Button.B)) { + img.showImage(x) + basic.pause(200) + x = x + 5 + if (x >= img.width()) { + x = 0 + } + } +} + +/** + * rotate canvas + */ +function rotateImage() { } + +function flashDigit(digit: number, times: number) { + for (let i = 0; i < times; i++) { + basic.showNumber(digit, 0) + basic.pause(500) + basic.clearScreen() + basic.pause(500) + } + basic.showNumber(digit, 0) +} + +function waitButtonB() { + while (!input.buttonIsPressed(Button.B)) { + basic.pause(100) + } +} + +function dotsToScore(dots: number): number { + if (dots == 25) { + return 9 + } else if (dots >= 22) { + return 8 + } else if (dots >= 19) { + return 7 + } else if (dots >= 16) { + return 6 + } else if (dots >= 13) { + return 5 + } else if (dots >= 10) { + return 4 + } else if (dots >= 7) { + return 3 + } else if (dots >= 4) { + return 2 + } else if (dots >= 1) { + return 1 + } else { + return 0 + } +} + +function calibrate() { + basic.showString("CAL", 150) + if (input.compassHeading() == -4) { + input.calibrate() + } + while (!input.buttonIsPressed(Button.B)) { + let h = input.compassHeading() + basic.showNumber(h, 150) + } +} diff --git a/tests/wg-perfect-pancakes.ts b/tests/wg-perfect-pancakes.ts new file mode 100644 index 00000000..ed4b73c2 --- /dev/null +++ b/tests/wg-perfect-pancakes.ts @@ -0,0 +1,267 @@ +let state: string +let timer: number +let gesturesRunning: boolean +let wasShake: boolean +let wasLogoUp: boolean +let wasLogoDown: boolean +let wasScreenUp: boolean +let wasScreenDown: boolean + +while (true) { + splashScreen() + if (input.buttonIsPressed(Button.B)) { + // animate: add pancake + basic.showAnimation(` + # # # # # # . . . # . . . . . . . . . . . . . . . + . . . . . . # # # . . # # # . . . . . . . . . . . + . . . . . . . . . . # . . . # # . . . # . . . . . + . . . . . . . . . . . . . . . . # # # . . # # # . + . . . . . . . . . . . . . . . . . . . . # . . . # + `, 250) + runGameOnce() + // animate: pancake done + basic.showAnimation(` + . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . # # # . # # # # # . . . . . . . . . . . . . . . . . . . . . . . . . + . . . . . . . . . . . . . . . . . . . . # . . . # # # # # # # . . . # . . . . . . . . . . . # . # . . . . . . . # . # . . . . . . + . . . . . . . . . . . # # # . # # # # # . # # # . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + # . . . # # # # # # # . . . # . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + . # # # . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + `, 250) + } else if (input.buttonIsPressed(Button.A)) { + testShake() + } +} + +/** + * Runs one complete game from start to end + */ +function runGameOnce() { + let score = 0 + let cooks = 0 + let target_time = 0 + // make sure no gestures are outstanding from last game + wasShake = false + wasLogoUp = false + wasLogoDown = false + wasScreenUp = false + wasScreenDown = false + state = "NEWSIDE" + while (true) { + // Handle any gestures that can happen at any time + let gesture = getGesture() + if (gesture == "FLOOR") { + state = "DROPPED" + } + // Run code appropriate to the present state of the game + if (state == "NEWSIDE") { + target_time = 5 + Math.randomInt(5) + state = "COOKING" + startTimer() + } else if (state == "COOKING") { + // animate: cooking + basic.showAnimation(` + . . . . . . . . . . . . . . . . . . . . + . . . . . . . . . . . . . . . . . . . . + . . . . . . . . . . . . . . . . . . . . + . . . . . # . . . . . . . . . . . . . # + # # # # # . # # # # # # # # # # # # # . + `, 100) + + if (gesture == "FLIP") { + state = "FLIPPING" + } else if (getTimerSec() >= target_time) { + state = "READY" + score = score + 1 + startTimer() + } + } else if (state == "READY") { + // animate: ready + basic.showAnimation(` + . . . . . + . . . . . + . . . . . + # . . . # + . # # # . + `, 100) + if (getTimerSec() > 2) { + state = "BURNING" + score = score - 1 + startTimer() + } else if (gesture == "FLIP") { + state = "FLIPPING" + } + } else if (state == "BURNING") { + // animate: burning + basic.showAnimation(` + . . . . . . . . . . . . . # . . . . # . + . . . . . . . . # . . # . # . . # . . . + . . . . . . # . # . . # . . . . . . . . + . . . . . . # . . . . . . . . . . . . . + # # # # # # # # # # # # # # # # # # # # + `, 100) + if (gesture == "SKY") { + state = "NEWSIDE" + } else if (getTimerSec() > 2) { + state = "BURNT" + } + } else if (state == "FLIPPING") { + // animate: flipping + basic.showAnimation(` + . . . . . . . . . . . . . . . . . . . . # . . . . . . . . . . . . . # . . . . . . . . . . . . . . . + . . . . . . . . . . . . . . . # # # # # . # # . . . # # # . . . # # . # # # # # . . . . . . . . . . + . . . . . . . . . . # # # # # . . . . . . . . # # . # # # . # # . . . . . . . . # # # # # . . . . . + . . . . . # # # # # . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . # # # # # + # # # # # . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + `, 100) + // Prevent a spurious double-flip from happening + wasShake = false + cooks = cooks + 1 + if (cooks == 5) { + state = "GAMEOVER" + } else { + state = "NEWSIDE" + } + } else if (state == "DROPPED") { + // animate: dropped + basic.showAnimation(` + # . . . # . . . . . # . . . # . . . . . + . # . # . . . . . . . # . # . . . . . . + . . # . . . . . . . . . # . . . . . . . + . # . # . . . . . . . # . # . . . . . . + # . . . # . . . . . # . . . # . . . . . + `, 250) + score = 0 + state = "GAMEOVER" + } else if (state == "BURNT") { + // animate: burnt + basic.showAnimation(` + . . . . . . . . . . . . . . . . . . . . . . # . . . . . . . . # . # . . . . . . . # # # . + . . . . . . . . . . . . . . . . . # . . . . . . . . # . # . . . . . . . # # # . . . . . . + . . . . . . . . . . . . . . . . . . . . . # . # . . . . . . . # # # . . . . . . . . . . . + . . . . . . # . # . . # # # . . # . # . . . . . . . # # # . . . . . . . . . . . . . . . . + # # # # # . # # # . . # # # . . # # # . . # # # . . . . . . . . . . . . . . . . . . . . . + `, 250) + score = 0 + state = "GAMEOVER" + } else if (state == "GAMEOVER") { + animateScore(score) + state = "WAITEJECT" + } else if (state == "WAITEJECT") { + if (gesture == "UPSIDEDOWN") { + return + } + } + } +} + +/** + * show score (0..9) flashing + * @param score TODO + */ +function animateScore(score: number) { + score = Math.clamp(0, 9, score) + for (let i = 0; i < 5; i++) { + basic.showNumber(score, 0) + basic.pause(500) + basic.clearScreen() + basic.pause(500) + } + basic.showNumber(score, 0) +} + +/** + * NOTE: Eventually this will move into a gesture library + * It hides all the nasty detail of detecting gestures + */ +function getGesture(): string { + if (!gesturesRunning) { + input.onShake(() => { + wasShake = true + }) + input.onLogoUp(() => { + wasLogoUp = true + }) + input.onLogoDown(() => { + wasLogoDown = true + }) + input.onScreenUp(() => { + wasScreenUp = true + }) + input.onScreenDown(() => { + wasScreenDown = true + }) + gesturesRunning = true + } + // work out which of a possible set of gestures has occurred: + // Button gestures and movement gestures both handled + // This is so that it is easy to also use this on the simulator too + // Generally, B is used for normal OK, A is used for abnormal RECOVERY + // (flip is a normal action, touch sky to turn off smoke alarm is recovery) + let a = input.buttonIsPressed(Button.A) + let b = input.buttonIsPressed(Button.B) + if (state == "COOKING" || state == "READY") { + if (b || wasShake) { + wasShake = false + return "FLIP" + } + } else if (state == "FLIPPING") { + if (a || wasLogoDown) { + wasLogoDown = false + return "FLOOR" + } + } else if (state == "BURNING") { + if (a || wasLogoUp) { + wasLogoUp = false + return "SKY" + } + } else if (state == "GAMEOVER" || state == "WAITEJECT") { + if (b || wasScreenDown) { + wasScreenDown = false + return "UPSIDEDOWN" + } + } + return "NONE" +} + +/** + * start timer by sampling runningtime and storing into starttime + */ +function startTimer() { + timer = input.runningTime() +} + +/** + * get the elapsed time from the global starttime with ref to running time + * in seconds. + */ +function getTimerSec(): number { + let t = (input.runningTime() - timer) / 1000 + return t +} + +/** + * Show a splash screen "Perfect Pancakes >>>" + * Splash screen "PP" with little arrow pointing to the start button + */ +function splashScreen() { + let splash = images.createImage(` + # # # # . . . . . . # # # # . . . . . . . . . . . . . . . . . . . . . + # . . . # . . . . . # . . . # # . . . . . # . . . . . # . . . . . # . + # # # # . . . . . . # # # # . . # . . . . . # . . . . . # . . . . . # + # . . . . . . . . . # . . . . # . . . . . # . . . . . # . . . . . # . + # . . . . . . . . . # . . . . . . . . . . . . . . . . . . . . . . . . + `) + // use show image (not show animation) so that button press is more responsive + let index = 0 + // Any button press finishes the splash screen + while (!input.buttonIsPressed(Button.B) && !input.buttonIsPressed(Button.A)) { + splash.showImage(index * 5) + index = index + 1 + if (index > splash.width() / 5) { + index = 0 + } + basic.pause(250) + } +} + +function testShake() { } diff --git a/tests/wg-right-sugar.ts b/tests/wg-right-sugar.ts new file mode 100644 index 00000000..1f2e653d --- /dev/null +++ b/tests/wg-right-sugar.ts @@ -0,0 +1,242 @@ +let sugarThreshold: number +let ketoneThreshold: number + +// Important parameters +sugarThreshold = 14 +ketoneThreshold = 6 +while (true) { + // splash screen sugar cube (just the right sugar) + basic.showAnimation(` + # # # . . . . . . . . . . . . . . . . . + # # # . . . # # # . . . . . . . . . . . + # # # . . . # # # . . . # # # . . # # # + . . . . . . # # # . . . # # # . . # # # + . . . . . . . . . . . . # # # . . # # # + `, 400) + // ask questions and give advice + quiz() + // wait for button press before restart + waitAnyButton() +} + +function getSugar(): string { + waitNoButtons() + let selection = "MID" + while (!input.buttonIsPressed(Button.B)) { + // high, low, normal? + basic.showAnimation(` + . . . . . # . # . . . . # . . + . # # # . # . # . . . # . # . + . # # # . # . # # # . . . # . + . # # # . # . . # . . . # . . + . . . . . # . . # . . . # . . + `, 400) + // show low, mid, or high as a bar + selection = getLowMidHigh(selection) + } + return selection +} + +function getKetone(): string { + waitNoButtons() + let selection = "MID" + while (!input.buttonIsPressed(Button.B)) { + // high, low, normal? + basic.showAnimation(` + . . . . . . . . # . . . # . . + # # . . . . . # . . . # . # . + # # # # # . . # # . . . . # . + # # . . # . . # . # . . # . . + . . . . . # . . # . . . # . . + `, 400) + // show low, mid, or high as a bar + selection = getLowMidHigh(selection) + } + return selection +} + +function getIll(): boolean { + waitNoButtons() + let selection = false + while (!input.buttonIsPressed(Button.B)) { + // ask question 'happy or sad' + basic.showAnimation(` + . . . . . . . . . . . . # . . . . # . . + . # . # . . # . # . . # . # . . # . # . + . . . . . . . . . . . . . # . . . . # . + # . . . # . # # # . . . # . . . . # . . + . # # # . # . . . # . . # . . . . # . . + `, 400) + // get answer from user + selection = getHappySad(selection) + } + // if we are happy, we are not ill + return !selection +} + +function getLowMidHigh(selection: string): string { + let timeout = 2000 + let timer = input.runningTime() + while (true) { + // show the present level as a line + if (selection == "LOW") { + basic.showLeds(` + . . . . . + . . . . . + . . . . . + . . . . . + # # # # # + `) + } else if (selection == "HIGH") { + basic.showLeds(` + # # # # # + . . . . . + . . . . . + . . . . . + . . . . . + `) + } else { + basic.showLeds(` + . . . . . + . . . . . + # # # # # + . . . . . + . . . . . + `) + } + // process any user input + if (input.buttonIsPressed(Button.A)) { + // cycle round the 3 possible levels + if (selection == "LOW") { + selection = "MID" + } else if (selection == "MID") { + selection = "HIGH" + } else { + selection = "LOW" + } + // This is the 'hold repeat' time if you hold the A button + basic.pause(300) + // restart timer, 2 seconds of inactivity before return to main + timer = input.runningTime() + } else if (input.buttonIsPressed(Button.B)) { + // user is selecting so better return quickly + return selection + } else if (input.runningTime() > timer + timeout) { + // timeout, so return to main to re-prompt user + return selection + } else { + // This slows the loop down to stop the emulator being busy + // and also preserves battery life on the micro:bit + // it also affects the worst case response time + // it also affects the response time + basic.pause(100) + } + } +} + +/** + * Wait for all buttons to be released + * This prevents spurious selection in next question + */ +function waitNoButtons() { + while (input.buttonIsPressed(Button.A) || input.buttonIsPressed(Button.B)) { + basic.pause(100) + } +} + +function getHappySad(selection: boolean): boolean { + let timeout = 2000 + let timer = input.runningTime() + while (!input.buttonIsPressed(Button.B)) { + // Show present selection + if (selection) { + basic.showLeds(` + . . . . . + . # . # . + . . . . . + # . . . # + . # # # . + `) + } else { + basic.showLeds(` + . . . . . + . # . # . + . . . . . + . # # # . + # . . . # + `) + } + // Wait for any change in the selection + if (input.buttonIsPressed(Button.A)) { + selection = !selection + // This is the repeat time if button A held down + basic.pause(500) + timer = input.runningTime() + } else if (input.runningTime() > timer + timeout) { + return selection + } else { + // Preserve battery life on micro:bit and prevent emulator being busy + // This is also the response time to a button press + basic.pause(100) + } + } + return selection +} + +/** + * Button A changes value, Button B selects value + */ +function quiz() { + let sugar = getSugar() + if (sugar != "HIGH") { + // All is ok (tick) + basic.showAnimation(` + . . . . . . . . . . . . . . . . . . . . . . . . . + . . . . . . . . . . . . . . . . . . . . . . . . # + . . . . . . . . . . . . . . . . . . # . . . . # . + # . . . . # . . . . # . # . . # . # . . # . # . . + . . . . . . # . . . . # . . . . # . . . . # . . . + `, 400) + } else { + // Button A changes value, Button B selects value + let ketone = getKetone() + if (ketone != "HIGH") { + // Button A changes value, Button B selects value + let ill = getIll() + if (!ill) { + // Time to rest (jump into bed) + basic.showAnimation(` + . . . . . # # . . . . # . . . . # . . . . . . # . . . . . . + . . . . # . . . . # # # . . # . # . . # . . # . # . . . . # + . . . . # . . . . # . . . . # # # . . # # # . . # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # . . . # # . . . # # . . . # # . . . # # . . . # # . . . # + `, 400) + } else { + // Test more often (clock shows 2 hour interval) + basic.showAnimation(` + . . # . . . . . . . . . . . . . . . . . . # # . . . . . . . . # # . . . . . . . . # # . . + . . # . . . . . . . . . . . . . . . . . . . . # . . . . . . . . . # . . . . . . . . . # . + . . # . . . . # # # . . # . . # # # . . . . # . . . . . . . . . # . . . . . . . . . # . . + . . . . . . . . . . . . # . . . . . . . . # . . . . . . . . . # . . . . . . . . . # . . . + . . . . . . . . . . . . # . . . . . . . . # # # . . . . . . . # # # . . . . . . . # # # . + `, 400) + } + } else { + // Get some help (call the diabetes care team on the phone) + basic.showAnimation(` + . . . . . . . . . . # # # # # # # . . . # # . . . # # . . . # # . . . # # # . . # # . # . # # . . # + . . . . . # # # # # # . . . # # . . . . # . . . . # . . . . # . . . . # . . . . # . . . . # . . . . + # # # # # # . . . # . . . . . # . . . . # . . . . # . . . . # . . . . # . . . . # . . . . # . . . . + # . # . # . . # . . . . # . . # . . . . # . . . . # . . . . # . . . . # . . . . # . . . . # . . . . + . # # # . . # # # . . # # # . # # . . . # # . . # # # . # . # # # . . # # . . . # # . . . # # . . . + `, 400) + } + } +} + +function waitAnyButton() { + while (!input.buttonIsPressed(Button.A) && !input.buttonIsPressed(Button.B)) { + basic.pause(100) + } +} diff --git a/tests/wg-user-confidance.ts b/tests/wg-user-confidance.ts new file mode 100644 index 00000000..d03df848 --- /dev/null +++ b/tests/wg-user-confidance.ts @@ -0,0 +1,488 @@ +let AWasPressed: boolean +let BWasPressed: boolean +let wasShake: boolean +let dots025: Image + +dots025 = images.createImage(` + . . . . . # . . . . # # . . . # # # . . # # # # . # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . # . . . . # # . . . # # # . . # # # # . # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . # . . . . # # . . . # # # . . # # # # . # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . # . . . . # # . . . # # # . . # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . # . . . . # # . . . # # # . . # # # # . # # # # # + `) +let tests = "DABPXYZSCT" +let test = 0 +let prevTest = -1 +startIOMonitor() +while (true) { + let testLetter = tests[test] + let autoRun = false + if (testLetter == "D" || testLetter == "A" || testLetter == "B") { + autoRun = true + } + if (!(test == prevTest)) { + basic.showString(tests[test], 200) + prevTest = test + } + if (AWasPressed || autoRun) { + AWasPressed = false + if (testLetter == "D") { + testDisplay() + test = test + 1 + } else if (testLetter == "A") { + testButtonA() + test = test + 1 + } else if (testLetter == "B") { + testButtonB() + test = test + 1 + } else if (testLetter == "P") { + testPads() + } else if (testLetter == "X") { + testTiltX() + } else if (testLetter == "Y") { + testTiltY() + } else if (testLetter == "Z") { + testTiltZ() + } else if (testLetter == "S") { + testShake() + } else if (testLetter == "C") { + testCompass() + } else if (testLetter == "T") { + testTemperature() + } else { + // end of tests + basic.showLeds(` + . . . . . + . . . . # + . . . # . + # . # . . + . # . . . + `, 400) + } + prevTest = -1 + AWasPressed = false + BWasPressed = false + } else if (BWasPressed) { + BWasPressed = false + if (test < tests.length - 1) { + test = test + 1 + } else { + test = 3 + } + } else { + basic.pause(100) + } +} + +/** + * flash all LEDs 5 times + */ +function testDisplay() { + for (let i = 0; i < 5; i++) { + basic.plotLeds(` + # # # # # + # # # # # + # # # # # + # # # # # + # # # # # + `) + basic.pause(200) + basic.clearScreen() + basic.pause(200) + } + // cycle all LEDs from 1 to 25 + basic.showAnimation(` + # . . . . # # . . . # # # . . # # # # . # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + . . . . . . . . . . . . . . . . . . . . . . . . . # . . . . # # . . . # # # . . # # # # . # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . # . . . . # # . . . # # # . . # # # # . # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . # . . . . # # . . . # # # . . # # # # . # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . # . . . . # # . . . # # # . . # # # # . # # # # # + `, 400) +} + +function testButtonA() { + basic.plotLeds(` + . . # . . + . # . # . + . # # # . + . # . # . + . # . # . + `) + // wait for A pressed + while (!input.buttonIsPressed(Button.A)) { + basic.pause(100) + } + basic.plotLeds(` + . # . . . + # . # . . + # # # . . + # . # . . + # . # . . + `) + // wait for A released + while (input.buttonIsPressed(Button.A)) { + basic.pause(100) + } + basic.plotLeds(` + . . # . . + . # . # . + . # # # . + . # . # . + . # . # . + `) + basic.pause(1000) +} + +function testTiltX() { + basic.clearScreen() + let prevx = 0 + while (!AWasPressed && !BWasPressed) { + basic.pause(100) + let x = input.acceleration(Dimension.X) + let x2 = x / 512 + 2 + let x3 = Math.clamp(0, 4, x2) + // sticky trace + led.plot(x3, 0) + // middle line is actual/live + if (x3 != prevx) { + led.unplot(prevx, 2) + prevx = x3 + } + led.plot(x3, 2) + // bottom line is -4G, -2G, 1G, +2G, +4G + if (x <= -2048) { + led.plot(0, 4) + } else if (x <= -1024) { + led.plot(1, 4) + } else if (x <= 1024) { + led.plot(2, 4) + } else if (x <= 2048) { + led.plot(3, 4) + } else { + led.plot(4, 4) + } + } +} + +function testShake() { + wasShake = false + basic.plotLeds(` + . . . . . + . . . . . + . . # . . + . . . . . + . . . . . + `) + while (!AWasPressed && !BWasPressed) { + if (wasShake) { + wasShake = false + basic.plotLeds(` + # # # # # + # # # # # + # # # # # + # # # # # + # # # # # + `) + basic.pause(500) + basic.plotLeds(` + . . . . . + . . . . . + . . # . . + . . . . . + . . . . . + `) + } else { + basic.pause(100) + } + } +} + +function testCompass() { + if (input.compassHeading() < 0) { + input.calibrate() + } + basic.clearScreen() + while (!AWasPressed && !BWasPressed) { + let d = input.compassHeading() + d = d / 22 + d = Math.clamp(0, 15, d) + d = (d + 2) % 16 + if (d < 4) { + led.plot(d, 0) + } else if (d < 8) { + led.plot(4, d - 4) + } else if (d < 12) { + led.plot(4 - d - 8, 4) + } else { + led.plot(0, 4 - d - 12) + } + basic.pause(100) + } +} + +function testPads() { + let TESTSPEED = 500 + AWasPressed = false + BWasPressed = false + // Make sure all pins are inputs, before test starts + let p0 = pins.digitalReadPin(DigitalPin.P0) + let p1 = pins.digitalReadPin(DigitalPin.P1) + let p2 = pins.digitalReadPin(DigitalPin.P2) + let ok0 = 0 + let ok1 = 0 + let ok2 = 0 + while (!AWasPressed && !BWasPressed) { + basic.clearScreen() + // ## P0 out low, read from P1 and P2 + ok0 = 0 + pins.digitalWritePin(DigitalPin.P0, 0) + basic.pause(TESTSPEED) + p1 = pins.digitalReadPin(DigitalPin.P1) + p2 = pins.digitalReadPin(DigitalPin.P2) + if (p1 == 0) { + led.plot(0, 0) + ok0 = ok0 + 1 + } + if (p2 == 0) { + led.plot(1, 0) + ok0 = ok0 + 1 + } + // ## P0 out high, read from P1 and P2 + pins.digitalWritePin(DigitalPin.P0, 1) + basic.pause(TESTSPEED) + p1 = pins.digitalReadPin(DigitalPin.P1) + p2 = pins.digitalReadPin(DigitalPin.P2) + if (p1 == 1) { + led.plot(2, 0) + ok0 = ok0 + 1 + } + if (p2 == 1) { + led.plot(3, 0) + ok0 = ok0 + 1 + } + // set back to an input + p0 = pins.digitalReadPin(DigitalPin.P0) + // ## P1 out low, read from P0 and P2 + ok1 = 0 + pins.digitalWritePin(DigitalPin.P1, 0) + basic.pause(TESTSPEED) + p0 = pins.digitalReadPin(DigitalPin.P0) + p2 = pins.digitalReadPin(DigitalPin.P2) + if (p0 == 0) { + led.plot(0, 1) + ok1 = ok1 + 1 + } + if (p2 == 0) { + led.plot(1, 1) + ok1 = ok1 + 1 + } + // ## P1 out high, read from P0 and P2 + pins.digitalWritePin(DigitalPin.P1, 1) + basic.pause(TESTSPEED) + p0 = pins.digitalReadPin(DigitalPin.P0) + p2 = pins.digitalReadPin(DigitalPin.P2) + if (p0 == 1) { + led.plot(2, 1) + ok1 = ok1 + 1 + } + if (p2 == 1) { + led.plot(3, 1) + ok1 = ok1 + 1 + } + // set back to an input + p0 = pins.digitalReadPin(DigitalPin.P1) + // ## P2 out low, read from P0 and P1 + ok2 = 0 + pins.digitalWritePin(DigitalPin.P2, 0) + basic.pause(TESTSPEED) + p0 = pins.digitalReadPin(DigitalPin.P0) + p1 = pins.digitalReadPin(DigitalPin.P1) + if (p0 == 0) { + led.plot(0, 2) + ok2 = ok2 + 1 + } + if (p1 == 0) { + led.plot(1, 2) + ok2 = ok2 + 1 + } + // ## P2 out high, read from P0 and P1 + pins.digitalWritePin(DigitalPin.P2, 1) + basic.pause(TESTSPEED) + p0 = pins.digitalReadPin(DigitalPin.P0) + p1 = pins.digitalReadPin(DigitalPin.P1) + if (p0 == 1) { + led.plot(2, 2) + ok2 = ok2 + 1 + } + if (p1 == 1) { + led.plot(3, 2) + ok2 = ok2 + 1 + } + p2 = pins.digitalReadPin(DigitalPin.P2) + // ## Assess final test status + if (ok0 == 4) { + led.plot(4, 0) + } + basic.pause(TESTSPEED) + if (ok1 == 4) { + led.plot(4, 1) + } + basic.pause(TESTSPEED) + if (ok2 == 4) { + led.plot(4, 2) + } + basic.pause(TESTSPEED) + if (ok0 + ok1 + ok2 == 12) { + // all tests passed + led.plot(4, 4) + } + // ## Test cycle finished + basic.pause(1000) + } + // intentionally don't clear A and B flags, so main loop can process them. +} + +/** + * - show number of dots on screen (0..25) to represent temperature in celcius + */ +function testTemperature() { + while (!AWasPressed && !BWasPressed) { + let temp = input.temperature() - 10 + temp = Math.clamp(0, 25, temp) + dots025.plotFrame(temp) + basic.pause(500) + } +} + +function testButtonB() { + basic.plotLeds(` + . # # . . + . # . # . + . # # . . + . # . # . + . # # . . + `) + // wait for B pressed + while (!input.buttonIsPressed(Button.B)) { + basic.pause(100) + } + basic.plotLeds(` + . . # # . + . . # . # + . . # # . + . . # . # + . . # # . + `) + // wait for B released + while (input.buttonIsPressed(Button.B)) { + basic.pause(100) + } + basic.plotLeds(` + . # # . . + . # . # . + . # # . . + . # . # . + . # # . . + `) + basic.pause(1000) +} + +function testTiltY() { + basic.clearScreen() + let prevy = 0 + while (!AWasPressed && !BWasPressed) { + basic.pause(100) + let y = input.acceleration(Dimension.Y) + let y2 = y / 512 + 2 + let y3 = Math.clamp(0, 4, y2) + // sticky trace + led.plot(0, y3) + // middle line is actual/live + if (y3 != prevy) { + led.unplot(2, prevy) + prevy = y3 + } + led.plot(2, y3) + // bottom line is -4G, -2G, 1G, +2G, +4G + if (y <= -2048) { + led.plot(4, 0) + } else if (y <= -1024) { + led.plot(4, 1) + } else if (y <= 1024) { + led.plot(4, 2) + } else if (y <= 2048) { + led.plot(4, 3) + } else { + led.plot(4, 4) + } + } +} + +function testTiltZ() { + basic.clearScreen() + while (!AWasPressed && !BWasPressed) { + let z = input.acceleration(Dimension.Z) + if (z < -2000) { + basic.plotLeds(` + # . . . # + # . . . # + # . . . # + # . . . # + # . . . # + `) + } else if (z <= -1030) { + basic.plotLeds(` + . # . # . + . # . # . + . # . # . + . # . # . + . # . # . + `) + } else if (z <= 1000) { + basic.plotLeds(` + . . # . . + . . # . . + . . # . . + . . # . . + . . # . . + `) + } else if (z <= 1030) { + basic.plotLeds(` + . . . . . + . . . . . + # # # # # + . . . . . + . . . . . + `) + } else if (z <= 2000) { + basic.plotLeds(` + . . . . . + # # # # # + . . . . . + # # # # # + . . . . . + `) + } else { + basic.plotLeds(` + # # # # # + . . . . . + . . . . . + . . . . . + # # # # # + `) + } + basic.pause(100) + } +} + +function startIOMonitor() { + input.onButtonPressed(Button.A, () => { + AWasPressed = true + }) + input.onButtonPressed(Button.B, () => { + BWasPressed = true + }) + input.onShake(() => { + wasShake = true + }) +} diff --git a/theme/blockly-toolbox.less b/theme/blockly-toolbox.less new file mode 100644 index 00000000..cdeca055 --- /dev/null +++ b/theme/blockly-toolbox.less @@ -0,0 +1,47 @@ + +/******************************* + Blockly toolbox +*******************************/ + +div.blocklyTreeRow { + box-shadow: inset 0 -1px 0 0 #ecf0f1; + + margin-bottom: 0px !important; + + -webkit-transition-property: background-color; /* Safari */ + -webkit-transition-duration: 1s; /* Safari */ + transition-property: background-color; + transition-duration: 1s; +} + +/* Blockly toolbox font size same as the page font */ +span.blocklyTreeLabel { + font-family: @pageFont !important; + font-weight: 200; +} + +.blocklyToolboxDiv, .monacoToolboxDiv { + background-color: white !important; + border-left: 1px solid #ecf0f1 !important; + box-shadow: 4px 0px 2px -4px rgba(0,0,0,0.12), 4px 0px 2px -4px rgba(0,0,0,0.24); +} + +/* Mobile */ +@media only screen and (max-width: @largestMobileScreen) { + .blocklyToolboxDiv, .monacoToolboxDiv { + border-left: 0 !important; + } + div.blocklyTreeRoot { + padding: 0; + } +} + +/* Tablet */ +@media only screen and (min-width: @tabletBreakpoint) and (max-width: @largestTabletScreen) { + .blocklyToolboxDiv, .monacoToolboxDiv { + border-left: 0 !important; + } + div.blocklyTreeRoot { + padding: 0; + } +} \ No newline at end of file diff --git a/theme/blockly.less b/theme/blockly.less index d0d5a807..f8e9ba23 100644 --- a/theme/blockly.less +++ b/theme/blockly.less @@ -4,41 +4,19 @@ @import 'blockly-core'; +/******************************* + Blockly CSS +*******************************/ + /* Reference import */ @import (reference) "semantic.less"; -/******************************* - Blockly -*******************************/ -.blocklyToolboxDiv { - padding:7px; -} - -div.blocklyTreeRow { - border-radius:8px; - box-shadow: inset 0 -1px 0 0 #ecf0f1; - - -webkit-transition-property: background-color; /* Safari */ - -webkit-transition-duration: 1s; /* Safari */ - transition-property: background-color; - transition-duration: 1s; -} - -/* Blockly toolbox font size same as the page font */ -span.blocklyTreeLabel { - font-family: @pageFont !important; - font-weight: 200; -} - -.blocklyToolboxDiv, .monacoToolboxDiv { - border-left: 1px solid #ecf0f1 !important; - box-shadow: 4px 0px 2px -4px rgba(0,0,0,0.12), 4px 0px 2px -4px rgba(0,0,0,0.24); -} - -/* Remove shadow around blockly blocks */ -.blocklyPathDark, .blocklyPathLight { - display: none; +text.blocklyText { + font-weight: 600; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: subpixel-antialiased; + -webkit-font-smoothing: antialiased; } /* Blockly Field: Grid picker */ @@ -50,26 +28,8 @@ span.blocklyTreeLabel { border-radius: 10px; } -.blocklyFlyoutBackground { - fill: #42495F !important; -} - -/* Mobile */ -@media only screen and (max-width: @largestMobileScreen) { - .blocklyToolboxDiv, .monacoToolboxDiv { - border-left: 0 !important; - } - div.blocklyTreeRoot { - padding: 0; - } -} - -/* Tablet */ -@media only screen and (min-width: @tabletBreakpoint) and (max-width: @largestTabletScreen) { - .blocklyToolboxDiv, .monacoToolboxDiv { - border-left: 0 !important; - } - div.blocklyTreeRoot { - padding: 0; - } +/* Led field editor */ +.blocklyLedOn { + stroke: white; + stroke-width: 1px; } \ No newline at end of file diff --git a/theme/site/collections/menu.variables b/theme/site/collections/menu.variables index df35e326..6f085f93 100644 --- a/theme/site/collections/menu.variables +++ b/theme/site/collections/menu.variables @@ -1,6 +1,3 @@ /******************************* User Variable Overrides *******************************/ - -@invertedBackground: #525A67; -@dropdownMenuDistance: 0px; diff --git a/theme/site/elements/input.overrides b/theme/site/elements/input.overrides index 3bb7de84..cba59efe 100644 --- a/theme/site/elements/input.overrides +++ b/theme/site/elements/input.overrides @@ -1,15 +1,3 @@ /******************************* Site Overrides *******************************/ - -.ui.inverted.input input { - background:#424852; - border-radius: 20px; - border: 0px !important; - padding: 0.2em !important; - padding-left: 0.6em !important; -} - -.rtl .ui.inverted.input input { - padding-right: 0.6em !important; -} diff --git a/theme/site/globals/site.variables b/theme/site/globals/site.variables index e13f9e3e..e73dad24 100644 --- a/theme/site/globals/site.variables +++ b/theme/site/globals/site.variables @@ -6,9 +6,8 @@ @fontName : 'Roboto Mono'; -/*------------------- - Site Colors ---------------------*/ +@headerFont : 'Roboto Mono'; +@pageFont : 'Roboto Mono'; @primaryColor: #3CB5B5; @secondaryColor: #43C9C9; @@ -27,7 +26,6 @@ @pageBackground : #FDFDFA; - /******************************* PXT Overrides *******************************/ @@ -35,3 +33,69 @@ @blocklyToolboxColor: #F6F4E6; @blocklyFlyoutColor: #42495F; + +/*------------------- + Menu +-------------------- + +@mainMenuInvertedBackground: @blue; +@mainMenuTutorialBackground: @orange; + +@mainMenuBlocksJsToggleColor: @primaryColor; + +@tutorialSelectedMenuColor: @blue; +*/ + +/*------------------- + Layout +-------------------- + +@sideBarWidth: 22rem; +@simulatorWidth: 27rem; +@simulatorWidthSmall: 20rem; +*/ + +/*------------------- + Background +-------------------- + +@simulatorBackground: #FDFDFF; +@editorToolsBackground: @simulatorBackground; +@blocklySvgColor: #ecf0f1; +*/ + +/*------------------- + Side Docs +-------------------- + +@sidedocsButtonsTop: (@mainMenuHeight + 1rem); +@sidedocsButtonsRight: 4.25rem; +*/ + +/*------------------- + Editor +-------------------- + +@blocklyToolboxColor: rgba(0, 0, 0, 0.05); +@trashIconColor: @primaryColor; +*/ + + +/*------------------- + Flyout +-------------------- + +@flyoutLabelColor: white; +@blocklyFlyoutColor: #4b4949; +@blocklyFlyoutColorOpacity: 1.0; +@monacoFlyoutColor: @blocklyFlyoutColor; +@blocklyFlyoutButtonColor: @secondaryColor; +*/ + +/*------------------- + Serial +-------------------- + +@serialTextColor: black; +@serialGraphBackground: #d9d9d9; +*/ \ No newline at end of file diff --git a/theme/site/modules/dimmer.variables b/theme/site/modules/dimmer.variables index 6f085f93..ed6cfe0b 100644 --- a/theme/site/modules/dimmer.variables +++ b/theme/site/modules/dimmer.variables @@ -1,3 +1,5 @@ /******************************* User Variable Overrides *******************************/ + +@backgroundColor: fade(@grey, 40%); \ No newline at end of file diff --git a/theme/site/modules/transition.overrides b/theme/site/modules/transition.overrides index d7ab3281..cba59efe 100644 --- a/theme/site/modules/transition.overrides +++ b/theme/site/modules/transition.overrides @@ -1,175 +1,3 @@ /******************************* Site Overrides *******************************/ - - -/*-------------- - Rotate In ----------------*/ - -/* Inward */ -.transition.rotate { - animation-duration: 0.6s; - transition-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); -} -.transition.rotate.in { - animation-name: rotateIn; -} -.transition[class*="rotate down left"].in { - animation-name: rotateInDownLeft; -} -.transition[class*="rotate down right"].in { - animation-name: rotateInDownRight; -} -.transition[class*="rotate up left"].in { - animation-name: rotateInUpLeft; -} -.transition[class*="rotate up right"].in { - animation-name: rotateInUpRight; -} - -/* Outward */ -.transition.rotate.out { - animation-name: rotateOut; -} -.transition[class*="rotate down left"].out { - animation-name: rotateOutDownLeft; -} -.transition[class*="rotate down right"].out { - animation-name: rotateOutDownRight; -} -.transition[class*="rotate up left"].out { - animation-name: rotateOutUpLeft; -} -.transition[class*="rotate up right"].out { - animation-name: rotateOutUpRight; -} - -/* In */ -@keyframes rotateIn { - from { - transform-origin: center; - transform: rotate3d(0, 0, 1, -200deg); - opacity: 0; - } - - to { - transform-origin: center; - transform: none; - opacity: 1; - } -} -@keyframes rotateInDownLeft { - from { - transform-origin: left bottom; - transform: rotate3d(0, 0, 1, -45deg); - opacity: 0; - } - - to { - transform-origin: left bottom; - transform: none; - opacity: 1; - } -} -@keyframes rotateInDownRight { - from { - transform-origin: right bottom; - transform: rotate3d(0, 0, 1, 45deg); - opacity: 0; - } - - to { - transform-origin: right bottom; - transform: none; - opacity: 1; - } -} -@keyframes rotateInUpLeft { - from { - transform-origin: left bottom; - transform: rotate3d(0, 0, 1, 45deg); - opacity: 0; - } - - to { - transform-origin: left bottom; - transform: none; - opacity: 1; - } -} -@keyframes rotateInUpRight { - from { - transform-origin: right bottom; - transform: rotate3d(0, 0, 1, -90deg); - opacity: 0; - } - - to { - transform-origin: right bottom; - transform: none; - opacity: 1; - } -} - -/* Out */ -@keyframes rotateOut { - from { - transform-origin: center; - opacity: 1; - } - - to { - transform-origin: center; - transform: rotate3d(0, 0, 1, 200deg); - opacity: 0; - } -} -@keyframes rotateOutDownLeft { - from { - transform-origin: left bottom; - opacity: 1; - } - - to { - transform-origin: left bottom; - transform: rotate3d(0, 0, 1, 45deg); - opacity: 0; - } -} -@keyframes rotateOutDownRight { - from { - transform-origin: right bottom; - opacity: 1; - } - - to { - transform-origin: right bottom; - transform: rotate3d(0, 0, 1, -45deg); - opacity: 0; - } -} -@keyframes rotateOutUpLeft { - from { - transform-origin: left bottom; - opacity: 1; - } - - to { - transform-origin: left bottom; - transform: rotate3d(0, 0, 1, -45deg); - opacity: 0; - } -} -@keyframes rotateOutUpRight { - from { - transform-origin: right bottom; - opacity: 1; - } - - to { - transform-origin: right bottom; - transform: rotate3d(0, 0, 1, 90deg); - opacity: 0; - } -} \ No newline at end of file diff --git a/theme/site/modules/video.overrides b/theme/site/modules/video.overrides deleted file mode 100644 index cba59efe..00000000 --- a/theme/site/modules/video.overrides +++ /dev/null @@ -1,3 +0,0 @@ -/******************************* - Site Overrides -*******************************/ diff --git a/theme/site/modules/video.variables b/theme/site/modules/video.variables deleted file mode 100644 index e69de29b..00000000 diff --git a/theme/style.less b/theme/style.less index 1ad967f9..dc4401e3 100644 --- a/theme/style.less +++ b/theme/style.less @@ -1,10 +1,10 @@ /* Import all components */ -@import 'semantic'; +@import 'pxtsemantic'; @import 'pxt'; +@import 'blockly-toolbox'; @import 'themes/default/globals/site.variables'; @import 'themes/pxt/globals/site.variables'; @import 'site/globals/site.variables'; -@import 'themes/default/collections/menu.variables'; /* Reference import */ @import (reference) "semantic.less"; @@ -12,62 +12,66 @@ /******************************* Add your custom CSS here *******************************/ -/* not relevant in new UI -.openproject { - background: #4ECC60 !important; -} */ -.blocks-menuitem.active, .javascript-menuitem.active { - background: #738791 !important; +/* Roboto font */ +@RobotoFont: data-uri("../docs/static/fonts/Roboto_400_normal.woff"); + +@font-face { + font-family: 'Roboto'; + src: @RobotoFont format("woff"); } -/* not relevant in new UI -.help-dropdown-menuitem, .more-dropdown-menuitem { - background: #424955 !important; - margin-right:0px !important; -} */ - -.huge.download-button i { - display:none !important; // otherwise spans 2 lines +.ui.button.download-button { + &:extend(.ui.purple.button all); } -.play-button { - &:extend(.ui all); - &:extend(.button all); - &:extend(.blue all); +.ui.button.download-button:hover { + background-color: #30a7a7; + color: white; } -.download-button { - &:extend(.ui all); - &:extend(.button all); - &:extend(.yellow all); +.docs.inlinebutton.ui.button.download-button:hover { + &:extend(.ui.purple.button all); } -#filelist .menu { - width: 100%; +.ui.button.play-button.play-button-full { + &:extend(.ui.inverted.button all); +} + +.ui.button.getting-started-btn { + &:extend(.ui.orange.button all); +} + +.ui.button.editortools-btn { + &:extend(.ui.blue.button all); +} + +.ui.button.exit-tutorial-btn { + &:extend(.ui.blue.button all); +} + +#filelist, #editortools { + background: #fff data-uri("../docs/static/logo_texture.png") 0 0 repeat !important; } #downloadArea { background: transparent !important; } -.organization { - top: 1.6em; -} - -/* Mobile */ -@media only screen and (max-width: @largestMobileScreen) { - .blocklyTreeLabel { - font-size: 0.5rem !important; +.ui.home { + .getting-started-segment { + background-position: 50% 25%; } } - /* Mobile */ @media only screen and (max-width: @largestMobileScreen) { #filelist { background: transparent !important; } + #blocklySearchArea { + display: none !important; + } } /* Tablet */ @@ -84,3 +88,29 @@ /* Large Monitor */ @media only screen and (min-width: @largeMonitorBreakpoint) { } + + +/* Download dialog */ +.ui.downloaddialog.modal>.content { + padding: 1rem; +} + +.ui.webusbpair, .ui.upload { + .firmware { + background-color: #FFFFCE; + div.image { + justify-content: center; + display: flex; + padding: 1rem; + + img { + height:100px; + } + } + } + .instructions { + img { + margin-bottom:1rem; + } + } +} \ No newline at end of file diff --git a/theme/theme.config b/theme/theme.config index 84bac825..0e68dd06 100644 --- a/theme/theme.config +++ b/theme/theme.config @@ -39,38 +39,38 @@ @step : 'pxt'; /* Collections */ -@breadcrumb : 'default'; -@form : 'default'; +@breadcrumb : 'pxt'; +@form : 'pxt'; @grid : 'pxt'; @menu : 'pxt'; @message : 'pxt'; -@table : 'default'; +@table : 'pxt'; /* Modules */ -@accordion : 'default'; -@checkbox : 'default'; +@accordion : 'pxt'; +@checkbox : 'pxt'; @dimmer : 'pxt'; -@dropdown : 'default'; -@embed : 'default'; +@dropdown : 'pxt'; +@embed : 'pxt'; @modal : 'pxt'; -@nag : 'default'; -@popup : 'default'; -@progress : 'default'; -@rating : 'default'; -@search : 'default'; -@shape : 'default'; -@sidebar : 'default'; -@sticky : 'default'; -@tab : 'default'; +@nag : 'pxt'; +@popup : 'pxt'; +@progress : 'pxt'; +@rating : 'pxt'; +@search : 'pxt'; +@shape : 'pxt'; +@sidebar : 'pxt'; +@sticky : 'pxt'; +@tab : 'pxt'; @transition : 'default'; /* Views */ -@ad : 'default'; +@ad : 'pxt'; @card : 'pxt'; -@comment : 'default'; -@feed : 'default'; -@item : 'default'; -@statistic : 'default'; +@comment : 'pxt'; +@feed : 'pxt'; +@item : 'pxt'; +@statistic : 'pxt'; /******************************* Folders @@ -91,9 +91,4 @@ @fontPath : 'fonts'; -/* -@headerFont : 'Segoe UI', 'Helvetica Neue', Arial, Helvetica, sans-serif; -@pageFont : 'Segoe UI', 'Helvetica Neue', Arial, Helvetica, sans-serif; -*/ - -/* End Config */ +/* End Config */ \ No newline at end of file diff --git a/travis-tests.sh b/travis-tests.sh index f1b58d3c..bcc0c613 100755 --- a/travis-tests.sh +++ b/travis-tests.sh @@ -7,3 +7,4 @@ export KS_FORCE_CLOUD=yes (cd libs/lang-test0; node ../../node_modules/pxt-core/built/pxt.js test) (cd libs/lang-test1; node ../../node_modules/pxt-core/built/pxt.js test) node node_modules/pxt-core/built/pxt.js testdir tests +(cd libs/hello; node ../../node_modules/pxt-core/built/pxt.js testconv https://az851932.vo.msecnd.net/files/td-converter-tests-v1.json) diff --git a/webmanifest.json b/webmanifest.json index b85ed476..68b81b56 100644 --- a/webmanifest.json +++ b/webmanifest.json @@ -1,5 +1,7 @@ { - "name": "mini.pxt.io", + "name": "makecode.microbit.org", + "display": "fullscreen", + "orientation": "portrait", "icons": [ { "src": "./static/icons/android-chrome-36x36.png", @@ -48,5 +50,10 @@ } ], "theme_color": "#ffffff", - "display": "standalone" -} + "related_applications": [ + { + "platform": "play", + "id": "com.samsung.microbit" + } + ] +} \ No newline at end of file