From e8195fbed7d36ad12539777242710472a854f9f8 Mon Sep 17 00:00:00 2001 From: Cookie Engineer Date: Wed, 28 Dec 2016 16:06:33 +0100 Subject: [PATCH] lychee.js 2016-Q4 release --- .eslintrc.json | 117 ++ .gitignore | 5 + CHANGELOG.md | 27 +- README.md | 15 +- bin/breeder.js | 234 ++-- bin/configure.js | 36 +- bin/configure.sh | 24 + bin/fertilizer.js | 50 +- bin/harvester.js | 208 ++-- bin/maintenance/do-install.sh | 4 +- bin/maintenance/do-update.sh | 5 +- bin/strainer.js | 163 ++- guides/CODESTYLE.md | 21 +- guides/RELEASE.md | 27 +- libraries/breeder/asset/index.html | 2 +- libraries/breeder/source/Template.index.tpl | 2 +- libraries/breeder/source/Template.js | 28 +- libraries/fertilizer/lychee.pkg | 1 + libraries/fertilizer/source/Main.js | 2 + libraries/fertilizer/source/data/Shell.js | 8 +- .../template/html-nwjs/Application.index.tpl | 2 +- .../html-webview/Application.index.tpl | 2 +- .../template/html/Application.appcache.tpl | 14 + .../template/html/Application.index.tpl | 4 +- .../source/template/html/Application.js | 38 +- libraries/harvester/lychee.pkg | 3 + libraries/harvester/public/desktop-dark.png | Bin 0 -> 19820 bytes libraries/harvester/public/desktop-dark.svg | 9 + libraries/harvester/source/Main.js | 239 +--- libraries/harvester/source/Watcher.js | 271 ++++ libraries/harvester/source/data/Filesystem.js | 107 +- libraries/harvester/source/data/Package.js | 22 +- libraries/harvester/source/data/Project.js | 26 +- libraries/harvester/source/data/Server.js | 6 +- libraries/harvester/source/mod/Fertilizer.js | 4 +- libraries/harvester/source/mod/Packager.js | 17 +- libraries/harvester/source/mod/Server.js | 6 +- libraries/harvester/source/mod/Updater.js | 4 +- libraries/harvester/source/net/Server.js | 8 +- .../harvester/source/net/client/Console.js | 2 + .../harvester/source/net/client/Library.js | 2 + .../harvester/source/net/client/Profile.js | 2 + .../harvester/source/net/client/Project.js | 2 + .../harvester/source/net/remote/Console.js | 2 + .../harvester/source/net/remote/Library.js | 2 + .../harvester/source/net/remote/Profile.js | 2 + .../harvester/source/net/remote/Project.js | 2 + .../harvester/source/net/remote/Server.js | 2 + libraries/harvester/source/net/server/File.js | 69 +- .../harvester/source/net/server/Redirect.js | 2 +- libraries/lychee/api/core/Asset.md | 44 - libraries/lychee/api/core/Debugger.md | 102 -- libraries/lychee/api/core/Definition.md | 301 ----- libraries/lychee/api/core/Environment.md | 853 ------------- libraries/lychee/api/core/Input.md | 479 ------- libraries/lychee/api/core/Package.md | 183 --- libraries/lychee/api/core/Stash.md | 331 ----- libraries/lychee/api/core/Storage.md | 473 ------- libraries/lychee/api/core/Viewport.md | 230 ---- libraries/lychee/api/core/lychee.md | 563 --------- libraries/lychee/api/data/BENCODE.md | 176 --- libraries/lychee/api/data/BitON.md | 220 ---- libraries/lychee/api/data/JSON.md | 108 -- libraries/lychee/api/data/MD.md | 107 -- libraries/lychee/api/event/Emitter.md | 223 ---- libraries/lychee/api/event/Flow.md | 140 --- libraries/lychee/api/event/Queue.md | 117 -- libraries/lychee/api/net/Tunnel.md | 532 -------- libraries/lychee/lychee.pkg | 112 +- libraries/lychee/source/ai/Agent.js | 342 +++++ libraries/lychee/source/ai/Genome.js | 271 ++++ libraries/lychee/source/ai/Layer.js | 452 +++++++ libraries/lychee/source/ai/bnn/Brain.js | 439 +++++++ libraries/lychee/source/ai/enn/Agent.js | 195 +++ libraries/lychee/source/ai/enn/Brain.js | 439 +++++++ libraries/lychee/source/ai/neural/Agent.js | 166 --- .../lychee/source/ai/neural/Evolution.js | 200 --- libraries/lychee/source/ai/neural/Genome.js | 84 -- libraries/lychee/source/ai/neural/Network.js | 210 ---- libraries/lychee/source/ai/qnn/Brain.js | 379 ++++++ libraries/lychee/source/app/Blueprint.js | 13 +- libraries/lychee/source/app/Element.js | 20 +- libraries/lychee/source/app/Entity.js | 18 +- libraries/lychee/source/app/Layer.js | 11 +- libraries/lychee/source/app/Main.js | 10 +- libraries/lychee/source/app/State.js | 4 +- libraries/lychee/source/app/layer/Table.js | 5 +- libraries/lychee/source/core/Asset.js | 5 - libraries/lychee/source/core/Debugger.js | 8 +- libraries/lychee/source/core/Definition.js | 34 +- libraries/lychee/source/core/Environment.js | 289 ++--- libraries/lychee/source/core/Package.js | 18 +- libraries/lychee/source/core/lychee.js | 323 +++-- libraries/lychee/source/crypto/CRC32.js | 4 +- libraries/lychee/source/crypto/MURMUR.js | 129 ++ libraries/lychee/source/crypto/SHA1.js | 9 +- libraries/lychee/source/data/HTML.js | 362 ------ libraries/lychee/source/data/MD.js | 593 --------- libraries/lychee/source/effect/Alpha.js | 69 +- libraries/lychee/source/effect/Color.js | 52 +- libraries/lychee/source/effect/Depth.js | 52 +- libraries/lychee/source/effect/Event.js | 12 +- libraries/lychee/source/effect/Height.js | 52 +- libraries/lychee/source/effect/Offset.js | 52 +- libraries/lychee/source/effect/Position.js | 54 +- libraries/lychee/source/effect/Radius.js | 52 +- libraries/lychee/source/effect/Shake.js | 54 +- libraries/lychee/source/effect/Sound.js | 14 +- libraries/lychee/source/effect/State.js | 12 +- libraries/lychee/source/effect/Velocity.js | 54 +- libraries/lychee/source/effect/Visible.js | 12 +- libraries/lychee/source/effect/Width.js | 53 +- libraries/lychee/source/math/Matrix.js | 18 +- libraries/lychee/source/math/Mersenne.js | 10 +- libraries/lychee/source/math/Vector3.js | 4 +- libraries/lychee/source/math/Vector4.js | 6 +- libraries/lychee/source/net/Service.js | 11 +- .../lychee/source/net/client/Debugger.js | 13 +- libraries/lychee/source/net/protocol/HTTP.js | 15 +- libraries/lychee/source/net/protocol/WS.js | 15 +- libraries/lychee/source/net/remote/Chat.js | 4 - .../lychee/source/net/remote/Debugger.js | 4 +- .../lychee/source/platform/html-nwjs/Stash.js | 23 +- .../source/platform/html-nwjs/Storage.js | 8 +- .../source/platform/html-nwjs/bootstrap.js | 33 +- .../source/platform/html-nwjs/net/Server.js | 2 +- .../platform/html-nwjs/net/socket/HTTP.js | 12 +- .../platform/html-nwjs/net/socket/WS.js | 51 +- .../platform/html-nwjs/ui/entity/Download.js | 221 ++++ .../platform/html-nwjs/ui/entity/Helper.js | 4 +- .../lychee/source/platform/html/Renderer.js | 32 +- .../lychee/source/platform/html/Stash.js | 12 +- .../lychee/source/platform/html/Storage.js | 2 +- .../lychee/source/platform/html/Viewport.js | 4 +- .../lychee/source/platform/html/bootstrap.js | 156 ++- .../lychee/source/platform/html/net/Server.js | 2 +- .../source/platform/html/net/socket/HTTP.js | 2 +- .../platform/html/ui/entity/Download.js | 6 +- .../source/platform/html/ui/entity/Upload.js | 4 +- .../lychee/source/platform/node/Renderer.js | 91 +- .../lychee/source/platform/node/Stash.js | 23 +- .../lychee/source/platform/node/Storage.js | 8 +- .../lychee/source/platform/node/bootstrap.js | 144 ++- .../lychee/source/platform/node/net/Server.js | 2 +- .../source/platform/node/net/socket/HTTP.js | 4 +- .../source/platform/node/net/socket/WS.js | 34 +- .../platform/node/ui/entity/Download.js | 11 +- .../source/platform/node/ui/entity/Helper.js | 8 +- libraries/lychee/source/policy/Position.js | 94 ++ libraries/lychee/source/policy/Velocity.js | 95 ++ libraries/lychee/source/ui/Blueprint.js | 33 +- libraries/lychee/source/ui/Element.js | 18 +- libraries/lychee/source/ui/Entity.js | 18 +- libraries/lychee/source/ui/Layer.js | 9 +- libraries/lychee/source/ui/Menu.js | 12 +- libraries/lychee/source/ui/Notice.js | 12 +- libraries/lychee/source/ui/State.js | 76 +- libraries/lychee/source/ui/State.json | 6 +- libraries/lychee/source/ui/element/Input.js | 2 + libraries/lychee/source/ui/element/Jukebox.js | 2 + libraries/lychee/source/ui/element/Network.js | 2 + libraries/lychee/source/ui/element/Search.js | 10 +- libraries/lychee/source/ui/element/Stash.js | 2 + libraries/lychee/source/ui/element/Storage.js | 2 + .../lychee/source/ui/element/Viewport.js | 2 + libraries/lychee/source/ui/entity/Input.js | 2 +- libraries/lychee/source/ui/entity/Joystick.js | 24 +- libraries/lychee/source/ui/entity/Select.js | 40 +- libraries/lychee/source/ui/entity/Texture.js | 7 +- libraries/lychee/source/ui/layer/Table.js | 5 +- libraries/lychee/source/ui/sprite/Emblem.js | 2 +- libraries/lychee/source/verlet/Constraint.js | 4 +- libraries/lychee/source/verlet/Entity.js | 15 +- libraries/lychee/source/verlet/Layer.js | 10 +- libraries/strainer/lychee.pkg | 20 +- libraries/strainer/source/Main.js | 29 +- libraries/strainer/source/Template.js | 260 ++-- libraries/strainer/source/api/Callback.js | 390 ++++++ libraries/strainer/source/api/Composite.js | 923 ++++++++++++++ libraries/strainer/source/api/Composite.json | 277 +++++ libraries/strainer/source/api/Definition.js | 235 ++++ libraries/strainer/source/api/Module.js | 685 ++++++++++ libraries/strainer/source/api/Module.json | 102 ++ libraries/strainer/source/data/API.js | 1030 --------------- libraries/strainer/source/data/API__OLD.js | 1100 ----------------- libraries/strainer/source/plugin/API.js | 174 +++ libraries/strainer/source/plugin/ESLINT.js | 409 ++++++ projects/boilerplate/index.html | 2 +- projects/cultivator/api/design/highlight.css | 155 --- projects/cultivator/api/design/highlight.js | 1 - projects/cultivator/api/icon.png | Bin 12621 -> 0 bytes projects/cultivator/api/index.html | 159 --- projects/cultivator/api/lychee.pkg | 21 - projects/cultivator/api/source/API.js | 1095 ---------------- projects/cultivator/api/source/Main.js | 475 ------- projects/cultivator/editor/lychee.pkg | 19 +- projects/cultivator/editor/source/Main.js | 4 +- .../cultivator/editor/source/data/Project.js | 60 + .../cultivator/editor/source/state/Asset.js | 167 +++ .../cultivator/editor/source/state/Asset.json | 66 + .../cultivator/editor/source/state/Project.js | 13 +- .../editor/source/state/Project.json | 4 +- .../editor/source/ui/element/Breeder.js | 2 +- .../source/ui/element/{ => modify}/Font.js | 78 +- .../source/ui/element/{ => modify}/Project.js | 3 +- .../editor/source/ui/element/preview/Font.js | 55 + projects/cultivator/index.html | 5 +- projects/lethalmaze/index.html | 2 +- projects/lethalmaze/source/Main.js | 8 +- projects/lethalmaze/source/app/sprite/Tank.js | 4 +- projects/lethalmaze/source/data/LEVEL.js | 6 +- .../lethalmaze/source/effect/Lightning.js | 28 +- .../lethalmaze/source/net/remote/Control.js | 6 +- projects/lethalmaze/source/state/Game.js | 5 +- .../lethalmaze/source/ui/layer/Control.js | 8 +- projects/mode7/index.html | 2 +- projects/mode7/source/Compositor.js | 6 +- projects/mode7/source/entity/Track.js | 16 +- projects/mode7/source/state/Game.js | 10 +- projects/over-there/index.html | 2 +- projects/over-there/source/Main.js | 8 +- .../over-there/source/entity/Midground.js | 2 +- projects/over-there/source/net/Client.js | 4 +- projects/over-there/source/state/App.js | 6 +- .../over-there/source/ui/entity/Bubble.js | 2 +- projects/pong/index.html | 2 +- projects/pong/source/Main.js | 3 +- projects/pong/source/state/Game.js | 6 +- projects/text-chat/index.html | 2 +- projects/text-chat/source/state/Chat.js | 18 +- projects/tictactoe/index.html | 2 +- projects/tictactoe/source/state/Game.js | 42 +- 232 files changed, 9416 insertions(+), 13075 deletions(-) create mode 100644 .eslintrc.json create mode 100644 libraries/fertilizer/source/template/html/Application.appcache.tpl create mode 100644 libraries/harvester/public/desktop-dark.png create mode 100644 libraries/harvester/public/desktop-dark.svg create mode 100644 libraries/harvester/source/Watcher.js delete mode 100644 libraries/lychee/api/core/Asset.md delete mode 100644 libraries/lychee/api/core/Debugger.md delete mode 100644 libraries/lychee/api/core/Definition.md delete mode 100644 libraries/lychee/api/core/Environment.md delete mode 100644 libraries/lychee/api/core/Input.md delete mode 100644 libraries/lychee/api/core/Package.md delete mode 100644 libraries/lychee/api/core/Stash.md delete mode 100644 libraries/lychee/api/core/Storage.md delete mode 100644 libraries/lychee/api/core/Viewport.md delete mode 100644 libraries/lychee/api/core/lychee.md delete mode 100644 libraries/lychee/api/data/BENCODE.md delete mode 100644 libraries/lychee/api/data/BitON.md delete mode 100644 libraries/lychee/api/data/JSON.md delete mode 100644 libraries/lychee/api/data/MD.md delete mode 100644 libraries/lychee/api/event/Emitter.md delete mode 100644 libraries/lychee/api/event/Flow.md delete mode 100644 libraries/lychee/api/event/Queue.md delete mode 100644 libraries/lychee/api/net/Tunnel.md create mode 100644 libraries/lychee/source/ai/Agent.js create mode 100644 libraries/lychee/source/ai/Genome.js create mode 100644 libraries/lychee/source/ai/Layer.js create mode 100644 libraries/lychee/source/ai/bnn/Brain.js create mode 100644 libraries/lychee/source/ai/enn/Agent.js create mode 100644 libraries/lychee/source/ai/enn/Brain.js delete mode 100644 libraries/lychee/source/ai/neural/Agent.js delete mode 100644 libraries/lychee/source/ai/neural/Evolution.js delete mode 100644 libraries/lychee/source/ai/neural/Genome.js delete mode 100644 libraries/lychee/source/ai/neural/Network.js create mode 100644 libraries/lychee/source/ai/qnn/Brain.js create mode 100644 libraries/lychee/source/crypto/MURMUR.js delete mode 100644 libraries/lychee/source/data/HTML.js delete mode 100644 libraries/lychee/source/data/MD.js create mode 100644 libraries/lychee/source/platform/html-nwjs/ui/entity/Download.js create mode 100644 libraries/lychee/source/policy/Position.js create mode 100644 libraries/lychee/source/policy/Velocity.js create mode 100644 libraries/strainer/source/api/Callback.js create mode 100644 libraries/strainer/source/api/Composite.js create mode 100644 libraries/strainer/source/api/Composite.json create mode 100644 libraries/strainer/source/api/Definition.js create mode 100644 libraries/strainer/source/api/Module.js create mode 100644 libraries/strainer/source/api/Module.json delete mode 100644 libraries/strainer/source/data/API.js delete mode 100644 libraries/strainer/source/data/API__OLD.js create mode 100644 libraries/strainer/source/plugin/API.js create mode 100644 libraries/strainer/source/plugin/ESLINT.js delete mode 100644 projects/cultivator/api/design/highlight.css delete mode 100644 projects/cultivator/api/design/highlight.js delete mode 100644 projects/cultivator/api/icon.png delete mode 100644 projects/cultivator/api/index.html delete mode 100644 projects/cultivator/api/lychee.pkg delete mode 100644 projects/cultivator/api/source/API.js delete mode 100644 projects/cultivator/api/source/Main.js create mode 100644 projects/cultivator/editor/source/state/Asset.js create mode 100644 projects/cultivator/editor/source/state/Asset.json rename projects/cultivator/editor/source/ui/element/{ => modify}/Font.js (70%) rename projects/cultivator/editor/source/ui/element/{ => modify}/Project.js (97%) create mode 100644 projects/cultivator/editor/source/ui/element/preview/Font.js diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 00000000..cfec3f74 --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,117 @@ +{ + "env": { + "browser": true, + "es6": true, + "node": true + }, + "extends": "eslint:recommended", + "parserOptions": { + "ecmaVersion": 2016, + "ecmaFeatures": { + "impliedStrict": true + } + }, + "globals": { + "Buffer": true, + "Config": true, + "Font": true, + "Music": true, + "Sound": true, + "Stuff": true, + "Texture": true, + "global": true, + "lychee": true + }, + "rules": { + "array-bracket-spacing": [ "error", "always", { + "singleValue": true, + "objectsInArrays": false + }], + "brace-style": [ "error", "1tbs", { + "allowSingleLine": false + }], + "camelcase": "off", + "comma-dangle": [ "error", { + "arrays": "never", + "objects": "never", + "imports": "never", + "exports": "never", + "functions": "never" + }], + "comma-spacing": [ "error", { + "before": false, + "after": true + }], + "comma-style": [ "error", "last" ], + "complexity": "off", + "consistent-return": "off", + "consistent-this": "off", + "eol-last": [ "error", "always" ], + "eqeqeq": [ "error", "always" ], + "func-names": [ "error", "never" ], + "func-style": [ "error", "expression" ], + "indent": [ "error", "tab", { + "SwitchCase": 1 + }], + "keyword-spacing": [ "error", { + "before": true, + "after": true + }], + "linebreak-style": [ "error", "unix" ], + "lines-around-comment": [ "error", { + "beforeBlockComment": true, + "afterBlockComment": true, + "beforeLineComment": false, + "afterLineComment": false + }], + "multiline-ternary": [ "error", "never" ], + "newline-before-return": "off", + "newline-after-var": "off", + "newline-per-chained-call": "off", + "no-console": [ "error", { + "allow": [ "clear", "log", "info", "warn", "error", "deserialize", "serialize" ] + }], + "no-control-regex": "off", + "no-dupe-args": [ "error" ], + "no-dupe-keys": [ "error" ], + "no-empty": [ "error", { + "allowEmptyCatch": true + }], + "no-extra-semi": [ "error" ], + "no-floating-decimal": [ "error" ], + "no-global-assign": [ "error", { + "exceptions": [ + "Audio", + "Image", + "console" + ] + }], + "no-mixed-spaces-and-tabs": [ "error", "smart-tabs" ], + "no-negated-in-lhs": [ "error" ], + "no-octal": "off", + "no-return-assign": [ "error" ], + "no-return-await": [ "error" ], + "no-sequences": [ "error" ], + "no-shadow": "off", + "no-shadow-restricted-names": [ "error" ], + "no-trailing-spaces": [ "error" ], + "no-undef": [ "error", { + "typeof": false + }], + "no-undef-init": "off", + "no-undefined": "off", + "no-unreachable": [ "error" ], + "no-unused-vars": [ "error", { + "args": "none", + "varsIgnorePattern": "^_[A-Za-z]+" + }], + "no-var": [ "error" ], + "object-curly-spacing": [ "error", "always" ], + "semi": [ "error", "always" ], + "semi-spacing": [ "error" ], + "space-before-blocks": [ "error", "always" ], + "space-in-parens": [ "error", "never" ], + "space-infix-ops": [ "error" ], + "space-unary-ops": [ "error" ] + } +} diff --git a/.gitignore b/.gitignore index 495747ad..4974ceaa 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,7 @@ # Fuck these guys +/node_modules /__TODO__ /.idea .DS_Store @@ -23,6 +24,7 @@ # Libraries /libraries/* +/libraries/*/api /libraries/*/build /libraries/*/lychee.store /libraries/lychee/source/DIST.js @@ -39,6 +41,7 @@ # Projects /projects/* +/projects/*/api /projects/*/build /projects/*/lychee.store !/projects/README.md @@ -56,8 +59,10 @@ # Cultivator Projects +/projects/cultivator/editor/api /projects/cultivator/editor/build /projects/cultivator/editor/lychee.store +/projects/cultivator/ranger/api /projects/cultivator/ranger/build /projects/cultivator/ranger/lychee.store diff --git a/CHANGELOG.md b/CHANGELOG.md index 20d6d66f..112bfad3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,19 +14,38 @@ As we cannot influence decisions of our Artificial Intelligence, some things might break temporarily on the `development` and `humansneednotapply` branch. -The update behaviour is changed as explained in the [RELEASE Guide](./guides/RELEASE.md). +The update behaviour is changed as explained in the +[RELEASE Guide](./guides/RELEASE.md). All entries in the changelog +are listed in this specific order: `changed`, `removed`, `added` +and `fixed`. -## [2016-Q3] - 2016-09-28 (UNRELEASED) +## [2016-Q4] - 2016-12-28 + +- **Changed**: `lychee.Environment.__FEATURES` represents Feature Prediction (by `bootstrap.js`). +- **Added**: `lychee.assimilate(target)` to include non-packaged non-lychee Assets and Implementations. +- Changed: ES6 Migration for integration scripts (`./bin`). +- Changed: Performance improvements for `lychee.interfaceof` using a cache. +- Added: lychee.js Strainer supports ESLint and automated code-refactoring features. +- Added: lychee.js Strainer understands `Callback`, `Composite` or `Module` API. +- Added: lychee.js Harvester uses a Watcher and faster bootup cycle. +- Added: `lychee.ai.enn` Stack implements a feed-forward NN architecture. +- Added: `lychee.ai.bnn` Stack implements a backpropagated NN architecture. +- Fixed: lychee.js Fertilizer supports `html` Application Cache manifests. +- Fixed: lychee.app.Main `changeState()` handles invalid states correctly. +- Fixed: `html-nwjs` platform has correct peer-to-peer Networking. + + +## [2016-Q3] - 2016-09-28 - Changed: Integration of [@humansneednotapply](https://github.com/humansneednotapply) Account. - Changed: Integration of `.github/TOKEN` file. - Changed: License to MIT/GPL3/CC4-BY-SA. - Changed: New Welcome Page for easier Project-based workflow. +- Removed: fyto.js was deprecated, lycheejs-legacy is embraced. +- Added: lychee.js Editor allows `project` changes. - Fixed: lychee.ui Entities. - Fixed: lychee.effect Stack is now completely delay-compatible. -- Added: lychee.js Editor allows `project` changes. -- Removed: fyto.js was deprecated, lycheejs-legacy is embraced. ## [2016-Q2] - 2016-06-27 diff --git a/README.md b/README.md index 7557b6ac..1eca266a 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -# lychee.js (2016-Q3) +# lychee.js (2016-Q4) brought to you as libre software with joy and pride by [Artificial Engineering](http://artificial.engineering). @@ -24,7 +24,6 @@ Support our libre Bot Cloud via BTC [1CamMuvrFU1QAMebPoDsL3JrioVDoxezY2](bitcoin - ## IMPORTANT NOTICE We went live with our AI on 1. Sept 2016. This caused a totally fucked up @@ -44,11 +43,10 @@ Thank you for your understanding. These are the things that we are currently working on: -- 2016-Q3: Strainer is being refactored to support better AI implementation. -- 2016-Q3: CARTEL (AI implementation) is being refactored. [Issue](https://github.com/Artificial-Engineering/lycheejs/issues/91) -- 2016-Q3: Guide is subject to change (to integrate the Editor). [Issue](https://github.com/Artificial-Engineering/lycheejs/issues/159) -- 2016-Q3: Editor is being refactored to integrate all other Cultivator Tools' functionalities. -- 2016-Q3: [lychee.js Garden](https://github.com/Artificial-Engineering/lycheejs-garden.git) is being implemented. +- lychee.ai.neat (ES/HyperNEAT AI) is being refactored. +- lychee.js Editor is being refactored to integrate all Cultivator Tools' functionalities. +- [lychee.js Guide](https://github.com/Artificial-Engineering/lycheejs-guide.git) is subject to change (to integrate new AI / Editor stack). +- [lychee.js Garden](https://github.com/Artificial-Engineering/lycheejs-garden.git) is being implemented. ## Overview @@ -56,7 +54,6 @@ These are the things that we are currently working on: The lychee.js Project started in 2012 and is in active development. The following Repositories are related to the lychee.js Engine: -- [lychee.js CARTEL](https://github.com/Artificial-Engineering/lycheejs-cartel.git) contains all academic work related to the CARTEL/ES-HyperNEAT concept (WIP). - [lychee.js Guide](https://github.com/Artificial-Engineering/lycheejs-guide.git) contains architecture explanations and concept documentations (WIP). - [lychee.js Runtime](https://github.com/Artificial-Engineering/lycheejs-runtime.git) contains all pre-compiled lychee.js Runtimes and Fertilizers. - [lychee.js Library](https://github.com/Artificial-Engineering/lycheejs-library.git) contains the lychee.js Library (installable via `bower` and `npm`). @@ -79,7 +76,6 @@ OpenGLES, libSDL) and is completely automated behind the scenes. - ## Features The lychee.js Engine aims to deliver Total Automation through @@ -199,6 +195,7 @@ repository). Notes: +- **Windows** is **unsupported** as development host. Use a VM or the [Dockerfile](https://github.com/Artificial-Engineering/lycheejs-bundle/blob/master/bin/package/docker/Dockerfile) instead. - GNU/Linux requires either of `apt-get`, `dnf`, `pacman`, `yum` or `zipper` installed beforehand. - Mac OSX requires [brew](https://brew.sh) installed beforehand. - FreeBSD/NetBSD requires `pkg` installed and [Linux Compatibility](https://www.freebsd.org/doc/handbook/linuxemu-lbc-install.html) activated beforehand. diff --git a/bin/breeder.js b/bin/breeder.js index 41b64fcb..1b5889d6 100755 --- a/bin/breeder.js +++ b/bin/breeder.js @@ -1,17 +1,17 @@ #!/usr/local/bin/lycheejs-helper env:node -var root = require('path').resolve(__dirname, '../'); -var fs = require('fs'); -var path = require('path'); +const _fs = require('fs'); +const _path = require('path'); +const _ROOT = _path.resolve(__dirname, '../'); -if (fs.existsSync(root + '/libraries/lychee/build/node/core.js') === false) { - require(root + '/bin/configure.js'); +if (_fs.existsSync(_ROOT + '/libraries/lychee/build/node/core.js') === false) { + require(_ROOT + '/bin/configure.js'); } -var lychee = require(root + '/libraries/lychee/build/node/core.js')(root); +const lychee = require(_ROOT + '/libraries/lychee/build/node/core.js')(_ROOT); @@ -19,16 +19,16 @@ var lychee = require(root + '/libraries/lychee/build/node/core.js')(root); * USAGE */ -var _print_help = function() { +const _print_help = function() { - var libraries = fs.readdirSync(root + '/libraries').sort().filter(function(value) { - return fs.existsSync(root + '/libraries/' + value + '/lychee.pkg'); + let libraries = _fs.readdirSync(_ROOT + '/libraries').sort().filter(function(value) { + return _fs.existsSync(_ROOT + '/libraries/' + value + '/lychee.pkg'); }).map(function(value) { return '/libraries/' + value; }); - var projects = fs.readdirSync(root + '/projects').sort().filter(function(value) { - return fs.existsSync(root + '/projects/' + value + '/lychee.pkg'); + let projects = _fs.readdirSync(_ROOT + '/projects').sort().filter(function(value) { + return _fs.existsSync(_ROOT + '/projects/' + value + '/lychee.pkg'); }).map(function(value) { return '/projects/' + value; }); @@ -47,17 +47,21 @@ var _print_help = function() { console.log('Available Libraries: '); console.log(' '); libraries.forEach(function(library) { - var diff = (' ').substr(library.length); + let diff = (' ').substr(library.length); console.log(' ' + library + diff); }); console.log(' '); console.log('Available Projects: '); console.log(' '); projects.forEach(function(project) { - var diff = (' ').substr(project.length); + let diff = (' ').substr(project.length); console.log(' ' + project + diff); }); console.log(' '); + console.log('Available Flags: '); + console.log(' '); + console.log(' --debug Debug Mode with debug messages '); + console.log(' '); console.log('Examples: '); console.log(' '); console.log(' cd /projects/my-project; '); @@ -72,91 +76,16 @@ var _print_help = function() { }; - - -var _settings = (function() { - - var args = process.argv.slice(2).filter(val => val !== ''); - var settings = { - action: null, - project: null, - library: null - }; - - - var action = args.find(val => /^(init|fork|pull|push)/g.test(val)); - var library = args.find(val => /^\/(libraries|projects)\/([A-Za-z0-9-_\/]+)$/g.test(val)); - var project = args.find(val => /--project=\/(libraries|projects)\/([A-Za-z0-9-_\/]+)/g.test(val)); - var debug_flag = args.find(val => /--([debug]{5})/g.test(val)); - var sandbox_flag = args.find(val => /--([sandbox]{7})/g.test(val)); - - - if (project !== undefined) { - - var tmp = project.substr(10); - if (tmp.indexOf('.') === -1) { - - try { - - var stat1 = fs.lstatSync(root + tmp); - if (stat1.isDirectory()) { - settings.project = tmp; - } - - } catch(e) { - - settings.project = null; - - } - - } - - } - - - if (action === 'pull' || action === 'fork') { - - if (library !== undefined) { - - settings.action = action; - - - try { - var stat1 = fs.lstatSync(root + library); - var stat2 = fs.lstatSync(root + library + '/lychee.pkg'); - if (stat1.isDirectory() && stat2.isFile()) { - settings.library = library; - } - - } catch(e) { - - settings.library = null; - - } - - } - - } else if (action !== undefined) { - - settings.action = action; - - } - - - return settings; - -})(); - -var _bootup = function(settings) { +const _bootup = function(settings) { console.info('BOOTUP (' + process.pid + ')'); - var environment = new lychee.Environment({ - id: 'breeder', - debug: false, - sandbox: false, - build: 'breeder.Main', - timeout: 1000, + let environment = new lychee.Environment({ + id: 'breeder', + debug: settings.debug === true, + sandbox: false, + build: 'breeder.Main', + timeout: 1000, packages: [ new lychee.Package('lychee', '/libraries/lychee/lychee.pkg'), new lychee.Package('fertilizer', '/libraries/fertilizer/lychee.pkg'), @@ -175,9 +104,8 @@ var _bootup = function(settings) { if (sandbox !== null) { - var lychee = sandbox.lychee; - var breeder = sandbox.breeder; - var fertilizer = sandbox.fertilizer; + let lychee = sandbox.lychee; + let breeder = sandbox.breeder; // Show less debug messages @@ -194,12 +122,17 @@ var _bootup = function(settings) { sandbox.MAIN.init(); - process.on('SIGHUP', function() { sandbox.MAIN.destroy(); this.exit(1); }); - process.on('SIGINT', function() { sandbox.MAIN.destroy(); this.exit(1); }); - process.on('SIGQUIT', function() { sandbox.MAIN.destroy(); this.exit(1); }); - process.on('SIGABRT', function() { sandbox.MAIN.destroy(); this.exit(1); }); - process.on('SIGTERM', function() { sandbox.MAIN.destroy(); this.exit(1); }); - process.on('error', function() { sandbox.MAIN.destroy(); this.exit(1); }); + const _on_process_error = function() { + sandbox.MAIN.destroy(); + process.exit(1); + }; + + process.on('SIGHUP', _on_process_error); + process.on('SIGINT', _on_process_error); + process.on('SIGQUIT', _on_process_error); + process.on('SIGABRT', _on_process_error); + process.on('SIGTERM', _on_process_error); + process.on('error', _on_process_error); process.on('exit', function() {}); @@ -227,21 +160,103 @@ var _bootup = function(settings) { +const _SETTINGS = (function() { + + let args = process.argv.slice(2).filter(val => val !== ''); + let settings = { + action: null, + project: null, + library: null, + debug: false + }; + + + let action = args.find(val => /^(init|fork|pull|push)/g.test(val)); + let library = args.find(val => /^\/(libraries|projects)\/([A-Za-z0-9-_\/]+)$/g.test(val)); + let project = args.find(val => /--project=\/(libraries|projects)\/([A-Za-z0-9-_\/]+)/g.test(val)); + let debug_flag = args.find(val => /--([debug]{5})/g.test(val)); + + + if (project !== undefined) { + + let tmp = project.substr(10); + if (tmp.indexOf('.') === -1) { + + try { + + let stat1 = _fs.lstatSync(_ROOT + tmp); + if (stat1.isDirectory()) { + settings.project = tmp; + } + + } catch (err) { + + settings.project = null; + + } + + } + + } + + + if (action === 'pull' || action === 'fork') { + + if (library !== undefined) { + + settings.action = action; + + + try { + + let stat1 = _fs.lstatSync(_ROOT + library); + let stat2 = _fs.lstatSync(_ROOT + library + '/lychee.pkg'); + if (stat1.isDirectory() && stat2.isFile()) { + settings.library = library; + } + + } catch (err) { + + settings.library = null; + + } + + } + + } else if (action !== undefined) { + + settings.action = action; + + } + + + if (debug_flag !== undefined) { + settings.debug = true; + } + + + return settings; + +})(); + + + (function(settings) { /* * IMPLEMENTATION */ - var action = settings.action; - var has_project = settings.project !== null; - var has_library = settings.library !== null; + let action = settings.action; + let has_project = settings.project !== null; + let has_library = settings.library !== null; if (action === 'init' && has_project) { _bootup({ action: 'init', + debug: settings.debug === true, project: settings.project }); @@ -250,6 +265,7 @@ var _bootup = function(settings) { _bootup({ action: 'fork', + debug: settings.debug === true, project: settings.project, library: settings.library }); @@ -258,6 +274,7 @@ var _bootup = function(settings) { _bootup({ action: 'pull', + debug: settings.debug === true, project: settings.project, library: settings.library }); @@ -266,6 +283,7 @@ var _bootup = function(settings) { _bootup({ action: 'push', + debug: settings.debug === true, project: settings.project }); @@ -279,5 +297,5 @@ var _bootup = function(settings) { } -})(_settings); +})(_SETTINGS); diff --git a/bin/configure.js b/bin/configure.js index 281bb42a..90978589 100755 --- a/bin/configure.js +++ b/bin/configure.js @@ -64,7 +64,7 @@ try { let stat = _fs.lstatSync(path); return stat.isDirectory(); - } catch(e) { + } catch (err) { return false; } @@ -75,7 +75,7 @@ try { let stat = _fs.lstatSync(path); return stat.isFile(); - } catch(e) { + } catch (err) { return false; } @@ -84,7 +84,7 @@ const _create_directory = function(path, mode) { if (mode === undefined) { - mode = 0777 & (~_process.umask()); + mode = 0o777 & (~_process.umask()); } @@ -94,7 +94,7 @@ is_directory = _fs.lstatSync(path).isDirectory(); - } catch(err) { + } catch (err) { if (err.code === 'ENOENT') { @@ -104,16 +104,15 @@ try { is_directory = _fs.lstatSync(path).isDirectory(); - } catch(err) { + } catch (err) { } } - } finally { + } - return is_directory; - } + return is_directory; }; @@ -292,7 +291,7 @@ try { data = JSON.parse(_fs.readFileSync(_path.resolve(_ROOT, './libraries/lychee/lychee.pkg'))); - } catch(e) { + } catch (err) { data = null; } @@ -323,12 +322,12 @@ lychee.envinit(null); - } catch(e) { + } catch (err) { console.log('\n\n\n'); console.log('Syntax Error in lychee.js core:'); console.log('- - - - - - - - - - - - - - - -'); - console.log(e); + console.log(err); console.log('\n\n\n'); errors++; @@ -401,6 +400,17 @@ Composite.prototype = { + // deserialize: function(blob) {}, + + serialize: function() { + + return { + 'constructor': 'lychee.DIST', + 'arguments': [] + }; + + } + }; return Composite; @@ -427,7 +437,7 @@ try { _fs.writeFileSync(path, code, 'utf8'); - } catch(e) { + } catch (err) { result = false; } @@ -651,7 +661,7 @@ try { _fs.writeFileSync(path, code, 'utf8'); - } catch(e) { + } catch (err) { result = false; } diff --git a/bin/configure.sh b/bin/configure.sh index fde9d7c8..666d0c07 100755 --- a/bin/configure.sh +++ b/bin/configure.sh @@ -143,3 +143,27 @@ if [ "$OS" == "linux" ] || [ "$OS" == "osx" ] || [ "$OS" == "bsd" ]; then fi; + +if [ "$OS" == "linux" ] || [ "$OS" == "osx" ] || [ "$OS" == "bsd" ]; then + + echo -e " (L) Fixing GIT config"; + + + cd $LYCHEEJS_ROOT; + + + check_remote=$(cat .git/config | grep '\[remote "upstream"\]'); + + if [ "$check_remote" == "" ]; then + + echo -e "[remote \"upstream\"]" >> .git/config; + echo -e "\turl = https://github.com/Artificial-Engineering/lycheejs.git" >> .git/config; + echo -e "\tfetch = +refs/heads/*:refs/remotes/upstream/*" >> .git/config; + + fi; + + + echo -e " (I) SUCCESS\n"; + +fi; + diff --git a/bin/fertilizer.js b/bin/fertilizer.js index 1958511b..b89ff5be 100755 --- a/bin/fertilizer.js +++ b/bin/fertilizer.js @@ -67,13 +67,14 @@ const _print_help = function() { console.log(' '); console.log('Available Flags: '); console.log(' '); - console.log(' --debug Debug Mode with verbose debug messages '); + console.log(' --debug Debug Mode with debug messages '); console.log(' --sandbox Sandbox Mode without software bots '); console.log(' '); console.log('Examples: '); console.log(' '); console.log(' lycheejs-fertilizer html-nwjs/main /projects/boilerplate; '); console.log(' lycheejs-fertilizer node/main /projects/boilerplate; '); + console.log(' lycheejs-fertilizer auto /libraries/lychee; '); console.log(' '); }; @@ -85,7 +86,7 @@ const _bootup = function(settings) { let environment = new lychee.Environment({ id: 'fertilizer', debug: settings.debug === true, - sandbox: true, + sandbox: settings.debug === true ? false : settings.sandbox === true, build: 'fertilizer.Main', timeout: 3000, packages: [ @@ -122,12 +123,17 @@ const _bootup = function(settings) { sandbox.MAIN.init(); - process.on('SIGHUP', function() { sandbox.MAIN.destroy(); this.exit(1); }); - process.on('SIGINT', function() { sandbox.MAIN.destroy(); this.exit(1); }); - process.on('SIGQUIT', function() { sandbox.MAIN.destroy(); this.exit(1); }); - process.on('SIGABRT', function() { sandbox.MAIN.destroy(); this.exit(1); }); - process.on('SIGTERM', function() { sandbox.MAIN.destroy(); this.exit(1); }); - process.on('error', function() { sandbox.MAIN.destroy(); this.exit(1); }); + const _on_process_error = function() { + sandbox.MAIN.destroy(); + process.exit(1); + }; + + process.on('SIGHUP', _on_process_error); + process.on('SIGINT', _on_process_error); + process.on('SIGQUIT', _on_process_error); + process.on('SIGABRT', _on_process_error); + process.on('SIGTERM', _on_process_error); + process.on('error', _on_process_error); process.on('exit', function() {}); @@ -222,7 +228,7 @@ const _SETTINGS = (function() { try { json = JSON.parse(_fs.readFileSync(_ROOT + project + '/lychee.pkg', 'utf8')); - } catch(e) { + } catch (err) { json = null; } @@ -258,7 +264,7 @@ const _SETTINGS = (function() { try { json = JSON.parse(_fs.readFileSync(_ROOT + project + '/lychee.pkg', 'utf8')); - } catch(e) { + } catch (err) { json = null; } @@ -292,9 +298,9 @@ const _SETTINGS = (function() { })(); -(function(project, identifier, settings, auto) { +(function(settings) { - if (auto === true) return; + if (settings.auto === true) return; @@ -302,25 +308,27 @@ const _SETTINGS = (function() { * IMPLEMENTATION */ - let has_project = project !== null; - let has_identifier = identifier !== null; - let has_settings = settings !== null; + let has_project = settings.project !== null; + let has_identifier = settings.identifier !== null; + let has_environment = settings.environment !== null; - if (has_project && has_identifier && has_settings) { + if (has_project && has_identifier && has_environment) { _bootup({ debug: settings.debug === true, sandbox: settings.sandbox === true, - project: project, - identifier: identifier, - settings: settings + project: settings.project, + identifier: settings.identifier, + settings: settings.environment }); } else if (has_project) { _bootup({ - project: project, + debug: settings.debug === true, + sandbox: settings.sandbox === true, + project: settings.project, identifier: null, settings: null }); @@ -335,5 +343,5 @@ const _SETTINGS = (function() { } -})(_SETTINGS.project, _SETTINGS.identifier, _SETTINGS.environment, _SETTINGS.auto); +})(_SETTINGS); diff --git a/bin/harvester.js b/bin/harvester.js index 46483df5..a8649166 100755 --- a/bin/harvester.js +++ b/bin/harvester.js @@ -1,17 +1,17 @@ #!/usr/local/bin/lycheejs-helper env:node -var root = require('path').resolve(__dirname, '../'); -var fs = require('fs'); -var path = require('path'); +const _fs = require('fs'); +const _path = require('path'); +const _ROOT = _path.resolve(__dirname, '../'); -if (fs.existsSync(root + '/libraries/lychee/build/node/core.js') === false) { - require(root + '/bin/configure.js'); +if (_fs.existsSync(_ROOT + '/libraries/lychee/build/node/core.js') === false) { + require(_ROOT + '/bin/configure.js'); } -var lychee = require(root + '/libraries/lychee/build/node/core.js')(root); +const lychee = require(_ROOT + '/libraries/lychee/build/node/core.js')(_ROOT); @@ -19,9 +19,9 @@ var lychee = require(root + '/libraries/lychee/build/node/core.js')(root); * USAGE */ -var _print_help = function() { +const _print_help = function() { - var profiles = fs.readdirSync(root + '/bin/harvester').map(function(value) { + let profiles = _fs.readdirSync(_ROOT + '/bin/harvester').map(function(value) { return '' + value.substr(0, value.indexOf('.json')) + ''; }); @@ -39,7 +39,7 @@ var _print_help = function() { console.log('Available Profiles: '); console.log(' '); profiles.forEach(function(profile) { - var diff = (' ').substr(profile.length); + let diff = (' ').substr(profile.length); console.log(' ' + profile + diff); }); console.log(' '); @@ -58,81 +58,11 @@ var _print_help = function() { }; - - -var _settings = (function() { - - var args = process.argv.slice(2).filter(val => val !== ''); - var settings = { - action: null, - profile: null, - debug: false, - sandbox: false - }; - - - var action = args.find(val => /(start|status|restart|stop)/g.test(val)); - var profile = args.find(val => /([A-Za-z0-9-_.])/g.test(val) && val !== action); - var debug_flag = args.find(val => /--([debug]{5})/g.test(val)); - var sandbox_flag = args.find(val => /--([sandbox]{7})/g.test(val)); - - - if (action === 'start') { - - if (profile !== undefined) { - - settings.action = 'start'; - - - try { - - var stat1 = fs.lstatSync(root + '/bin/harvester/' + profile + '.json'); - if (stat1.isFile()) { - - var json = null; - try { - json = JSON.parse(fs.readFileSync(root + '/bin/harvester/' + profile + '.json', 'utf8')); - } catch(e) { - } - - if (json !== null) { - settings.profile = json; - settings.debug = json.debug === true; - settings.sandbox = json.sandbox === true; - } - - } - - } catch(e) { - } - - } - - } else if (action !== undefined) { - - settings.action = action; - - } - - - if (debug_flag !== undefined) { - settings.debug = true; - } - - if (sandbox_flag !== undefined) { - settings.sandbox = true; - } - - - return settings; - -})(); - -var _clear_pid = function() { +const _clear_pid = function() { try { - fs.unlinkSync(root + '/bin/harvester.pid'); + _fs.unlinkSync(_ROOT + '/bin/harvester.pid'); return true; } catch(e) { @@ -143,13 +73,13 @@ var _clear_pid = function() { }; -var _read_pid = function() { +const _read_pid = function() { - var pid = null; + let pid = null; try { - pid = fs.readFileSync(root + '/bin/harvester.pid', 'utf8'); + pid = _fs.readFileSync(_ROOT + '/bin/harvester.pid', 'utf8'); if (!isNaN(parseInt(pid, 10))) { pid = parseInt(pid, 10); @@ -163,11 +93,11 @@ var _read_pid = function() { }; -var _write_pid = function() { +const _write_pid = function() { try { - fs.writeFileSync(root + '/bin/harvester.pid', process.pid); + _fs.writeFileSync(_ROOT + '/bin/harvester.pid', process.pid); return true; } catch(e) { @@ -178,11 +108,11 @@ var _write_pid = function() { }; -var _bootup = function(settings) { +const _bootup = function(settings) { console.info('BOOTUP (' + process.pid + ')'); - var environment = new lychee.Environment({ + let environment = new lychee.Environment({ id: 'harvester', debug: settings.debug === true, sandbox: true, @@ -205,8 +135,8 @@ var _bootup = function(settings) { if (sandbox !== null) { - var lychee = sandbox.lychee; - var harvester = sandbox.harvester; + let lychee = sandbox.lychee; + let harvester = sandbox.harvester; // Show more debug messages @@ -223,12 +153,12 @@ var _bootup = function(settings) { _write_pid(); - process.on('SIGHUP', function() { sandbox.MAIN.destroy(); _clear_pid(); this.exit(1); }); - process.on('SIGINT', function() { sandbox.MAIN.destroy(); _clear_pid(); this.exit(1); }); - process.on('SIGQUIT', function() { sandbox.MAIN.destroy(); _clear_pid(); this.exit(1); }); - process.on('SIGABRT', function() { sandbox.MAIN.destroy(); _clear_pid(); this.exit(1); }); - process.on('SIGTERM', function() { sandbox.MAIN.destroy(); _clear_pid(); this.exit(1); }); - process.on('error', function() { sandbox.MAIN.destroy(); _clear_pid(); this.exit(1); }); + process.on('SIGHUP', function() { _clear_pid(); sandbox.MAIN.destroy(); this.exit(1); }); + process.on('SIGINT', function() { _clear_pid(); sandbox.MAIN.destroy(); this.exit(1); }); + process.on('SIGQUIT', function() { _clear_pid(); sandbox.MAIN.destroy(); this.exit(1); }); + process.on('SIGABRT', function() { _clear_pid(); sandbox.MAIN.destroy(); this.exit(1); }); + process.on('SIGTERM', function() { _clear_pid(); sandbox.MAIN.destroy(); this.exit(1); }); + process.on('error', function() { _clear_pid(); sandbox.MAIN.destroy(); this.exit(1); }); process.on('exit', function() {}); @@ -239,8 +169,8 @@ var _bootup = function(settings) { console.warn('harvester: [ESC] pressed, exiting ...'); - sandbox.MAIN.destroy(); _clear_pid(); + sandbox.MAIN.destroy(); }, this); @@ -260,15 +190,85 @@ var _bootup = function(settings) { +const _SETTINGS = (function() { + + let args = process.argv.slice(2).filter(val => val !== ''); + let settings = { + action: null, + profile: null, + debug: false, + sandbox: false + }; + + + let action = args.find(val => /(start|status|restart|stop)/g.test(val)); + let profile = args.find(val => /([A-Za-z0-9-_.])/g.test(val) && val !== action); + let debug_flag = args.find(val => /--([debug]{5})/g.test(val)); + let sandbox_flag = args.find(val => /--([sandbox]{7})/g.test(val)); + + + if (action === 'start') { + + if (profile !== undefined) { + + settings.action = 'start'; + + + try { + + let stat1 = _fs.lstatSync(_ROOT + '/bin/harvester/' + profile + '.json'); + if (stat1.isFile()) { + + let json = null; + try { + json = JSON.parse(_fs.readFileSync(_ROOT + '/bin/harvester/' + profile + '.json', 'utf8')); + } catch(e) { + } + + if (json !== null) { + settings.profile = json; + settings.debug = json.debug === true; + settings.sandbox = json.sandbox === true; + } + + } + + } catch(e) { + } + + } + + } else if (action !== undefined) { + + settings.action = action; + + } + + + if (debug_flag !== undefined) { + settings.debug = true; + } + + if (sandbox_flag !== undefined) { + settings.sandbox = true; + } + + + return settings; + +})(); + + + (function(settings) { /* * IMPLEMENTATION */ - var action = settings.action; - var has_action = settings.action !== null; - var has_profile = settings.profile !== null; + let action = settings.action; + let has_action = settings.action !== null; + let has_profile = settings.profile !== null; if (action === 'start' && has_profile) { @@ -280,7 +280,7 @@ var _bootup = function(settings) { } else if (action === 'status') { - var pid = _read_pid(); + let pid = _read_pid(); if (pid !== null) { console.log('Running (' + pid + ')'); process.exit(0); @@ -292,12 +292,12 @@ var _bootup = function(settings) { } else if (action === 'stop') { - var pid = _read_pid(); + let pid = _read_pid(); if (pid !== null) { console.info('SHUTDOWN (' + pid + ')'); - var killed = false; + let killed = false; try { @@ -343,5 +343,5 @@ var _bootup = function(settings) { } -})(_settings); +})(_SETTINGS); diff --git a/bin/maintenance/do-install.sh b/bin/maintenance/do-install.sh index cdfafc66..71477250 100755 --- a/bin/maintenance/do-install.sh +++ b/bin/maintenance/do-install.sh @@ -120,9 +120,9 @@ else # Arch elif [[ -x "/usr/bin/pacman" ]]; then REQUIRED_LIST="bash binutils arm-none-eabi-binutils coreutils libicns sed zip unzip tar curl git"; - REQUIRED_CMD="pacman -S --noconfirm $REQUIRED_LIST"; + REQUIRED_CMD="pacman -S --noconfirm --needed $REQUIRED_LIST"; OPTIONAL_LIST="lib32-glibc lib32-libstdc++5 lib32-ncurses lib32-zlib"; - OPTIONAL_CMD="pacman -S --noconfirm $OPTIONAL_LIST"; + OPTIONAL_CMD="pacman -S --noconfirm --needed $OPTIONAL_LIST"; # openSUSE elif [[ -x "/usr/bin/zypper" ]]; then diff --git a/bin/maintenance/do-update.sh b/bin/maintenance/do-update.sh index cfa890e9..553af494 100755 --- a/bin/maintenance/do-update.sh +++ b/bin/maintenance/do-update.sh @@ -60,8 +60,11 @@ elif [ "$LYCHEEJS_CHANGE" == "" ]; then cd $LYCHEEJS_FOLDER; + git checkout $LYCHEEJS_BRANCH; - git pull origin $LYCHEEJS_BRANCH; + git fetch; + git reset "origin/$LYCHEEJS_BRANCH" --hard; + # git pull origin $LYCHEEJS_BRANCH; if [ ! -d $LYCHEEJS_FOLDER/bin/runtime ]; then diff --git a/bin/strainer.js b/bin/strainer.js index 9ebb1dd5..0609855c 100755 --- a/bin/strainer.js +++ b/bin/strainer.js @@ -1,17 +1,17 @@ #!/usr/local/bin/lycheejs-helper env:node -var root = require('path').resolve(__dirname, '../'); -var fs = require('fs'); -var path = require('path'); +const _fs = require('fs'); +const _path = require('path'); +const _ROOT = _path.resolve(__dirname, '../'); -if (fs.existsSync(root + '/libraries/lychee/build/node/core.js') === false) { - require(root + '/bin/configure.js'); +if (_fs.existsSync(_ROOT + '/libraries/lychee/build/node/core.js') === false) { + require(_ROOT + '/bin/configure.js'); } -var lychee = require(root + '/libraries/lychee/build/node/core.js')(root); +const lychee = require(_ROOT + '/libraries/lychee/build/node/core.js')(_ROOT); @@ -19,16 +19,16 @@ var lychee = require(root + '/libraries/lychee/build/node/core.js')(root); * USAGE */ -var _print_help = function() { +const _print_help = function() { - var libraries = fs.readdirSync(root + '/libraries').sort().filter(function(value) { - return fs.existsSync(root + '/libraries/' + value + '/lychee.pkg'); + let libraries = _fs.readdirSync(_ROOT + '/libraries').sort().filter(function(value) { + return _fs.existsSync(_ROOT + '/libraries/' + value + '/lychee.pkg'); }).map(function(value) { return '/libraries/' + value; }); - var projects = fs.readdirSync(root + '/projects').sort().filter(function(value) { - return fs.existsSync(root + '/projects/' + value + '/lychee.pkg'); + let projects = _fs.readdirSync(_ROOT + '/projects').sort().filter(function(value) { + return _fs.existsSync(_ROOT + '/projects/' + value + '/lychee.pkg'); }).map(function(value) { return '/projects/' + value; }); @@ -42,70 +42,43 @@ var _print_help = function() { console.log(' '); console.log('Available Actions: '); console.log(' '); - console.log(' stash '); + console.log(' check, stage '); console.log(' '); console.log('Available Libraries: '); console.log(' '); libraries.forEach(function(library) { - var diff = (' ').substr(library.length); + let diff = (' ').substr(library.length); console.log(' ' + library + diff); }); console.log(' '); console.log('Available Projects: '); console.log(' '); projects.forEach(function(project) { - var diff = (' ').substr(project.length); + let diff = (' ').substr(project.length); console.log(' ' + project + diff); }); console.log(' '); + console.log('Available Flags: '); + console.log(' '); + console.log(' --debug Debug Mode with debug messages '); + console.log(' '); console.log('Examples: '); console.log(' '); - console.log(' lycheejs-strainer stash /libraries/lychee; '); - console.log(' lycheejs-strainer stash /projects/boilerplate; '); + console.log(' lycheejs-strainer check /libraries/lychee; '); + console.log(' lycheejs-strainer stage /libraries/lychee; '); + console.log(' lycheejs-strainer stage /projects/boilerplate; '); console.log(' '); }; - - -var _settings = (function() { - - var settings = { - action: null, - project: null - }; - - - var raw_arg0 = process.argv[2] || ''; - var raw_arg1 = process.argv[3] || ''; - - - var pkg_path = root + raw_arg1 + '/lychee.pkg'; - if (fs.existsSync(pkg_path) === true) { - settings.project = raw_arg1; - } - - - // stash /projects/boilerplate - if (raw_arg0 === 'stash') { - - settings.action = 'stash'; - - } - - - return settings; - -})(); - -var _bootup = function(settings) { +const _bootup = function(settings) { console.info('BOOTUP (' + process.pid + ')'); - var environment = new lychee.Environment({ + let environment = new lychee.Environment({ id: 'strainer', - debug: false, - sandbox: true, + debug: settings.debug === true, + sandbox: settings.debug === true ? false : true, build: 'strainer.Main', timeout: 3000, packages: [ @@ -126,8 +99,8 @@ var _bootup = function(settings) { if (sandbox !== null) { - var lychee = sandbox.lychee; - var strainer = sandbox.strainer; + let lychee = sandbox.lychee; + let strainer = sandbox.strainer; // Show less debug messages @@ -144,12 +117,17 @@ var _bootup = function(settings) { sandbox.MAIN.init(); - process.on('SIGHUP', function() { sandbox.MAIN.destroy(); this.exit(1); }); - process.on('SIGINT', function() { sandbox.MAIN.destroy(); this.exit(1); }); - process.on('SIGQUIT', function() { sandbox.MAIN.destroy(); this.exit(1); }); - process.on('SIGABRT', function() { sandbox.MAIN.destroy(); this.exit(1); }); - process.on('SIGTERM', function() { sandbox.MAIN.destroy(); this.exit(1); }); - process.on('error', function() { sandbox.MAIN.destroy(); this.exit(1); }); + const _on_process_error = function() { + sandbox.MAIN.destroy(); + process.exit(1); + }; + + process.on('SIGHUP', _on_process_error); + process.on('SIGINT', _on_process_error); + process.on('SIGQUIT', _on_process_error); + process.on('SIGABRT', _on_process_error); + process.on('SIGTERM', _on_process_error); + process.on('error', _on_process_error); process.on('exit', function() {}); @@ -177,21 +155,74 @@ var _bootup = function(settings) { -(function(action, project) { +const _SETTINGS = (function() { + + let args = process.argv.slice(2).filter(val => val !== ''); + let settings = { + action: null, + project: null, + debug: false + }; + + + let action = args.find(val => /^(check|stage)/g.test(val)); + let project = args.find(val => /^\/(libraries|projects)\/([A-Za-z0-9-_\/]+)$/g.test(val)); + let debug_flag = args.find(val => /--([debug]{5})/g.test(val)); + + + if (action === 'check' || action === 'stage') { + + if (project !== undefined) { + + settings.action = action; + + + try { + + let stat1 = _fs.lstatSync(_ROOT + project); + let stat2 = _fs.lstatSync(_ROOT + project + '/lychee.pkg'); + if (stat1.isDirectory() && stat2.isFile()) { + settings.project = project; + } + + } catch (err) { + + settings.project = null; + + } + + } + + } + + + if (debug_flag !== undefined) { + settings.debug = true; + } + + + return settings; + +})(); + + + +(function(settings) { /* * IMPLEMENTATION */ - var has_action = action !== null; - var has_project = project !== null; + let has_action = settings.action !== null; + let has_project = settings.project !== null; if (has_action && has_project) { _bootup({ - action: action, - project: project + action: settings.action, + debug: settings.debug === true, + project: settings.project }); } else { @@ -204,5 +235,5 @@ var _bootup = function(settings) { } -})(_settings.action, _settings.project); +})(_SETTINGS); diff --git a/guides/CODESTYLE.md b/guides/CODESTYLE.md index 7e2f5bba..7168b8cc 100644 --- a/guides/CODESTYLE.md +++ b/guides/CODESTYLE.md @@ -1,26 +1,39 @@ # Codestyle Guide for lychee.js -1. [Project Layout](#project-layout) +1. [Linting](#linting) +2. [Project Layout](#project-layout) - [Packages](#packages) - [Namespaces](#namespaces) - [Definitions](#definitions) -2. [Definition Layout](#definition-layout) +3. [Definition Layout](#definition-layout) - [Modules](#modules) - [Composites](#composites) - [Callbacks](#callbacks) -3. [Code Layout](#code-layout) +4. [Code Layout](#code-layout) - [Editorconfig](#editorconfig) - [Indentation and Whitespaces](#indentation-and-whitespaces) - [Naming of Variables](#naming-variables) - [Naming of Properties and Methods](#naming-properties-and-methods) - [Data Type Comparison](#data-type-comparison) - [Data Type Validation](#data-type-validation) -4. [Entity Layout](#entity-layout) +5. [Entity Layout](#entity-layout) - [Naming of Attachments](#naming-attachments) - [Naming of Events](#naming-events) +## Linting + +All lychee.js Libraries and Projects are linted and validated in the identical way. +All third-party projects must follow the same rules, otherwise AI support is dropped. + +- Use [eslint](https://github.com/eslint/eslint) with our [.eslintrc.json](/.eslintrc.json) file. +- Use [editorconfig](http://editorconfig.org) plugin for your Editor with our [.editorconfig](/.editorconfig) file. +- Install `eslint` globally via `(sudo) npm install -g eslint`. +- Install the `editorconfig plugin` for your IDE from mentioned website. +- Use the `lycheejs-strainer` CLI tool to `check` and `stage` all libraries and projects. + + ## Project Layout ### Packages diff --git a/guides/RELEASE.md b/guides/RELEASE.md index 508371da..78500e5a 100644 --- a/guides/RELEASE.md +++ b/guides/RELEASE.md @@ -2,8 +2,9 @@ # Release Guide for lychee.js 1. [Configure Token](#configure-token) -2. [Update lychee.js](#update-lycheejs) -3. [Release lychee.js](#release-lycheejs) +2. [Log in NPM](#log-in-npm) +3. [Update lychee.js](#update-lycheejs) +4. [Release lychee.js](#release-lycheejs) ## Configure Token @@ -21,6 +22,28 @@ echo "MY-PERSONAL-ACCESS-TOKEN" > .github/TOKEN; ``` +## Log in NPM + +The NPM package manager is some kind of bloat, as it is +not integrated with `git` and neither with `github` and +therefore has its own publishing process. + +In order to have a machine setup for a successful `npm publish`, +it is necessary to execute an initial `npm login` first. + +The account name for NPM is [~artificial-engineering](https://www.npmjs.com/~artificial-engineering). +Contact [@cookiengineer](https://github.com/cookiengineer) to +get a login token for your machine. + +```bash +npm login; + +# Username: artificial-engineering +# Password: Contact @cookiengineer +# Email: robot [ insert an at here ] artificial.engineering +``` + + ## Update lychee.js The `development` branch is the branch that is the newest HEAD diff --git a/libraries/breeder/asset/index.html b/libraries/breeder/asset/index.html index b90efb33..cd8e2882 100644 --- a/libraries/breeder/asset/index.html +++ b/libraries/breeder/asset/index.html @@ -1,4 +1,4 @@ - + lychee.js Boilerplate diff --git a/libraries/breeder/source/Template.index.tpl b/libraries/breeder/source/Template.index.tpl index b2eb7518..f9fdd0a2 100644 --- a/libraries/breeder/source/Template.index.tpl +++ b/libraries/breeder/source/Template.index.tpl @@ -1,4 +1,4 @@ - + lychee.js Fork Boilerplate diff --git a/libraries/breeder/source/Template.js b/libraries/breeder/source/Template.js index 1d68facb..69be402a 100644 --- a/libraries/breeder/source/Template.js +++ b/libraries/breeder/source/Template.js @@ -255,15 +255,14 @@ lychee.define('breeder.Template').requires([ this.bind('fork', function(oncomplete) { - let library = this.settings.library; - let project = this.settings.project; - let sandbox = this.sandbox; - let stash = this.stash; - let urls = []; - let assets = []; - let pkg = new Config(library + '/lychee.pkg'); - let folder = project.split('/')[1]; - let namespace = library.split('/')[2]; + let library = this.settings.library; + let project = this.settings.project; + let sandbox = this.sandbox; + let stash = this.stash; + let urls = []; + let assets = []; + let pkg = new Config(library + '/lychee.pkg'); + let folder = project.split('/')[1]; console.log('breeder: FORK'); @@ -454,17 +453,18 @@ lychee.define('breeder.Template').requires([ tmp_stash.batch('read', injections); + this.__injections = injections; + } - setTimeout(function() { + this.__main = main; - this.__main = main; - this.__injections = injections; + setTimeout(function() { - this.trigger('pull-inject', [function(result) { + this.trigger('pull-inject', [ function(result) { oncomplete(result); - }]); + } ]); }.bind(this), 500); diff --git a/libraries/fertilizer/lychee.pkg b/libraries/fertilizer/lychee.pkg index 5b77daa8..1d89151e 100644 --- a/libraries/fertilizer/lychee.pkg +++ b/libraries/fertilizer/lychee.pkg @@ -68,6 +68,7 @@ "template": { "html": { "Application": [ + "appcache.tpl", "config.tpl", "icon.png", "index.tpl", diff --git a/libraries/fertilizer/source/Main.js b/libraries/fertilizer/source/Main.js index c3e772e0..ffff8156 100644 --- a/libraries/fertilizer/source/Main.js +++ b/libraries/fertilizer/source/Main.js @@ -327,6 +327,8 @@ lychee.define('fertilizer.Main').requires([ * ENTITY API */ + // deserialize: function(blob) {}, + serialize: function() { let data = _Emitter.prototype.serialize.call(this); diff --git a/libraries/fertilizer/source/data/Shell.js b/libraries/fertilizer/source/data/Shell.js index 230689d0..613f7099 100644 --- a/libraries/fertilizer/source/data/Shell.js +++ b/libraries/fertilizer/source/data/Shell.js @@ -7,12 +7,12 @@ lychee.define('fertilizer.data.Shell').tags({ try { - let child_process = global.require('child_process'); - let path = global.require('path'); + global.require('child_process'); + global.require('path'); return true; - } catch(err) { + } catch (err) { } } @@ -134,7 +134,7 @@ lychee.define('fertilizer.data.Shell').tags({ }); - } catch(err) { + } catch (err) { callback.call(scope, false); diff --git a/libraries/fertilizer/source/template/html-nwjs/Application.index.tpl b/libraries/fertilizer/source/template/html-nwjs/Application.index.tpl index bdde5244..0407a61d 100644 --- a/libraries/fertilizer/source/template/html-nwjs/Application.index.tpl +++ b/libraries/fertilizer/source/template/html-nwjs/Application.index.tpl @@ -1,4 +1,4 @@ - + diff --git a/libraries/fertilizer/source/template/html-webview/Application.index.tpl b/libraries/fertilizer/source/template/html-webview/Application.index.tpl index 866d63de..a9ece3f3 100644 --- a/libraries/fertilizer/source/template/html-webview/Application.index.tpl +++ b/libraries/fertilizer/source/template/html-webview/Application.index.tpl @@ -1,4 +1,4 @@ - + ${id} diff --git a/libraries/fertilizer/source/template/html/Application.appcache.tpl b/libraries/fertilizer/source/template/html/Application.appcache.tpl new file mode 100644 index 00000000..d0e269c1 --- /dev/null +++ b/libraries/fertilizer/source/template/html/Application.appcache.tpl @@ -0,0 +1,14 @@ +CACHE MANIFEST + +CACHE: +/favicon.ico +core.js +icon.png +index.html +manifest.json + +NETWORK: +/api +http://harvester.artificial.engineering:4848 +http://localhost:4848 + diff --git a/libraries/fertilizer/source/template/html/Application.index.tpl b/libraries/fertilizer/source/template/html/Application.index.tpl index 4517e0e6..31cb9738 100644 --- a/libraries/fertilizer/source/template/html/Application.index.tpl +++ b/libraries/fertilizer/source/template/html/Application.index.tpl @@ -1,5 +1,5 @@ - - + + ${id} diff --git a/libraries/fertilizer/source/template/html/Application.js b/libraries/fertilizer/source/template/html/Application.js index 6ea68d81..bb21aa0c 100644 --- a/libraries/fertilizer/source/template/html/Application.js +++ b/libraries/fertilizer/source/template/html/Application.js @@ -5,10 +5,11 @@ lychee.define('fertilizer.template.html.Application').includes([ const _Template = lychee.import('fertilizer.Template'); const _TEMPLATES = { - config: attachments["config.tpl"], - core: null, - icon: attachments["icon.png"], - index: attachments["index.tpl"] + appcache: attachments["appcache.tpl"], + config: attachments["config.tpl"], + core: null, + icon: attachments["icon.png"], + index: attachments["index.tpl"] }; @@ -22,10 +23,11 @@ lychee.define('fertilizer.template.html.Application').includes([ _Template.call(this, data); - this.__config = lychee.deserialize(lychee.serialize(_TEMPLATES.config)); - this.__core = lychee.deserialize(lychee.serialize(_TEMPLATES.core)); - this.__icon = lychee.deserialize(lychee.serialize(_TEMPLATES.icon)); - this.__index = lychee.deserialize(lychee.serialize(_TEMPLATES.index)); + this.__appcache = lychee.deserialize(lychee.serialize(_TEMPLATES.appcache)); + this.__config = lychee.deserialize(lychee.serialize(_TEMPLATES.config)); + this.__core = lychee.deserialize(lychee.serialize(_TEMPLATES.core)); + this.__icon = lychee.deserialize(lychee.serialize(_TEMPLATES.icon)); + this.__index = lychee.deserialize(lychee.serialize(_TEMPLATES.index)); @@ -115,11 +117,12 @@ lychee.define('fertilizer.template.html.Application').includes([ console.log('fertilizer: BUILD ' + env.id); - let sandbox = this.sandbox; - let config = this.__config; - let core = this.__core; - let icon = this.__icon; - let index = this.__index; + let sandbox = this.sandbox; + let appcache = this.__appcache; + let config = this.__config; + let core = this.__core; + let icon = this.__icon; + let index = this.__index; config.buffer = config.buffer.replaceObject({ @@ -135,10 +138,11 @@ lychee.define('fertilizer.template.html.Application').includes([ }); - stash.write(sandbox + '/manifest.json', config); - stash.write(sandbox + '/core.js', core); - stash.write(sandbox + '/icon.png', icon); - stash.write(sandbox + '/index.html', index); + stash.write(sandbox + '/manifest.json', config); + stash.write(sandbox + '/core.js', core); + stash.write(sandbox + '/icon.png', icon); + stash.write(sandbox + '/index.appcache', appcache); + stash.write(sandbox + '/index.html', index); oncomplete(true); diff --git a/libraries/harvester/lychee.pkg b/libraries/harvester/lychee.pkg index 7bc426d7..01245290 100644 --- a/libraries/harvester/lychee.pkg +++ b/libraries/harvester/lychee.pkg @@ -251,6 +251,9 @@ "Main": [ "js" ], + "Watcher": [ + "js" + ], "data": { "Filesystem": [ "js" diff --git a/libraries/harvester/public/desktop-dark.png b/libraries/harvester/public/desktop-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..982448dcfd29a4ca7f9e5502b40c3df9cdfec6f3 GIT binary patch literal 19820 zcmeFZg;!PG7cRWdp}R}Ekq&7DBm|^eBn2tyZa9F_DM(0ngLIcjNTYOjcQ<$Q{=V;z zxMN%x4C0)%_S|#Lxz;nEXKq4Olw>eaU!Vd2fFUOS2s@^<8vsxNa#C+J z+-LU}JiIj~Zp4m9oQ~+IA*MK==k5k4HC5o+SS|d;L#+h&H zZ8440=CIT7>n*{pMK5-7ssH!!e}xASB#5EeziNzoW^&@*(!g(ra(*JiUjvGu=bXR> zfO+&#A`I*!9urdSLG+*$L=9!H<@ycJ~vsQUn?XKq?-= zvkT+xpu@0ccOEPiv17Z7Jy%-es2KaI&4h?;*Z2UN3qnN`-Ku7|Warf$ru=681<<=W zy<(%bT&Ko=vKJaH+Vr(n`Zqi*FLqhE`>0N;RLYt-(T-y&Ie{#O{nfK6JXhVTVlU3SsR%MHZcH9vHLXfwpE}x#wqn zOrq{N%1qMFOdE1Sz53OWEp1b3lig;{2`}ZtA!IeF0M`>HL4FU(+!961Y4q7Fv)_lCwhTQ*bz;*Qb#D5-F8%}so2Z71z+vn&8I_Nj$oJok_{^7rT@b zJypHcsB^#?LrMV%36rSF%Ig2hiY@EH)%(VuA9A(-LpnU6N)y|Z=mnZ0%CeENScbQ~~C)_mNJtuSo&}-QN|0YK{ z6*Vc4IOE5zIr59=$M~!!3D6N#U5_b%Y*u%(%~T;tXD(E8rwj#EKpTOOt>Jst^R)3( z+0|w<#ivX#|A?MWdPwoL@z5$lyD?J;7#tg0gY8)>QgA)EfFyCGq#g?PgND({FE0|* zXIJ0wUT64DGIb^DAsVsf#C{XNH%BDoaF74ryhO9Zg61*K-A@=s+&QrcP zfkW+1UIH}HI~e@LZ?*5E$?jh}G!(MBZ=P4b<-&jVlH-S0WH+JEYGRa;2=2l4mZw** z;{U%_)WD_9fVan>UE%5+PvgAS0AdRY2yi@%y9cX_VlKH>Hxf~udvOnU_iP2yDzH5I(k~1!LyBdFAme;4A6H}^ab5zQ?&-3cW zkI=iz5YyS%F~M)_UWOQjrX0XFef)hw@B61y%v=jnwg#c=WN&F? zg8YmWvW=(eiBYm8pY00HbnD76Cm`;!SdafgTzJCq{^z$Ws#R1V_NrR3dR++fQSeVe z`TQU!wgUpJVfz8%OE%ZV*{{Ue>^eS^Iy+?(G70L>BI#ar;LN*h}xFG%G{ke?Sh z-6F-q47md#LTZ?FsnuzV9v$vEOO-?D+OZ6{2cnzQZf;L`MoNw7o&zQ?&u26FA0)X` zc0Dqd9_7k0$RBiQEK#*zKP|hxkGy2p%KsK6zGmo$OOu4?pzONNUqmuh_DzESy)cf5 z`~ArT|1^%d++cG0{jlt_6NTsw%m*uhaUNWc6eyWao70v#G19Yj!F+c_8~b8QdnyhK zr$#@Ek=QIi0B&xb1qzu3}^&jFqYjXvS;ha@zos&uIK&yOQFPu#`qzZj<#UB zA5FOq3kK%0v{B4o*4sB2BT=LsabiEG`s|h57{L=6(o;anu6OL4=ecW?!ObuTwIN)u zlO7PdN)8J8i2h%cwT9J6DFv@Gz0F>ZM~OfqL3}pv?$=finhOqa&6*>A-sTh#0#Mz@ zIz=v9v#QK8ci?WB5k78D3!z6$4{*pf0ITz;zz?z_~P z##e(RPWOP)C%Uk=ep9T%X&9m zS6sN@=t9}rkz{og3s@{uRW6o*v8>LM(Axm;$^?4~qb?&5x8JPq$~(VPK5u_5jIe&z zw^8lG~6J5a< zk_vqP&noGu2bK&3j!OpMBk6xuPTlZ8j4=BM0On26m_lS}^TF*3vp;-*H(^U(vfNVA zpXk>$QL$8D>Ja$n#*aH3GXnOJ*UoSKpKV0p`kE#R0q}cX{qJ{qXr|D2)y#AQm1J~W zaCgW~I$5v}gmjqE6}q7qtycB)I3oUca}Dq12Py$fbGpLBil;fdI}*g_8(h}wLgq$2 zZ{y4Ak^7&=>{kO&fYx?JVk4+HxNxZL^+c|h=f3@XZ=N^&PP!nNXbePQyHzm$d268# z8%}bdgJng)`-pp3>+HP``p?S3Tpd?vj=0xam={gXf78UHxSrNT503(IlF!#I)cExL zx;{ijFkSW8D__Ax=pr6n)CQc%a>Tp8*h%JyYHDk1xBYX8=G2Tp3cPRRCz5(NG zb4cFI>>f$jW7g}R(Of1CEjq+BMGXH3Q~s;sY@Ck8@;|)@?!%h*3+6xkyz?79YPFXZ z7CGrgPpGxD&5xGe?QH{UH0m zu;-$3FQYFByB{ww1kw#_7pSs>dS-$ayj0=hG9EhRq-RmUk!Gq0)qqEU}8B2FVz*mU1z6+ z_>B+DJT3~GzZPsAY3`!dJI{XL#g$`$95;rt03@p$FA+nQzC4Z^TD{Jddr)M>^}ua0 zge3tgh8EV=ub!%14|)k22uFWd`&6L5y)@lY>gIf;E#u3MIpc{pPLLR53VL;GvnPhy zNNY*lu0Ju~^0oGD(dt`q=h0`+)SBwwua;P87cEC)f3iCE(}G{(qRM(Tup$q$c!Fz4 zF(6gd-eOw+ES_L?%o$Cvt=RU-F>tBw@I-ggp;YkQ%N0}PZSkIosVmZk<}+NTHmH#^ zVcTELZd|Toaqc3l@(8I(4^<1@uGFtk8>7g-zGlbap9zODHl%fY2ZWUT&!jksc0>`X z{p7?S%?clDh8z;A2}4l;k51(GlhWn>M`6YagiT8X*^Y)17b6B3w?`9Ta9RTY-j~%- z%EN^dDqJ;<%GK%H6#JqEpaBtm^Dn=2XWy1x%6^G%1~dHK(E994jQkg3TA4y!hP68W zUV42#EL|(_8QKe5Kf0oKe41oG@VXy=Ka~BIB&BR>YU-};V3t=>`Uxq_DJGfJT+=^T zzptL#M+rRln5lT{e6rD62|9|B_st1TzhrsJcyA2{Yn6SNNQ+z|v`K2!ijDk^-fvAPi6RAZ3ERfW1{uR>*;9`97 zGO@Cei2!d;pxzT1`70?@x=) z7*Sy&$t>85({^Au_$u1ct#I|pILe8mAsXO=}Ty06-#edyM}*;DEus?#T9j`WPTi3>wLoas^>GG zRM`n$hWhxHW}_n2x>>c?qw@8>o)Hr(Q-a5})z-C?@kD|Pb4fZ1Ku`znzfS?M`X96wj56TE9i=k zMRf;f3ftW7UWrfY`5%=cg1WT7cCC=_&xfLjPg*pu4W7||iz9GkY|*Jbesf~dZu*c{ zUS6I$1OqP)w43@EWcqz|b8ENL?wc6<=`_nTG*mLvh=&Jj8=IYNdQFIFSR950cO5NL z0&x;vSXakm-9zR>U;yHKp$QjYG;Dl)Ew(F9ryTONiyzMZe$&1>TCzse%ceg5{jumJ;~JONPDwk*4&KHHck=A;Gj` zPyIuV2M8IF&S)Wv(GrFqh}iB=J5e_b1&(`EIlDcX==u1F@x}aFH9kFMUn+h>B_>NjYXSpB;iZ`nC?gUwLOCaZP?Ap;i^%vJ5qBxeLzi;Ql3yqbk-O z0p=*{qlR#!gcO;rWp~0|(Nv#*c;J9p8Z;U6a4yVYezBRl~tF z@n&2pMz?15b#;XI41%UXcc{7;2fgK6i0JRt`^0|M*77dqSx7Y{cEO8bAO_M~bA!h= zRzyj~Q9%G@zHU^QgO2q~)l?X@86FY)JiHN_F4lpGhL^AHVfz@j&4}=DN_oRh`89b4 z=g`2k8MuCw#M3i3V!+=P5*c4gD@%`tK8Y(ba1brIZ{2&}ov?(BaQttJ4?sXk#}pC| zBvaJE@<+zfVxFf>C4wT%e8$twqPW(uv@}`c2JL9V90&$=A-y>y8iSzP;uaN8OzS%r#Rt?6`BYr?9ED2WDIL zp6Q}~wK}TV@P<9f-0jNg(2H;Tkx~_BB!!rt?WWz?7`dHy^xMS5AQ9gf`FijHR;n_90XmtAcD?bdF=8G z#8}W5X7brrBcE!EEc}}G9@)#B`a6QBpHF(iYnZcLlTIx+Srmbrd33k6+3G+>pI(=*%`fg5*49`03~BQ z5Kzu=vA3d2gg-Jg>>{8UD4F+2eofFYIeDq57@8gBAMT8s>A$wScUMUd8XA#NL>#A; zePm1@hzvAjP*VZoxPGjc*daUlwMf5~4-Z$YWkHw~r~Z`Ade`UNZ;!Et@fH`mp&cOx ztT)=|TN1oY{+UQ;z|qr{`F3hD05^TT*!T5DoB}n?_>vfXD?$A$yZuH)0($7^_{;VP zm@-FC8m2#iV6^f5v@9&OodpVY2jX1*o-kD8e%v6B-^H7o@vcikEzNiKxs4ZQeqHWy zyy(|NY#){uIjyLv%(-7kD=ggQ*VOfdzeYDLzcc$KyOx(-uJhxNO98}Xt4?ut5@QH& z%48B|md}-Tm>FnxirQ^9Z(^JK5T76Wet8L4L&Iw^!Wylm= za}9zpv9V2jN$CklirrVbB7TP(YBG*3u7a4k|N3E*6BxZx^f^xxy;%_3IryBnm7$5C z;t!!(fxEB!4jdz9R!FY%BJhzGSClMce6@x~OrguQQLFtOYxTM7(Jaw&A@Xe9@`0*= z6~m(|4cA}J2-R#MH4HM0@2c43DBo3KQSh9TiVTD4leySFZrcg1QS&7G4(MydRJG*2 z3jaWZl=2>h-7uj)L-i@_|K^}kMDq>aCI&=v5is7!{6{a6!P3gTq=a5)hJLGAs@e&Q z7_sNrhvS6C;EcMxh1SVu3}X&QOg;s#s&kCh9xz7r!9&7G3J8 z%aiA)X{~4GhD>Mt`B#ATR>Zd^M7UqYB)6CX15PG<)dHc%t?7?{(3tvnX0Kw2rH3an zlMsryUGr$s+wF29L;V!nuauqe%de{uCEMVLl(})c1s-}wh`%ms^vPldrrff9)HgLv z`74I_dK2#7eH$Nfhmn7JgLzb;N(d@EDnCx}QdJYxwo2as^vX1(rIelTN06;7-N|W~ z>?aIQqHoE-zB!CvGul=9ZRl>_75Z^6_2NSHNDb=wLJgapI{U;p9?auxlm4OZf)F-- zwaCYX;thXD?vH?${#k5oP>ypx9JqOvDZ|Z-V8a6Q2=W((qHWf5lX+E9^TfQZXqt#C z>z)u`IP$zqA0UuHJGa=^QN-@h^#8crjth@7gZv$X=5QdC&LExBc77JT(8bJ9U$PPq z@p+DdzC)mcoRP*v|9d6Wjf~19i#XifP3P!(v6?Ak3-10+P11>_ZyVewN>RqP8r*Wl z{>fq-yvS`IGcdKZG<|(>A}plLrKndN<^;rZ3L#Lx3@Feea*LUrmM{IZj>BYvx!RE7 z3=x+F#G~*m>;jI57f_Dpw8%Py#Q7wg;q+QqX*iB_-pF3zc0q!d;q(H@oa+{1Q;_6`UEDPytq|;+ zzgZwchDXfG{gfI;hG0Y{)$`_piC6$N%pt@LYnsPpJo|n2i1+Z6{s&KV*tqMWnzig1 zKF+^*Ct$w6SU^CX!ebrdyyeYFdY#iS$(Qoq){^JenyFADCff0WMeI)X@_tFCGqysH z<4zm&Kh&Vn|+ znw7V0`?ol02Vt11*IQy_fnVmAUxY^XTTu6F8$t!uIAXdsLWD{P!ADeIAAE ziN_egkE2RDPv0WXqN$Lx+#&L*Oz5MHD^T{E4RL!Qj*%y+V5I}>m1RxN508z$?+dh> zrjfg(`u*hl`|r*;OBk3xdDatTrKPbsm0UEf5Ry)9jTK+cW_CDA<|5c<%>SL4xoso5 zVtwC%oJYOFQx4C`*?RM(QD|XJMOz6w>S^W$Y?Flkgk?6NruDHc28q?G4%HVf^P6fv z8NvO_$yL3izv$yt_vM)jfn642wu93zeQuE7as9_tCyVlLqXuLnLtj8UeEwb83d6o* zTM|f@H2s~u`+{f+YcDUywLR52x3)?z9=4bkM7JzwxIGxnfZV`a(dY27tcSf9xbH|8 zb6-*i4x*~5u#px1R(&IFd=b+LKPcVL0xS>^aNM}McsdaK6HS&i;&)W&&?YD-cQ20zwsx+nAjpX4Y1liV`S57NMK_~ zc~Che`mwl-1xXKNOvE*XTG3Tk`x=UP+#oFl{~VD{gxQR!ZQF$vs`uyDRGGEg*uZoC z3S67c&OiDxU1eHP`R;b{%skEIy&JbjD#L|A$(1-oBZBbtBdXC^@uEV8oo~` z#1{C}$}EKLG8OugBjLwpI39)XHQS`?5?BaEqnz7OM6g~-cddl~W&ORquv{9zyVj_v zqSsb2(0bRpi;Iqk#Nged3^c-fi*%_6?T}8@S?j#xp=h@e!`OZmjkz&qF>MLh-3@wN z@$>yyt9QZRm&eT^AkP1c{-q%>lN-5%3XT}LlL`pTBF=ry;(auDj8DvTbZ9^6ODmVL97uvr4!JbDH71~sE zOo)#^f>YW4tQ?JSD+wk?=Lc$Ly~xPOO?LhhB7}f+4Bn1vOGcdX&b_Bad+G+8`U+=> zW~b%Or%XHmaR0dTw?3O~IPv#r+{&9g9=ML&c(LNsmR=ckXlKidfzxW^5Y*~kkCh2+ zzp|KW5mu)y2b13XCkkNfPicBh8RB}4Mfh1BQ3CtxZ7*v~kA=Ke!K%STSwyM^iq}(^ zFKg!oV|E$i%p9c=F}FFje^MFE^;X%2pjsVY&1LB#c!u_N*Lj^1SH6R3##h1P^V@P% zB#~hRX9$gB6*#ZtffWXYjf1T-h7&3k<{nkvTQM$T^!)R>M%sQ%T?`{P#HeDmEcyGa zQ7J8K)kiCk2z#h=A)?a$lzClaSfFQUcoet{KdJF9n?09rS755b^7A`O5!t=raDt&B z7R1CvW%a&^?bh%lOg@jdI(qBZ8ltn~DSh_6`g55be`N(dcetVB`2TwWa*}VOa*8PtP zQpDL98(gYVa>YB@Xg$jAi(fDem6|PyfhMv(Gz~Hd(&&JQwu$@wyTPf6es_uS)xSVawew}-2!c)4ZTyslITCte&0GeRV)!8K5 ze<#=?7{kP`i2C*IomE+H=ILuPqd@-X+w#1{2%CNam{0fH6I?2DDc#h@!wGeyeQ^@2heiD6BhR24t#GpXB+emgclnxn91&6ifKS(SQ9IZuR4bt4!C5U2>3M zEI-QOfx^4#qKq$nm$XR_nb#-b6>Ya1heYDzz15FJohJ9SlVZ}xNI+oq%>sSsZ*Hux zB2%`0?sqSKkZ5`l5l_+uQdV=cn)G*QYGYjpIRN z!v_#Z>y?!tIC^*q+>f*g!9;zKOa>hi_Q|R?=y1H@#LZ**0>aAl?F!DhBX|`Ro3q}h zqlrmmVU#bEfFKL6u#CKyJ%!1~UxjJCzD!2?Sc)Co24P=BlWlQMzJ2>6EpqJ^woED< zY@Ixw80eS52mn7l$9Bsv3Ad0q2iJgk-H5U`ycc<#I1k#G5BP8$(z{I~cQ$*j3{a_} zletUhb{jS=Niu-PaeH*qs}d(N>w|VY0ZS5xv4XXogYSQH>23dXlBj8Hq&h*4I~ydae$|{-OX=ctTRn;!X+ztB4Gl48y7HNpZ_F%{DpBt zJp2H$gJ@zj$Rgay%u9aYhu)9Mjrhxi1P1Vw#m$_8POIXZx6*7_3#b~jp^J;i_l)3l*g_wVo0G}rcrmzuj1IrH7$fPLWngCULJ z%SkewR4=DmGD37j83ymoNI*1sulI*5!zN3SwQiHMBy&btU70C#{m-`_qHx6R(}L?m zcTOKsA_^-Me!LLrQAkQGTy}zzsct`vBi&wLAQ*NA-2BNkXyeA!No)>ILV{+g$YQM3 zr8c54@RR^Vb;83LYB!}zb$;;M7ao^!OTaqT4~4~@jRCe0M{hNC+^d^m+=fKRDbD&b z^S-YLDTc769TLTVqRbV6J+F-BNnX+#>z|u1?3CFv6robtEB0y3q7yv!__^w8KuT4xHM5MxMChd+ zk*bz?(V|GLjm2J(^bIS}Z?P0;nfl$-L@he?z?Z2FFeSa-kv>stUW-tE$$-b0aEo~E z2iNh@gB)I(2>o7Ne^6daaz}& zWr+|nO>xaK;86Xan@zsKY#0189O$4v-u2D<#!DY;9*=+g-OS!FhG zqJ+EFZOq{a4F=|Ak<$6MrEL(XWYbCW`V zrU!ALKxVso^?J&UYg)SnF6^~u1&>lAN@=M|F1YAkN`}x^BpRTnJUBR5hSb z+@P12irWjoqq9`Pi`{{xClmxGXs3q-rPU-JmJ}!?)8$vvV9ETs$xkx$1yxa(EX~pi zY+b9PNM|DLsmVt*4L`)~8gD^Y%``ZwJopY3pAG_iC#Xu+C?ezqe8;4In(#y20_H@) z#Au$}3EO|NTNi1oHb@g64e2-ELlua|EbUdXh`K!UG5dj+hgYA-cukdjAFNrmwJUUR zLhqYZO0>cx#Xnm-Aa86g~nM7H?J6Ji^f9>-Yf)&;M zH;hp!_5Ei|;$sAVu(VKN&#-Tka+Cr^rFWzh2>YXosEr8^lWz)cDoSKEV1>m!zn!(| zT=ze8_hO<2;QTx=$$SCxhcVv+P=J}_M<4}tdPtpsWqVhS`BTEWRo_9Y?jm95NZm!r zwFCA1vKyy&_unWl;q#Qh&SgqG`px>R26S;bOp4-UR<2>-xHrCsM{=vv6l#x5KF_(+ z*yHsB8JGfDqNguQbp~ITbs!(~ElLOBkMhm= zXuBu(XhWzDY<+i`GI*K4&HYrkNU5a(8e{Hhiy!esNtH3wTB`Aciy2c@XZ6X*FRg|Nok)WG7S%8x#!mI zB`j6>B6dDiJ@prptF+JsB;r?nkT%5qp7<(xK8B1lGccNwV){Dh#1yU$lN?1ZN=^EE zu|tG-FB+#o)*6JQo5|FPBA{Ef*HX4V$%ym)x8vjr>R|R(=5>cIm-fFDp*2KK1Ux2- zJQkCRm6<*KS$(m>nj7OF8=(=_o`+a|f^NlIun+$e?0G=ulQ7MJrl3z?$aVQBPV56e zJxm4eU!YodHi62Mw>h`qFV1<@@*lL+hfI=O(3p1!Z-GJ$BdN9)+Y50Ghv@nL1S2e!W8fC-{OF5F_#L=Uxl0r5wWTG^%JHE zl@wB#aSRkL3oH!9@u%_yzZ%b7o`%I5%%g8r)IL(;8y>DL{mTxk=q1~d(_+Je!4(%_ zq-_>^Q^FQxZmxnX1h`+k6b)Jh-%AvhQOOXx9fO3}T`@<#<%ku=eP35g=u;o7rhzYJ z;g;I&Umx)3w!sPSH8qLrA@aiYGsf6I$d|iid@@ZNotI)fB|%4`fWssm4!Psg$ENnH zPc)iDLXFXgPp+zikwIxcTzivyJ2OyVM4{sHTI#@9biwV+bNT(IGKp7KDtP;=#hGJo zoD|JV%8}E`Ba&<7)s7MPjymO}o4A}DBeAC~5D%0P)(k0DmH_x3W$;Zi7u_<#Dc&h9}$OKt@y*lZ(f_RKdtQQ#D?KmCS zSXdRL9fta}H(dlnWh2#fV0QCpNzrhCh`t2f@Q*u!E%fI?PBxOJHMt0Fq$Vs9Tcqy= zP4W^*s&H9z z5{l!~q5IbDszOA8QPc_9&x03!s$_?h+{R(kvlfCwPG$hzHu0TH#~fqH51@BTHc-O5xlTct$U*^YHQ^$pbnb#)QfD)f^l2f-?; z_~Gt?vXLz=_ltl%NK4BIp61XVf?=q6A`(XD<82`(ldVFN zrv@vTXzSID59XsDB=ag=(sxc2V^kS>%>;Wqy0J?GH(L$xaO#gHzO}h)hWW;QWS~)< zpEwjqbXU~^11IS?nH11y*@||9UJFw_lTE#`t8wxji_`RmoqX>)Ufr9l)p+~If& z704?zo2^m(Bee>JFud(rQ7%wV0P!*EHg5#8s%kSo_}0r}&UTw8C4bHQkt;^g>JhNr zM*}qO$8jMQO1eRu;@+)D=$=1uVW z&J|D9KW#CnL~nz(9KiqatkO^jI{qf7WoB7R5f(B~s7)OrCl`LJp?L$O{wl;J!0xom zQCfGc2s_iAOvTAzX&2iqq)p*#Z3<1q2j}&nHkzxBaG!by5TP80J6v2m{C&xBayci4 zc+5&Gufe%^+#NUNrTO0hiG7bA_O`zHQy$1qs0Jm0+O5+v7Chn&Sg7GQ0WqpTW`GIe z;i89)&_?-(+G1Vm41}dwX$@=*2h)+srN!-b(_?K2+014@wT!#e~+qngmu*_^STJpW35F?^NCQIt%F z8};LO@~CDKT{;xN;@$__N23t}JNao2FKU1iwGgr#a(Cp z*7*UbV%K%|^UK8L0e;t3Wp|8|6Br+_lYtnS`?}Y(D?HkOg(VB+pd*k zOn>j#SjK+k?1qohbf;C?8x!L}N^s{LQ+EWBqWq0jO?=J_R@7G~FJWX_pup!VHBqPw zxrcUi1U_cIv)|5q8oJ!0wNnDhxs><Lg}~_C^v8@zG+MGnTM~vh z2!ShC0M*LXKLe0bQyc7!$TXT$vF9E{Pfa7ar$=o#p_LdSYIwux9R^*-sR;+%*c^8} zBh2Eu(s1cxmi;@=xlVVqAdmm5@idd?`dvJwV}d4oKI0yZJ+xN9%|mnXw~ED=kr*O? zEd4E4GyZAqdx60#>~&(-UBTaV2VKFMnva+Pc2Fk8>IQCc89Rd|E{-$_J~!tUq3q&f zvJU4-Y*qH?$M7?hOlewKjed{%0+FQTC6v7NtE^ zyYKbEmWW`mG}AOb`;SnS@qo@{6~D5JpW=T0=ZW`MriG9P#ip;N7PdYV*%_u~ zI2+UG6301(YlBx+3iWeWR)CDzc8pK)b=?vsTRJgnq!9);gh^#x-(y zdson0ngz#fw%B$v3oUV}BE`oPL=d9a75K!NreXEd@>9`ews>FZimQzQfUBg=L= zMBz=!kivdr8HW_2naj-6$0_LhUmxgpol-CicfKkrDyF|SU#dQjwr04|Ty1&+8UK>^ zX$k=9>@%1JdGBE4M<7!qWr?i=M>JOWFIz!T(aTtS7xqlj_c>BN3@c4S^)@?d$|I8X z&F8MjL8cdp$o=rQXdp?X4uc+}Cg& zD%z&8OI2-yyTh!9@JZCq%@vU(4(s|*y~M!K$x7Pdx2?5}CX!A~2sVe??#9>K{U$em zsj?%yx|t#~9{2G^4v(uwVWvLP2#H(McDz&qCSX>hbVU<4xr52oGM@wi;RnQjcGf}V ziW;HV>6){-dtwJ96Mlz(GB+~c!oyZDJ-{>ljoBc?`y#aTv`WQq0UxdWUjRsHSCjslngJRBE;u%m*5y~iSgx-C`!{hAI zI(nOm6p(~qcK^=i-^U{tVt^kmm44i0WN5y%07MPM383?$d%RL1ZHiI+CESA4L5f>g zYpe1-#p!j*Vz^vaNpT(MA>;zx(Vj@s`e2AILT;eCD?&p#ieMwF0?>m52AYg?0@pM<}+JWy_jAx+N>~jlc=>nn0|5A z&9nPDC?vlKCE{1Nv2NahQccm+#w18Xu~+twKKS(_EKg!wA4#3<^qZd_!hWvR!kwGZpmxz7?LPX`2@H#%p%9}5bv%ZWp43(T3N1f#| zn?a{LwIrQYww4vg2pMUoHrGU#I3THdM${z%R;*wvZ=?0=;3$3wMK;JdeTUw#!K$EX zzVI>;#E}245&B0ID#(rn5fJXDJUT5zrAIfYkQYz$T8aYU4ql? zlj%k|h#KT)VlcDn&5iVuIr3MTT@T$Zb?Wu)W1afh&p;d%(( z`mwx-^5(#!N3yl!&%o1RGn*h4Z6kwmj#{-lj?1&8~{RVLSfb%u!^XmG>w^g>% zPJ3tRLlUfeOgJK#%NBLa*^3_St3L|Y?nUsvUePTcasz>3Ou2qDf}i%DN)2k7!iU09 z#64%6s5txB*nCvrDcOHzv>QCPg1fhBBPfBoL`pvE7h_yqB7#ORE@lq}{Q9I;TJ5fN z5smb4@-+vVVAY`3$3HW88OaYhlo_hA%&94@DUwC<0}62)&_F^%yaH8^B(zliyreMD zNK}`Ypt62^w3>(ano`VW_9MzaJ(c)Czmaj*&&kV6VBDamyugD=YCSj4^W)e-mN^b( z`_{jV+~0v6Mz7~yeR`%Rdm|~lFyZSf^Hgzmv9-nU!NP5Lbg(_wkVX_Mz}QdZ@b{My z>lKrLyPg8zlJ7cLf)eMSJAOxO1R}7^^pb_V+QX+;(tzN4zj|bM^MX7)NL$keZ`qk4 zM}rJc{Wrej=Wz#v!EtSLQsG-$h-i-m9Do_v&lsewCG@=F9|e+teeI4ab{O>;aBlu; zamoP!gmM^*^J6PJrKV0YGVa&gV+YW*zyP0`Z^$akSyCR|so&)j+hU83j&pnCll z?aE>}sbVcvr+FX}WFf(10K6#g4@Nhb9T~$`9g^dxX^V@!!K56N)K?imppP?TS3&|9PwZ6dehaj&blQd*eq3kNh-p!~e!k|Eujys;M z4|_u5zL=sU4pfvcxSAZVHZK-!8!8)f)`oI=BOZM8T<8FU>KuvWi}sf>PB~F$q@Rut zTp)98AN(mfSMTVtQ^)T3I(wfD1gL!H+DJO4NWuayaX8%2=1m@MFG4}{!LqZ|TN<7x z)~`Z~!SiT)330h5X|2ZW)T-D@QX6`W0Ovbu*>N7LnS*GzJAKRqqWH<_X^R9hzGWpK zV@t;&qyT%Av!%G$%Sop9p8-)@V-Bt7C(Vh~#S}Osp85FToG0=*mRtU|n9jWiV7b1O z15KMBRMIFWUu|`}d6qTo=syYc}VrI-PHG zVU-)Ui>jtlGf6ymfXiR3&@3+Z?rAyu)O0s;sdsBneKiXUZ@!^`^gBeqX!|x&!=~Rv z{m*b66yX9_d(j(_1XETGH)zbkzUFK%E6Xu@0B>(M=z4x#0^mz&E8xi>1-;JuY5Q$~ zI2EVtK))@*c^o?5Mv^}2%?D67MIdPzvs2E{m*SuwFhjbG_(6|RX*ytF0#(U;KKJe8 zlmUTs3{gBm*u2Mm5|?2TznuZM`V!91QZx;F78rGez=k-|?a`Oy`@w$GG7i(*<`<-- zLrj=IX6m&q;NlrXk~tprCWYm zjyXXuC?gocyJ6?HRccZ%g?{a-r$MVoCtu=hD}9=zzLFU08#N!F%}u_S<--+X0CaFc zCY0b79yVsZq;nFlt9DySpe)wPn?rlHb=0>HSb3p*j968wTPEkGWPNi=#C<~#vO8^T&93^? zqeoDI)Q<(|o~rt-B7~tLv9*sZ_(C7hlQ}w2(EYS*TrtkhpM`Gl6y6&Y!$&RbGr9 zZc@80ti-%Vh6V>TEWfF4lF)_7pY+eU%h3!%tUO2pwa#2O#eKF?mi_gBiNEDPBBSmJ zHpuHYHMK1)F1E3y81B~}glBp(e&Oib-J=77gn4FL=3oA%)Q%y~eSQL_3DCnG&Qn;9 z`aPFs_@VZ*rW+w%2PH({Yh{7ty2LT8b(|Dx$@(L2#gOe)+uXmO9K5f22PW2HN8bP1>~!4^8RB( z_A-;Ym@``k!B*`EyWS5U(s#n)lE_ef`Z(7sfVV$|94FZ&&r9nPWIJ2rej4Edn2#Rx zDBa3Ff7bb{J=6&Rjj73Wx?O|FbT{#1v(D8?jO7XyZ!xf~{jwV}P!mK90O%{v{}qy%?oU z==>6qA;ohyTB&vUuLl~cI34n@@-Qv&LwmP_TN75oxtW3oEgK7V4PQ7TY%2zi1L%4x zcsLW|0mJt%9})zXIOW*~dQ!$O8<~yf-oPE^!Mt%>LTgl75VkWuZXb+oZrJ$va89Tf zP`tEV<+I(5=$g`=hRE-VLi88)q22Ff((*xwQ zuGbE~eG_Z_>Aa)cXs-ep_^i=c0ic@_5JcEAi6&IYi5oBguaANg{p^o9rU!3vxFT4p zAJ8uigbzS8T)sO4eRX(QzoE@PE{(n#WT&=;lh(=LLvs3#BwL|(0@!p&~cHe1UHcYgRIoFOW!pB-w?C#G{o+c^#B|mMm!eJl`)>*)W^G_qi)fc6~_!5FteV z3jN#{x4if${i;!t2wjBL-p+`oK8#BRQR^w4tWl^+XmE4 zH_XM`>1S5e@d38vB)RhyxUEJF@4d0R3o$yT!mT%@ z_V$zA(P2PN>7hW>)1$eYKNXZl1z(mE6`2KP=ZCdKHe%)MWMXBS*?G2!uutQzLWR&j zC63gc^ItpCN1juzv$L)}nB)a(XfCWws9e_ER_N}`+rpDm)yR?H*8Yv3w%U&YVa8MkG-0znjXzobc*y1silQ`{~tllaV#; z3hGlJEbg-?#FupLyWY`14ytuMTP5=!lCF2Edn8n%D{3WDY-dZzv+*@jF`I&Yo@Ca` ze=sf+3j!ILw~7P*E_-j5WfZ-ne$XL(5U;&3{JnVt<9NSUq@UcC3hnek)H9CLNEkUw z*5DskYEr$={Y$pZ4poEm_8gYGz+M6AAPRbIDE)QM{bd4%;h7!Jj}l*l>D}vNF;GDj z3o~i3H^|~|A5<%ALO;QrPANFL3K}s_lW`Ig>Y}ZqT&HzREuUEgl1+Rb_qbb{`zC;w zOydIl#V9etuW=P6#n-&nPA^=`Z|YK0Q!{1kyGTg%!@~5E8h_@29fym&2%0bdtBSDQb4g^1Q*7YeKQuto3mUIdTTx6d~p`Z5xU z98$Mm^^x>_+2*eO!;1@9Cb>kkTnw6_M%Zb^D(&r;@qDuNCiFX96r4TpUK-!GEK!-8 zf*O4Zc9riqt*9D;ypMsskg@gO3xNZ7r^wecGd+oxz}m<>+*Y(s*B%Pb!FryRuXKgj zU!OlYvPd*@zm*Nu5K5j|2-u*dg!_`*eIMAsE8Fbl1? zLZi_j$(!`;%gYF(AyXfJRp?nDwDLYqH!OrZN{hOHwl>vGk4a6{A4v{`hmeS@U}*z| zxVAC*EV<6t)!U(BQU9kn=b~&OyGqGjkGk84k=&CRA7?eG3(En|f$*rbp;t(5Z!<^r zlv(UCwdiyVQjpu_GFI^UGpJw&)GYd`!ok#3+N*LUK8X>^3{K-floE@pPB)Nb znEfRUC?A$h_-$s*x=;x(-5}$Zs9VgDGmU1C>N{uVm$cDZ`Gx`3Y%i+^;LuDf!DG(j z;Uxe0S#-|f4Iw)EhDWd>kV%^C5FE1YWmZ|j#4VpMjp_CW$kWU1aqa|em@5RpaA^*X z@I$z=dX8P1$HR3Y9j?9Cmc-9fi`7Z^DRSUW0NR7Z!bKEH%W6*WdCPGVm+ON|_3ofMLDWEdF9$*)Opgjb>P9 zC+yfk#n{+?4IV*^GI*D#?_B)PWyOru9VDMk`;M6r zH{juTaoFH}MSEZbZY}($D&V8FTcj{jS3o>r4{i3XE)VY7ZZh!$I4rbgH@`7|Knuna zgR+NnGsm$g+rsbEKxp#D6|77rb|F|pk;Qm9apCAalwX-2C+1jodb142(W3@fE|8Mq8!75Bg0w3BzAzIOC>! zA(jUQnSM_u@7Ca_>KVF#FAgVqaHQwry0}M>q_h3Q@ff;UvMp!x!>v4bm+D2j2jV*j zU@F3pZxde}mSQRRz4xvWDo}hJN|^QO>5<;OTUy`kr!+j{^IZhS0F-_viWyYE4RG4# zIDs75li5v?=r;wMZ+X+krH-9u@pS-9{2C+j%22)XoS{ea9+vWbbP2{bZMIg)IFI;x z{xspEJg+I~0}klw>Y;~tm%bX{Rve&TFbi~mkvddJRdAiZkv++a*AYf0j-lFXb^xAP z&Mwy{EDZE)VI|-4g`*UYlRgyYL#4HRM zEX|d3(!#3`Dh|jz-qYk)_v-F{{EMKS>h7`c#KPEf=B^V!EIOiTXDC}b*PJLUUCcU? zTx5Auh%bWpT6Ut@p{$L%-g%lze2=iSV)R*&dIMDn%CC`(o536{I(a5XE$2!0IX2?R zkvolB@4PuiY1E68j?T;r@HYT}kAbH74DmXWLfg?P!NO*2#XQ(<%MNVaw1IVr%{Z?{ mt8d^hf8hW1KM^P|jsdp*mVCv2#5?w91JtRru6*Y!_x=HqQ=r`d literal 0 HcmV?d00001 diff --git a/libraries/harvester/public/desktop-dark.svg b/libraries/harvester/public/desktop-dark.svg new file mode 100644 index 00000000..2d11f6bc --- /dev/null +++ b/libraries/harvester/public/desktop-dark.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/libraries/harvester/source/Main.js b/libraries/harvester/source/Main.js index 22d1093c..8c0dfbeb 100644 --- a/libraries/harvester/source/Main.js +++ b/libraries/harvester/source/Main.js @@ -3,41 +3,27 @@ lychee.define('harvester.Main').requires([ 'lychee.Input', 'harvester.net.Admin', 'harvester.net.Server', - 'harvester.mod.Fertilizer', - 'harvester.mod.Packager', - 'harvester.mod.Server', -// 'harvester.mod.Strainer', - 'harvester.mod.Updater' + 'harvester.Watcher' ]).includes([ 'lychee.event.Emitter' ]).exports(function(lychee, global, attachments) { - const _harvester = lychee.import('harvester'); - const _mod = { - Fertilizer: lychee.import('harvester.mod.Fertilizer'), - Packager: lychee.import('harvester.mod.Packager'), - Server: lychee.import('harvester.mod.Server'), - Strainer: lychee.import('harvester.mod.Strainer'), - Updater: lychee.import('harvester.mod.Updater') - }; - const _setInterval = global.setInterval; - const _setTimeout = global.setTimeout; - const _Emitter = lychee.import('lychee.event.Emitter'); - const _LIBRARIES = {}; - const _PROJECTS = {}; - const _PUBLIC_IPS = (function() { + const _harvester = lychee.import('harvester'); + const _clearInterval = global.clearInterval || function() {}; + const _setInterval = global.setInterval; + const _Emitter = lychee.import('lychee.event.Emitter'); + const _PUBLIC_IPS = (function() { let os = null; try { os = require('os'); - } catch(err) { + } catch (err) { } if (os !== null) { - let candidates = []; Object.values(os.networkInterfaces()).forEach(function(iface) { @@ -69,184 +55,6 @@ lychee.define('harvester.Main').requires([ - /* - * HELPERS - */ - - const _initialize = function(sandbox) { - - let libraries = Object.values(_LIBRARIES); - let projects = Object.values(_PROJECTS); - let Fertilizer = _mod.Fertilizer; - let Packager = _mod.Packager; - let Server = _mod.Server; - let Strainer = _mod.Strainer; - let Updater = _mod.Updater; - - - if (sandbox === true) { - - console.info('harvester: SANDBOX mode active'); - console.info('harvester: Software bots disabled'); - console.log('\n\n'); - - Fertilizer = null; - Strainer = null; - Updater = null; - - } else { - - console.info('harvester: SANDBOX mode inactive'); - console.info('harvester: Software bots enabled'); - console.log('\n\n'); - - } - - - - /* - * BOOTUP: LIBRARIES - */ - - libraries.forEach(function(library, l) { - - if (Packager !== null && Packager.can(library) === true) { - Packager.process(library); - } - - if (Server !== null && Server.can(library) === true) { - Server.process(library); - } - - if (Updater !== null && Updater.can(library) === true) { - Updater.process(library); - } - - if (Fertilizer !== null && Fertilizer.can(library) === true) { - Fertilizer.process(library); - } - - }); - - - - /* - * BOOTUP: PROJECTS - */ - - _setTimeout(function() { - - projects.forEach(function(project, p) { - - if (Packager !== null && Packager.can(project) === true) { - Packager.process(project); - } - - if (Server !== null && Server.can(project) === true) { - Server.process(project); - } - - if (Updater !== null && Updater.can(project) === true) { - Updater.process(project); - } - - if (Fertilizer !== null && Fertilizer.can(project) === true) { - - _setTimeout(function() { - Fertilizer.process(project); - }, p * 2000); - - } - - }); - - }, 3000); - - - - /* - * INTERVAL - */ - - _setInterval(function() { - - libraries.forEach(function(library) { - - if (Packager !== null && Packager.can(library) === true) { - Packager.process(library); - } - - }); - - projects.forEach(function(project) { - - if (Packager !== null && Packager.can(project) === true) { - Packager.process(project); - } - - }); - - }, 30000); - - - }; - - - - /* - * FEATURE DETECTION - */ - - (function(libraries, projects) { - - let filesystem = new _harvester.data.Filesystem(); - - - filesystem.dir('/libraries').filter(function(value) { - return /README\.md/.test(value) === false; - }).map(function(value) { - return '/libraries/' + value; - }).forEach(function(identifier) { - - let info1 = filesystem.info(identifier + '/lychee.pkg'); - if ((info1 !== null && info1.type === 'file')) { - libraries[identifier] = new _harvester.data.Project(identifier); - } - - }); - - filesystem.dir('/projects').filter(function(value) { - return /cultivator|README\.md/.test(value) === false; - }).map(function(value) { - return '/projects/' + value; - }).forEach(function(identifier) { - - let info1 = filesystem.info(identifier + '/index.html'); - let info2 = filesystem.info(identifier + '/lychee.pkg'); - if ((info1 !== null && info1.type === 'file') || (info2 !== null && info2.type === 'file')) { - projects[identifier] = new _harvester.data.Project(identifier); - } - - }); - - filesystem.dir('/projects/cultivator').filter(function(value) { - return /design|index\.html|robots\.txt/.test(value) === false; - }).map(function(value) { - return '/projects/cultivator/' + value; - }).forEach(function(identifier) { - - let info1 = filesystem.info(identifier + '/index.html'); - let info2 = filesystem.info(identifier + '/lychee.pkg'); - if ((info1 !== null && info1.type === 'file') || (info2 !== null && info2.type === 'file')) { - projects[identifier] = new _harvester.data.Project(identifier); - } - - }); - - })(_LIBRARIES, _PROJECTS); - - - /* * IMPLEMENTATION */ @@ -257,12 +65,15 @@ lychee.define('harvester.Main').requires([ this.defaults = lychee.assignunlink({}, this.settings); - this.admin = null; - this.server = null; + // Updated by Watcher instance + this._libraries = {}; + this._projects = {}; + this.admin = null; + this.server = null; + this.watcher = new _harvester.Watcher(this); - this._libraries = _LIBRARIES; - this._projects = _PROJECTS; + this.__interval = null; settings.host = typeof settings.host === 'string' ? settings.host : null; @@ -312,7 +123,18 @@ lychee.define('harvester.Main').requires([ this.bind('init', function() { - _initialize.call(this, settings.sandbox); + + let watcher = this.watcher || null; + if (watcher !== null) { + + watcher.init(settings.sandbox); + + this.__interval = _setInterval(function() { + watcher.update(); + }.bind(this), 30000); + + } + }, this, true); }; @@ -376,9 +198,9 @@ lychee.define('harvester.Main').requires([ destroy: function() { - for (let identifier in _PROJECTS) { + for (let pid in this._projects) { - let project = _PROJECTS[identifier]; + let project = this._projects[pid]; if (project.server !== null) { if (typeof project.server.destroy === 'function') { @@ -400,6 +222,11 @@ lychee.define('harvester.Main').requires([ this.server = null; } + if (this.__interval !== null) { + _clearInterval(this.__interval); + this.__interval = null; + } + this.trigger('destroy'); diff --git a/libraries/harvester/source/Watcher.js b/libraries/harvester/source/Watcher.js new file mode 100644 index 00000000..3af23a12 --- /dev/null +++ b/libraries/harvester/source/Watcher.js @@ -0,0 +1,271 @@ + +lychee.define('harvester.Watcher').requires([ + 'harvester.data.Filesystem', + 'harvester.data.Project', + 'harvester.mod.Fertilizer', + 'harvester.mod.Packager', + 'harvester.mod.Server' +// 'harvester.mod.Strainer', +// 'harvester.mod.Updater' +]).exports(function(lychee, global, attachments) { + + const _Filesystem = lychee.import('harvester.data.Filesystem'); + const _Project = lychee.import('harvester.data.Project'); + const _mod = { + Fertilizer: lychee.import('harvester.mod.Fertilizer'), + Packager: lychee.import('harvester.mod.Packager'), + Server: lychee.import('harvester.mod.Server'), + Strainer: null, + Updater: null + // Strainer: lychee.import('harvester.mod.Strainer'), + // Updater: lychee.import('harvester.mod.Updater') + }; + + + + /* + * HELPERS + */ + + const _update_cache = function() { + + this.filesystem.dir('/libraries').filter(function(value) { + return /README\.md/.test(value) === false; + }).map(function(value) { + return '/libraries/' + value; + }).forEach(function(identifier) { + + let check = this.libraries[identifier] || null; + let info1 = this.filesystem.info(identifier + '/lychee.pkg'); + + if (check === null && (info1 !== null && info1.type === 'file')) { + this.libraries[identifier] = new _Project(identifier); + } + + }.bind(this)); + + this.filesystem.dir('/projects').filter(function(value) { + return /cultivator|README\.md/.test(value) === false; + }).map(function(value) { + return '/projects/' + value; + }).forEach(function(identifier) { + + let check = this.projects[identifier] || null; + let info1 = this.filesystem.info(identifier + '/index.html'); + let info2 = this.filesystem.info(identifier + '/lychee.pkg'); + + if (check === null && ((info1 !== null && info1.type === 'file') || (info2 !== null && info2.type === 'file'))) { + this.projects[identifier] = new _Project(identifier); + } + + }.bind(this)); + + this.filesystem.dir('/projects/cultivator').filter(function(value) { + return /design|index\.html|robots\.txt/.test(value) === false; + }).map(function(value) { + return '/projects/cultivator/' + value; + }).forEach(function(identifier) { + + let check = this.projects[identifier] || null; + let info1 = this.filesystem.info(identifier + '/index.html'); + let info2 = this.filesystem.info(identifier + '/lychee.pkg'); + + if (check === null && ((info1 !== null && info1.type === 'file') || (info2 !== null && info2.type === 'file'))) { + this.projects[identifier] = new _Project(identifier); + } + + }.bind(this)); + + }; + + const _update_mods = function() { + + let Fertilizer = _mod.Fertilizer; + let Packager = _mod.Packager; + let Server = _mod.Server; + let Strainer = _mod.Strainer; + let Updater = _mod.Updater; + let sandbox = this.sandbox; + + if (sandbox === true) { + + Fertilizer = null; + Server = null; + Strainer = null; + + } else { + + // Fertilizer is disabled for now + // (Performance reasons) + Fertilizer = null; + + } + + + // TODO: Check if libraries and projects still exist + + + for (let lid in this.libraries) { + + let library = this.libraries[lid]; + + if (Packager !== null && Packager.can(library) === true) { + Packager.process(library); + } + + if (Server !== null && Server.can(library) === true) { + Server.process(library); + } + + if (Updater !== null && Updater.can(library) === true) { + Updater.process(library); + } + + if (Strainer !== null && Strainer.can(library) === true) { + Strainer.process(library); + } + + if (Fertilizer !== null && Fertilizer.can(library) === true) { + Fertilizer.process(library); + } + + } + + for (let pid in this.projects) { + + let project = this.projects[pid]; + + if (Packager !== null && Packager.can(project) === true) { + Packager.process(project); + } + + if (Server !== null && Server.can(project) === true) { + Server.process(project); + } + + if (Updater !== null && Updater.can(project) === true) { + Updater.process(project); + } + + if (Strainer !== null && Strainer.can(project) === true) { + Strainer.process(project); + } + + if (Fertilizer !== null && Fertilizer.can(project) === true) { + Fertilizer.process(project); + } + + } + + }; + + + + /* + * IMPLEMENTATION + */ + + let Composite = function(main) { + + this.filesystem = new _Filesystem(); + this.libraries = {}; + this.projects = {}; + this.sandbox = true; + + + // Figure out if there's a cleaner way + main._libraries = this.libraries; + main._projects = this.projects; + + }; + + Composite.prototype = { + + /* + * ENTITY API + */ + + // deserialize: function(blob) {}, + + serialize: function() { + + return { + 'constructor': 'harvester.Watcher', + 'arguments': [] + }; + + }, + + + // TODO: can(project)? + + init: function(sandbox) { + + sandbox = sandbox === true; + + + if (sandbox === true) { + + console.info('harvester.Watcher: SANDBOX mode active'); + console.info('harvester.Watcher: Software bots disabled'); + console.log('\n\n'); + + this.sandbox = true; + + } else { + + console.info('harvester.Watcher: SANDBOX mode inactive'); + console.info('harvester.Watcher: Software bots enabled'); + console.log('\n\n'); + + this.sandbox = false; + + } + + + _update_cache.call(this); + + + for (let lid in this.libraries) { + + let library = this.libraries[lid]; + + if (_mod.Packager !== null && _mod.Packager.can(library) === true) { + _mod.Packager.process(library); + } + + if (_mod.Server !== null && _mod.Server.can(library) === true) { + _mod.Server.process(library); + } + + } + + for (let pid in this.projects) { + + let project = this.projects[pid]; + + if (_mod.Packager !== null && _mod.Packager.can(project) === true) { + _mod.Packager.process(project); + } + + if (_mod.Server !== null && _mod.Server.can(project) === true) { + _mod.Server.process(project); + } + + } + + }, + + update: function() { + + _update_mods.call(this); + + } + + }; + + + return Composite; + +}); + diff --git a/libraries/harvester/source/data/Filesystem.js b/libraries/harvester/source/data/Filesystem.js index 1ae5b12b..772693b9 100644 --- a/libraries/harvester/source/data/Filesystem.js +++ b/libraries/harvester/source/data/Filesystem.js @@ -10,7 +10,7 @@ lychee.define('harvester.data.Filesystem').tags({ return true; - } catch(err) { + } catch (err) { } @@ -19,9 +19,9 @@ lychee.define('harvester.data.Filesystem').tags({ }).exports(function(lychee, global, attachments) { - var _ROOT = lychee.ROOT.lychee; - var _fs = require('fs'); - var _path = require('path'); + const _ROOT = lychee.ROOT.lychee; + const _fs = require('fs'); + const _path = require('path'); @@ -29,20 +29,20 @@ lychee.define('harvester.data.Filesystem').tags({ * HELPERS */ - var _create_directory = function(path, mode) { + const _create_directory = function(path, mode) { if (mode === undefined) { - mode = 0777 & (~process.umask()); + mode = 0o777 & (~process.umask()); } - var is_directory = false; + let is_directory = false; try { is_directory = _fs.lstatSync(path).isDirectory(); - } catch(err) { + } catch (err) { if (err.code === 'ENOENT') { @@ -52,16 +52,15 @@ lychee.define('harvester.data.Filesystem').tags({ try { is_directory = _fs.lstatSync(path).isDirectory(); - } catch(err) { + } catch (err) { } } - } finally { + } - return is_directory; - } + return is_directory; }; @@ -71,7 +70,7 @@ lychee.define('harvester.data.Filesystem').tags({ * IMPLEMENTATION */ - var Composite = function(root) { + let Composite = function(root) { root = typeof root === 'string' ? root : null; @@ -114,11 +113,19 @@ lychee.define('harvester.data.Filesystem').tags({ scope = scope !== undefined ? scope : this; - if (path === null) return false; + if (path === null) { + + if (callback !== null) { + callback(null); + } else { + return null; + } + } - var asset = null; - var resolved = _path.normalize(this.root.substr(process.cwd().length) + path); + + let asset = null; + let resolved = _path.normalize(this.root.substr(process.cwd().length) + path); if (callback !== null) { asset = new lychee.Asset(resolved, null, true); @@ -149,7 +156,7 @@ lychee.define('harvester.data.Filesystem').tags({ return asset; - } catch(err) { + } catch (err) { return null; } @@ -164,10 +171,18 @@ lychee.define('harvester.data.Filesystem').tags({ scope = scope !== undefined ? scope : this; - if (path === null) return false; + if (path === null) { + + if (callback !== null) { + callback([]); + } else { + return []; + } + + } - var resolved = _path.normalize(this.root + path); + let resolved = _path.normalize(this.root + path); if (callback !== null) { _fs.readdir(resolved, function(err, data) { @@ -184,7 +199,7 @@ lychee.define('harvester.data.Filesystem').tags({ try { return _fs.readdirSync(resolved); - } catch(err) { + } catch (err) { return []; } @@ -199,16 +214,24 @@ lychee.define('harvester.data.Filesystem').tags({ scope = scope !== undefined ? scope : this; - if (path === null) return false; + if (path === null) { + + if (callback !== null) { + callback(null); + } else { + return null; + } + + } - var resolved = _path.normalize(this.root + path); + let resolved = _path.normalize(this.root + path); if (callback !== null) { - var data = null; + let data = null; try { data = _fs.readFileSync(resolved); - } catch(err) { + } catch (err) { data = null; } @@ -218,7 +241,7 @@ lychee.define('harvester.data.Filesystem').tags({ try { return _fs.readFileSync(resolved); - } catch(err) { + } catch (err) { return null; } @@ -233,10 +256,18 @@ lychee.define('harvester.data.Filesystem').tags({ scope = scope !== undefined ? scope : this; - if (path === null) return false; + if (path === null) { + + if (callback !== null) { + callback(false); + } else { + return false; + } + + } - var encoding = 'binary'; + let encoding = 'binary'; if (typeof data === 'string') { encoding = 'utf8'; @@ -245,20 +276,20 @@ lychee.define('harvester.data.Filesystem').tags({ } - _create_directory(_path.dirname(path)); + _create_directory(_path.dirname(this.root + path)); - var info = this.info(_path.dirname(path)); - var resolved = _path.normalize(this.root + path); + let info = this.info(_path.dirname(path)); + let resolved = _path.normalize(this.root + path); if (resolved !== null && info !== null && info.type === 'directory') { if (callback !== null) { - var result = false; + let result = false; try { _fs.writeFileSync(resolved, data, encoding); result = true; - } catch(err) { + } catch (err) { result = false; } @@ -266,11 +297,11 @@ lychee.define('harvester.data.Filesystem').tags({ } else { - var result = false; + let result = false; try { _fs.writeFileSync(resolved, data, encoding); result = true; - } catch(err) { + } catch (err) { result = false; } @@ -295,17 +326,17 @@ lychee.define('harvester.data.Filesystem').tags({ path = typeof path === 'string' ? path : null; - if (path === null) return false; + if (path === null) return null; - var resolved = _path.normalize(this.root + path); + let resolved = _path.normalize(this.root + path); if (resolved !== null) { - var stat = null; + let stat = null; try { stat = _fs.lstatSync(resolved); - } catch(err) { + } catch (err) { stat = null; } diff --git a/libraries/harvester/source/data/Package.js b/libraries/harvester/source/data/Package.js index e21f47a3..d8dc39bc 100644 --- a/libraries/harvester/source/data/Package.js +++ b/libraries/harvester/source/data/Package.js @@ -7,9 +7,16 @@ lychee.define('harvester.data.Package').includes([ * HELPERS */ - var _parse_buffer = function() { + const _parse_buffer = function() { + + let json = null; + + try { + json = JSON.parse(this.buffer.toString('utf8')); + } catch (err) { + } + - var json = JSON.parse(this.buffer.toString()); if (json instanceof Object) { if (json.api instanceof Object) { @@ -66,7 +73,7 @@ lychee.define('harvester.data.Package').includes([ }; - var _walk_directory = function(files, node, path) { + const _walk_directory = function(files, node, path) { if (node instanceof Array) { @@ -110,7 +117,7 @@ lychee.define('harvester.data.Package').includes([ * IMPLEMENTATION */ - var Composite = function(buffer) { + let Composite = function(buffer) { this.buffer = null; @@ -136,7 +143,7 @@ lychee.define('harvester.data.Package').includes([ deserialize: function(blob) { - var buffer = lychee.deserialize(blob.buffer); + let buffer = lychee.deserialize(blob.buffer); if (buffer !== null) { this.setBuffer(buffer); } @@ -145,12 +152,11 @@ lychee.define('harvester.data.Package').includes([ serialize: function() { - var data = lychee.event.Emitter.prototype.serialize.call(this); + let data = lychee.event.Emitter.prototype.serialize.call(this); data['constructor'] = 'harvester.data.Package'; - var settings = {}; - var blob = data['blob'] || {}; + let blob = data['blob'] || {}; if (this.buffer !== null) blob.buffer = lychee.serialize(this.buffer); diff --git a/libraries/harvester/source/data/Project.js b/libraries/harvester/source/data/Project.js index 8c5abd1b..dc26255f 100644 --- a/libraries/harvester/source/data/Project.js +++ b/libraries/harvester/source/data/Project.js @@ -7,9 +7,9 @@ lychee.define('harvester.data.Project').requires([ 'lychee.event.Emitter' ]).exports(function(lychee, global, attachments) { - var _Filesystem = lychee.import('harvester.data.Filesystem'); - var _Package = lychee.import('harvester.data.Package'); - var _Server = lychee.import('harvester.data.Server'); + const _Filesystem = lychee.import('harvester.data.Filesystem'); + const _Package = lychee.import('harvester.data.Package'); + const _Server = lychee.import('harvester.data.Server'); @@ -17,7 +17,7 @@ lychee.define('harvester.data.Project').requires([ * IMPLEMENTATION */ - var Composite = function(identifier) { + let Composite = function(identifier) { identifier = typeof identifier === 'string' ? identifier : null; @@ -29,6 +29,11 @@ lychee.define('harvester.data.Project').requires([ this.harvester = this.filesystem.info('/harvester.js') !== null; + if (Object.keys(this.package.source).length === 0) { + console.error('harvester.data.Project: Invalid package at "' + identifier + '/lychee.pkg".'); + } + + lychee.event.Emitter.call(this); }; @@ -46,12 +51,11 @@ lychee.define('harvester.data.Project').requires([ serialize: function() { - var data = lychee.event.Emitter.prototype.serialize.call(this); + let data = lychee.event.Emitter.prototype.serialize.call(this); data['constructor'] = 'harvester.data.Project'; - var settings = data['arguments'] || {}; - var blob = data['blob'] || {}; + let blob = data['blob'] || {}; if (this.filesystem !== null) blob.filesystem = lychee.serialize(this.filesystem); @@ -73,14 +77,14 @@ lychee.define('harvester.data.Project').requires([ * CUSTOM API */ - setPackage: function(package) { + setPackage: function(pkg) { - package = package instanceof _Package ? package : null; + pkg = pkg instanceof _Package ? pkg : null; - if (package !== null) { + if (pkg !== null) { - this.package = package; + this.package = pkg; return true; diff --git a/libraries/harvester/source/data/Server.js b/libraries/harvester/source/data/Server.js index 607f54be..b8a82a00 100644 --- a/libraries/harvester/source/data/Server.js +++ b/libraries/harvester/source/data/Server.js @@ -5,9 +5,9 @@ lychee.define('harvester.data.Server').exports(function(lychee, global, attachme * IMPLEMENTATION */ - var Composite = function(data) { + let Composite = function(data) { - var settings = Object.assign({}, data); + let settings = Object.assign({}, data); this.host = settings.host || null; @@ -31,7 +31,7 @@ lychee.define('harvester.data.Server').exports(function(lychee, global, attachme serialize: function() { - var settings = {}; + let settings = {}; if (this.host !== null) settings.host = this.host; diff --git a/libraries/harvester/source/mod/Fertilizer.js b/libraries/harvester/source/mod/Fertilizer.js index d21674d1..2a4fd516 100644 --- a/libraries/harvester/source/mod/Fertilizer.js +++ b/libraries/harvester/source/mod/Fertilizer.js @@ -13,7 +13,7 @@ lychee.define('harvester.mod.Fertilizer').tags({ return true; - } catch(err) { + } catch (err) { } @@ -97,7 +97,7 @@ lychee.define('harvester.mod.Fertilizer').tags({ * IMPLEMENTATION */ - let Module = { + const Module = { /* * ENTITY API diff --git a/libraries/harvester/source/mod/Packager.js b/libraries/harvester/source/mod/Packager.js index 6f9890c9..a140b189 100644 --- a/libraries/harvester/source/mod/Packager.js +++ b/libraries/harvester/source/mod/Packager.js @@ -18,9 +18,18 @@ lychee.define('harvester.mod.Packager').requires([ try { + json = JSON.parse(project.filesystem.read('/lychee.pkg')); - } catch(err) { - json = JSON.parse(JSON.stringify(project.package.json)); + + } catch (err) { + + console.error('harvester.mod.Packager: FAILURE ("' + project.identifier + '")'); + + try { + json = JSON.parse(JSON.stringify(project.package.json)); + } catch (err) { + } + } if (json === null) json = {}; @@ -81,7 +90,7 @@ lychee.define('harvester.mod.Packager').requires([ let name = path.split('/').pop(); let info = this.info(path); - if (info !== null) { + if (info !== null && name.substr(0, 1) !== '.') { if (info.type === 'file') { @@ -130,7 +139,7 @@ lychee.define('harvester.mod.Packager').requires([ * IMPLEMENTATION */ - let Module = { + const Module = { /* * ENTITY API diff --git a/libraries/harvester/source/mod/Server.js b/libraries/harvester/source/mod/Server.js index 80048221..ac24cf24 100644 --- a/libraries/harvester/source/mod/Server.js +++ b/libraries/harvester/source/mod/Server.js @@ -15,7 +15,7 @@ lychee.define('harvester.mod.Server').tags({ return true; - } catch(err) { + } catch (err) { } @@ -280,7 +280,7 @@ lychee.define('harvester.mod.Server').tags({ }; - } catch(err) { + } catch (err) { server = null; @@ -296,7 +296,7 @@ lychee.define('harvester.mod.Server').tags({ * IMPLEMENTATION */ - let Module = { + const Module = { /* * ENTITY API diff --git a/libraries/harvester/source/mod/Updater.js b/libraries/harvester/source/mod/Updater.js index 4ac5f226..c2f6c62a 100644 --- a/libraries/harvester/source/mod/Updater.js +++ b/libraries/harvester/source/mod/Updater.js @@ -12,7 +12,7 @@ lychee.define('harvester.mod.Updater').requires([ * HELPERS */ - let _on_sync = function(project, data) { + const _on_sync = function(project, data) { console.log('SYNCHRONIZING UPDATES', project, data); @@ -24,7 +24,7 @@ lychee.define('harvester.mod.Updater').requires([ * IMPLEMENTATION */ - let Module = { + const Module = { /* * ENTITY API diff --git a/libraries/harvester/source/net/Server.js b/libraries/harvester/source/net/Server.js index e3dbab4e..15052670 100644 --- a/libraries/harvester/source/net/Server.js +++ b/libraries/harvester/source/net/Server.js @@ -12,8 +12,12 @@ lychee.define('harvester.net.Server').requires([ const _Remote = lychee.import('harvester.net.Remote'); const _Server = lychee.import('lychee.net.Server'); const _CODEC = { - encode: function(data) { return data; }, - decode: function(data) { return data; } + encode: function(data) { + return data; + }, + decode: function(data) { + return data; + } }; diff --git a/libraries/harvester/source/net/client/Console.js b/libraries/harvester/source/net/client/Console.js index 9c59a469..2526cba3 100644 --- a/libraries/harvester/source/net/client/Console.js +++ b/libraries/harvester/source/net/client/Console.js @@ -46,6 +46,8 @@ lychee.define('harvester.net.client.Console').includes([ * ENTITY API */ + // deserialize: function(blob) {}, + serialize: function() { let data = _Service.prototype.serialize.call(this); diff --git a/libraries/harvester/source/net/client/Library.js b/libraries/harvester/source/net/client/Library.js index ad11dda7..33d92491 100644 --- a/libraries/harvester/source/net/client/Library.js +++ b/libraries/harvester/source/net/client/Library.js @@ -46,6 +46,8 @@ lychee.define('harvester.net.client.Library').includes([ * ENTITY API */ + // deserialize: function(blob) {}, + serialize: function() { let data = _Service.prototype.serialize.call(this); diff --git a/libraries/harvester/source/net/client/Profile.js b/libraries/harvester/source/net/client/Profile.js index f4cb1b3d..0561cb95 100644 --- a/libraries/harvester/source/net/client/Profile.js +++ b/libraries/harvester/source/net/client/Profile.js @@ -46,6 +46,8 @@ lychee.define('harvester.net.client.Profile').includes([ * ENTITY API */ + // deserialize: function(blob) {}, + serialize: function() { let data = _Service.prototype.serialize.call(this); diff --git a/libraries/harvester/source/net/client/Project.js b/libraries/harvester/source/net/client/Project.js index 97e852c6..7f3b7374 100644 --- a/libraries/harvester/source/net/client/Project.js +++ b/libraries/harvester/source/net/client/Project.js @@ -46,6 +46,8 @@ lychee.define('harvester.net.client.Project').includes([ * ENTITY API */ + // deserialize: function(blob) {}, + serialize: function() { let data = _Service.prototype.serialize.call(this); diff --git a/libraries/harvester/source/net/remote/Console.js b/libraries/harvester/source/net/remote/Console.js index a03a0eac..305efac7 100644 --- a/libraries/harvester/source/net/remote/Console.js +++ b/libraries/harvester/source/net/remote/Console.js @@ -25,6 +25,8 @@ lychee.define('harvester.net.remote.Console').includes([ * ENTITY API */ + // deserialize: function(blob) {}, + serialize: function() { let data = _Service.prototype.serialize.call(this); diff --git a/libraries/harvester/source/net/remote/Library.js b/libraries/harvester/source/net/remote/Library.js index 48b3a960..a7db5e6e 100644 --- a/libraries/harvester/source/net/remote/Library.js +++ b/libraries/harvester/source/net/remote/Library.js @@ -123,6 +123,8 @@ lychee.define('harvester.net.remote.Library').requires([ * ENTITY API */ + // deserialize: function(blob) {}, + serialize: function() { let data = _Service.prototype.serialize.call(this); diff --git a/libraries/harvester/source/net/remote/Profile.js b/libraries/harvester/source/net/remote/Profile.js index cda8082c..d587ebf7 100644 --- a/libraries/harvester/source/net/remote/Profile.js +++ b/libraries/harvester/source/net/remote/Profile.js @@ -132,6 +132,8 @@ lychee.define('harvester.net.remote.Profile').requires([ * ENTITY API */ + // deserialize: function(blob) {}, + serialize: function() { let data = _Service.prototype.serialize.call(this); diff --git a/libraries/harvester/source/net/remote/Project.js b/libraries/harvester/source/net/remote/Project.js index 1a1bc9d0..395f6889 100644 --- a/libraries/harvester/source/net/remote/Project.js +++ b/libraries/harvester/source/net/remote/Project.js @@ -135,6 +135,8 @@ lychee.define('harvester.net.remote.Project').requires([ * ENTITY API */ + // deserialize: function(blob) {}, + serialize: function() { let data = _Service.prototype.serialize.call(this); diff --git a/libraries/harvester/source/net/remote/Server.js b/libraries/harvester/source/net/remote/Server.js index 295ddbe9..8dff8b56 100644 --- a/libraries/harvester/source/net/remote/Server.js +++ b/libraries/harvester/source/net/remote/Server.js @@ -97,6 +97,8 @@ lychee.define('harvester.net.remote.Server').includes([ * ENTITY API */ + // deserialize: function(blob) {}, + serialize: function() { let data = _Service.prototype.serialize.call(this); diff --git a/libraries/harvester/source/net/server/File.js b/libraries/harvester/source/net/server/File.js index be37ce15..3c51d5cb 100644 --- a/libraries/harvester/source/net/server/File.js +++ b/libraries/harvester/source/net/server/File.js @@ -5,33 +5,33 @@ lychee.define('harvester.net.server.File').requires([ const _Filesystem = lychee.import('harvester.data.Filesystem'); const _MIME = { - 'default': { binary: true, type: 'application/octet-stream' }, - 'css': { binary: false, type: 'text/css' }, - 'env': { binary: false, type: 'application/json' }, - 'eot': { binary: false, type: 'application/vnd.ms-fontobject' }, - 'gz': { binary: true, type: 'application/x-gzip' }, - 'fnt': { binary: false, type: 'application/json' }, - 'html': { binary: false, type: 'text/html' }, - 'ico': { binary: true, type: 'image/x-icon' }, - 'jpg': { binary: true, type: 'image/jpeg' }, - 'js': { binary: false, type: 'application/javascript' }, - 'json': { binary: false, type: 'application/json' }, - 'md': { binary: false, type: 'text/x-markdown' }, - 'mf': { binary: false, type: 'text/cache-manifest' }, - 'mp3': { binary: true, type: 'audio/mp3' }, - 'ogg': { binary: true, type: 'application/ogg' }, - 'pkg': { binary: false, type: 'application/json' }, - 'store': { binary: false, type: 'application/json' }, - 'tar': { binary: true, type: 'application/x-tar' }, - 'ttf': { binary: false, type: 'application/x-font-truetype' }, - 'txt': { binary: false, type: 'text/plain' }, - 'png': { binary: true, type: 'image/png' }, - 'svg': { binary: true, type: 'image/svg+xml' }, - 'woff': { binary: true, type: 'application/font-woff' }, - 'woff2': { binary: true, type: 'application/font-woff' }, - 'xml': { binary: false, type: 'text/xml' }, - 'zip': { binary: true, type: 'application/zip' } - + 'default': { binary: true, type: 'application/octet-stream' }, + 'appcache': { binary: false, type: 'text/cache-manifest' }, + 'css': { binary: false, type: 'text/css' }, + 'env': { binary: false, type: 'application/json' }, + 'eot': { binary: false, type: 'application/vnd.ms-fontobject' }, + 'gz': { binary: true, type: 'application/x-gzip' }, + 'fnt': { binary: false, type: 'application/json' }, + 'html': { binary: false, type: 'text/html' }, + 'ico': { binary: true, type: 'image/x-icon' }, + 'jpg': { binary: true, type: 'image/jpeg' }, + 'js': { binary: false, type: 'application/javascript' }, + 'json': { binary: false, type: 'application/json' }, + 'md': { binary: false, type: 'text/x-markdown' }, + 'mf': { binary: false, type: 'text/cache-manifest' }, + 'mp3': { binary: true, type: 'audio/mp3' }, + 'ogg': { binary: true, type: 'application/ogg' }, + 'pkg': { binary: false, type: 'application/json' }, + 'store': { binary: false, type: 'application/json' }, + 'tar': { binary: true, type: 'application/x-tar' }, + 'ttf': { binary: false, type: 'application/x-font-truetype' }, + 'txt': { binary: false, type: 'text/plain' }, + 'png': { binary: true, type: 'image/png' }, + 'svg': { binary: true, type: 'image/svg+xml' }, + 'woff': { binary: true, type: 'application/font-woff' }, + 'woff2': { binary: true, type: 'application/font-woff' }, + 'xml': { binary: false, type: 'text/xml' }, + 'zip': { binary: true, type: 'application/zip' } }; const _PUBLIC_CULTIVATOR = { @@ -79,7 +79,7 @@ lychee.define('harvester.net.server.File').requires([ * IMPLEMENTATION */ - let Module = { + const Module = { /* * MODULE API @@ -102,12 +102,13 @@ lychee.define('harvester.net.server.File').requires([ receive: function(payload, headers) { - let info = null; - let path = null; - let project = null; - let tunnel = this.tunnel; - let url = headers['url']; - let mime = _MIME[url.split('.').pop()] || _MIME['default']; + let identifier = null; + let info = null; + let path = null; + let project = null; + let tunnel = this.tunnel; + let url = headers['url']; + let mime = _MIME[url.split('.').pop()] || _MIME['default']; // Single-project mode diff --git a/libraries/harvester/source/net/server/Redirect.js b/libraries/harvester/source/net/server/Redirect.js index 9dba3e0e..34a044a0 100644 --- a/libraries/harvester/source/net/server/Redirect.js +++ b/libraries/harvester/source/net/server/Redirect.js @@ -5,7 +5,7 @@ lychee.define('harvester.net.server.Redirect').exports(function(lychee, global, * IMPLEMENTATION */ - let Module = { + const Module = { /* * MODULE API diff --git a/libraries/lychee/api/core/Asset.md b/libraries/lychee/api/core/Asset.md deleted file mode 100644 index 55a64463..00000000 --- a/libraries/lychee/api/core/Asset.md +++ /dev/null @@ -1,44 +0,0 @@ - -= constructor - -```javascript -(null || Config || Font || Music || Sound || Texture || Stuff) new lychee.Asset(url [, type]); -``` - -- `(String) url` is the resource identifier of the asset. -- `(String) type` is the type of the resource. Valid types are `json`, `fnt`, `msc`, `snd`, `png`. - -This constructor returns an instance on success and `null` on failure. -It integrates the Assets of the [bootstrap](bootstrap) file with the core stack. - -```javascript -var foo = new lychee.Asset('/libraries/lychee/lychee.pkg'); // absolute path -var bar = new lychee.Asset('./lychee.pkg'); // relative path - -var qux = new lychee.Asset('http://localhost:8080/api/Server?identifier=boilerplate'); -var doo = new lychee.Asset('http://localhost:8080/api/Server?identifier=boilerplate', 'json'); - -foo instanceof Config; // true -bar instanceof Config; // true -qux instanceof Config; // false, no type in URL -doo instanceof Config; // true, enforced type -``` - -#### Implementation Notes - -The defaulted Asset type is [Stuff](bootstrap#constructor-Stuff). - -Some Asset types are made for dynamic interaction, such as [lychee.Package](lychee.Package) -instances using the `pkg` file extension or [lychee.Storage](lychee.Storage) using the -`store` file extension. - -The mapped extensions for processing the file contents are mapped as listed here: - -- [Buffer](bootstrap#constructor-Buffer) for a generic binary buffer. -- [Config](bootstrap#constructor-Config) for files with the `json`, `pkg` or `store` extension. -- [Font](bootstrap#constructor-Font) for files with the `fnt` extension. -- [Music](bootstrap#constructor-Music) for files with the `msc` extension. -- [Sound](bootstrap#constructor-Sound) for files with the `snd` extension. -- [Texture](bootstrap#constructor-Texture) for files with the `png` extension. - - diff --git a/libraries/lychee/api/core/Debugger.md b/libraries/lychee/api/core/Debugger.md deleted file mode 100644 index 67473de0..00000000 --- a/libraries/lychee/api/core/Debugger.md +++ /dev/null @@ -1,102 +0,0 @@ - -= constructor - -```javascript -lychee.Debugger; -``` - -This implementation is a Module and has no constructor. - -```javascript -console.log(lychee.Debugger); // lychee.Debugger -``` - -#### Implementation Notes - -The Debugger offers an integration with a server-side -[lychee.net.Service](lychee.net.Service) with -the identifier `debugger`. - - - -= methods-expose - -```javascript -(Object || null) lychee.Debugger.expose(environment); -``` - -- `(lychee.Environment) environment` is an instance of `lychee.Environment`. - -This method determines the difference from the `global` scopes between -the given environment and the default environment. - -It can be used to determine differences in runtime memory that are caused -by feature detection algorithms or memory leaks. - -```javascript -var env = new lychee.Environment({ - // ... more settings required -}); - -env.init(function() { - - var diff = lychee.Debugger.expose(env); - if (diff !== null) { - console.log('Environment is different!', env); - } - -}); -``` - - - -= methods-report - -```javascript -(Boolean) lychee.Debugger.report(environment, error [, definition]); -``` - -- `(lychee.Environment) environment` is an instance of `lychee.Environment`. -- `(Error) error` is an instance of `Error`. -- `(lychee.Definition) definition` is the optional instance of `lychee.Definition` that threw the error. - -- `(Function) callback` is a Function that returns the Definition. Allowed return types are Callback, Class and Module - -This method returns `true` on success and `false` on failure. -It will report the serialized environment and the error to the `Harvester`. - -```javascript -var Bar = new lychee.Definition('foo.Bar').exports(function(lychee, foo, global, attachments) { - - var Class = function() {}; - - Class.prototype = { - throwError: function() { - throw new Error("Me want cookies!"); - } - }; - - return Class; - -}); - -var env = new lychee.Environment({ - build: 'foo.Bar' -}); - -env.define(Bar); - -env.init(function(sandbox) { - - var foo = sandbox.foo; - var bar = new foo.Bar(); - - try { - bar.throwError(); - } catch(e) { - lychee.Debugger.report(env, e, env.definitions['foo.Bar']); - } - -}); -``` - diff --git a/libraries/lychee/api/core/Definition.md b/libraries/lychee/api/core/Definition.md deleted file mode 100644 index 0240d9be..00000000 --- a/libraries/lychee/api/core/Definition.md +++ /dev/null @@ -1,301 +0,0 @@ - -= constructor - -```javascript -new lychee.Definition(identifier); -``` - -- `identifier` is unique `String`. - -This constructor returns an instance of `lychee.Definition`. - -```javascript -new lychee.Definition('foo.Foo').exports(function(lychee, foo, global, attachments) { - - var Class = function() {}; - Class.prototype = {}; - return Class; - -}); - -new lychee.Definition('foo.Bar').requires([ - 'foo.Foo' -]).exports(function(lychee, foo, global, attachments) { - - console.log(foo.Foo); // Yes, we have a constructor - - var Class = function() {}; - Class.prototype = {}; - return Class; - -}); -``` - -#### Implementation Notes - -The unique identifier is used for determination of all dependencies -in the current [lychee.environment](?module=/lychee/source/core/lychee#properties-environment). - - - -= methods-deserialize - -```javascript -(void) lychee.Definition.prototype.deserialize(blob); -``` - -- `(Object) blob` is an Object that is part of the Serialization Object. - -This method is not intended for direct usage. -You can deserialize an object using the [lychee.deserialize](?module=/lychee/source/core/lychee#methods-deserialize) method. - -```javascript -var Foo1 = new lychee.Definition('foo.Foo'); -var data = lychee.serialize(Foo1); -var Foo2 = lychee.deserialize(data); - -data; // { constructor: 'lychee.Definition', arguments: [ 'foo.Foo' ]} -Foo2; // lychee.Definition instance -``` - - - -= methods-serialize - -```javascript -(Serialization Object) lychee.Definition.prototype.serialize(void); -``` - -- This method has no arguments. - -This method is not intended for direct usage. -You can serialize an instance using the [lychee.serialize](lychee#methods-serialize) method. - -```javascript -var Foo1 = new lychee.Definition('foo.Foo'); -var data = lychee.serialize(Foo1); -var Foo2 = lychee.deserialize(data); - -data; // { constructor: 'lychee.Definition', arguments: [ 'foo.Foo' ]} -Foo2; // lychee.Definition instance -``` - - - -= methods-attaches - -```javascript -(Boolean) lychee.Definition.prototype.attaches(map); -``` - -- `(Object) map` is an Object consisting of a `(String) key` and a `(Asset) value`. - -This method returns `true` on success and `false` on failure. - -```javascript -var Foo = new lychee.Definition('foo.Foo'); - -Foo.attaches({ - 'fnt': new Font('./url/to/Font.fnt'), - 'png': new Texture('./url/to/Texture.png'), - 'msc': new Music('./url/to/Music.msc') -}); -``` - - - -= methods-exports - -```javascript -(Boolean) lychee.Definition.prototype.exports(callback); -``` - -- `(Function) callback` is a Function that returns the Definition. Allowed return types are Callback, Class and Module - -This method returns `true` on success and `false` on failure. - -```javascript -var Foo = new lychee.Definition('foo.Foo'); -var Bar = new lychee.Definition('foo.Bar'); -var Qux = new lychee.Definition('foo.Qux'); - -Foo.exports(function(lychee, foo) { - var Class = function() {}; - Class.prototype = {}; - return Class; -}); - -Bar.exports(function(lychee, foo) { - var Module = { foo: function() {} }; - return Module; -}); - -Qux.exports(function(lychee, foo) { - var Callback = function() {}; - return Callback; -}); -``` - - - -= methods-includes - -```javascript -(Boolean) lychee.Definition.prototype.includes(definitions); -``` - -- `(Array) definitions` is an Array consisting of `(String) values`. - -This method returns `true` on success and `false` on failure. - -```javascript -var Foo = new lychee.Definition('foo.Foo'); -var Bar = new lychee.Definition('foo.Bar'); - - -Foo.exports(function(lychee, foo, global, attachments) { - - var Class = function() {}; - Class.prototype = { doStuff: function() { console.log('doStuff() from Foo'); } }; - return Class; - -}); - -Bar.includes([ - 'foo.Bar', - 'foo.Qux' -]); - -Bar.exports(function(lychee, foo, global, attachments) { - - var _Foo = foo.Foo; - var Class = function() {}; - - Class.prototype = { - doStuff: function() { - _Foo.doStuff(); - console.log('doStuff() from Bar'); - } - }; - - return Class; - -}); -``` - - - -= methods-requires - -```javascript -(Boolean) lychee.Definition.prototype.requires(definitions); -``` - -- `(Array) definitions` is an Array consisting of `(String) values`. - -This method returns `true` on success and `false` on failure. - -```javascript -var Foo = new lychee.Definition('foo.Foo'); -var Bar = new lychee.Definition('foo.Bar'); - - -Foo.exports(function(lychee, foo, global, attachments) { - - var Class = function() {}; - Class.prototype = { doStuff: function() { console.log('doStuff() from Foo'); } }; - return Class; - -}); - -Bar.requires([ - 'foo.Bar', - 'foo.Qux' -]); - -Bar.exports(function(lychee, foo, global, attachments) { - - var _Foo = foo.Foo; - var Class = function() {}; - - Class.prototype = { - doStuff: function() { - _Foo.doStuff(); - console.log('doStuff() from Bar'); - } - }; - - return Class; - -}); -``` - - - -= methods-supports - -```javascript -(Boolean) lychee.Definition.prototype.supports(callback); -``` - -- `(Function) callback` is a Function that returns either `true` or `false`. - -This method returns `true` on success and `false` on failure. - -The callback is called at compilation runtime, which means it should work -multiple times, even if the Definition defined in the [exports](#methods-exports) -method is replaced by another one. - -If no callback is defined, it is assumed that this Definition will work on -every theoretical JavaScript environment. - -```javascript -var Foo = new lychee.Definition('foo.Foo'); - -Foo.supports(function(lychee, global) { - - var document = global.document || null; - if (document !== null && typeof document.createElement === 'function') { - - var canvas = document.createElement('canvas'); - if (typeof canvas.getContext === 'function') { - return true; - } - - } - - return false; - -}); -``` - - - -= methods-tags - -```javascript -(Boolean) lychee.Definition.prototype.tags(map); -``` - -- `(Object) map` is an Object consisting of a `(String) key` and a `(String) value`. - -This method returns `true` on success and `false` on failure. - -Each tag has to be unique. Only one unique Definition with the same -identifier can be used to determine its functionality. - -```javascript -var CanvasRenderer = new lychee.Definition('foo.Renderer'); -var WebGLRenderer = new lychee.Definition('foo.Renderer'); - -CanvasRenderer.tags({ - platform: 'html', - rendering: '2d' -}); - -WebGLRenderer.tags({ - platform: 'html-webgl', - rendering: '2d' -}); -``` - diff --git a/libraries/lychee/api/core/Environment.md b/libraries/lychee/api/core/Environment.md deleted file mode 100644 index e56328e0..00000000 --- a/libraries/lychee/api/core/Environment.md +++ /dev/null @@ -1,853 +0,0 @@ - -= constructor - -```javascript -new lychee.Environment(settings); -``` - -- `settings` is an `Object`. - -This constructor returns an instance of `lychee.Environment`. -The `settings` object consists of the following properties: - -- `(String) id` will be passed to [setId](#methods-setId). -- `(String) build` will be passed to [setBuild](#methods-setBuild). -- `(Boolean) debug` will be passed to [setDebug](#methods-setDebug). -- `(Object) definitions` will be passed to [setDefinitions](#methods-setDefinitions). -- `(Array) packages` will be passed to [setPackages](#methods-setPackages). -- `(Boolean) sandbox` will be passed to [setSandbox](#methods-setSandbox). -- `(Object) tags` will be passed to [setTags](#methods-setTags). -- `(Number) timeout` will be passed to [setTimeout](#methods-setTimeout). -- `(String) type` will be passed to [setType](#methods-setType). - -```javascript -var environment = new lychee.Environment({ - id: 'example', - build: 'app.Main', - debug: true, - sandbox: false, - tags: { - platform: [ 'html' ] - }, - timeout: 5000, - type: 'source' -}); -``` - - - -= properties-id - -```javascript -(String) new lychee.Environment().id; -``` - -The `(String) id` property is the unique identifier of the environment. - -It influences the behaviour of the [lychee.Debugger](lychee.Debugger). -It is important that this identifier is unique across the peer cloud. - -It is set via `settings.id` in the [constructor](#constructor) -or via [setId](#methods-setId). - -```javascript -var environment = new lychee.Environment({ - id: 'test' -}); - -environment.id; // 'test' -environment.setId('example'); // true -environment.id; // 'example' -environment.setId(null); // false -environment.id; // 'example' -``` - - - -= properties-build - -```javascript -(String) new lychee.Environment().build; -``` - -The `(String) build` property is the build target of the environment instance. - -It influences the [init](#methods-init) callback behaviour. - -It is set via `settings.build` in the [constructor](#constructor) -or via [setBuild](#methods-setBuild). - -```javascript -var environment = new lychee.Environment({ - build: 'example.Foo', - packages: [ - new lychee.Package('example', './lychee.pkg') - ] -}); - -environment.build; // 'example.Foo' -environment.setBuild('example.Bar'); // true - -environment.init(function(sandbox) { - - var lychee = sandbox.lychee; - var example = sandbox.example; - - // This configuration assumes that a "./source/Bar.js" exists as example.Bar - -}); -``` - - - -= properties-debug - -```javascript -(Boolean) new lychee.Environment().debug; -``` - -The `(Boolean) debug` property is the state whether the environment -and its loaded definitions should print debug output to the console -or not. - -It influences the logging of additional debug data to the console. -It is reflected by the [lychee.debug](lychee#properties-debug) -property inside the sandbox. - -It is set via `settings.debug` in the [constructor](#constructor) -or via [setDebug](#methods-setDebug). - -```javascript -var environment = new lychee.Environment({ - debug: false -}); - -environment.debug; // false -environment.setDebug(true); // true -environment.debug; // true - -environment.init(function(sandbox) { - - var lychee = sandbox.lychee; - if (lychee.debug === true) { - console.log('Additional debug data is dumped to console'); - } - -}); - -``` - - - -= properties-definitions - -```javascript -(Object) new lychee.Environment().definitions; -``` - -The `(Object) definitions` property is the object consisting of -the map of available [lychee.Definition](lychee.Definition) -instances inside the environment, each mapped as the available -identifier. - -It is set via `settings.definitions` in the [constructor](#constructor) -or via [setDefinitions](#methods-setDefinitions). - -```javascript -var Foo = new lychee.Definition('example.Foo'); -var Bar = new lychee.Definition('example.Bar'); - -var environment = new lychee.Definition({ - debug: true, - build: 'example.Foo', - type: 'build' // avoid loading from source path -}); - -environment.setDefinitions({ - 'example.Foo': Foo, - 'example.Bar': Bar, - 'example.Qux': Foo, - 'another.Bar': Bar -}); - -environment.init(function(sandbox) { - - var lychee = sandbox.lychee; - var another = sandbox.another; - var example = sandbox.example; - - // Note the mapped namespaces by the setDefinitions() call - -}); -``` - - - -= properties-global - -```javascript -(Object) new lychee.Environment().global; -``` - -The `(Object) global` property is the scope that is the result -of the build process. If the [sandbox](#properties-sandbox) -property is set to `false`, this is identical to the global -scope of the runtime. - - - -= properties-packages - -```javascript -(Array) new lychee.Environment().packages; -``` - -The `(Array) packages` property is an array of all registered -[lychee.Package](lychee.Package) instances. - -It influences the behaviour of loading additional definitions -into the environment. As each package's id is associated with -the equivalent namespace, they are responsible for loading -definitions inside their namespace. - -It is set via `settings.packages` in the [constructor](#constructor) -or via [setPackages](#methods-setPackages). - -```javascript -var foo = new lychee.Package('foo', './foo/lychee.pkg'); -var bar = new lychee.Package('bar', './bar/lychee.pkg'); - -var environment = new lychee.Environment({ - debug: false, - packages: [ foo ] -}); - -// Note that the lychee package is auto-filled -environment.packages.length; // 2 - -environment.setPackages([ foo, bar ]); // true -environment.packages.length; // 3 -``` - - - -= properties-sandbox - -```javascript -(Boolean) new lychee.Environment().sandbox; -``` - -The `(Boolean) sandbox` property is the state whether the sandboxing -mode is activated or not. - -It influences how the [global](#properties-global) property of the -environment is built up. If set to `true`, it will create an isolated -scope for the build. If set to `false`, it will use the global scope -of the runtime and dispatch all namespaces there. - -It is set via `settings.sandbox` in the [constructor](#constructor) -or via [setSandbox](#methods-setSandbox). - -```javascript -var global = this; -var environment = new lychee.Environment({ - sandbox: true -}); - -environment.sandbox; // true -environment.global === global; // false - -environment.init(function(sandbox) { - sandbox === environment.global; // true -}); -``` - - - -= properties-tags - -```javascript -(Object) new lychee.Environment().tags; -``` - -The `(Object) tags` property is the settings object -that contains all specific tags for the build. - -It influences how the environment is built up. If -the tags are set, the environment tries to match -each loaded definition to the tags, dependent on -the [type](#properties-type) property. - -It will use the preferred tags of the build in -descending order and fallback to later entries -if the most significant tag isn't matchable in -the current environment. The first tag is the -most significant one. - -It is set via `settings.tags` in the [constructor](#constructor) -or set via [setTags](#methods-setTags). - -```javascript -var environment = new lychee.Environment({ - build: 'example.Main', - tags: { - platform: [ 'html-webgl', 'html' ] - } -}); - -environment.init(function(sandbox) { - - var lychee = sandbox.lychee; - var definition = lychee.environment.definitions['example.Main'] || null; - if (definition !== null) { - definition.tags; // { platform: 'html-webgl' } or { platform: 'html' } - } - -}); -``` - - - -= properties-timeout - -```javascript -(Number) new lychee.Environment().timeout; -``` - -The `(Number) timeout` property is the timeout in milliseconds -until the active build stops. - -It influences when the environment build stops. -If set to `0`, there is no timeout active until the active build stops. - -It is set via `settings.timeout` in the [constructor](#constructor) -or set via [setTimeout](#methods-setTimeout). - -```javascript -var start = Date.now(); -var foo = new lychee.Environment({ - build: 'app.Doesnotexit', - timeout: 5000 -}); -var bar = new lychee.Environment({ - build: 'app.Main', - timeout: 5000 -}); - -foo.timeout; // 5000 -foo.setTimeout(10000); // true -bar.timeout; // 5000 -bar.setTimeout(10000); // true - -foo.init(function() { - // This will never fire, because requirements are not met -}); -bar.init(function() { - console.log('Environment built in ' + (Date.now() - start) + 'ms'); -}); -``` - - - -= properties-type - -```javascript -(String) new lychee.Environment().type; -``` - -The `(String) type` property is the type of the active build. - -It influences how the environment build is created. -The default value is `source`. - -If set to `source`, the environment loads all definitions -from `project/source` and matches them against the given -[tags](#properties-tags) property. - -If set to `export`, the environment loads all definitions -from `project/source` and does not match them against the -given `tags`. - -If set to `build`, the environment assumes all definitions -and requirements are included already. This type is used -to deserialize a serialized environment snapshot. - - -```javascript -var environment = new lychee.Environment({ - build: 'example.Foo', - packages: [ - new lychee.Package('example', './lychee.pkg') - ] -}); - -environment.type; // 'source' -environment.setType('export'); // true - -environment.init(function(sandbox) { - // This configuration assumes that a "./source/Foo.js" exists as example.Foo -}); -``` - - - -= methods-deserialize - -```javascript -(void) lychee.Environment.prototype.deserialize(blob); -``` - -- `(Object) blob` is an Object that is part of the Serialization Object. - -This method is not intended for direct usage. -You can deserialize an object using the [lychee.deserialize](lychee#methods-deserialize) method. - -``` -var foo1 = new lychee.Environment({ id: 'example' }); -var data = lychee.serialize(foo1); -var foo2 = lychee.deserialize(data); - -data; // { constructor: 'lychee.Environment', arguments: [ { id: 'example' }]} -foo2; // lychee.Environment instance -``` - - - -= methods-serialize - -```javascript -(Serialization Object) lychee.Environment.prototype.serialize(void); -``` - -- This method has no arguments - -This method is not intended for direct usage. -You can serialize an instance using the [lychee.serialize](lychee#methods-serialize) method. - -``` -var foo1 = new lychee.Environment({ id: 'example' }); -var data = lychee.serialize(foo1); -var foo2 = lychee.deserialize(data); - -data; // { constructor: 'lychee.Environment', arguments: [ { id: 'example' }]} -foo2; // lychee.Environment instance -``` - - - -= methods-load - -```javascript -(Boolean) lychee.Environment.prototype.load(identifier); -``` - -- `(String) identifier` is the identifier of the definition including its namespace. - -This method returns `true` on success and `false` on failure. -It will try to load the definition if both the package and -the definition is ready. After the definition is ready, it -is available in the [definitions](#properties-definitions) -property. - -```javascript -var environment = new lychee.Environment({ - build: 'foo.Main', - packages: [ - new lychee.Package('foo', './foo/lychee.pkg'), - new lychee.Package('bar', './bar/lychee.pkg') - ] -}); - -environment.load('foo.Example'); // false, Package not ready -environment.load('bar.Example'); // false, Package not ready - -setTimeout(function() { - - // Assuming Packages are both ready - - environment.load('foo.Example'); // true - environment.load('bar.Example'); // true - -}, 5000); -``` - - - -= methods-define - -```javascript -(void) lychee.Environment.prototype.define(definition); -``` - -- `(lychee.Definition) definition` is the definition which needs to be dispatched to the environment. - -This method returns `true` on success and `false` on failure. -This method is not intended for direct usage. -It is called by [lychee.define](lychee#methods-define) in -order to map all definitions to the active environment. - -```javascript -var Example = new lychee.Definition('foo.Example').exports(function() { - return { foo: 'bar' }; -}); -var environment = new lychee.Environment({ - build: 'foo.Example' -}); - -environment.define(Example); - -environment.init(function(sandbox) { - - var foo = sandbox.foo; - if (foo.Example) { - console.log(foo.Example); - } - -}); -``` - - - -= methods-init - -```javascript -(void) lychee.Environment.prototype.init(callback); -``` - -- `(Function) callback` is the callback that is fired once the environment [build](#properties-build) is completed. - -This method returns nothing. -It initializes the build of the environment based on the given -settings. - -The callback is called with the `sandbox` parameter which reflects -the [global](#properties-global) property of the environment. - -```javascript -var environment = new lychee.Environment({ - id: 'example', - build: 'example.Main', - packages: [ - new lychee.Package('lychee', '/lychee/lychee.pkg'), - new lychee.Package('example', './lychee.pkg') - ] -}); - -environment.init(function(sandbox) { - - // All namespaces are attached to sandbox - // It is not recommended to use the "with" - // statement due to deoptimization issues - - var lychee = sandbox.lychee; - var example = sandbox.example; - - sandbox.MAIN = new example.Main({ - foo: 'bar' - }); - -}); -``` - - - -= methods-resolve - -```javascript -(void) lychee.Environment.prototype.resolve(path); -``` - -- `(String) path` is the relative path to an Asset. - -This method returns the correctly rooted `Asset url`. - -The method supports both relative and absolute paths -and roots them accordingly to the current environment. - -As this is heavily integrated with the `bootstrap` process, -all Asset types supported by [lychee.Asset](lychee.Asset) -are relying on this method. - -```javascript -var environment = new lychee.Environment({}); - -var rel_path = environment.resolve('./lychee.pkg'); -var abs_path = environment.resolve('/libraries/lychee/lychee.pkg'); - -rel_path; // '/opt/lycheejs/projects/example/lychee.pkg'; -abs_path; // '/opt/lycheejs/libraries/lychee/lychee.pkg'; -``` - - - -= methods-setBuild - -```javascript -(Boolean) lychee.Environment.prototype.setBuild(build); -``` - -- `(String) build` is the identifier of a definition. - -This method returns `true` on success and `false` on failure. -It will set the [build](#properties-build) property of the instance. - -```javascript -var environment = new lychee.Environment({ - id: 'example' -}); - -environment.build; // 'app.Main', defaulted -environment.setBuild('example.Main'); // false, no such package available - -environment.setPackages([ - new lychee.Package('example', './lychee.pkg'), - new lychee.Package('other', '../other/lychee.pkg') -]); - -environment.setBuild('example.Main'); // true, if package contains such a definition - -environment.init(function(sandbox) { - // example.Main and its requirements are ready -}); -``` - - - -= methods-setDebug - -```javascript -(Boolean) lychee.Environment.prototype.setDebug(debug); -``` - -- `(Boolean) debug` is a flag. If set to `true`, the `console` prints additional debug messages. - -This method returns `true` on success and `false` on failure. -It will set the [debug](#properties-debug) property of the instance. - -It also reflects the property onto the [lychee.debug](lychee#properties-debug) -property to maintain concurrency. - -```javascript -var environment = new lychee.Environment({ - id: 'example' -}); - -environment.debug; // true -environment.global.lychee.debug; // true - -environment.setDebug(false); // true - -environment.debug; // false -environment.global.lychee.debug; // false -``` - - - -= methods-setDefinitions - -```javascript -(Boolean) lychee.Environment.prototype.setDefinitions(definitions); -``` - -- `(Array) definitions` is an array of [lychee.Definitions](lychee.Definition). - -This method returns `true` on success and `false` on failure. -It will try to inject definitions into the environment, which will be available -with their identifier as the key in the [definitions](#properties-definitions) -property. - -```javascript -var Foo = new lychee.Definition('example.Foo').requires([ 'example.Bar' ]); -var Bar = new lychee.Definition('example.Bar'); -var environment = new lychee.Environment({ - id: 'example', - build: 'example.Foo' -}); - -environment.definitions; // {} -environment.setDefinitions([ Foo, Bar ]); // true -environment.definitions; // { 'example.Foo': lychee.Definition, 'example.Bar': lychee.Definition } -``` - - - -= methods-setId - -```javascript -(Boolean) lychee.Environment.prototype.setId(id); -``` - -- `(String) id` is the unique identifier of the environment. - -This method returns `true` on success and `false` on failure. -It will set the [id](#properties-id) property of the instance. - -It is important that this identifier is unique across the peer cloud. - -```javascript -var environment = new lychee.Environment({ - id: 'example' -}); - -environment.id; // 'example' -environment.setId('blubb'); // true -environment.id; // 'blubb' -``` - - - -= methods-setPackages - -```javascript -(Boolean) lychee.Environment.prototype.setPackages(packages); -``` - -- `(Array) packages` is an array of [lychee.Packages](lychee.Package). - -This method returns `true` on success and `false` on failure. -It will set the [packages](#properties-packages) property of the instance. - -It is important that each package has a unique namespace (identifier) as -what it is included. Each package can refer its components internally under -a different namespace compared to as under what namespace they are available. - -For example, you can include two projects that have internally all definitions -in the `app` namespace. If you want to do so, you can include one project as -`foo` and the other as `bar`, so now their `app.Main` is available as -`foo.Main` or `bar.Main`. - -```javascript -// The packages themselves have both an 'app.Main' identifier -var foo = new lychee.Package('foo', '../projects/foo/lychee.pkg'); -var bar = new lychee.Package('bar', '../projects/bar/lychee.pkg'); - -var environment = new lychee.Environment({ - id: 'example' -}); - -environment.setPackages([ foo, bar ]); - -environment.setBuild('app.Main'); // false, Package not ready - -environment.setBuild('foo.Main'); // true -environment.setBuild('bar.Main'); // true -``` - - - -= methods-setSandbox - -```javascript -(Boolean) lychee.Environment.prototype.setSandbox(sandbox); -``` - -- `(Boolean) sandbox` is a flag. If set to `true`, the environment will create an isolated [global](#properties-global) property. - -This method returns `true` on success and `false` on failure. -It will set the [sandbox](#properties-sandbox) property of the instance. - -This method creates a new sandbox each time the method is called. - -```javascript -var da_real_global = typeof global !== 'undefined' ? global : this; -var environment = new lychee.Environment({ - id: 'example' -}); - -environment.sandbox; // true -environment.global === da_real_global; // false - -environment.setSandbox(false); // true -environment.sandbox; // false -environment.global === da_real_global; // true -``` - - - -= methods-setTags - -```javascript -(Boolean) lychee.Environment.prototype.setTags(tags); -``` - -- `(Object) tags` is an object that contains all specific tags for the build. - -This method returns `true` on success and `false` on failure. -It will set the [tags](#properties-tags) property of the instance. - -```javascript -var environment = new lychee.Environment({ - build: 'example.Main', - tags: { - platform: [ 'html-webgl', 'html' ] - } -}); - -environment.init(function(sandbox) { - - var lychee = sandbox.lychee; - var definition = lychee.environment.definitions['example.Main'] || null; - if (definition !== null) { - definition.tags; // { platform: 'html-webgl' } or { platform: 'html' } - } - -}); -``` - - - -= methods-setTimeout - -```javascript -(Boolean) lychee.Environment.prototype.setTimeout(timeout); -``` - -- `(Number) timeout` is the timeout in milliseconds until the active build stops. - -This method returns `true` on success and `false` on failure. -It will set the [timeout](#properties-timeout) property of the instance. - -```javascript -var environment = new lychee.Environment({ - id: 'example' -}); - -environment.timeout; // 10000 -environment.setTimeout(5000); // true -environment.timeout; // 5000 -``` - - - -= methods-setType - -```javascript -(Boolean) lychee.Environment.prototype.setType(type); -``` - -- `(String) type` is the type of the active build. - -This method returns `true` on success and `false` on failure. -It will set the [type](#properties-type) property of the instance. - -If `type` is set to `source`, the environment loads all definitions -from `project/source` and matches them against the given -[tags](#properties-tags) property. - -If `type` is set to `export`, the environment loads all definitions -from `project/source` and does not match them against the given `tags`. - -If `type` is set to `build`, the environment assumes all definitions -and requirements are included already. This type is used to deserialize -a serialized environment snapshot. - -```javascript -var environment = new lychee.Environment({ - id: 'example' -}); - -environment.type; // 'source' -environment.setType('build'); // true -environment.type; // 'build' -``` - diff --git a/libraries/lychee/api/core/Input.md b/libraries/lychee/api/core/Input.md deleted file mode 100644 index 5d2c21fb..00000000 --- a/libraries/lychee/api/core/Input.md +++ /dev/null @@ -1,479 +0,0 @@ - -= constructor - -```javascript -new lychee.Input(settings); -``` - -- `settings` is an `Object`. - -This constructor returns an instance of `lychee.Input`. -The `settings` object consists of the following properties: - -- `(Number) delay` will be passed to [setDelay](#methods-setDelay). -- `(Boolean) key` will be passed to [setKey](#methods-setKey). -- `(Boolean) keymodifier` will be passed to [setKeyModifier](#methods-setKeyModifier). -- `(Boolean) touch` will be passed to [setTouch](#methods-setTouch). -- `(Boolean) swipe` will be passed to [setSwipe](#methods-setSwipe). - -```javascript -var input = new lychee.Input({ - delay: 0, - key: true, - keymodifier: true, - touch: true, - swipe: true -}); -``` - - - -= events-name - -```javascript -new lychee.Input().bind(name, function(delta) {}, scope); -``` - -The unique `name` event is fired on keyboard interaction. - -- `(String) name` is the unique identifier of the key event itself. It contains all modifiers in the following order if they are pressed. The resulting event name is in the maximum case `ctrl-alt-shift-(key)`. -- `(Number) delta` is the delta to the last event of the same type in milliseconds. - -```javascript -var input = new lychee.Input({ - key: true, - keymodifier: true -}); - -input.bind('ctrl-a', function(delta) { - // User is pressing [Ctrl] + [A] -}, this); - -input.bind('ctrl-shift-a', function(delta) { - // User is pressing [Ctrl] + [Shift] + [A] -}, this); -``` - - - -= events-key - -```javascript -new lychee.Input().bind('key', function(key, name, delta) {}, scope); -``` - -The `key` event is fired on keyboard interaction. -It is fired right before the corresponding `name` event is fired. - -- `(String) key` is the mapped key as a UTF8 character. -- `(String) name` is the unique identifier of the key event itself. It contains all modifiers in the following order if they are pressed. The resulting event name is in the maximum case `ctrl-alt-shift-(key)`. -- `(Number) delta` is the delta to the last event of the same type in milliseconds. - -```javascript -var input = new lychee.Input({ - key: true, - keymodifier: true -}); - -input.bind('key', function(key, name, delta) { - - // User is pressing [A] - // key == 'a', name == 'a' - - // User is pressing [Shift] + [A] - // key == 'A', name == 'shift-a' - -}, this); -``` - - - -= events-touch - -```javascript -new lychee.Input().bind('touch', function(id, position, delta) {}, scope); -``` - -The `touch` event is fired on mouse or touchscreen interaction. - -- `(Number) id` is the finger that is used for the touch. On missing multi-touch support, it is defaulted with `0`. -- `(Object) position` is the absolute position of the touch. It consists of the following properties: `(Number) x`, `(Number) y`, `(Number) z`. -- `(Number) delta` is the delta to the last event of the same type in milliseconds. - -```javascript -var input = new lychee.Input({ - touch: true -}); - -input.bind('touch', function(id, position, delta) { - // User is touching screen on Mobile or clicking on Desktop -}, this); -``` - - - -= events-swipe - -```javascript -new lychee.Input().bind('swipe', function(id, state, position, delta, swipe) {}, scope); -``` - -The `swipe` event is fired on mouse or touchscreen interaction. - -- `(Number) id` is the finger that is used for the touch. On missing multi-touch support, it is defaulted with `0`. -- `(String) state` is the touch interaction state. It consists either of the following values: `'start'`, `'move'`, `'end'`. -- `(Object) position` is the absolute position of the touch. It consists of the following properties: `(Number) x`, `(Number) y`, `(Number) z`. -- `(Number) delta` is the delta to the last event of the same type in milliseconds. -- `(Object) swipe` is the position delta from the beginning of the `swipe` event. It consists of the following properties: `(Number) x`, `(Number) y`, `(Number) z`. - -The `swipe` event allows implementations of drag and drop behaviours and is -therefore available to track the movement and acceleration of `touch` events. - -```javascript -var input = new lychee.Input({ - touch: true, - swipe: true -}); - -var _dragged = null; - -input.bind('swipe', function(id, state, position, delta, swipe) { - - if (drag === null && state === 'start') { - _drag = getEntityByPosition(position); - } else if (_drag !== null && state === 'move') { - _drag.setPosition(position); - } else if (drag !== null && state === 'end') { - _drag.setPosition(position); - _drag = null; - } - -}, this); -``` - - - -= properties-delay - -```javascript -(Number) new lychee.Input().delay; -``` - -The `(Number) delay` property is the delay in milliseconds after -which an event is fired. - -It influences all events, meaning that a [touch](#events-touch) -event can delay a [key](#events-key) event. - -It is set via `settings.delay` in the [constructor](#constructor) -or via [setDelay](#methods-setDelay). - -```javascript -var input = new lychee.Input({ - delay: 2000, - touch: true -}); - -input.bind('touch', function() { - - console.log('Input is locked for 2000ms.'); - - setTimeout(function() { - console.log('Input is unlocked now.'); - }, input.delay); - -}, this); -``` - - - -= properties-key - -```javascript -(Boolean) new lychee.Input().key; -``` - -The `(Boolean) key` property is the state whether the instance is -firing the [key](#events-key) event. - -It influences the [key](#events-key) event and the -[name](#events-name) event. - -It is set via `settings.key` in the [constructor](#constructor) -or via [setKey](#methods-setKey). - -```javascript -var input = new lychee.Input({ - key: true -}); - -input.bind('key', function() { - - input.setKey(false); - console.log('Input is locked now.'); - -}, this); -``` - - - -= properties-keymodifier - -```javascript -(Boolean) new lychee.Input().keymodifier; -``` - -The `(Boolean) keymodifier` property is the state whether the instance is -firing the [name](#events-name) event. - -It influences the [name](#events-name) event. - -It is set via `settings.keymodifier` in the [constructor](#constructor) -or via [setKeyModifier](#methods-setKeyModifier). - -```javascript -var input = new lychee.Input({ - key: true, - keymodifier: true -}); - -input.bind('key', function(key) { - - console.log('Input fired key ' + key + '.'); - -}, this); - -input.bind('ctrl-s', function() { - - input.setKey(false); - console.log('Input is locked now, name event depends on key property.'); - -}, this); -``` - - - -= properties-touch - -```javascript -(Boolean) new lychee.Input().touch; -``` - -The `(Boolean) touch` property is the state whether the instance is -firing the [touch](#events-touch) event. - -It influences the [touch](#events-touch) event and the -[swipe](#events-swipe) event. - -It is set via `settings.touch` in the [constructor](#constructor) -or via [setTouch](#methods-setTouch). - -```javascript -var input = new lychee.Input({ - touch: true -}); - -input.bind('touch', function() { - - input.setTouch(false); - console.log('Input is locked now.'); - -}, this); -``` - - - -= properties-swipe - -```javascript -(Boolean) new lychee.Input().swipe; -``` - -The `(Boolean) swipe` property is the state whether the instance is -firing the [swipe](#events-swipe) event. - -It influences the [swipe](#events-swipe) event. - -It is set via `settings.swipe` in the [constructor](#constructor) -or via [setSwipe](#methods-setSwipe). - -```javascript -var input = new lychee.Input({ - touch: true, - swipe: true -}); - -input.bind('swipe', function() { - - input.setTouch(false); - console.log('Input is locked now, swipe event depends on touch property.'); - -}, this); -``` - - - -= methods-destroy - -```javascript -(Boolean) lychee.Viewport.prototype.destroy(void); -``` - -- This method has no arguments. - -This method returns `true` on success and `false` on failure. -It will destroy the instance from any interaction bindings. - - - -= methods-serialize - -```javascript -(Serialization Object) lychee.Input.prototype.serialize(void); -``` - -- This method has no arguments. - -This method is not intended for direct usage. -You can serialize an instance using the [lychee.serialize](lychee#methods-serialize) method. - -```javascript -var foo1 = new lychee.Input({ delay: 5000 }); -var data = lychee.serialize(foo1); -var foo2 = lychee.deserialize(data); - -data; // { constructor: 'lychee.Input', arguments: [{ delay: 5000 }]} -foo2; // lychee.Input instance -``` - - - -= methods-setDelay - -```javascript -(Boolean) lychee.Input.prototype.setDelay(delay); -``` - -- `(Number) delay` is the delay in milliseconds. If set to a value bigger than `0`, the instance will wait the amount of milliseconds until a new event of any kind is fired. - -This method returns `true` on success and `false` on failure. -It will set the [delay](#properties-delay) property of the instance. - -```javascript -var input = new lychee.Input({ - key: true -}); - -input.delay; // 0 -input.setDelay(1337); // true -input.delay; // 1337 - -input.bind('key', function(key, name, delta) { - delta >= input.delay; // true -}, this); -``` - - - -= methods-setKey - -```javascript -(Boolean) lychee.Input.prototype.setKey(key); -``` - -- `(Boolean) key` is a flag. If set to `true`, the [key](#events-key) event is fired. - -This method returns `true` on success and `false` on failure. -It will set the [key](#properties-key) property of the instance. - -```javascript -var input = new lychee.Input(); - -input.key; // false -input.setKey(true); // true -input.key; // true - -input.bind('key', function() { - // key event is only fired if input.key === true -}, this); -``` - - - -= methods-setKeyModifier - -```javascript -(Boolean) lychee.Input.prototype.setKeyModifier(keymodifier); -``` - -- `(Boolean) keymodifier` is a flag. If set to `true`, the [name](#events-name) event is fired. - -This method returns `true` on success and `false` on failure. -It will set the [keymodifier](#properties-keymodifier) property of the instance. - -```javascript -var input = new lychee.Input({ - key: true -}); - -input.keymodifier; // false -input.setKeyModifier(true); // true -input.keymodifier; // true - -input.bind('ctrl-a', function() { - // key event is only fired if input.key === true and input.keymodifier === true -}, this); -``` - - - -= methods-setTouch - -```javascript -(Boolean) lychee.Input.prototype.setTouch(touch); -``` - -- `(Boolean) touch` is a flag. If set to `true`, the [touch](#events-touch) event is fired. - -This method returns `true` on success and `false` on failure. -It will set the [touch](#properties-touch) property of the instance. - -```javascript -var input = new lychee.Input(); - -input.touch; // false -input.setTouch(true); // true -input.touch; // true - -input.bind('touch', function() { - // touch event is only fired if input.touch === true -}, this); -``` - - - -= methods-setSwipe - -```javascript -(Boolean) lychee.Input.prototype.setSwipe(swipe); -``` - -- `(Boolean) swipe` is a flag. If set to `true`, the [swipe](#events-swipe) event is fired. - -This method returns `true` on success and `false` on failure. -It will set the [swipe](#properties-swipe) property of the instance. - -```javascript -var input = new lychee.Input({ - touch: true -}); - -input.swipe; // false -input.setSwipe(true); // true -input.swipe; // true - -input.bind('swipe', function() { - // swipe event is only fired if input.touch === true and input.swipe === true -}, this); -``` - diff --git a/libraries/lychee/api/core/Package.md b/libraries/lychee/api/core/Package.md deleted file mode 100644 index 01cdf0b6..00000000 --- a/libraries/lychee/api/core/Package.md +++ /dev/null @@ -1,183 +0,0 @@ - -= constructor - -```javascript -new lychee.Package(id, url); -``` - -- `(String) id` is a unique identifier. -- `(String) url` is the url to the `lychee.pkg` file. - -This constructor returns an instance of `lychee.Package`. - -```javascript -// Package initialized as namespace 'lychee' -var pkg1 = new lychee.Package('lychee', '/lychee/lychee.pkg'); - -// Package initialized as namespace 'myname' -var pkg2 = new lychee.Package('myname', '/lychee/lychee.pkg'); -``` - - - -= properties-id - -```javascript -(String) new lychee.Package().id; -``` - -The `(String) id` property is the unique identifier of -the package. - -It influences into which namespace the Definitions are -mapped after they were loaded. - -It is set via `id` in the [constructor](#constructor). - -```javascript -var pkg = new lychee.Package('app', './lychee.pkg'); - -pkg.id; // 'app' -``` - - - -= properties-url - -```javascript -(String || null) new lychee.Package().url; -``` - -The `(String) url` property represents the location of -the `lychee.pkg` file. - -If the property is set to `null`, the `url` argument -in the constructor had an invalid value. - -```javascript -var foo = new lychee.Package('foo', './lychee.pkg'); -var bar = new lychee.Package('bar', './invalid/value'); - -foo.url; // './lychee.pkg' -bar.url; // null -``` - - - -= properties-root - -```javascript -(String || null) new lychee.Package().root; -``` - -The `(String) root` property represents the folder -of the `lychee.pkg` file. - -If the property is set to `null`, the `url` argument -in the constructor had an invalid value. - -```javascript -var foo = new lychee.Package('foo', './path/to/lychee.pkg'); -var bar = new lychee.Package('bar', './invalid/value'); - -foo.root; // './path/to' -bar.root; // null -``` - - - -= methods-serialize - -```javascript -(Serialization Object) lychee.Package.prototype.serialize(void); -``` - -- This method has no arguments. - -This method is not intended for direct usage. -You can serialize an instance using the [lychee.serialize](lychee#methods-serialize) method. - -``` -var foo1 = new lychee.Package('example', './lychee.pkg'); -var data = lychee.serialize(foo1); -var foo2 = lychee.deserialize(data); - -data; // { constructor: 'lychee.Package', arguments: [ 'example', './lychee.pkg' ]} -foo2; // lychee.Package instance -``` - - - -= methods-isReady - -```javascript -(Boolean) lychee.Package.prototype.isReady(void); -``` - -This method returns `true` if the instance is ready and `false` -if the instance is not ready. - -Due to asynchronous loading behaviours, this method might give -different results on otherwise identical systems. The `lychee.pkg` -file is loaded and parsed. After this process is done, the `lychee.Package` -instance is marked as being ready. - -This method is not intended for public usage. It is called -by the [lychee.Environment](lychee.Environment) instance. - - - -= methods-load - -```javascript -(Boolean) lychee.Package.prototype.load(id, tags); -``` - -- `(String) id` is the unique identifier of a Definition. -- `(Object) tags` is an object consisting of a key and an Array of values. - -This method returns `true` on success and `false` on failure. -It will try to load a Definition that matches the given tags -and is properly supporting the target environment. - -This method is not intended for public usage. It is called -by the [lychee.Environment](lychee.Environment) instance. - - - -= methods-setEnvironment - -```javascript -(Boolean) lychee.Package.prototype.setEnvironment(environment); -``` - -- `(lychee.Environment) environment` is a [lychee.Environment](lychee.Environment) instance. - -This method returns `true` on success and `false` on failure. -It will set the [environment](#properties-delay) property of the instance. - -```javascript -var pkg = new lychee.Package('app', './lychee.pkg'); - -pkg.environment; // null -pkg.setEnvironment(env); // true - -``` - - - -= methods-setType - -```javascript -(Boolean) lychee.Package.prototype.setType(type); -``` - -- `(String) type` is a string that can have the following values: `source`, `export` or `build`. - -This method returns `true` on success and `false` on failure. -It will set the type of the package that influences the -behaviour of the [load](#methods-load) method. - -This method is not intended for public usage. It is called -by the [lychee.Environment](lychee.Environment) instance. - diff --git a/libraries/lychee/api/core/Stash.md b/libraries/lychee/api/core/Stash.md deleted file mode 100644 index f6a1d609..00000000 --- a/libraries/lychee/api/core/Stash.md +++ /dev/null @@ -1,331 +0,0 @@ - -= constructor - -```javascript -new lychee.Stash(settings); -``` - -- `settings` is an `Object`. - -This constructor returns an instance of `lychee.Stash`. -The `settings` object consists of the following properties: - -- `(String) id` will be passed to [setId](#methods-setId). -- `(Enum) type` will be passed to [setType](#methods-setType). - -```javascript -var stash = new lychee.Stash({ - id: 'app-stash', - type: lychee.Stash.TYPE.persistent -}); -``` - -#### Implementation Notes - -This implementation offers a temporary or persistent stash -that can be used for filesystem and asset modification -simulations. - -The events are used to integrate instances with the network stack. -Note that events are not guaranteed, as the implementation is -non-blocking and using asynchronous i/o. - - - -= enums-TYPE - -```javascript -(Enum) lychee.Stash.TYPE; -``` - -The `(Enum) TYPE` enum consist of the following properties: - -- `(Number) persistent` that reflects a persistent stash. -- `(Number) temporary` that reflects a temporary stash. - -If a stash is persistent, all assets will be stored forever. -If a stash is temporary, all assets will be stored until the -current session ends. - - - -= events-sync - -```javascript -new lychee.Stash().bind('sync', function(assets) {}, scope); -``` - -The `sync` event is triggered on stash [write](#methods-write) -and [remove](#methods-remove) method calls. - -- `(Object) assets` is an object consisting of `(String) id` and `(Asset) value`. - -```javascript -var stash = new lychee.Stash(); -var foo = stash.read('./foo.json'); - -stash.bind('sync', function(assets) { - console.log(assets); -}); - -foo; // Config instance -foo.load(); // true - -foo.buffer; // Parsed JSON - -foo.buffer = { - squad: 1337 -}; - - -stash.write('./foo.json', foo); // true -``` - - - -= properties-id - -```javascript -(String) new lychee.Stash().id; -``` - -The `(String) id` property is the unique identifier -of the stash instance. - -It influences the `sync` event and the `sync` method. - -It is set via `settings.id` in the [constructor](#constructor) -or via [setId](#methods-setId). - -```javascript -var stash = new lychee.Stash({ - id: 'awesome' -}); - -stash.id; // 'awesome' -stash.setId('more-awesome'); // true -stash.id; // 'more-awesome' -``` - - - -= properties-type - -```javascript -(Number) new lychee.Stash().type; -``` - -The `(Number) type` property is the type -of the stash instance. - -It influences how long created assets are stored. -Possible values are all values of the [TYPE](#enums-TYPE) enum. - -It is set via `settings.type` in the [constructor](#constructor) -or via [setType](#methods-setType). - -```javascript -var stash = new lychee.Stash({ - type: lychee.Stash.TYPE.persistent -}); - -stash.type; // 0 -stash.type === lychee.Stash.TYPE.persistent; // true - -stash.setType(lychee.Stash.TYPE.temporary); // true -stash.type; // 1 -stash.type === lychee.Stash.TYPE.temporary; // true -``` - - - -= methods-sync - -```javascript -(Boolean) lychee.Stash.prototype.sync(silent); -``` - -- `(Boolean) silent` is a flag. If set to `true`, the instance will not fire a `sync` event. - -This method returns `true` on success and `false` on failure. - - - -= methods-deserialize - -```javascript -(void) lychee.Stash.prototype.deserialize(blob); -``` - -- `(Object) blob` is an Object that is part of the Serialization Object. - -This method is not intended for direct usage. -You can deserialize an object using the [lychee.deserialize](lychee#methods-deserialize) method. - -```javascript -var foo1 = new lychee.Stash({ id: 'foo' }); -var data = lychee.serialize(foo1); -var foo2 = lychee.deserialize(data); - -data; // { constructor: 'lychee.Stash', arguments: [{ id: 'foo' }]} -foo2; // lychee.Stash instance -``` - - - -= methods-serialize - -```javascript -(Serialization Object) lychee.Stash.prototype.serialize(void); -``` - -- This method has no arguments. - -This method is not intended for direct usage. -You can serialize an instance using the [lychee.serialize](lychee#methods-serialize) method. - -```javascript -var foo1 = new lychee.Stash({ id: 'foo' }); -var data = lychee.serialize(foo1); -var foo2 = lychee.deserialize(data); - -data; // { constructor: 'lychee.Stash', arguments: [{ id: 'foo' }]} -foo2; // lychee.Stash instance -``` - - - -= methods-read - -```javascript -(null || Asset instance) lychee.Stash.prototype.read(id); -``` - -- `(String) id` is the relative path to the asset that is compatible with [lychee.Asset](lychee.Asset). - -This method returns an `Asset instance` on success and on failure. -It returns the `Asset instance` that matches the specified criteria. - -```javascript -var stash = new lychee.Stash(); -var foo = stash.read('./foo.json'); - -foo; // Config instance -foo.load(); // true - -foo.buffer; // Parsed JSON - -foo.buffer = { - squad: 1337 -}; - - -stash.write('./foo.json', foo); // true -stash.read('./foo.json') === foo; // true -``` - - - -= methods-remove - -```javascript -(Boolean) lychee.Stash.prototype.remove(id); -``` - -- `(String) id` is the unique identifier of the asset that was previously stored via [write](#methods-write) method call. - -This method returns `true` on success and `false` on failure. -It removes the `object` from the stash. - -Note that a stash instance can get out of sync if you prevent -the `sync` event chain that is integrated with the network stack. - -```javascript -var stash = new lychee.Stash(); -var foo = stash.read('./foo.json'); - -stash.write('./foo.json', foo); // true -stash.read('./foo.json') === foo; // true - -stash.remove('./foo.json'); // true -stash.read('./foo.json') === foo; // false, new Asset instance -``` - - - -= methods-write - -```javascript -(Boolean) lychee.Stash.prototype.write(id, asset); -``` - -- `(String) id` is the unique identifier of the asset. -- `(Asset instance) asset` is the asset that was previously created via [read](#methods-read) method call. - -This method returns `true` on success and `false` on failure. -It writes the `asset` into the stash. - -Note that a stash instance can get out of sync if you prevent -the `sync` event chain that is integrated with the network stack. - -```javascript -var stash = new lychee.Stash(); -var foo = stash.read('./foo.json'); - -stash.write('./foo.json', foo); // true -stash.read('./foo.json') === foo; // true - -stash.remove('./foo.json'); // true - - -var bar = stash.read('./foo.json'); - -foo === bar; // false, new Asset instance -stash.write('./foo.json', qux); // true -``` - - - -= methods-setId - -```javascript -(Boolean) lychee.Stash.prototype.setId(id); -``` - -- `(String) id` is a unique identifier used for the instance. - -This method returns `true` on success and `false` on failure. - -The unique identifier is used for synchronization purposes, -so the stash can be used among different sessions in the -same environment. - -```javascript -var stash = new lychee.Stash(); - -stash.id; // 'lychee-Stash-0' -stash.setId('awesome'); // true -stash.id; // 'awesome' -``` - - - -= methods-setType - -```javascript -(Boolean) lychee.Stash.prototype.setType(type); -``` - -- `(Number) type` is an `enum of [lychee.Stash.TYPE](#enums-TYPE)`. It is defaulted with lychee.Stash.TYPE.persistent. - -This method returns `true` on success and `false` on failure. - -```javascript -var stash = new lychee.Stash(); - -stash.type; // 0 -stash.setType(lychee.Stash.TYPE.temporary); // true -stash.type; // 1 -stash.type === lychee.Stash.TYPE.temporary; // true -``` - diff --git a/libraries/lychee/api/core/Storage.md b/libraries/lychee/api/core/Storage.md deleted file mode 100644 index b26eb929..00000000 --- a/libraries/lychee/api/core/Storage.md +++ /dev/null @@ -1,473 +0,0 @@ - -= constructor - -```javascript -new lychee.Storage(settings); -``` - -- `settings` is an `Object`. - -This constructor returns an instance of `lychee.Storage`. -The `settings` object consists of the following properties: - -- `(String) id` will be passed to [setId](#methods-setId). -- `(Object) model` will be passed to [setModel](#methods-setModel). -- `(Enum) type` will be passed to [setType](#methods-setType). - -```javascript -var model = { - name: 'robot', - squad: 'Artificial-Engineering', - score: 1337 -}; - -var storage = new lychee.Storage({ - id: 'app-trainingdata', - model: model, - type: lychee.Storage.TYPE.persistent -}); -``` - -#### Implementation Notes - -This implementation uses a view-based concept, which means -each instance is a projected view based on its identifier. - -The events are used to integrate instances with the network stack. -Note that events are not guaranteed, as the implementation is -non-blocking and using asynchronous i/o. - - - -= enums-TYPE - -```javascript -(Enum) lychee.Storage.TYPE; -``` - -The `(Enum) TYPE` enum consist of the following properties: - -- `(Number) persistent` that reflects a persistent storage. -- `(Number) temporary` that reflects a temporary storage. - -If a storage is persistent, all objects will be stored forever. -If a storage is temporary, all objects will be stored until the -current session ends. - - - -= events-sync - -```javascript -new lychee.Storage().bind('sync', function(objects) {}, scope); -``` - -The `sync` event is triggered on storage [write](#methods-write) -and [remove](#methods-remove) method calls. - -- `(Array) objects` is an array of modified objects. - -```javascript -var storage = new lychee.Storage({ model: { foo: 0 }}); - -var obj1 = storage.create(); -var obj2 = storage.create(); - -storage.bind('sync', function(objects) { - console.log(objects); -}); - -storage.write('id1', obj1); // triggers event -storage.write('id2', obj2); // triggers event - -obj1.foo = 1; -obj2.foo = 2; - -storage.remove('id1'); // triggers event -storage.remove('id2'); // triggers event -``` - - - -= properties-id - -```javascript -(String) new lychee.Storage().id; -``` - -The `(String) id` property is the unique identifier -of the storage instance. - -It influences the `sync` event and the `sync` method. - -It is set via `settings.id` in the [constructor](#constructor) -or via [setId](#methods-setId). - -```javascript -var storage = new lychee.Storage({ - id: 'awesome' -}); - -storage.id; // 'awesome' -storage.setId('more-awesome'); // true -storage.id; // 'more-awesome' -``` - - - -= properties-model - -```javascript -(Object) new lychee.Storage().model; -``` - -The `(Object) model` property is the object model -of the storage instance. - -It influences how the [write](#methods-write) -method validates objects of the storage instance. - -It is set via `settings.model` in the [constructor](#constructor) -or via [setModel](#methods-setModel). - -```javascript -var storage = new lychee.Storage(); - -storage.model; // {} -storage.setModel({ foo: 'bar' }); // true -storage.model; // { foo: 'bar' } - -var object = storage.create(); - -object; // { foo: 'bar' } -object === storage.model; // false -object.foo === storage.foo; // true -``` - - - -= properties-type - -```javascript -(Number) new lychee.Storage().type; -``` - -The `(Number) type` property is the type -of the storage instance. - -It influences how long created objects are stored. -Possible values are all values of the [TYPE](#enums-TYPE) enum. - -It is set via `settings.type` in the [constructor](#constructor) -or via [setType](#methods-setType). - -```javascript -var storage = new lychee.Storage({ - type: lychee.Storage.TYPE.persistent -}); - -storage.type; // 0 -storage.type === lychee.Storage.TYPE.persistent; // true - -storage.setType(lychee.Storage.TYPE.temporary); // true -storage.type; // 1 -storage.type === lychee.Storage.TYPE.temporary; // true -``` - - - -= methods-sync - -```javascript -(Boolean) lychee.Storage.prototype.sync(silent); -``` - -- `(Boolean) silent` is a flag. If set to `true`, the instance will not fire a `sync` event. - -This method returns `true` on success and `false` on failure. - - - -= methods-deserialize - -```javascript -(void) lychee.Storage.prototype.deserialize(blob); -``` - -- `(Object) blob` is an Object that is part of the Serialization Object. - -This method is not intended for direct usage. -You can deserialize an object using the [lychee.deserialize](lychee#methods-deserialize) method. - -```javascript -var foo1 = new lychee.Storage({ id: 'foo' }); -var data = lychee.serialize(foo1); -var foo2 = lychee.deserialize(data); - -data; // { constructor: 'lychee.Storage', arguments: [{ id: 'foo' }]} -foo2; // lychee.Storage instance -``` - - - -= methods-serialize - -```javascript -(Serialization Object) lychee.Storage.prototype.serialize(void); -``` - -- This method has no arguments. - -This method is not intended for direct usage. -You can serialize an instance using the [lychee.serialize](lychee#methods-serialize) method. - -```javascript -var foo1 = new lychee.Storage({ id: 'foo' }); -var data = lychee.serialize(foo1); -var foo2 = lychee.deserialize(data); - -data; // { constructor: 'lychee.Storage', arguments: [{ id: 'foo' }]} -foo2; // lychee.Storage instance -``` - - - -= methods-create - -```javascript -(Model instance) lychee.Storage.prototype.create(void); -``` - -This method returns a `Model` instance. -It creates a unique `Object instance` that is created from -the `Model` template previously set via [setModel](#methods-setModel). - -The `Model instance` can be integrated with the instance -by using [write](#methods-write). - -```javascript -var storage = new lychee.Storage(); - -storage.model; // {} (empty object) -storage.setModel({ foo: 'bar' }); // true - -var object = storage.create(); // { foo: 'bar' } - -storage.model; // { foo: 'bar' } -storage.model === object; // false - -storage.write('id1', object); // true -storage.write('id1', object); // false, already in storage -``` - - - -= methods-filter - -```javascript -(Array) lychee.Storage.prototype.filter(callback [, scope]); -``` - -- `(Function) callback` is the callback that is executed to filter the objects. If set to a `Function`, it will filter the returned array. If the callback returns `true` for an `object`, it is pushed to the returned array. -- `(Object) scope` is the scope of the callback. - -This method returns an `(Array) objects` of filtered objects. - -```javascript -var storage = new lychee.Storage(); - -storage.setModel({ foo: 'bar' }); - -var obj1 = storage.create(); -var obj2 = storage.create(); -var obj3 = storage.create(); - -obj1.foo = 'foo'; -obj2.foo = 'baz'; -obj3.foo = 'qux'; - -storage.write('foo', obj1); // true -storage.write('baz', obj2); // true -storage.write('qux', obj3); // true - -var filtered = storage.filter(function(object, index) { - - if (object.foo !== 'foo') { - return true; - } else { - return false; - } - -}, this); - -filtered.length; // 2 -filtered.indexOf(obj1); // -1 -filtered.indexOf(obj2); // 0 -filtered.indexOf(obj3); // 1 -``` - - - -= methods-read - -```javascript -(null || Model instance) lychee.Storage.prototype.read(id); -``` - -- `(String) id` is the unique identifier of the object that was previously stored via [write](#methods-write) method call. - -This method returns a `Model instance` on success and `null` on failure. -It returns the `Model instance` that matches the specified criteria. - -```javascript -var storage = new lychee.Storage({ - model: { foo: 'bar' } -}); - - -var obj1 = storage.create(); -var obj2 = storage.create(); - -storage.write('foo', obj1); -storage.write('bar', obj2); - -storage.read('foo') === obj1; // true -storage.read('bar') === obj2; // true -storage.read('qux') === null; // true -``` - - - -= methods-remove - -```javascript -(Boolean) lychee.Storage.prototype.remove(id); -``` - -- `(String) id` is the unique identifier of the object that was previously stored via [write](#methods-write) method call. - -This method returns `true` on success and `false` on failure. -It removes the `object` from the storage. - -Note that a storage instance can get out of sync if you prevent -the `sync` event chain that is integrated with the network stack. - -```javascript -var storage = new lychee.Storage({ - model: { foo: 'bar' } -}); - - -var obj1 = storage.create(); -var obj2 = storage.create(); - -storage.write('foo', obj1); -storage.write('bar', obj2); - -storage.remove('foo'); // true -storage.remove('foo'); // false, already removed -storage.remove('bar'); // true -``` - - - -= methods-write - -```javascript -(Boolean) lychee.Storage.prototype.write(id, object); -``` - -- `(String) id` is the unique identifier of the object. -- `(Model instance) object` is the object that was previously created via [create](#methods-create) method call. - -This method returns `true` on success and `false` on failure. -It writes the `object` into the storage. - -Note that a storage instance can get out of sync if you prevent -the `sync` event chain that is integrated with the network stack. - -```javascript -var storage = new lychee.Storage({ - model: { foo: 0 } -}); - - -var obj = storage.create(); - -storage.write('foo', obj); // true -obj.foo++; // 1 - -storage.write('foo', obj); // true -``` - - - -= methods-setId - -```javascript -(Boolean) lychee.Storage.prototype.setId(id); -``` - -- `(String) id` is a unique identifier used for the instance. - -This method returns `true` on success and `false` on failure. - -The unique identifier is used for synchronization purposes, -so the storage can be used among different sessions in the -same environment. - -```javascript -var storage = new lychee.Storage(); - -storage.id; // 'lychee-Storage-0' -storage.setId('awesome'); // true -storage.id; // 'awesome' -``` - - - -= methods-setModel - -```javascript -(Boolean) lychee.Storage.prototype.setModel(model); -``` - -- `(Object) model` is an Object that is used as a template for the creation of new Storage Objects via [create](#methods-create) method call. - -This method returns `true` on success and `false` on failure. - -The model object is dereferenced, so it is not the same as the argument. - -```javascript -var storage = new lychee.Storage(); - -var model = { foo: 'bar' }; - -Object.keys(storage.model); // [] -storage.setModel(model); // true - -storage.model; // { foo: 'bar' } -storage.model === model; // false -``` - - - -= methods-setType - -```javascript -(Boolean) lychee.Storage.prototype.setType(type); -``` - -- `(Number) type` is an `enum of [lychee.Storage.TYPE](#enums-TYPE)`. It is defaulted with lychee.Storage.TYPE.persistent. - -This method returns `true` on success and `false` on failure. - -```javascript -var storage = new lychee.Storage(); - -storage.type; // 0 -storage.setType(lychee.Storage.TYPE.temporary); // true -storage.type; // 1 -storage.type === lychee.Storage.TYPE.temporary; // true -``` - diff --git a/libraries/lychee/api/core/Viewport.md b/libraries/lychee/api/core/Viewport.md deleted file mode 100644 index db7b44cd..00000000 --- a/libraries/lychee/api/core/Viewport.md +++ /dev/null @@ -1,230 +0,0 @@ - -= constructor - -```javascript -new lychee.Viewport(settings); -``` - -- `settings` is an `Object`. - -This constructor returns an instance of `lychee.Viewport`. -The `settings` object consists of the following properties: - -- `(Boolean) fullscreen` will be passed to [setFullscreen](#methods-setFullscreen). - -```javascript -var viewport = new lychee.Viewport({ - fullscreen: true -}); -``` - -#### Implementation Notes - -Desktop systems are treated by their resolution, so if a -monitor is rotated by 90 degrees, its `orientation` is `portrait`. - -If the monitor is not rotated and has a width/height ratio lower -than 1, it is treated as its `orientation` is `portrait`. - - - -= events-reshape - -```javascript -new lychee.Viewport().bind('reshape', function(orientation, rotation, width, height) {}, scope); -``` - -The `reshape` event is fired on viewport size change or rotation of the device. - -- `(String) orientation` is the orientation the device was built for. It consists either of the following values: `'landscape'`, `'portrait'` -- `(String) rotation` is the rotation of the device in its current state. If it differs from `orientation`, the device was rotated and the physical buttons are not in the original place anymore. It consists either of the following values: `'landscape'`, `'portrait'` -- `(Number) width` is the width of the device in its current state. -- `(Number) height` is the height of the device in its current state. - -```javascript -var viewport = new lychee.Viewport(); - -viewport.bind('reshape', function(orientation, rotation) { - - if (viewport.width > viewport.height) { - console.log('Viewport is in landscape rotation'); - } else { - console.log('Viewport is in portrait rotation'); - } - -}, this); -``` - - - -= events-show - -```javascript -new lychee.Viewport().bind('show', function() {}, scope); -``` - -The `show` event is fired if the window is made visible and was not visible before. - -- This event has no arguments. - -```javascript -var viewport = new lychee.Viewport(); - -viewport.bind('show', function() { - console.log('Viewport is visible'); -}, this); - -viewport.bind('hide', function() { - console.log('Viewport is hidden'); -}, this); -``` - - - -= events-hide - -```javascript -new lychee.Viewport().bind('hide', function() {}, scope); -``` - -The `show` event is fired if the window is made not visible and was visible before. - -- This event has no arguments. - -```javascript -var viewport = new lychee.Viewport(); - -viewport.bind('show', function() { - console.log('Viewport is visible'); -}, this); - -viewport.bind('hide', function() { - console.log('Viewport is hidden'); -}, this); -``` - - - -= properties-fullscreen - -```javascript -(Boolean) new lychee.Viewport().fullscreen; -``` - -The `(Boolean) fullscreen` property is the state whether the instance is -in fullscreen mode. - -It influences the `reshape` event. - -It is set via `settings.fullscreen` in the [constructor](#constructor) -or via [setFullscreen](#methods-setFullscreen). - -```javascript -var viewport = new lychee.Viewport({ - fullscreen: true -}); - -viewport.bind('reshape', function() { - console.log('Viewport width and height initially change.'); -}, this); -``` - - - -= properties-width - -```javascript -(Number) new lychee.Viewport().width; -``` - -The `(Number) width` property is the current width of the Viewport. - -```javascript -var viewport = new lychee.Viewport(); - -viewport.bind('reshape', function() { - console.log('Viewport width is ' + viewport.width); -}, this); -``` - - - -= properties-height - -```javascript -(Number) new lychee.Viewport().height; -``` - -The `(Number) height` property is the current height of the Viewport. - -```javascript -var viewport = new lychee.Viewport(); - -viewport.bind('reshape', function() { - console.log('Viewport height is ' + viewport.height); -}, this); -``` - - - -= methods-destroy - -```javascript -(Boolean) lychee.Viewport.prototype.destroy(void); -``` - -- This method has no arguments. - -This method returns `true` on success and `false` on failure. -It will destroy the instance from any interaction bindings. - - - -= methods-serialize - -```javascript -(Serialization Object) lychee.Viewport.prototype.serialize(void); -``` - -- This method has no arguments. - -This method is not intended for direct usage. -You can serialize an instance using the [lychee.serialize](lychee#methods-serialize) method. - -``` -var foo1 = new lychee.Viewport({ fullscreen: true }); -var data = lychee.serialize(foo1); -var foo2 = lychee.deserialize(data); - -data; // { constructor: 'lychee.Viewport', arguments: [ { fullscreen: true }]} -foo2; // lychee.Viewport instance -``` - - - -= methods-setFullscreen - -```javascript -(Boolean) lychee.Viewport.prototype.setFullscreen(fullscreen); -``` - -- `(Boolean) fullscreen` is a flag. If set to `true`, the instance will try to go into fullscreen mode. - -This method returns `true` on success and `false` on failure. -It depends on asynchronous user interaction. -It will set the [fullscreen](#properties-fullscreen) property of the instance. - -```javascript -var viewport = new lychee.Viewport({ - fullscreen: false -}); - -viewport.fullscreen; // false -viewport.setFullscreen(true); // true -viewport.fullscreen; // false - -setTimeout(function() { - viewport.fullscreen; // true, if User confirmed Fullscreen Mode -}, 10000); -``` - diff --git a/libraries/lychee/api/core/lychee.md b/libraries/lychee/api/core/lychee.md deleted file mode 100644 index 9744d60a..00000000 --- a/libraries/lychee/api/core/lychee.md +++ /dev/null @@ -1,563 +0,0 @@ - -= constructor - -```javascript -lychee; -``` - -This implementation is a Module and has no constructor. - -```javascript -console.log(lychee); // lychee core -``` - -#### Implementation Notes - -The lychee core offers many functionalities that are -necessary across the whole Stack. These functions are -independent of platform-specific variants and -therefore are identical across all platforms. - -As the [Definition](lychee.Definition) uses a mixin-based -inheritance system, there is currently no practical use -for ES6 modules and imports. - -There are several Polyfills implemented in the lychee -core module that offer ES6 / ES7 functionality across -all platforms. - -- `Array.prototype.find` returns a matching `(Array || Boolean || Date || Number || Object || String || null) value` to the `(Function) predicate` of the given `(Array) instance`. -- `Array.prototype.unique` returns a matching `(Array) values` to the `(Function) predicate` of the given `(Array) instance` which has unique `values`. -- `Boolean.prototype.toJSON` converts the `Boolean` data type to its raw `JSON value`. -- `Date.prototype.toJSON` converts the `Date` data type to its raw `JSON value`, which is the `ISO-8601 Date String`. -- `Number.prototype.toJSON` converts the `Number` data type to its raw `JSON value`. -- `Object.filter` returns a matching `(Array) values` to the `(Function) predicate` of the given `(Object) instance`. -- `Object.find` returns a matching `(Array || Boolean || Date || Number || Object || String || null) value` to the `(Function) predicate` of the given `(Object) instance`. -- `Object.keys` returns the `(Array) keys` of the given `(Object) instance`. -- `Object.sort` returns a sorted `Object` of the given `(Object) instance`. -- `Object.values` returns a `(Array) values` of the given `(Object) instance`. -- `String.prototype.toJSON` converts the `String` data type to its raw `JSON value`. -- `String.prototype.trim` trims leading and trailing whitespaces and returns the modified `String`. - - - -= properties-debug - -```javascript -(Boolean) lychee.debug; -``` - -The `(Boolean) debug` property is the flag that -determines if the current environment is being -debugged. - -If set to `true`, it influences event -serialization and logging additional debug data -to the console. - -```javascript -var env = new lychee.Environment({ - debug: true -}); - -lychee.setEnvironment(env); - -environment.init(function(sandbox) { - - var lychee = sandbox.lychee; - - if (lychee.debug === true) { - console.log('additional debug data'); - } - -}); -``` - - - -= properties-environment - -```javascript -(lychee.Environment) lychee.environment; -``` - -The `(lychee.Environment) environment` property -has a back-reference to the currently active -environment. - -The active environment is important for the -loading process of new Definitions and dependencies. - -You can manually switch the environment and -isolate the loading process into it by calling -the [setEnvironment](#methods-setEnvironment) -method. - -```javascript -var foo = new lychee.Environment({ id: 'foo' }); -var bar = new lychee.Environment({ id: 'bar' }); - -lychee.setEnvironment(foo); -foo.init(function(sandbox) { - - console.log(sandbox.lychee.environment.id); // foo - - lychee.setEnvironment(bar); - bar.init(function(sandbox) { - - // sandbox is now the sandbox of the isolated environment - console.log(sandbox.lychee.environment.id); - - }); - -}); -``` - - - -= properties-ENVIRONMENTS - -```javascript -(Object) lychee.ENVIRONMENTS; -``` - -The `(Object) ENVIRONMENTS` property is a cache -that contains all previously loaded isolated -environments that were built for library usage. - -The key is the unique identifier of the environment, -consisting of a `\*project\*/\*target\*` structure -to match the structure of the fertilizer (or build -system); for example `boilerplate/main` or -`harvester/dist`. - -The environments are fertilized automatically into -the `/build/\*platform\*/\*target\*` folder of the -project or library. - - - -= properties-ROOT - -```javascript -(Object) lychee.ROOT; -``` - -The `(Object) ROOT` property is a cache that contains -the `root paths` of both the `project` and the `lychee` -library. - -```javascript -lychee.ROOT.project; // '/opt/lycheejs/projects/boilerplate' -lychee.ROOT.lychee; // '/opt/lycheejs' -``` - - - -= properties-VERSION - -```javascript -(String) lychee.VERSION; -``` - -The `(String) VERSION` property is representing the -lycheeJS version. The lycheeJS version is built using -the year and quartal of the release, for example -`2015-Q4` or `2016-Q1`. - - - -= methods-diff - -```javascript -(Boolean) lychee.diff(aobject, bobject); -``` - -- `(Object) aobject` is an Object. -- `(Object) bobject` is an Object. - -This method returns `true` if the objects are different and `false` if they are identical. - -```javascript -var foo = { foo: 'bar' }; -var bar = { foo: 'bar' }; -var qux = { foo: 'foo' }; - -console.log(lychee.diff(foo, bar)); // false -console.log(lychee.diff(foo, qux)); // true -console.log(lychee.diff(bar, qux)); // true -console.log(lychee.diff(bar, foo)); // false -``` - - - -= methods-enumof - -```javascript -(Boolean) lychee.enumof(template, value); -``` - -- `(Enum) template` is an object consisting of `(String) key` and `(Number) value`. -- `(Number) value` is representing the Enum data to verify. - -``` -var MY_ENUM = { - 'foo': 0, - 'bar': 1 -}; - -console.log(lychee.enumof(MY_ENUM, MY_ENUM.foo)); // true -console.log(lychee.enumof(MY_ENUM, MY_ENUM.bar)); // true -console.log(lychee.enumof(MY_ENUM, 1337)); // false -``` - - - -= methods-extend - -```javascript -(Object) lychee.extend(target [, object1, object2, ...]); -``` - -- `(Object) target` is the target object that will be extended with the properties of the other objects. - -This method will extend the target object and iterate -over additional arguments in order to extend the -target object with their properties. - -```javascript -var foo = { bar: 'qux' }; -var bar = { qux: 'doo' }; - -var qux = lychee.extend({}, foo, bar); -console.log(qux); // { bar: 'qux', qux: 'doo' } - -var doo = lychee.extend(foo, bar); -console.log(doo === foo); // true -console.log(foo); // { bar: 'qux', qux: 'doo' } -``` - - - -= methods-extendsafe - -```javascript -(Object) lychee.extendsafe(target [, object1, object2, ...]); -``` - -- `(Object) target` is the target object that will be extended with the properties of the other objects. - -This method will extend the target object and iterate -over additional arguments in order to extend the -target object with their properties. - -The behavioural difference to [extend](#methods-extend) -is that this method only extends the target with the -properties if they are from the same type as the -target. So the target acts as a typed template. - -```javascript -var foo = { bar: 'qux' }; -var bar = { qux: 13.37 }; -var tpl = { bar: 'str', qux: 1337 } - -var qux = lychee.extendsafe({}, foo, bar); -console.log(qux); // {} - -var doo = lychee.extendsafe(foo, bar); -console.log(doo === foo); // true -console.log(foo); // {} - -var blu = lychee.extendsafe(tpl, foo, bar); -console.log(blu); // { bar: 'qux', qux: 13.37 } -``` - - - -= methods-extendunlink - -```javascript -(Object) lychee.extendunlink(target [, object1, object2, ...]); -``` - -- `(Object) target` is the target object that will be extended with the properties of the other objects. - -This method will extend the target object and iterate -over additional arguments in order to extend the -target object with their properties. - -The behavioural difference to [extend](#methods-extend) -is that this method only extends the target with the -properties if they are from the same type as the -target. So the target acts as a typed template. - -```javascript -var foo = { bar: 'qux' }; -var bar = { qux: 13.37 }; -var tpl = { bar: 'str', qux: 1337 } - -var qux = lychee.extendsafe({}, foo, bar); -console.log(qux); // {} - -var doo = lychee.extendsafe(foo, bar); -console.log(doo === foo); // true -console.log(foo); // {} - -var blu = lychee.extendsafe(tpl, foo, bar); -console.log(blu); // { bar: 'qux', qux: 13.37 } -``` - - - -= methods-interfaceof - -```javascript -(Boolean) lychee.interfaceof(template, instance); -``` - -- `(Class || Module) template` is the interface the instance is be validated against. -- `(Object) instance` is the instance that is validated. - -This method returns `true` on success and `false` on failure. -It will match the API of the instance against the template. -It will check properties, enums and method names. - -```javascript -var Foo = lychee.app.Entity; -var Bar = function() {}; -Bar.prototype = { method: function() {} }; - -var qux = new Foo(); -var doo = new Bar(); - -lychee.interfaceof(Foo, qux); // true -lychee.interfaceof(Foo, doo); // false -lychee.interfaceof(Bar, qux); // false -lychee.interfaceof(Bar, doo); // true -``` - - - -= methods-deserialize - -```javascript -(Object || null) lychee.deserialize(data); -``` - -- `(Serialization Object) data` is the serialized -data of an instance that was created by a previous -[serialize](#methods-serialize) method call. - -This method returns a `Serialization Object` on success and `null` on failure. -It will try to serialize the given definition. - -The JSON structure for a `Serialization Object` has always the same specified -format. A serialized `Module` definition has to return a proper `reference` -while a serialized `Class` definition has to return a proper `constructor`. - -```javascript -var data_ref = lychee.serialize(lychee.data.JSON); -var data_con = lychee.serialize(new lychee.Input({ key: true })); - -console.log(data_ref); // { 'reference': 'lychee.data.JSON', 'arguments': []} -console.log(data_con); // { 'constructor': 'lychee.Input', 'arguments': [ { 'key': true }]} -``` - -```javascript -var data = lychee.serialize(new lychee.Input()); - -var instance = lychee.deserialize(data); -if (instance instanceof lychee.Input) { - console.log('Success!', instance); -} else { - console.log('Failure!', instance); -} -``` - - - -= methods-serialize - -```javascript -(Serialization Object || null) lychee.serialize(definition); -``` - -- `(Object) definition` is the instance that is serialized. - -This method returns a `Serialization Object` on success and `null` on failure. -It will try to serialize the given definition. - -The JSON structure for a `Serialization Object` has always the same specified -format. A serialized `Module` definition has to return a proper `reference` -while a serialized `Class` definition has to return a proper `constructor`. - -```javascript -var data_ref = lychee.serialize(lychee.data.JSON); -var data_con = lychee.serialize(new lychee.Input({ key: true })); - -console.log(data_ref); // { 'reference': 'lychee.data.JSON', 'arguments': []} -console.log(data_con); // { 'constructor': 'lychee.Input', 'arguments': [ { 'key': true }]} -``` - -```javascript -var instance = new lychee.Input(); - -var data = instance.serialize(); -if (data !== null) { - console.log('Success!', data); -} else { - console.log('Failure!', data); -} -``` - - - -= methods-define - -```javascript -(lychee.Definition) lychee.define(identifier); -``` - -- `(String) identifier` is the unique identifier for the lychee.Definition. - -This method returns a `lychee.Definition` instance. -It will currify the [exports](lychee.Definition#methods-exports) -method in order to define the definition in the -currently active [lychee.environment](#properties-environment). - - - -= methods-import - -```javascript -(Object || Function || null) lychee.import(reference); -``` - -- `(String) reference` is the unique reference for the `lychee.Definition` export. - -This method returns an `Object` or `Function` on succes and `null` on failure. -It will try to resolve the `Module` or `Class`, dependent on the reference. - -As every [lychee.Environment](#properties-environment) can be sandboxed, this method -tries to resolve the namespaces and instances to the sandboxed `global` scope. - -```javascript -lychee.define('foo.Main').requires([ - 'bar.Template', - 'qux.Other' -]).exports(function(lychee, global, attachments) { - - var bar = lychee.import('bar'); - var qux = lychee.import('qux'); - var Template = lychee.import('bar.Template'); - var Other = lychee.import('qux.Other'); - -}); -``` - - - -= methods-envinit - -```javascript -(void) lychee.envinit(environment, profile); -``` - -- `(lychee.Environment) environment` is the initialized [lychee.environment](#properties-environment) instance. -- `(Object) profile` is the profile that is passed to the initialized `environment.build` instance. - -This method returns nothing. -It will initialize the active [lychee.Environment](lychee.Environment) -instance which is reflected by the [lychee.environment](#properties-environment) -property. - -```javascript -var env = new lychee.Environment({ /* ... */ }); - - -lychee.envinit(env, { - foo: 'bar' -}); -``` - - - -= methods-pkginit - -```javascript -(void) lychee.pkginit(identifier, settings, profile); -``` - -- `(String) identifier` is the unique identifier of the environment inside the `lychee.pkg` file. -- `(Object) settings` are the settings that are passed to the initialized [lychee.environment](#properties-environment) instance. -- `(Object) profile` is the profile that is passed to the initialized `environment.build` instance. - -This method returns nothing. -It will initialize the active [lychee.Environment](lychee.Environment) -instance which is reflected by the [lychee.environment](#properties-environment) -property. - -The environment settings are gathered by loading the [lychee.Package](lychee.Package) of the -current project and tracing `/build/environments/*identifier*` in the `lychee.pkg` file. - -```javascript -lychee.pkginit('html/main', { - debug: true, - sandbox: false -}, { - foo: 'bar' -}); -``` - - - -= methods-inject - -```javascript -(Boolean) lychee.inject(environment); -``` - -- `(lychee.Environment) environment` is a [lychee.Environment](lychee.Environment) instance. If set to `null`, the original environment will be used. - -This method returns `true` on success and `false` on failure. -It will inject the given environment into the active environment -and dispatch its [definitions](lychee.Environment#properties-definitions) -property. - -```javascript -// This is the API for serialized environment snapshots in sandboxed builds -lychee.ENVIRONMENTS['lychee'] = new lychee.Environment({ /* ... */ }); - - -var env = new lychee.Environment({ /* ... */ }); - -lychee.setEnvironment(env); // true -console.log(lychee.environment === env); // true - -lychee.inject(lychee.ENVIRONMENTS['lychee']); // true, if preloaded -``` - - - -= methods-setEnvironment - -```javascript -(Boolean) lychee.setEnvironment(environment); -``` - -- `(lychee.Environment) environment` is a [lychee.Environment](lychee.Environment) instance. If set to `null`, the original environment will be used. - -This method returns `true` on success and `false` on failure. -It will set the active environment and dispatch its -[debug](lychee.Environment#properties-debug) property. - -```javascript -var env = new lychee.Environment({ /* ... */ }); - -lychee.setEnvironment(env); // true -console.log(lychee.environment === env); // true - -lychee.setEnvironment({ not: 'an environment' }); // false -console.log(lychee.environment === env); // false -``` - diff --git a/libraries/lychee/api/data/BENCODE.md b/libraries/lychee/api/data/BENCODE.md deleted file mode 100644 index 5b5bba81..00000000 --- a/libraries/lychee/api/data/BENCODE.md +++ /dev/null @@ -1,176 +0,0 @@ - -= constructor - -```javascript -lychee.data.BENCODE; -``` - -This implementation is a Module and has no constructor. - - -```javascript -lychee.data.BENCODE; // lychee.data.BENCODE reference -``` - - -#### Implementation Notes - -The BENCODE codec offers an encoder and decoder for the popular -BENCODE (BitTorrent encode) format. The implementation -is built for stream usage, which means that the codec works -for partial or fragmented data. - -It can be used with the [lychee.net.Tunnel](lychee.net.Tunnel) -interface as its `codec` setting in the constructor. - -It is backwards compatible to other BENCODE implementations, -but extends the BENCODE format with support for Booleans and -Null. - -The BENCODE codec strips out any dangerous unicode characters -that might crash your application or result in buffer overflows -of any kind. It has no support for the `undefined` value. - -```javascript -var data = { - foo: null, - bar: true, - qux: 13.37, - doo: [ 'foo', 'bar' ] -}; - - -var blob = lychee.data.BENCODE.encode(data); -var check = lychee.data.BENCODE.decode(blob); - -blob; // "d3:barbte3:dool3:foo3:bare3:foobne3:quxi13ee" -data; // { "foo": null, "bar": true, "qux": 13, "doo": [ "foo", "bar" ] } -``` - - - -#### BENCODE Specification - -The BENCODE format is bytewise and using a dictionary and list -structure. It has no support for floats or doubles and -therefore represents Numbers only as integers. - -Booleans and Null are represented as binary flags (`b`). All -serialized binary flags have a 1-byte value, which can be -either `t`, `f` or `n`. - -```bash -| Value | Header | Value | Complete Blob | -| null | b | n | bne | -| true | b | t | bte | -| false | b | f | bfe | -``` - -Numbers are represented as integers (`i`) only. All serialized -numbers have a leading `i`, an optional sign (`-`) and a -trailing `e`. - -```bash -| Value | Header | Value | Complete Blob | -| 1 | i | 1 | i1e | -| -1 | i | -1 | i-1e | -| 1.0 | i | 1 | i1e | -``` - -Strings are represented as string values directly. They are -optimized by the necessary leading integer to represent their -length in base 10. - -```bash -| Value | Header | Value | Complete Blob | -| "foo" | 3: | foo | 3:foo | -| "foobar" | 6: | foobar | 6:foobar | -``` - -Arrays are represented as lists (`l`) with their cell values. - -Arrays are filled recursively to reflect their internal data -structures. - -```bash -| Value | Header | Value | Complete Blob | -| [ 1 ] | l | i1e | li1ee | -| [ 1, 2 ] | l | i1ei2e | li1ei2ee | -| [ 1, "foo" ] | l | i1e3:foo | li1e3:fooe | -``` - -Objects are represented as dictionaries (`d`) with their -property names and property values. - -Objects are filled recursively to reflect their internal data -structures. - -```bash -| Value | Header | Value | Complete Blob | -| { foo: "bar" } | d | 3:foo3:bar | d3:foo3:bare | -| { foo: 1 } | d | 3:fooi1e | d3:fooi1e | -``` - - - -= methods-serialize - -```javascript -(Serialization Object) lychee.data.BENCODE.serialize(void); -``` - -- This method has no arguments - -This method is not intended for direct usage. -You can serialize a module using the [lychee.serialize](lychee#methods-serialize) method. - -```javascript -var foo1 = lychee.data.BENCODE; -var data = lychee.serialize(foo1); -var foo2 = lychee.deserialize(data); - -data; // { reference: "lychee.data.BENCODE" } -foo2; // lychee.data.BENCODE module -``` - - - -= methods-decode - -```javascript -(Object || null) lychee.data.BENCODE.decode(data); -``` - -- `(String) data` is a string. It is defaulted with `null`. - -This method returns `Object` on success and `null` on failure. - -```javascript -var data = "d3:bari123e3:foo3:bare"; -var object = lychee.data.BENCODE.decode(data); -if (object !== null) { - object.foo; // "bar" - object.bar; // 123 -} -``` - - - -= methods-encode - -```javascript -(String || null) lychee.data.BENCODE.encode(data); -``` - -- `(Object) data` is an `Object instance`. It is defaulted with `null`. - -This method returns `String` on success and `null` on failure. - -```javascript -var data = { foo: "bar", "bar": 123 }; -var blob = lychee.data.BENCODE.encode(data); -if (blob !== null) { - blob; // "d3:bari123e3:foo3:bare" -} -``` - diff --git a/libraries/lychee/api/data/BitON.md b/libraries/lychee/api/data/BitON.md deleted file mode 100644 index 38eaf114..00000000 --- a/libraries/lychee/api/data/BitON.md +++ /dev/null @@ -1,220 +0,0 @@ - -= constructor - -```javascript -lychee.data.BitON; -``` - -This implementation is a Module and has no constructor. - - -```javascript -lychee.data.BitON; // lychee.data.BitON reference -``` - - -#### Implementation Notes - -The BitON codec offers an encoder and decoder with the custom -bitwise BitON format. The implementation is built for stream -usage, which means that the codec works for partial or -fragmented data. - -It can be used with the [lychee.net.Tunnel](lychee.net.Tunnel) -interface as its `codec` setting in the constructor. - -The BitON codec is built for bytewise streams, which means the -trailing 0-Bits will be added until the stream has a bytewise -length. It has no support for the `undefined` value. - -```javascript -var data = { - foo: null, - bar: true, - qux: 13.37, - doo: [ 'foo', 'bar' ] -}; - - -var blob = lychee.data.BitON.encode(data); -var check = lychee.data.BitON.decode(blob); - - -blob; // "¡ŒfoocbarcquxF§\" `dooŒfoo `barü" -``` - - - -#### BitON Specification - -The BitON format is bitwise and using a 3-Bit header field. Each -data type has a sub-header with a varying length that optimizes -internal data structures. - -Booleans and Null are represented as binary flags (`000`). All -serialized binary flags have a 2-Bit value. - -```bash -| Value | Header | Value | Complete Blob | -| null | 000 | 01 | 000 01 | -| true | 000 | 11 | 000 11 | -| false | 000 | 10 | 000 10 | -``` - -Numbers are represented as integers (`001`) and doubles -(`002`). All serialized numbers have a trailing 1-Bit sign -value. - -If the sign is set to `0`, the number was positive. -If the sign is set to `1`, the number was negative. - -Integers don't have a trailing shift while doubles have their -shift represented as a 4-Bit value. That means they will lose -precision if their digits are too long and smaller than -`10^-16`. - -```bash -| Value | Header | Value | Complete Blob | -| 1 | 001 | 0000 01 0 | 001 0000 01 0 | -| -1 | 001 | 0000 01 1 | 001 0000 01 1 | -| 1.0 | 002 | 0000 01 0 0000 | 002 0000 01 0 0000 | -``` - -Numbers are also not represented as 64-Bit values as you might -have noticed. They are optimized by the necessary bits they -require to be represented. - -The magic values for optimization are `2`, `16`, `256`, -`4096`, `65536`, `1048576`, `16777216`, `268435456`. - -Numbers greater than 32-Bit are represented with their `string` -representation. That means big integers like date timestamps -are transferred with their `toString()` value. - -```bash -| Value | Header | Value | Complete Blob | -| 2 | 001 | 0001 0010 0 | 001 0001 0010 0 | -| 15 | 001 | 0001 1111 0 | 001 0001 1111 0 | -| 16 | 001 | 0010 0001 1111 0 | 001 0010 0001 1111 0 | -| 255 | 001 | 0010 1111 1111 0 | 001 0010 1111 1111 0 | -| 256 | 001 | 0011 0001 1111 1111 0 | 001 0011 0001 1111 1111 0 | -``` - -Strings (`003`) are represented as string values directly. They -are optimized by the necessary bits to represent their length. - -The magic string value lengths for optimization are `28`, `255`, -`65535`. - -```bash -| Value Length | Header | Value | Complete Blob | -| > 65535 | 011 | 11111 "value" | 011 11111 "value" | -| > 255 | 011 | 11110 "value" | 011 11110 "value" | -| > 28 | 011 | 11101 "value" | 011 11101 "value" | -| <= 28 | 011 | "value" | 011 "value" | -``` - -Arrays (`004`) are represented with their cell values. - -They are optimized by using a 3-Bit `EOC` (End of Cell) marker -in between each cell and an `EOO` (End of Object) marker after -the array. - -Arrays are filled recursively to reflect their internal data -structures. - -```bash -| Value | Header | Value | Complete Blob | -| [ 1 ] | 100 | 000 001 0000 01 0 | 100 000 001 0000 01 0 111 | -| [ 1, 2 ] | 100 | 000 001 0000 01 0 000 001 0000 10 0 | 100 000 001 0000 01 0 000 001 0000 10 0 111 | -``` - -Objects (`005`) are represented with their property names and -property values. - -They are optimized by using a 3-Bit `EOC` (End of Cell) marker in -between each property name/value pair and an `EOO` (End of Object) -marker after the object. - -Objects are filled recursively to reflect their internal data -structures. - -```bash -| Value | Header | Value | Complete Blob | -| { foo: "bar" } | 101 | 000 "foo" "bar" | 101 000 "foo" "bar" 111 | -| { foo: 1 } | 101 | 000 "foo" 001 0000 01 0 | 101 000 "foo" 001 0000 01 0 111 | -``` - -Instances (`006`) are represented with their `lychee.serialize()` -blob. - -This data structure is used internally by lycheeJS components to -optimize the JSON data structures and to have automatic -deserialization on the other end. - -Instances have a trailing `EOO` (End of Object) marker, -everything else is encoded as a JSON object (`005`). - - - -= methods-serialize - -```javascript -(Serialization Object) lychee.data.BitON.serialize(void); -``` - -- This method has no arguments - -This method is not intended for direct usage. -You can serialize a module using the [lychee.serialize](lychee#methods-serialize) method. - -```javascript -var foo1 = lychee.data.BitON; -var data = lychee.serialize(foo1); -var foo2 = lychee.deserialize(data); - -data; // { reference: "lychee.data.BitON" } -foo2; // lychee.data.BitON module -``` - - - -= methods-decode - -```javascript -(Object || null) lychee.data.BitON.decode(data); -``` - -- `(String) data` is a string. It is defaulted with `null`. - -This method returns `Object` on success and `null` on failure. - -```javascript -var data = "¡Œfoocbar `bar$öà"; -var object = lychee.data.BitON.decode(data); -if (object !== null) { - object.foo; // "bar" - object.bar; // 123 -} -``` - - - -= methods-encode - -```javascript -(String || null) lychee.data.BitON.encode(data); -``` - -- `(Object) data` is an `Object instance`. It is defaulted with `null`. - -This method returns `String` on success and `null` on failure. - -```javascript -var data = { foo: "bar", "bar": 123 }; -var blob = lychee.data.BitON.encode(data); -if (blob !== null) { - blob; // "¡Œfoocbar `bar$öà"; -} -``` - diff --git a/libraries/lychee/api/data/JSON.md b/libraries/lychee/api/data/JSON.md deleted file mode 100644 index 9fdeb2de..00000000 --- a/libraries/lychee/api/data/JSON.md +++ /dev/null @@ -1,108 +0,0 @@ - -= constructor - -```javascript -lychee.data.JSON; -``` - -This implementation is a Module and has no constructor. - - -```javascript -lychee.data.JSON; // lychee.data.JSON reference -``` - - -#### Implementation Notes - -The JSON codec offers an encoder and decoder for the popular -JSON (JavaScript Object Notation) format. The implementation -is built for stream usage, which means that the codec works -for partial or fragmented data. - -It can be used with the [lychee.net.Tunnel](lychee.net.Tunnel) -interface as its `codec` setting in the constructor. - -The JSON codec strips out any dangerous unicode characters -that might crash your application or result in buffer overflows -of any kind. It has no support for the `undefined` value. - -```javascript -var data = { - foo: null, - bar: true, - qux: 13.37, - doo: [ 'foo', 'bar' ] -}; - - -var blob = lychee.data.JSON.encode(data); -var check = lychee.data.JSON.decode(blob); - - -blob; // "{\"foo\":null,\"bar\":true,\"qux\":13.37,\"doo\":[\"foo\",\"bar\"]}" -``` - - - -= methods-serialize - -```javascript -(Serialization Object) lychee.data.JSON.serialize(void); -``` - -- This method has no arguments - -This method is not intended for direct usage. -You can serialize a module using the [lychee.serialize](lychee#methods-serialize) method. - -```javascript -var foo1 = lychee.data.JSON; -var data = lychee.serialize(foo1); -var foo2 = lychee.deserialize(data); - -data; // { reference: "lychee.data.JSON" } -foo2; // lychee.data.JSON module -``` - - - -= methods-decode - -```javascript -(Object || null) lychee.data.JSON.decode(data); -``` - -- `(String) data` is a string. It is defaulted with `null`. - -This method returns `Object` on success and `null` on failure. - -```javascript -var data = '{"foo":"bar","bar":123}'; -var object = lychee.data.JSON.decode(data); -if (object !== null) { - object.foo; // "bar" - object.bar; // 123 -} -``` - - - -= methods-encode - -```javascript -(String || null) lychee.data.JSON.encode(data); -``` - -- `(Object) data` is an `Object instance`. It is defaulted with `null`. - -This method returns `String` on success and `null` on failure. - -```javascript -var data = { foo: "bar", "bar": 123 }; -var blob = lychee.data.JSON.encode(data); -if (blob !== null) { - blob; // '{"foo":"bar","bar":123}' -} -``` - diff --git a/libraries/lychee/api/data/MD.md b/libraries/lychee/api/data/MD.md deleted file mode 100644 index 55b80185..00000000 --- a/libraries/lychee/api/data/MD.md +++ /dev/null @@ -1,107 +0,0 @@ - -= constructor - -```javascript -lychee.data.MD; -``` - -This implementation is a Module and has no constructor. - - -```javascript -lychee.data.MD; // lychee.data.MD reference -``` - - -#### Implementation Notes - -The MD codec offers an encoder and decoder for the popular -MD (MarkDown or CommonMark) format. The implementation is -built for stream usage, which means that the codec works -for partial or fragmented data. - -The MD codec strips out any dangerous characters and -shrinks error-prone new-line characters. - -The blob requires a leading `\n=` and a trailing `\n\n` -to operate properly and be compatible with other formats. - -It has no support for link names containing whitespaces. -It has no support for image names containing whitespaces. - -The decoded format matches the interchange format, which is -fully compatible with [lychee.data.HTML](lychee.data.HTML). - -```javascript -var blob = '\n= introduction\n\n# This is a test\n\nWoohoo with *italic* and **bold** `code`!'; - - -var data = lychee.data.MD.decode(blob); -var blob = lychee.data.MD.encode(data); - -blob; // "\n= introduction\n\n# This is a test\n\nWoohoo with *italic* and **bold** `code`!" -``` - - - -= methods-serialize - -```javascript -(Serialization Object) lychee.data.MD.serialize(void); -``` - -- This method has no arguments - -This method is not intended for direct usage. -You can serialize a module using the [lychee.serialize](lychee#methods-serialize) method. - -```javascript -var foo1 = lychee.data.MD; -var data = lychee.serialize(foo1); -var foo2 = lychee.deserialize(data); - -data; // { reference: "lychee.data.MD" } -foo2; // lychee.data.MD module -``` - - - -= methods-decode - -```javascript -(Array || null) lychee.data.MD.decode(data); -``` - -- `(String) data` is a string. It is defaulted with `null`. - -This method returns `Array` on success and `null` on failure. - -```javascript -var data = '\n= section\n\n'; -var array = lychee.data.MD.decode(data); -if (array !== null) { - array.length; // 1 - array[1]; // { token: 'Section', type: null, value: 'section' } -} -``` - - - -= methods-encode - -```javascript -(String || null) lychee.data.MD.encode(data); -``` - -- `(Object) data` is an `Array instance`. It is defaulted with `null`. - -This method returns `String` on success and `null` on failure. - -```javascript -var data = { token: 'Section', type: null, value: 'section' }; -var blob = lychee.data.MD.encode(data); -if (blob !== null) { - blob; // '\n= section\n\n'; -} -``` - diff --git a/libraries/lychee/api/event/Emitter.md b/libraries/lychee/api/event/Emitter.md deleted file mode 100644 index 00a3decc..00000000 --- a/libraries/lychee/api/event/Emitter.md +++ /dev/null @@ -1,223 +0,0 @@ - -= constructor - -```javascript -new lychee.event.Emitter(void); -``` - -This constructor returns an instance of `lychee.event.Emitter`. - -```javascript -var emitter = new lychee.event.Emitter(); - -emitter.bind('foo', function(foo, bar, qux) { - - console.log('foo event was triggered!'); - - foo === 'Foo'; // true - bar === 'Bar'; // true - qux === 'Qux'; // true - -}, this); - -emitter.bind('#foo', function(self, foo, bar, qux) { - - console.log('foo event was triggered!'); - - self === this; // false - self === emitter; // true - -}, this); - -emitter.bind('@foo', function(event, self, foo, bar, qux) { - - console.log('foo event was triggered!'); - - event; // 'foo' - self === this; // false - self === emitter; // true - -}, this); - -emitter.trigger('foo', [ 'Foo', 'Bar', 'Qux' ]); // true -emitter.trigger('#foo'); // false -emitter.trigger('@foo'); // false -``` - - - -= methods-deserialize - -```javascript -(void) lychee.event.Emitter.prototype.deserialize(blob); -``` - -- `(Object) blob` is an Object that is part of the Serialization Object. - -This method returns nothing. -It is not intended for direct usage. -You can deserialize an object using the [lychee.deserialize](lychee#methods-deserialize) method. - -```javascript -var foo1 = new lychee.event.Emitter(); -var data = lychee.serialize(foo1); -var foo2 = lychee.deserialize(data); - -data; // { constructor: 'lychee.event.Emitter', arguments: []} -foo2; // lychee.event.Emitter instance -``` - - - -= methods-serialize - -```javascript -(Serialization Object) lychee.event.Emitter.prototype.serialize(void); -``` - -- This method has no arguments. - -This method is not intended for direct usage. -You can serialize an instance using the [lychee.serialize](lychee#methods-serialize) method. - -```javascript -var foo1 = new lychee.event.Emitter(); -var data = lychee.serialize(foo1); -var foo2 = lychee.deserialize(data); - -data; // { constructor: 'lychee.event.Emitter', arguments: []} -foo2; // lychee.event.Emitter instance -``` - - - -= methods-bind - -```javascript -(Boolean) lychee.event.Emitter.prototype.bind(event, callback [, scope, once]); -``` - -- `(String) event` is the event name. -- `(Function) callback` is the callback that is executed when the event is triggered. -- `(Object) scope` is the scope of the callback. -- `(Boolean) once` is a flag. If set to `true`, the callback will be executed once and then removed via [unbind](#methods-unbind) method. - -This method returns `true` on success and `false` on failure. -It will try to bind the callback to an event name and parse the modifier of the -event name beforehand. - -Supported event name modifiers are: - -- `@` will pass the `event name` and `self` parameters to the callback. -- `#` will pass the `self` parameter to the callback. - -```javascript -var emitter = new lychee.event.Emitter(); - -emitter.bind('foo', function(a, b, c) {}, this); // true -emitter.bind('foo', function(a, b, c) {}, this, true); // true, triggered only once -emitter.bind(null, function(a, b, c) {}, this); // false, invalid event - -emitter.bind('@foo', function(event, self, a, b, c) {}, this); // true -emitter.bind('#foo', function(self, a, b, c) {}, this); // true -``` - - - -= methods-relay - -```javascript -(Boolean) lychee.event.Emitter.prototype.relay(event, instance [, once]); -``` - -- `(String) event` is the event name. -- `(Emitter) instance` is an instance of `lychee.event.Emitter`. -- `(Boolean) once` is a flag. If set to `true`, the callback will be executed once - -This method returns `true` on success and `false` on failure. -It will try to relay an event to another emitter and parse the modifier of the -event name beforehand. - -Supported event name modifiers are: - -- `@` will pass the `event name` and `self` parameters to the callback. -- `#` will pass the `self` parameter to the callback. - -```javascript -var source = new lychee.event.Emitter(); -var target = new lychee.event.Emitter(); - -source.relay('foo', target, true); -source.relay('bar', target); - -source.trigger('foo'); // true -source.trigger('foo'); // false, only bound once - -source.trigger('bar'); // true -source.trigger('bar'); // true -``` - - -= methods-trigger - -```javascript -(Boolean) lychee.event.Emitter.prototype.trigger(event [, data]); -``` - -- `(String) event` is the event name. -- `(Array) data` is an array of parameters that will be passed to the bound callbacks. - -This method returns `true` on success and `false` on failure. -It will try to find and execute callbacks that are bound to the given event name. - -```javascript -var emitter = new lychee.event.Emitter(); - -emitter.bind('foo', function() {}, this); - -emitter.trigger('foo'); // true -emitter.trigger('foo', []); // true -emitter.trigger('bar', []); // false -``` - - - -= methods-unbind - -```javascript -(Boolean) lychee.event.Emitter.prototype.unbind(event [, callback, scope]); -``` - -- `(String) event` is the event name. -- `(Function) callback` is the callback that is executed when the event is triggered. -- `(Object) scope` is the scope of the callback. - -This method returns `true` on success and `false` on failure. -It will try to unbind the callback of an event name. -It unbinds all callbacks that match the specified criteria. - -```javascript -// keep references for later -var emitter = new lychee.event.Emitter(); -var _callback = function() {}; -var _scope = this; - -// unbind a single callback -emitter.bind('foo', _callback, _scope); -emitter.unbind('foo', _callback, _scope); // true - -// unbind multiple callbacks at once -emitter.bind('foo', _callback, _scope); -emitter.bind('foo', _callback, emitter); -emitter.unbind('foo', _callback); // true -emitter.unbind('foo', _callback); // false - -// unbind all callbacks and all scopes at once -emitter.bind('foo', function() {}, this); -emitter.bind('foo', _callback, _scope); -emitter.bind('foo', _callback, emitter); - -emitter.unbind('foo'); // true -emitter.unbind('foo'); // false -``` - diff --git a/libraries/lychee/api/event/Flow.md b/libraries/lychee/api/event/Flow.md deleted file mode 100644 index 857988e2..00000000 --- a/libraries/lychee/api/event/Flow.md +++ /dev/null @@ -1,140 +0,0 @@ - -= constructor - -```javascript -new lychee.event.Flow(void); -``` - -This constructor returns an instance of `lychee.event.Flow`. - -```javascript -var flow = new lychee.event.Flow(); - - -flow.then('first'); -flow.then('second', [ 'foo', { bar: 'qux' }]); - - -// default behaviour -flow.bind('first', function(oncomplete) { - oncomplete(true); -}); - -// data behaviour -flow.bind('second', function(a, b, oncomplete) { - a === 'foo'; // true - b.bar === 'qux'; // true - oncomplete(true); -}); - - -flow.bind('complete', function() { - console.log('Flow stack has been processed!'); -}); - -flow.bind('error', function(event) { - console.log('Flow event "' + event + '" failed!'); -}); - - -flow.init(); -``` - - - -= methods-serialize - -```javascript -(Serialization Object) lychee.event.Flow.prototype.serialize(void); -``` - -- This method has no arguments. - -This method is not intended for direct usage. -You can serialize an instance using the [lychee.serialize](lychee#methods-serialize) method. - -```javascript -var foo1 = new lychee.event.Flow(); -var data = lychee.serialize(foo1); -var foo2 = lychee.deserialize(data); - -data; // { constructor: 'lychee.event.Flow', arguments: []} -foo2; // lychee.event.Flow instance -``` - - - -= methods-then - -```javascript -(Boolean) lychee.event.Flow.prototype.then(event [, data]); -``` - -- `(String) event` is the event name that is triggered when the stack is processed. -- `(Array || null) data` is an array that is passed as the first arguments to the callback. - -This method returns `true` on success and `false` on failure. -It will try to bind the callback to the stack. - -If the `data` parameter is not `null` the `callback` gets its contents as the first -parameters, the last argument is always the `oncomplete` callback. - -```javascript -var flow = new lychee.event.Flow(); - - -flow.then('first'); -flow.then('second', [ 'foo', 'bar' ]); -flow.then('third'); - - -flow.bind('first', function(oncomplete) { - oncomplete(true); -}); - -flow.bind('second', function(foo, bar, oncomplete) { - oncomplete(true); -}); - -flow.bind('third', function(oncomplete) { - oncomplete(true); -}); - - -flow.bind('complete', function() { - console.log('Flow stack has been processed!'); -}); - -flow.bind('error', function(event) { - console.log('Flow event "' + event + '" failed!'); -}); - - -flow.init(); -``` - - - -= methods-init - -```javascript -(Boolean) lychee.event.Flow.prototype.init(void); -``` - -- This method has no arguments. - -This method returns `true` on success and `false` on failure. -It will try to initialize the processing of the stack. - -```javascript -var flow = new lychee.event.Flow(); - -flow.bind('complete', function() { - console.log('Flow stack has been processed!'); -}); - -flow.init(); // false -flow.then('first'); // true -flow.init(); // true -``` - diff --git a/libraries/lychee/api/event/Queue.md b/libraries/lychee/api/event/Queue.md deleted file mode 100644 index 4e611d89..00000000 --- a/libraries/lychee/api/event/Queue.md +++ /dev/null @@ -1,117 +0,0 @@ - -= constructor - -```javascript -new lychee.event.Queue(void); -``` - -This constructor returns an instance of `lychee.event.Queue`. - -```javascript -var queue = new lychee.event.Queue(); - -queue.then({ foo: 'bar' }); -queue.then({ foo: 'qux' }); -queue.then({ qux: 'bar' }); - -queue.bind('update', function(data, oncomplete) { - - if (data.qux === 'bar') { - oncomplete(false); - } else { - oncomplete(true); - } - -}, this); - -queue.bind('complete', function() { - console.log('All Queue steps were successful!'); -}); - -queue.bind('error', function() { - console.log('A Queue step was unsuccessful!'); -}); - -queue.init(); -``` - - - -= methods-serialize - -```javascript -(Serialization Object) lychee.event.Queue.prototype.serialize(void); -``` - -- This method has no arguments. - -This method is not intended for direct usage. -You can serialize an object using the [lychee.serialize](lychee#methods-serialize) method. - -```javascript -var foo1 = new lychee.event.Queue(); -var data = lychee.serialize(foo1); -var foo2 = lychee.deserialize(data); - -data; // { constructor: 'lychee.event.Queue', arguments: []} -foo2; // lychee.event.Queue instance -``` - - - -= methods-then - -```javascript -(Boolean) lychee.event.Queue.prototype.then(data); -``` - -- `(Object) data` is an object that is passed to the update event. - -This method returns `true` on success and `false` on failure. -It will try to bind the data to the stack. - -```javascript -var queue = new lychee.event.Queue(); - -queue.then({ step: 1 }); // true -queue.then({ step: 2 }); // true -queue.then({ step: 3 }); // true - -queue.then('invalid data'); // false - -queue.bind('complete', function() { - console.log('All Queue steps were successful!'); -}); - -queue.bind('error', function() { - console.log('A Queue step was unsuccessful!'); -}); - -queue.init(); -``` - - - -= methods-init - -```javascript -(Boolean) lychee.event.Queue.prototype.init(void); -``` - -- This method has no arguments. - -This method returns `true` on success and `false` on failure. -It will try to initialize the processing of the stack. - -```javascript -var queue = new lychee.event.Queue(); - -queue.bind('complete', function() { - console.log('The Queue was successful!'); -}); - -queue.init(); // false -queue.then({ foo: 'bar' }); // true -queue.init(); // true -``` - diff --git a/libraries/lychee/api/net/Tunnel.md b/libraries/lychee/api/net/Tunnel.md deleted file mode 100644 index eda81204..00000000 --- a/libraries/lychee/api/net/Tunnel.md +++ /dev/null @@ -1,532 +0,0 @@ - -= constructor - -```javascript -new lychee.net.Tunnel(settings); -``` - -- `settings` is an `Object`. - -This constructor returns an instance of `lychee.net.Tunnel`. -The `settings` object consists of the following properties: - - -- `(Object) codec` is a reference to an encoder Module, e.g. [lychee.data.BENCODE](lychee.data.BENCODE), [lychee.data.BitON](lychee.data.BitON) or [lychee.data.JSON](lychee.data.JSON). -- `(Boolean) binary` will be passed to [setBinary](#methods-setBinary). -- `(String) host` will be passed to [setHost](#methods-setHost). -- `(Number) port` will be passed to [setPort](#methods-setPort). -- `(Number) reconnect` will be passed to [setReconnect](#methods-setReconnect). - -```javascript -var tunnel = new lychee.net.Tunnel({ - codec: lychee.data.JSON, - host: 'localhost', - port: 1337, - reconnect: 10000 -}); -``` - -#### Implementation Notes - -This implementation is an interface which is reused by both -[lychee.net.Client](lychee.net.Client) and [lychee.net.Remote](lychee.net.Remote). - -The events are integrated with the services, so this interface -automatically manages all services, authentication flows and -synchronization flows. - - - -= events-connect - -```javascript -new lychee.net.Tunnel().bind('connect', function() {}, scope); -``` - -The `connect` event is fired on connect of the socket. - -Note that this event is reserved to be implemented by extending implementations, -e.g. [lychee.net.Client](lychee.net.Client) or [lychee.net.Remote](lychee.net.Remote). - -```javascript -var socket = new DummySocket(); -var tunnel = new lychee.net.Tunnel(); - -socket.onopen = function() { - tunnel.trigger('connect'); -}; - -tunnel.bind('connect', function() { - console.log('Tunnel connected!'); -}); -``` - - - -= events-disconnect - -```javascript -new lychee.net.Tunnel().bind('disconnect', function() {}, scope); -``` - -The `disconnect` event is fired on disconnect of the socket. - -Note that this event is reserved to be implemented by extending implementations, -e.g. [lychee.net.Client](lychee.net.Client) or [lychee.net.Remote](lychee.net.Remote). - -By default this event is used to implement the [reconnect](#properties-reconnect) property. - -```javascript -var socket = new DummySocket(); -var tunnel = new lychee.net.Tunnel(); - -socket.onclose = function() { - tunnel.trigger('disconnect'); -}; - -tunnel.bind('disconnect', function() { - console.log('Tunnel disconnected!'); -}); -``` - - - -= events-send - -```javascript -new lychee.net.Tunnel().bind('send', function(blob, binary) {}, scope); -``` - -The `send` event is fired on data needing to be send via the socket. - -- `(String) blob` is an encoded string. -- `(Boolean) binary` is a flag. If set to `true`, the `blob` is encoded as `binary`. If set to `false`, the `blob` is encoded as `utf-8`. - -Note that this event is reserved to be implemented by extending implementations, -e.g. [lychee.net.Client](lychee.net.Client) or [lychee.net.Remote](lychee.net.Remote). - -```javascript -var socket = new DummySocket(); -var tunnel = new lychee.net.Tunnel(); - -tunnel.bind('send', function(blob, binary) { - binary === true ? socket.sendAsBinary(blob) : socket.sendAsText(blob); -}); -``` - - - -= events-receive - -```javascript -new lychee.net.Tunnel().bind('receive', function(data) {}, scope); -``` - -The `send` event is fired on data needing to be send via the socket. - -- `(Object) data` is an object. - -Note that this event is reserved to be implemented by extending implementations, -e.g. [lychee.net.Client](lychee.net.Client) or [lychee.net.Remote](lychee.net.Remote). - -```javascript -var socket = new DummySocket(); -var tunnel = new lychee.net.Tunnel(); - -socket.onmessage = function(blob) { - tunnel.receive(blob); -}; - -tunnel.bind('receive', function(data) { - console.log('Tunnel received ', data); -}); -``` - - - -= properties-binary - -```javascript -(Boolean) new lychee.net.Tunnel().binary; -``` - -The `(Boolean) binary` property the state whether the instance is -encoding all data as `binary` or not. - -It influences the [send](#events-send) event, the [send](#methods-send) method -the [receive](#events-receive) event and the [receive](#methods-receive) method. - -It is set via `settings.binary` in the [constructor](#constructor) -or via [setBinary](#methods-setBinary). - -```javascript -var tunnel = new lychee.net.Tunnel({ - binary: false -}); - -tunnel.binary; // false -tunnel.setBinary(true); // true -tunnel.binary; // true -``` - - - -= properties-host - -```javascript -(String) new lychee.net.Tunnel().host; -``` - -The `(String) host` property is the host for the socket. - -It is set via `settings.host` in the [constructor](#constructor) -or via [setHost](#methods-setHost). - -```javascript -var tunnel = new lychee.net.Tunnel({ - host: 'localhost' -}); - -tunnel.host; // 'localhost' -tunnel.setHost('1.3.3.7'); // true -tunnel.host; // '1.3.3.7' -``` - - - -= properties-port - -```javascript -(Number) new lychee.net.Tunnel().port; -``` - -The `(Number) port` property is the port for the socket. - -It is set via `settings.port` in the [constructor](#constructor) -or via [setPort](#methods-setPort). - -```javascript -var tunnel = new lychee.net.Tunnel({ - port: 1337 -}); - -tunnel.port; // 1337 -tunnel.setPort(13337); // true -tunnel.port; // 13337 -``` - - - -= properties-reconnect - -```javascript -(Number) new lychee.net.Tunnel().reconnect; -``` - -The `(Number) reconnect` property is the timeout in milliseconds -until the disconnected instance reconnects. If set to a greater -value than `0`, reconnects are active. - -It influences the [disconnect](#events-disconnect) event. - -It is set via `settings.reconnect` in the [constructor](#constructor) -or via [setReconnect](#methods-setReconnect). - -```javascript -var tunnel = new lychee.net.Tunnel({ - reconnect: 0 -}); - -tunnel.reconnect; // 0, disabled -tunnel.setReconnect(1337); // true -tunnel.reconnect; // 1337 -``` - - - -= methods-deserialize - -```javascript -(void) lychee.Storage.prototype.deserialize(blob); -``` - -- `(Object) blob` is an Object that is part of the Serialization Object. - -This method is not intended for direct usage. -You can deserialize an object using the [lychee.deserialize](lychee#methods-deserialize) method. - -```javascript -var foo1 = new lychee.net.Tunnel({ host: 'localhost', port: 1337 }); -var data = lychee.serialize(foo1); -var foo2 = lychee.deserialize(data); - -data; // { constructor: 'lychee.net.Tunnel', arguments: [{ host: 'localhost', port: 1337 }]} -foo2; // lychee.net.Tunnel instance -``` - - - -= methods-serialize - -```javascript -(Serialization Object) lychee.net.Tunnel.prototype.serialize(void); -``` - -- This method has no arguments. - -This method is not intended for direct usage. -You can serialize an instance using the [lychee.serialize](lychee#methods-serialize) method. - -```javascript -var foo1 = new lychee.net.Tunnel({ host: 'localhost', port: 1337 }); -var data = lychee.serialize(foo1); -var foo2 = lychee.deserialize(data); - -data; // { constructor: 'lychee.net.Tunnel', arguments: [{ host: 'localhost', port: 1337 }]} -foo2; // lychee.net.Tunnel instance -``` - - - -= methods-send - -```javascript -(Boolean) lychee.net.Tunnel.prototype.send(data [, service ]); -``` - -- `(Object) data` is the data object to send. -- `(Object) service` is the optional service description object. - -This method returns `true` on success and `false` on failure. -It encodes the `data` object into a `blob` string and sends it -to the remote side. - -There are three variants on how to send/receive data, the latter -is the preferred and recommended one: - -- If the `service` object is `null`, the remote side triggers the [receive](#events-receive) event. -- If the `service` object has a valid `(String) id` and a valid `(String) method`, the remote side's service's method will be called. -- If the `service` object has a valid `(String) id` and a valid `(String) event`, the remote side's service's event will be triggered. - -```javascript -var tunnel = new lychee.net.Tunnel(); - -tunnel.send({ - foo: 'bar' -}); // will land in the remote's receive event - -tunnel.send({ - foo: 'bar' -}, { - id: 'my-service', - method: 'my-method' -}); // will call remote's service's method - -tunnel.send({ - foo: 'bar' -}, { - id: 'my-service', - event: 'my-event' -}); // will trigger remote's service's event -``` - - - -= methods-receive - -```javascript -(Boolean) lychee.net.Tunnel.prototype.receive(blob); -``` - -- `(String) blob` is the blob to be received. - -This method returns `true` on success and `false` on failure. -It decodes the `blob` string into the `data` object and receives -it from the remote side. - -There are three variants on how to send/receive data, the latter -is the preferred and recommended one: - -- If the `service` object is `null`, the remote side triggers the [receive](#events-receive) event. -- If the `service` object has a valid `(String) id` and a valid `(String) method`, the remote side's service's method will be called. -- If the `service` object has a valid `(String) id` and a valid `(String) event`, the remote side's service's event will be triggered. - -```javascript -// Simulating the remote side -var blob = lychee.data.JSON.encode({ - foo: 'bar' -}); - -var tunnel = new lychee.net.Tunnel({ - codec: lychee.data.JSON -}); - -tunnel.bind('receive', function(data) { - console.log(data); -}, this); - -tunnel.receive(blob); // true -``` - - - -= methods-setBinary - -```javascript -(Boolean) lychee.net.Tunnel.prototype.setBinary(binary); -``` - -- `(Boolean) binary` is a flag. If set to `true`, all data is encoded as `binary`. If set to `false`, all data is encoded as `utf-8`. - -This method returns `true` on success and `false` on failure. -It will set the [binary](#properties-binary) property of the instance. - -```javascript -var tunnel = new lychee.net.Tunnel(); - -tunnel.binary; // false -tunnel.setBinary(true); // true -tunnel.binary; // true -``` - - - -= methods-setHost - -```javascript -(Boolean) lychee.net.Tunnel.prototype.setHost(host); -``` - -- `(String) host` is the host for the socket. - -This method returns `true` on success and `false` on failure. -It will set the [host](#properties-host) property of the instance. - -```javascript -var tunnel = new lychee.net.Tunnel(); - -tunnel.host; // 'localhost' -tunnel.setHost('1.3.3.7'); // true -tunnel.host; // '1.3.3.7' -``` - - - -= methods-setPort - -```javascript -(Boolean) lychee.net.Tunnel.prototype.setPort(port); -``` - -- `(Number) port` is the port for the socket. - -This method returns `true` on success and `false` on failure. -It will set the [port](#properties-port) property of the instance. - -```javascript -var tunnel = new lychee.net.Tunnel(); - -tunnel.port; // 1337 -tunnel.setPort(1338); // true -tunnel.port; // 1338 -``` - - - -= methods-setReconnect - -```javascript -(Boolean) lychee.net.Tunnel.prototype.setReconnect(reconnect); -``` - -- `(Number) reconnect` is the timeout in milliseconds until the disconnected instance reconnects. If set to a greater value than `0`, reconnects are active. - -This method returns `true` on success and `false` on failure. -It will set the [reconnect](#properties-reconnect) property of the instance. - -```javascript -var tunnel = new lychee.net.Tunnel(); - -tunnel.reconnect; // 0, disabled -tunnel.setReconnect(1337); // true -tunnel.reconnect; // 1337 -``` - - - -= methods-addService - -```javascript -(Boolean) lychee.net.Tunnel.prototype.addService(service); -``` - -- `(lychee.net.Service) service` is a [lychee.net.Service](lychee.net.Service) instance. - -This method returns `true` on success and `false` on failure. -It will add the service to the internal service pool, whose services -are trigger-able via their service [id](lychee.net.Service#properties-id) property. - -```javascript -var tunnel = new lychee.net.Tunnel(); -var service = new lychee.net.Service('my-service', tunnel, lychee.net.Service.TYPE.client); - - -service.bind('my-event', function(data) { - console.log(data); -}); - -tunnel.addService(service); - -// This has to be executed on the remote side -tunnel.send({ foo: 'bar' }, { - id: 'my-service', - event: 'my-event' -}); -``` - - - -= methods-getService - -```javascript -(null || lychee.net.Service) lychee.net.Tunnel.prototype.getService(id); -``` - -- `(String) id` is the unique service identifier from a service in the internal service pool. - -This method returns a `lychee.net.Service` instance on success and `null` on failure. -It returns the `lychee.net.Service` that matches the specified criteria. - -```javascript -var tunnel = new lychee.net.Tunnel(); -var service = new lychee.net.Service('bar', tunnel, lychee.net.Service.TYPE.client); - -tunnel.addService(service); - -tunnel.getService('foo'); // null -tunnel.getService('bar'); // lychee.net.Service -tunnel.getService('bar') === service; // true -``` - - - -= methods-removeService - -```javascript -(Boolean) lychee.net.Tunnel.prototype.removeService(service); -``` - -- `(lychee.net.Service) service` is a [lychee.net.Service](lychee.net.Service) instance. - -This method returns `true` on success and `false` on failure. -It will remove the service from the internal service pool. - -```javascript -var tunnel = new lychee.net.Tunnel(); -var service = new lychee.net.Service('my-service', tunnel, lychee.net.Service.TYPE.client); - -tunnel.removeService(service); // false -tunnel.addService(service); // true -tunnel.removeService(service); // true -``` - diff --git a/libraries/lychee/lychee.pkg b/libraries/lychee/lychee.pkg index 18d90739..611c7fe0 100644 --- a/libraries/lychee/lychee.pkg +++ b/libraries/lychee/lychee.pkg @@ -1,69 +1,6 @@ { "api": { - "files": { - "core": { - "Asset": [ - "md" - ], - "Debugger": [ - "md" - ], - "Definition": [ - "md" - ], - "Environment": [ - "md" - ], - "Input": [ - "md" - ], - "Package": [ - "md" - ], - "Stash": [ - "md" - ], - "Storage": [ - "md" - ], - "Viewport": [ - "md" - ], - "lychee": [ - "md" - ] - }, - "data": { - "BENCODE": [ - "md" - ], - "BitON": [ - "md" - ], - "JSON": [ - "md" - ], - "MD": [ - "md" - ] - }, - "event": { - "Emitter": [ - "md" - ], - "Flow": [ - "md" - ], - "Queue": [ - "md" - ] - }, - "net": { - "Tunnel": [ - "md" - ] - } - } + "files": {} }, "build": { "environments": { @@ -190,17 +127,30 @@ "js" ], "ai": { - "neural": { - "Agent": [ + "Agent": [ + "js" + ], + "Genome": [ + "js" + ], + "Layer": [ + "js" + ], + "bnn": { + "Brain": [ "js" - ], - "Evolution": [ + ] + }, + "enn": { + "Agent": [ "js" ], - "Genome": [ + "Brain": [ "js" - ], - "Network": [ + ] + }, + "qnn": { + "Brain": [ "js" ] } @@ -299,15 +249,10 @@ "MD5": [ "js" ], - "SHA1": [ - "js" - ] - }, - "data": { - "HTML": [ + "MURMUR": [ "js" ], - "MD": [ + "SHA1": [ "js" ] }, @@ -513,6 +458,9 @@ }, "ui": { "entity": { + "Download": [ + "js" + ], "Helper": [ "js", "json", @@ -570,6 +518,14 @@ } } }, + "policy": { + "Position": [ + "js" + ], + "Velocity": [ + "js" + ] + }, "ui": { "Blueprint": [ "js" diff --git a/libraries/lychee/source/ai/Agent.js b/libraries/lychee/source/ai/Agent.js new file mode 100644 index 00000000..8deca38b --- /dev/null +++ b/libraries/lychee/source/ai/Agent.js @@ -0,0 +1,342 @@ + +lychee.define('lychee.ai.Agent').exports(function(lychee, global, attachments) { + + /* + * HELPERS + */ + + const _update_brain = function() { + + let controls = this.controls; + let sensors = this.sensors; + let entity = this.entity; + + + for (let s = 0, sl = sensors.length; s < sl; s++) { + sensors[s].entity = entity; + } + + for (let c = 0, cl = controls.length; c < cl; c++) { + controls[c].entity = entity; + } + + + let brain = this.brain; + if (brain !== null) { + brain.setSensors(sensors); + brain.setControls(controls); + } + + }; + + const _validate_brain = function(brain) { + + if (brain instanceof Object) { + + if (typeof brain.update === 'function' && typeof brain.setControls === 'function' && typeof brain.setSensors === 'function') { + + return true; + + } + + } + + + return false; + + }; + + const _validate_entity = function(entity) { + + if (entity instanceof Object) { + return true; + } + + + return false; + + }; + + + + /* + * IMPLEMENTATION + */ + + let Composite = function(data) { + + let settings = Object.assign({}, data); + + + this.brain = null; + this.controls = []; + this.entity = null; + this.fitness = 0; + this.sensors = []; + + this.__training = null; + this.__trainings = []; + + + // XXX: Must be in this exact order + this.setBrain(settings.brain); + this.setSensors(settings.sensors); + this.setControls(settings.controls); + + this.setEntity(settings.entity); + this.setFitness(settings.fitness); + + + settings = null; + + }; + + + Composite.prototype = { + + /* + * ENTITY API + */ + + deserialize: function(blob) { + + let brain = lychee.deserialize(blob.brain); + if (brain !== null) { + this.setBrain(brain); + } + + let entity = lychee.deserialize(blob.entity); + if (entity !== null) { + this.setEntity(entity); + } + + + if (blob.controls instanceof Array) { + this.controls = blob.controls.map(lychee.deserialize); + } + + if (blob.sensors instanceof Array) { + this.sensors = blob.sensors.map(lychee.deserialize); + } + + + if (blob.trainings instanceof Array) { + this.__trainings = blob.trainings.map(lychee.deserialize); + } + + }, + + serialize: function() { + + let settings = {}; + let blob = {}; + + + if (this.fitness !== 0) settings.fitness = this.fitness; + + + if (this.brain !== null) blob.brain = lychee.serialize(this.brain); + if (this.controls.length > 0) blob.controls = this.controls.map(lychee.serialize); + if (this.sensors.length > 0) blob.sensors = this.sensors.map(lychee.serialize); + if (this.__trainings.length > 0) blob.trainings = this.__trainings.map(lychee.serialize); + + // XXX: Entity is not serialized, tracked by lychee.ai.Layer automatically + // if (this.entity !== null) blob.entity = lychee.serialize(this.entity); + + + return { + 'constructor': 'lychee.ai.Agent', + 'arguments': [ settings ], + 'blob': Object.keys(blob).length > 0 ? blob : null + }; + + }, + + update: function(clock, delta) { + + let brain = this.brain; + if (brain !== null) { + this.__training = brain.update(clock, delta); + } + + }, + + + + /* + * CUSTOM API + */ + + crossover: function(agent) { + + agent = agent instanceof Composite ? agent : null; + + + if (agent !== null) { + + // XXX: This is implemented by AI Agents + + let zw_agent = lychee.deserialize(lychee.serialize(this)); + let zz_agent = lychee.deserialize(lychee.serialize(agent)); + + return [ zw_agent, zz_agent ]; + + } + + + return null; + + }, + + reward: function(diff) { + + diff = typeof diff === 'number' ? Math.abs(diff | 0) : 1; + + + this.fitness += diff; + + + let training = this.__training; + if (training !== null) { + + training.iterations = diff; + this.__trainings.push(training); + + let brain = this.brain; + if (brain !== null) { + brain.train(training); + } + + } + + }, + + punish: function(diff) { + + diff = typeof diff === 'number' ? Math.abs(diff | 0) : 1; + + this.fitness -= diff; + + }, + + setBrain: function(brain) { + + brain = _validate_brain(brain) === true ? brain : null; + + + if (brain !== null) { + + this.brain = brain; + + return true; + + } + + + return false; + + }, + + setControls: function(controls) { + + controls = controls instanceof Array ? controls : null; + + + if (controls !== null) { + + controls = controls.filter(function(control) { + return control instanceof Object; + }); + + + if (controls !== this.controls) { + this.controls = controls; + _update_brain.call(this); + } + + + return true; + + } + + + return false; + + }, + + setEntity: function(entity) { + + entity = _validate_entity(entity) === true ? entity : null; + + + if (entity !== null) { + + if (entity !== this.entity) { + + this.entity = entity; + _update_brain.call(this); + + } + + + return true; + + } + + + return false; + + }, + + setFitness: function(fitness) { + + fitness = typeof fitness === 'number' ? (fitness | 0) : null; + + + if (fitness !== null) { + + this.fitness = fitness; + + return true; + + } + + + return false; + + }, + + setSensors: function(sensors) { + + sensors = sensors instanceof Array ? sensors : null; + + + if (sensors !== null) { + + sensors = sensors.filter(function(sensor) { + return sensor instanceof Object; + }); + + + if (sensors !== this.sensors) { + this.sensors = sensors; + _update_brain.call(this); + } + + + return true; + + } + + + return false; + + } + + }; + + + return Composite; + +}); + diff --git a/libraries/lychee/source/ai/Genome.js b/libraries/lychee/source/ai/Genome.js new file mode 100644 index 00000000..b91d526a --- /dev/null +++ b/libraries/lychee/source/ai/Genome.js @@ -0,0 +1,271 @@ + +lychee.define('lychee.ai.Genome').exports(function(lychee, global, attachments) { + + /* + * IMPLEMENTATION + */ + + let Composite = function(data) { + + let settings = Object.assign({}, data); + + + this.genes = []; + + this.__map = {}; + + + this.setGenes(settings.genes); + + settings = null; + + }; + + + Composite.prototype = { + + /* + * ENTITY API + */ + + deserialize: function(blob) { + + if (blob.genes instanceof Array) { + + let genes = blob.genes; + let map = {}; + + + if (blob.map instanceof Object) { + + for (let bid in blob.map) { + + let index = blob.map[bid]; + if (typeof index === 'number') { + map[bid] = index; + } + + } + + } + + + for (let g = 0, gl = genes.length; g < gl; g++) { + + let id = null; + for (let mid in map) { + + if (map[mid] === g) { + id = mid; + } + + } + + + if (id !== null) { + this.setGene(id, genes[g]); + } else { + this.addGene(genes[g]); + } + + } + + } + + }, + + serialize: function() { + + let blob = {}; + + + if (this.genes.length > 0) { + blob.genes = this.genes.map(lychee.serialize); + } + + + if (blob.genes instanceof Array && Object.keys(this.__map).length > 0) { + + blob.map = Object.map(this.__map, function(val, key) { + + let index = this.genes.indexOf(val); + if (index !== -1) { + return index; + } + + + return undefined; + + }, this); + + } + + + return { + 'constructor': 'lychee.ai.Genome', + 'arguments': [], + 'blob': Object.keys(blob).length > 0 ? blob : null + }; + + }, + + + + /* + * CUSTOM API + */ + + addGene: function(gene) { + + gene = gene instanceof Array ? gene : null; + + + if (gene !== null) { + + let index = this.genes.indexOf(gene); + if (index === -1) { + + this.genes.push(gene); + + return true; + + } + + } + + + return false; + + }, + + setGene: function(id, gene) { + + id = typeof id === 'string' ? id : null; + gene = gene instanceof Array ? gene : null; + + + if (id !== null && gene !== null && this.__map[id] === undefined) { + + this.__map[id] = gene; + + let result = this.addGene(gene); + if (result === true) { + return true; + } else { + delete this.__map[id]; + } + + } + + + return false; + + }, + + getGene: function(id) { + + id = typeof id === 'string' ? id : null; + + + let found = null; + + + if (id !== null) { + + if (this.__map[id] !== undefined) { + found = this.__map[id]; + } + + } + + + return found; + + }, + + removeGene: function(gene) { + + gene = gene instanceof Array ? gene : null; + + + if (gene !== null) { + + let found = false; + + let index = this.genes.indexOf(gene); + if (index !== -1) { + this.genes.splice(index, 1); + found = true; + } + + + for (let id in this.__map) { + + if (this.__map[id] === gene) { + + delete this.__map[id]; + found = true; + + } + + } + + + return found; + + } + + + return false; + + }, + + setGenes: function(genes) { + + genes = genes instanceof Array ? genes : null; + + + let all = true; + + if (genes !== null) { + + for (let g = 0, gl = genes.length; g < gl; g++) { + + let result = this.addGene(genes[g]); + if (result === false) { + all = false; + } + + } + + } + + + return all; + + }, + + removeGenes: function() { + + let genes = this.genes; + + for (let g = 0, gl = genes.length; g < gl; g++) { + + this.removeGene(genes[g]); + + gl--; + g--; + + } + + return true; + + } + + }; + + + return Composite; + +}); + diff --git a/libraries/lychee/source/ai/Layer.js b/libraries/lychee/source/ai/Layer.js new file mode 100644 index 00000000..269384ce --- /dev/null +++ b/libraries/lychee/source/ai/Layer.js @@ -0,0 +1,452 @@ + +lychee.define('lychee.ai.Layer').requires([ + 'lychee.ai.Agent', +// 'lychee.ai.bnn.Agent', + 'lychee.ai.enn.Agent' +// 'lychee.ai.neat.Agent', +// 'lychee.ai.bneat.Agent', +// 'lychee.ai.hyperneat.Agent' +]).includes([ + 'lychee.app.Layer' +]).exports(function(lychee, global, attachments) { + + const _Agent = lychee.import('lychee.ai.Agent'); + const _Layer = lychee.import('lychee.app.Layer'); + const _agent = { + ENN: lychee.import('lychee.ai.enn.Agent'), + BNN: lychee.import('lychee.ai.bnn.Agent'), + NEAT: lychee.import('lychee.ai.neat.Agent'), + BNEAT: lychee.import('lychee.ai.bneat.Agent'), + HYPERNEAT: lychee.import('lychee.ai.hyperneat.Agent') + }; + + + + /* + * HELPERS + */ + + const _create_agent = function() { + + let Agent = _Agent; + let type = this.type; + if (type === Composite.TYPE.ENN) { + Agent = _agent.ENN; + } else if (type === Composite.TYPE.BNN) { + Agent = _agent.BNN; + } else if (type === Composite.TYPE.NEAT) { + Agent = _agent.NEAT; + } else if (type === Composite.TYPE.BNEAT) { + Agent = _agent.BNEAT; + } else if (type === Composite.TYPE.HYPERNEAT) { + Agent = _agent.HYPERNEAT; + } + + + return new Agent(); + + }; + + const _initialize = function() { + + let controls = this.controls; + let entities = this.entities; + let sensors = this.sensors; + let population = this.__population; + + + for (let e = 0, el = entities.length; e < el; e++) { + + let entity = entities[e]; + let agent = _create_agent.call(this); + + agent.setSensors(sensors.map(function(sensor) { + return lychee.deserialize(lychee.serialize(sensor)); + })); + + agent.setControls(controls.map(function(control) { + return lychee.deserialize(lychee.serialize(control)); + })); + + agent.setEntity(entity); + + + population.push(agent); + + } + + }; + + const _epoche = function() { + + let entities = this.entities; + let oldcontrols = []; + let oldsensors = []; + let oldpopulation = this.__population; + let newpopulation = []; + let fitness = this.__fitness; + + + oldpopulation.sort(function(a, b) { + if (a.fitness > b.fitness) return -1; + if (a.fitness < b.fitness) return 1; + return 0; + }); + + + fitness.total = 0; + fitness.average = 0; + fitness.best = -Infinity; + fitness.worst = Infinity; + + for (let op = 0, opl = oldpopulation.length; op < opl; op++) { + + let agent = oldpopulation[op]; + + oldsensors.push(agent.sensors); + oldcontrols.push(agent.controls); + + // XXX: Avoid updates of Brain + agent.sensors = []; + agent.controls = []; + agent.setEntity(null); + + fitness.total += agent.fitness; + fitness.best = Math.max(fitness.best, agent.fitness); + fitness.worst = Math.min(fitness.worst, agent.fitness); + + } + + fitness.average = fitness.total / oldpopulation.length; + + + let amount = Math.round(0.2 * oldpopulation.length); + if (amount % 2 === 1) { + amount++; + } + + if (amount > 0) { + + // Survivor Population + for (let a = 0; a < amount; a++) { + newpopulation.push(oldpopulation[a]); + } + + + // Mutant Population + for (let a = 0; a < amount; a++) { + newpopulation.push(_create_agent.call(this)); + } + + + // Breed Population + let b = 0; + let count = 0; + + while (newpopulation.length < oldpopulation.length) { + + let agent_mum = oldpopulation[b]; + let agent_dad = oldpopulation[b + 1]; + let children = agent_mum.crossover(agent_dad); + + if (children !== null) { + + let agent_sister = children[0]; + let agent_brother = children[1]; + + if (newpopulation.indexOf(agent_sister) === -1) { + newpopulation.push(agent_sister); + } + + if (newpopulation.indexOf(agent_brother) === -1) { + newpopulation.push(agent_brother); + } + + } + + + b += 1; + b %= amount; + + count += 1; + + + // Fallback if there's no crossover() Implementation + if (count > oldpopulation.length) { + break; + } + + } + + } + + + if (newpopulation.length < oldpopulation.length) { + + if (lychee.debug === true) { + console.warn('lychee.ai.Layer: Too less Agents for healthy Evolution'); + } + + + let diff = oldpopulation.length - newpopulation.length; + + for (let o = 0; o < oldpopulation.length; o++) { + + if (newpopulation.indexOf(oldpopulation[o]) === -1) { + newpopulation.push(oldpopulation[o]); + diff--; + } + + if (diff === 0) { + break; + } + + } + + } + + + for (let np = 0, npl = newpopulation.length; np < npl; np++) { + + let agent = newpopulation[np]; + let entity = entities[np]; + + agent.sensors = oldsensors[np]; + agent.controls = oldcontrols[np]; + + agent.setEntity(entity); + agent.setFitness(0); + + this.trigger('epoche', [ agent ]); + + } + + + this.__population = newpopulation; + + oldpopulation = null; + oldsensors = null; + oldcontrols = null; + + }; + + + + /* + * IMPLEMENTATION + */ + + let Composite = function(data) { + + let settings = Object.assign({}, data); + + + this.lifetime = 30000; + this.sensors = []; + this.controls = []; + this.type = Composite.TYPE.ENN; + + this.__fitness = { + total: 0, + average: 0, + best: -Infinity, + worst: Infinity + }; + this.__population = []; + this.__start = null; + + + this.setSensors(settings.sensors); + this.setControls(settings.controls); + this.setLifetime(settings.lifetime); + + delete settings.sensors; + delete settings.controls; + delete settings.lifetime; + + + _Layer.call(this, settings); + + + /* + * INITIALIZATION + */ + + if (settings.type !== this.type) { + this.setType(settings.type); + } else { + _initialize.call(this); + } + + settings = null; + + }; + + + Composite.TYPE = { + ENN: 0, + BNN: 1, + NEAT: 2, + BNEAT: 3, + HYPERNEAT: 4 + }; + + + Composite.prototype = { + + /* + * ENTITY API + */ + + // deserialize: function(blob) {}, + + serialize: function() { + + let data = _Layer.prototype.serialize.call(this); + data['constructor'] = 'lychee.ai.Layer'; + + let settings = data['arguments'][0]; + let blob = (data['blob'] || {}); + + + if (this.sensors.length > 0) settings.sensors = this.sensors.map(lychee.serialize); + if (this.controls.length > 0) settings.controls = this.controls.map(lychee.serialize); + if (this.lifetime !== 30000) settings.lifetime = this.lifetime; + if (this.type !== Composite.TYPE.ENN) settings.type = this.type; + + + data['blob'] = Object.keys(blob).length > 0 ? blob : null; + + + return data; + + }, + + update: function(clock, delta) { + + _Layer.prototype.update.call(this, clock, delta); + + + if (this.__start === null) { + this.__start = clock; + } + + + let population = this.__population; + for (let p = 0, pl = population.length; p < pl; p++) { + + let agent = population[p]; + + agent.update(clock, delta); + this.trigger('update', [ agent ]); + + } + + + let t = (clock - this.__start) / this.lifetime; + if (t > 1) { + + _epoche.call(this); + + this.__start = clock; + + } + + }, + + + + /* + * CUSTOM API + */ + + setControls: function(controls) { + + controls = controls instanceof Array ? controls.unique() : null; + + + if (controls !== null) { + + this.controls = controls.filter(function(control) { + return control instanceof Object; + }); + + return true; + + } + + + return false; + + }, + + setLifetime: function(lifetime) { + + lifetime = typeof lifetime === 'number' ? (lifetime | 0) : null; + + + if (lifetime !== null) { + + this.lifetime = lifetime; + + return true; + + } + + + return false; + + }, + + setSensors: function(sensors) { + + sensors = sensors instanceof Array ? sensors.unique() : null; + + + if (sensors !== null) { + + this.sensors = sensors.filter(function(sensor) { + return sensor instanceof Object; + }); + + return true; + + } + + + return false; + + }, + + setType: function(type) { + + type = lychee.enumof(Composite.TYPE, type) ? type : null; + + + if (type !== null) { + + let oldtype = this.type; + if (oldtype !== type) { + + this.type = type; + + _initialize.call(this); + + return true; + + } + + } + + + return false; + + } + + }; + + + return Composite; + +}); + diff --git a/libraries/lychee/source/ai/bnn/Brain.js b/libraries/lychee/source/ai/bnn/Brain.js new file mode 100644 index 00000000..45c72c13 --- /dev/null +++ b/libraries/lychee/source/ai/bnn/Brain.js @@ -0,0 +1,439 @@ + +lychee.define('lychee.ai.bnn.Brain').exports(function(lychee, global, attachments) { + + const _NEURON_BIAS = 1; + + + + /* + * HELPERS + */ + + const _random = function() { + return (Math.random() * 2) - 1; + }; + + const _init_network = function() { + + let input_size = this.__sensors_map.reduce(function(a, b) { + return a + b; + }, 0); + + let output_size = this.__controls_map.reduce(function(a, b) { + return a + b; + }, 0); + + + let hidden_size = 1; + let weight_size = 0; + + if (input_size > output_size) { + hidden_size = input_size; + } else { + hidden_size = output_size; + } + + + let layer_amount = 6; + + for (let l = 0; l < layer_amount; l++) { + + let prev = hidden_size; + let size = hidden_size; + + if (l === 0) { + prev = 0; + size = input_size; + } else if (l === 1) { + prev = input_size; + size = hidden_size; + } else if (l === layer_amount - 1) { + prev = hidden_size; + size = output_size; + } + + + let layer = new Array(size); + + for (let n = 0, nl = layer.length; n < nl; n++) { + + let neuron = { + value: _random(), + weights: [] + }; + + for (let p = 0; p < prev; p++) { + neuron.weights.push(_random()); + weight_size++; + } + + layer[n] = neuron; + + } + + this.__layers[l] = layer; + + } + + + this.__size.input = input_size; + this.__size.hidden = hidden_size; + this.__size.output = output_size; + this.__size.weight = weight_size; + + }; + + const _sigmoid = function(value) { + + return (1 / (1 + Math.exp((-1 * value) / 1))); + + }; + + + + /* + * IMPLEMENTATION + */ + + let Composite = function(data) { + + let settings = Object.assign({}, data); + + + this.controls = []; + this.sensors = []; + + this.__controls_map = []; + this.__layers = []; + this.__sensors_map = []; + + // cache structures + this.__size = { + input: 0, + hidden: 0, + output: 0, + weight: 0 + }; + + + this.setSensors(settings.sensors); + this.setControls(settings.controls); + + settings = null; + + }; + + + Composite.prototype = { + + /* + * ENTITY API + */ + + deserialize: function(blob) { + + if (blob.layers instanceof Array) { + this.__layers = lychee.deserialize(blob.layers); + } + + if (blob.size instanceof Object) { + this.__size = lychee.deserialize(blob.size); + } + + }, + + serialize: function() { + + let settings = {}; + let blob = {}; + + + // XXX: controls and sensors are handled by lychee.ai.Agent + // if (this.controls.length > 0) settings.controls = lychee.serialize(this.controls); + // if (this.sensors.length > 0) settings.sensors = lychee.serialize(this.sensors); + + + if (this.__layers.length > 0) { + blob.layers = lychee.serialize(this.__layers); + } + + if (this.__size.input !== 0 || this.__size.output !== 0) { + blob.size = lychee.serialize(this.__size); + } + + + return { + 'constructor': 'lychee.ai.bnn.Brain', + 'arguments': [ settings ], + 'blob': Object.keys(blob).length > 0 ? blob : null + }; + + }, + + update: function(clock, delta) { + + let controls = this.controls; + let controls_map = this.__controls_map; + let layers = this.__layers; + let sensors = this.sensors; + let training = { + inputs: null, + outputs: null + }; + + + // 1. Transform Policies to Inputs + let inputs = new Array(this.__size.input); + + for (let i = 0, s = 0, sl = sensors.length; s < sl; s++) { + + let sensor = sensors[s]; + let values = sensor.sensor(); + + for (let v = 0, vl = values.length; v < vl; v++) { + inputs[i++] = values[v]; + } + + } + + training.inputs = inputs; + + + // 2. Update Input Layer + let input_layer = layers[0]; + + for (let il = 0, ill = input_layer.length; il < ill; il++) { + input_layer[il].value = inputs[il]; + } + + + // 3. Update Hidden Layers + let prev_layer = layers[0]; + + for (let l = 1, ll = layers.length; l < ll; l++) { + + let current_layer = layers[l]; + + for (let n = 0, nl = current_layer.length; n < nl; n++) { + + let neuron = current_layer[n]; + let value = 0; + + for (let p = 0, pl = prev_layer.length; p < pl; p++) { + value += prev_layer[p].value * neuron.weights[p]; + } + + neuron.value = _sigmoid(value); + + } + + prev_layer = current_layer; + + } + + + // 4. Update Output Layer + let outputs = new Array(this.__size.output); + let output_layer = layers[layers.length - 1]; + + for (let o = 0, ol = output_layer.length; o < ol; o++) { + outputs[o] = output_layer[o].value; + } + + training.outputs = outputs; + + + // 5. Transform Outputs to Policies + let offset = 0; + + for (let c = 0, cl = controls_map.length; c < cl; c++) { + + let control = controls[c]; + let length = controls_map[c]; + let values = [].slice.call(outputs, offset, length); + + if (values.length > 0) { + control.control(values); + } + + offset += length; + + } + + + return training; + + }, + + + + /* + * CUSTOM API + */ + + train: function(training) { + + training = training instanceof Object ? training : null; + + + if (training !== null) { + + // XXX: Feed Forward NN has no training + + return true; + + } + + + return false; + + }, + + setControls: function(controls) { + + controls = controls instanceof Array ? controls : null; + + + if (controls !== null) { + + this.controls = controls; + + this.__controls_map = controls.map(function(control) { + return (control.sensor() || [ 1 ]).length; + }); + + + let size = this.__controls_map.reduce(function(a, b) { + return a + b; + }, 0); + + if (size !== this.__size.output) { + _init_network.call(this); + } + + + return true; + + } + + + return false; + + }, + + setSensors: function(sensors) { + + sensors = sensors instanceof Array ? sensors : null; + + + if (sensors !== null) { + + this.sensors = sensors; + + this.__sensors_map = sensors.map(function(sensor) { + return (sensor.sensor() || [ 1 ]).length; + }); + + + let size = this.__sensors_map.reduce(function(a, b) { + return a + b; + }, 0); + + if (size !== this.__size.input) { + _init_network.call(this); + } + + + return true; + + } + + + return false; + + }, + + getWeights: function() { + + let layers = this.__layers; + let weights = []; + + + for (let l = 0, ll = layers.length; l < ll; l++) { + + let layer = layers[l]; + + for (let n = 0, nl = layer.length; n < nl; n++) { + + let neuron = layer[n]; + if (neuron.weights.length !== 0) { + + for (let w = 0, wl = neuron.weights.length; w < wl; w++) { + weights.push(neuron.weights[w]); + } + + } + + } + + } + + + this.__size.weight = weights.length; + + + return weights; + + }, + + setWeights: function(weights) { + + weights = weights instanceof Array ? weights : null; + + + if (weights !== null) { + + let size = this.__size.weight; + if (size === weights.length) { + + let count = 0; + let layers = this.__layers; + + for (let l = 0, ll = layers.length; l < ll; l++) { + + let layer = layers[l]; + + for (let n = 0, nl = layer.length; n < nl; n++) { + + let neuron = layer[n]; + if (neuron.weights.length !== 0) { + + for (let w = 0, wl = neuron.weights.length; w < wl; w++) { + neuron.weights[w] = weights[count++]; + } + + } + + } + + } + + + return true; + + } + + } + + + return false; + + } + + }; + + + return Composite; + +}); + diff --git a/libraries/lychee/source/ai/enn/Agent.js b/libraries/lychee/source/ai/enn/Agent.js new file mode 100644 index 00000000..b83e0a29 --- /dev/null +++ b/libraries/lychee/source/ai/enn/Agent.js @@ -0,0 +1,195 @@ + +lychee.define('lychee.ai.enn.Agent').includes([ + 'lychee.ai.Agent' +]).requires([ + 'lychee.ai.Genome', + 'lychee.ai.enn.Brain' +]).exports(function(lychee, global, attachments) { + + const _Agent = lychee.import('lychee.ai.Agent'); + const _Genome = lychee.import('lychee.ai.Genome'); + const _Brain = lychee.import('lychee.ai.enn.Brain'); + const _MUTATION_RANGE = 0.25; + const _MUTATION_RATE = 0.1; + + + + /* + * IMPLEMENTATION + */ + + let Composite = function(data) { + + let settings = Object.assign({}, data); + + + this.genome = null; + + + settings.brain = settings.brain || new _Brain(); + settings.genome = settings.genome || new _Genome(); + + _Agent.call(this, settings); + + + this.setGenome(settings.genome); + + settings = null; + + }; + + + Composite.prototype = { + + /* + * ENTITY API + */ + + // deserialize: function(blob) {}, + + serialize: function() { + + let data = _Agent.prototype.serialize.call(this); + data['constructor'] = 'lychee.ai.enn.Agent'; + + + return data; + + }, + + + + /* + * CUSTOM API + */ + + crossover: function(agent) { + + agent = lychee.interfaceof(Composite, agent) ? agent : null; + + + if (agent !== null) { + + let zw_brain = this.brain; + let zw_genome = this.genome; + let zz_brain = agent.brain; + let zz_genome = agent.genome; + + + if (zw_brain !== null && zz_brain !== null) { + zw_genome.setGene('weights', zw_brain.getWeights()); + zz_genome.setGene('weights', zz_brain.getWeights()); + } + + + let zw_dna = zw_genome.getGene('weights'); + let zz_dna = zz_genome.getGene('weights'); + + if (zw_dna.length === zz_dna.length) { + + let zw0_dna = []; + let zw1_dna = []; + let dna_split = (Math.random() * zw_dna.length) | 0; + + + for (let d = 0, dl = zw_dna.length; d < dl; d++) { + + if (d <= dna_split) { + zw0_dna.push(zw_dna[d]); + zw1_dna.push(zz_dna[d]); + } else { + zw0_dna.push(zz_dna[d]); + zw1_dna.push(zw_dna[d]); + } + + + if (Math.random() <= _MUTATION_RATE) { + zw0_dna[d] += (Math.random() * _MUTATION_RANGE * 2) - _MUTATION_RANGE; + } + + if (Math.random() <= _MUTATION_RATE) { + zw1_dna[d] += (Math.random() * _MUTATION_RANGE * 2) - _MUTATION_RANGE; + } + + } + + + let zw0_brain = null; + let zw1_brain = null; + + if (zw_brain !== null && zz_brain !== null) { + + zw0_brain = lychee.deserialize(lychee.serialize(zw_brain)); + zw0_brain.setWeights(zw0_dna); + + zw1_brain = lychee.deserialize(lychee.serialize(zz_brain)); + zw1_brain.setWeights(zw1_dna); + + } + + + let zw0_genome = lychee.deserialize(lychee.serialize(zw_genome)); + let zw1_genome = lychee.deserialize(lychee.serialize(zz_genome)); + + zw0_genome.setGene('weights', zw0_dna); + zw1_genome.setGene('weights', zw1_dna); + + let zw0_baby = new Composite({ brain: zw0_brain, genome: zw0_genome }); + let zw1_baby = new Composite({ brain: zw1_brain, genome: zw1_genome }); + + + return [ zw0_baby, zw1_baby ]; + + } + + } + + + return null; + + }, + + setGenome: function(genome) { + + genome = genome instanceof _Genome ? genome : null; + + + if (genome !== null) { + + this.genome = genome; + + + let brain = this.brain; + if (brain !== null) { + + let gene = genome.getGene('weights'); + if (gene !== null && gene.length > 0) { + + brain.setWeights(gene); + + } else { + + genome.setGene('weights', brain.getWeights()); + + } + + } + + + return true; + + } + + + return false; + + } + + + }; + + + return Composite; + +}); + diff --git a/libraries/lychee/source/ai/enn/Brain.js b/libraries/lychee/source/ai/enn/Brain.js new file mode 100644 index 00000000..c76d2517 --- /dev/null +++ b/libraries/lychee/source/ai/enn/Brain.js @@ -0,0 +1,439 @@ + +lychee.define('lychee.ai.enn.Brain').exports(function(lychee, global, attachments) { + + const _NEURON_BIAS = 1; + + + + /* + * HELPERS + */ + + const _random = function() { + return (Math.random() * 2) - 1; + }; + + const _init_network = function() { + + let input_size = this.__sensors_map.reduce(function(a, b) { + return a + b; + }, 0); + + let output_size = this.__controls_map.reduce(function(a, b) { + return a + b; + }, 0); + + + let hidden_size = 1; + let weight_size = 0; + + if (input_size > output_size) { + hidden_size = input_size; + } else { + hidden_size = output_size; + } + + + let layer_amount = 6; + + for (let l = 0; l < layer_amount; l++) { + + let prev = hidden_size; + let size = hidden_size; + + if (l === 0) { + prev = 0; + size = input_size; + } else if (l === 1) { + prev = input_size; + size = hidden_size; + } else if (l === layer_amount - 1) { + prev = hidden_size; + size = output_size; + } + + + let layer = new Array(size); + + for (let n = 0, nl = layer.length; n < nl; n++) { + + let neuron = { + value: _random(), + weights: [] + }; + + for (let p = 0; p < prev; p++) { + neuron.weights.push(_random()); + weight_size++; + } + + layer[n] = neuron; + + } + + this.__layers[l] = layer; + + } + + + this.__size.input = input_size; + this.__size.hidden = hidden_size; + this.__size.output = output_size; + this.__size.weight = weight_size; + + }; + + const _sigmoid = function(value) { + + return (1 / (1 + Math.exp((-1 * value) / 1))); + + }; + + + + /* + * IMPLEMENTATION + */ + + let Composite = function(data) { + + let settings = Object.assign({}, data); + + + this.controls = []; + this.sensors = []; + + this.__controls_map = []; + this.__layers = []; + this.__sensors_map = []; + + // cache structures + this.__size = { + input: 0, + hidden: 0, + output: 0, + weight: 0 + }; + + + this.setSensors(settings.sensors); + this.setControls(settings.controls); + + settings = null; + + }; + + + Composite.prototype = { + + /* + * ENTITY API + */ + + deserialize: function(blob) { + + if (blob.layers instanceof Array) { + this.__layers = lychee.deserialize(blob.layers); + } + + if (blob.size instanceof Object) { + this.__size = lychee.deserialize(blob.size); + } + + }, + + serialize: function() { + + let settings = {}; + let blob = {}; + + + // XXX: controls and sensors are handled by lychee.ai.Agent + // if (this.controls.length > 0) settings.controls = lychee.serialize(this.controls); + // if (this.sensors.length > 0) settings.sensors = lychee.serialize(this.sensors); + + + if (this.__layers.length > 0) { + blob.layers = lychee.serialize(this.__layers); + } + + if (this.__size.input !== 0 || this.__size.output !== 0) { + blob.size = lychee.serialize(this.__size); + } + + + return { + 'constructor': 'lychee.ai.enn.Brain', + 'arguments': [ settings ], + 'blob': Object.keys(blob).length > 0 ? blob : null + }; + + }, + + update: function(clock, delta) { + + let controls = this.controls; + let controls_map = this.__controls_map; + let layers = this.__layers; + let sensors = this.sensors; + let training = { + inputs: null, + outputs: null + }; + + + // 1. Transform Policies to Inputs + let inputs = new Array(this.__size.input); + + for (let i = 0, s = 0, sl = sensors.length; s < sl; s++) { + + let sensor = sensors[s]; + let values = sensor.sensor(); + + for (let v = 0, vl = values.length; v < vl; v++) { + inputs[i++] = values[v]; + } + + } + + training.inputs = inputs; + + + // 2. Update Input Layer + let input_layer = layers[0]; + + for (let il = 0, ill = input_layer.length; il < ill; il++) { + input_layer[il].value = inputs[il]; + } + + + // 3. Update Hidden Layers + let prev_layer = layers[0]; + + for (let l = 1, ll = layers.length; l < ll; l++) { + + let current_layer = layers[l]; + + for (let n = 0, nl = current_layer.length; n < nl; n++) { + + let neuron = current_layer[n]; + let value = 0; + + for (let p = 0, pl = prev_layer.length; p < pl; p++) { + value += prev_layer[p].value * neuron.weights[p]; + } + + neuron.value = _sigmoid(value); + + } + + prev_layer = current_layer; + + } + + + // 4. Update Output Layer + let outputs = new Array(this.__size.output); + let output_layer = layers[layers.length - 1]; + + for (let o = 0, ol = output_layer.length; o < ol; o++) { + outputs[o] = output_layer[o].value; + } + + training.outputs = outputs; + + + // 5. Transform Outputs to Policies + let offset = 0; + + for (let c = 0, cl = controls_map.length; c < cl; c++) { + + let control = controls[c]; + let length = controls_map[c]; + let values = [].slice.call(outputs, offset, length); + + if (values.length > 0) { + control.control(values); + } + + offset += length; + + } + + + return training; + + }, + + + + /* + * CUSTOM API + */ + + train: function(training) { + + training = training instanceof Object ? training : null; + + + if (training !== null) { + + // XXX: Feed Forward NN has no training + + return true; + + } + + + return false; + + }, + + setControls: function(controls) { + + controls = controls instanceof Array ? controls : null; + + + if (controls !== null) { + + this.controls = controls; + + this.__controls_map = controls.map(function(control) { + return (control.sensor() || [ 1 ]).length; + }); + + + let size = this.__controls_map.reduce(function(a, b) { + return a + b; + }, 0); + + if (size !== this.__size.output) { + _init_network.call(this); + } + + + return true; + + } + + + return false; + + }, + + setSensors: function(sensors) { + + sensors = sensors instanceof Array ? sensors : null; + + + if (sensors !== null) { + + this.sensors = sensors; + + this.__sensors_map = sensors.map(function(sensor) { + return (sensor.sensor() || [ 1 ]).length; + }); + + + let size = this.__sensors_map.reduce(function(a, b) { + return a + b; + }, 0); + + if (size !== this.__size.input) { + _init_network.call(this); + } + + + return true; + + } + + + return false; + + }, + + getWeights: function() { + + let layers = this.__layers; + let weights = []; + + + for (let l = 0, ll = layers.length; l < ll; l++) { + + let layer = layers[l]; + + for (let n = 0, nl = layer.length; n < nl; n++) { + + let neuron = layer[n]; + if (neuron.weights.length !== 0) { + + for (let w = 0, wl = neuron.weights.length; w < wl; w++) { + weights.push(neuron.weights[w]); + } + + } + + } + + } + + + this.__size.weight = weights.length; + + + return weights; + + }, + + setWeights: function(weights) { + + weights = weights instanceof Array ? weights : null; + + + if (weights !== null) { + + let size = this.__size.weight; + if (size === weights.length) { + + let count = 0; + let layers = this.__layers; + + for (let l = 0, ll = layers.length; l < ll; l++) { + + let layer = layers[l]; + + for (let n = 0, nl = layer.length; n < nl; n++) { + + let neuron = layer[n]; + if (neuron.weights.length !== 0) { + + for (let w = 0, wl = neuron.weights.length; w < wl; w++) { + neuron.weights[w] = weights[count++]; + } + + } + + } + + } + + + return true; + + } + + } + + + return false; + + } + + }; + + + return Composite; + +}); + diff --git a/libraries/lychee/source/ai/neural/Agent.js b/libraries/lychee/source/ai/neural/Agent.js deleted file mode 100644 index 7ed4e86d..00000000 --- a/libraries/lychee/source/ai/neural/Agent.js +++ /dev/null @@ -1,166 +0,0 @@ - -lychee.define('lychee.ai.neural.Agent').requires([ - 'lychee.ai.neural.Evolution', - 'lychee.ai.neural.Genome', - 'lychee.ai.neural.Network' -]).exports(function(lychee, global, attachments) { - - var _Evolution = lychee.import('lychee.ai.neural.Evolution'); - var _Genome = lychee.import('lychee.ai.neural.Genome'); - var _Network = lychee.import('lychee.ai.neural.Network'); - var _instances = {}; - var _evolutions = {}; - - - - /* - * HELPERS - */ - - var _connect = function() { - - var id = this.id; - - - var instances = _instances[id] || null; - if (instances === null) { - - instances = _instances[id] = [ this ]; - - } else { - - if (instances.indexOf(this) === -1) { - instances.push(this); - } - - } - - - var evolution = _evolutions[id] || null; - if (evolution === null) { - - var network = this.__network; - var weights = 0; - - if (network !== null) { - weights = network.countWeights(); - } - - - evolution = _evolutions[id] = new _Evolution({ - population: instances.length, - weights: weights - }); - - this.__evolution = evolution; - - } else { - - if (evolution.population !== instances.length) { - evolution.setPopulation(instances.length); - } - - this.__evolution = evolution; - - } - - }; - - var _disconnect = function() { - - var id = this.id; - - - var instances = _instances[id] || null; - if (instances !== null) { - - var index = instances.indexOf(this); - if (index !== -1) { - instances.splice(index, 1); - } - - } - - - var evolution = this.__evolution; - if (evolution !== null) { - this.__evolution = null; - } - - }; - - - - /* - * IMPLEMENTATION - */ - - var Composite = function(data) { - - var settings = Object.assign({}, data); - - - this.id = 'lychee-ai-neural-Agent-' + _id++; - - this.__evolution = null; - this.__genome = new _Genome({ - weights: this.__network.countWeights() - }); - this.__network = new _Network({ - inputs: 4, - outputs: 2, - layers: 2, - neurons: 6 - }); - - - this.setId(settings.id); - - - _connect.call(this); - -/* - * TODO: This might be some crap shit, so evaluate this - * this.network.putWeights(this.__evolution.population[_instances[this.id].indexOf(this)].weights); - */ - - }; - - - Composite.prototype = { - - reward: function() { - // TODO: Reward method - }, - - punish: function() { - // TODO: Punish method - }, - - setId: function(id) { - - id = typeof id === 'string' ? id : null; - - - if (id !== null) { - - _disconnect.call(this); - this.id = id; - _connect.call(this); - - return true; - - } - - - return false; - - } - - }; - - - return Composite; - -}); - diff --git a/libraries/lychee/source/ai/neural/Evolution.js b/libraries/lychee/source/ai/neural/Evolution.js deleted file mode 100644 index a90e5263..00000000 --- a/libraries/lychee/source/ai/neural/Evolution.js +++ /dev/null @@ -1,200 +0,0 @@ - -lychee.define('lychee.ai.neural.Evolution').exports(function(lychee, global, attachments) { - - /* - * HELPERS - */ - - var _get_genome = function(fitness) { - - var current = 0; - var genome = null; - - for (var p = 0; p < this.length; p++) { - - current += this[p].fitness; - - - if (current >= fitness) { - genome = this[p]; - break; - } - - } - - - return genome; - - }; - - - - /* - * IMPLEMENTATION - */ - - var Composite = function(data) { - - var settings = Object.assign({}, data); - - - this.fitness = { - total: 0, - average: 0, - best: -Infinity, - worst: Infinity - }; - this.population = 0; - this.weights = 0; - - - this.__population = []; - - - this.setWeights(settings.weights); - - this.setPopulation(settings.population); - - - settings = null; - - }; - - - Composite.prototype = { - - /* - * LOGIC API - */ - - update: function() { - - var oldpopulation = this.__population; - var newpopulation = []; - - - // 1. Sort Population by fitness - - oldpopulation.sort(function(a, b) { - if (a.fitness < b.fitness) return -1; - if (b.fitness > a.fitness) return 1; - return 0; - }); - - - // 2. Calculate Fitness statistics - - var fitness = this.fitness; - - fitness.total = 0; - fitness.average = 0; - fitness.best = -Infinity; - fitness.worst = Infinity; - - oldpopulation.forEach(function(genome) { - - fitness.total += genome.fitness; - fitness.best = Math.max(fitness.best, genome.fitness); - fitness.worst = Math.min(fitness.worst, genome.fitness); - - }); - - fitness.average = fitness.total / oldpopulation.length; - - - - // 3. Fill the population with fittest genomes first - - var elite = (oldpopulation.length / 5) | 0; - if (elite % 2 === 1) { - elite++; - } - - var survivors = oldpopulation.slice(oldpopulation.length - elite - 1, elite); - if (survivors.length > 0) { - newpopulation.push.apply(newpopulation, survivors); - } - - - // 4. Fill the population with random genome crossovers - - while (newpopulation.length < oldpopulation.length) { - - var zwgenome = _get_genome.call(oldpopulation, Math.random() * fitness.total); - var zzgenome = _get_genome.call(oldpopulation, Math.random() * fitness.total); - - var babies = zwgenome.crossover(zzgenome); - if (babies !== null) { - - babies[0].mutate(); - babies[1].mutate(); - - newpopulation.push(babies[0]); - newpopulation.push(babies[1]); - - } - - } - - - this.__population = newpopulation; - - }, - - - - /* - * CUSTOM API - */ - - setPopulation: function(population) { - - population = typeof population === 'number' ? population : null; - - - if (population !== null) { - - this.population = population; - this.__population = []; - - - var weights = this.weights; - - for (var p = 0; p < population; p++) { - this.__population.push(new _Genome(weights)); - } - - return true; - - } - - - return false; - - }, - - setWeights: function(weights) { - - weights = typeof weights === 'number' ? weights : null; - - - if (weights !== null) { - - this.weights = weights; - - return true; - - } - - - return false; - - } - - }; - - - return Composite; - -}); - diff --git a/libraries/lychee/source/ai/neural/Genome.js b/libraries/lychee/source/ai/neural/Genome.js deleted file mode 100644 index f68157f1..00000000 --- a/libraries/lychee/source/ai/neural/Genome.js +++ /dev/null @@ -1,84 +0,0 @@ - -lychee.define('lychee.ai.neural.Genome').exports(function(lychee, global, attachments) { - - var Composite = function(weights) { - - weights = typeof weights === 'number' ? weights : 0; - - - this.fitness = 0; - this.weights = []; - - - for (var w = 0; w < weights; w++) { - this.weights.push(Math.random() - Math.random()); - } - - }; - - Composite.prototype = { - - crossover: function(partner, babies) { - - var dnalength = this.weights.length; - - - partner = partner instanceof _Genome ? partner : null; - babies = babies instanceof Array ? babies : [ new Composite(dnalength), new Composite(dnalength) ]; - - - if (partner !== null && babies.length > 0) { - - var that = this; - - babies.forEach(function(baby, index) { - - var parent_a = (index % 2 === 0) ? that : partner; - var parent_b = (index % 2 === 0) ? partner : that; - var dnasplit = (Math.random() * (dnalength + 0.999999)) | 0; - - - for (var w0 = 0; w0 < dnasplit; w0++) { - baby.weights[w0] = parent_a.weights[w0]; - } - - for (var w1 = dnasplit; w1 < length; w1++) { - baby.weights[w1] = parent_b.weights[w1]; - } - - }); - - - return babies; - - } - - - return null; - - }, - - mutate: function() { - - // Mutation Rate: 0.1 - // Maximal Perturbation Rate: 0.3 - - this.weights = this.weights.map(function(value) { - - if (Math.random() < 0.1) { - return value + (Math.random() - Math.random()) * 0.3; - } else { - return value; - } - - }); - - } - - }; - - - return Composite; - -}); - diff --git a/libraries/lychee/source/ai/neural/Network.js b/libraries/lychee/source/ai/neural/Network.js deleted file mode 100644 index 9d602484..00000000 --- a/libraries/lychee/source/ai/neural/Network.js +++ /dev/null @@ -1,210 +0,0 @@ - -lychee.define('lychee.ai.neural.Network').exports(function(lychee, global, attachments) { - - var _BIAS = -1; - var _ACTIVATION_RESPONSE = 1; - - - - /* - * HELPERS - */ - - var _Neuron = function(weights) { - - weights = typeof weights === 'number' ? weights : 1; - - - this.weights = []; - - for (var i = 0; i < weights; i++) { - this.weights.push(Math.random() - Math.random()); - } - - // Threshold (bias) that is multiplied by -1 - this.weights.push(Math.random() - Math.random()); - - }; - - var _Layer = function(neurons, weights) { - - neurons = typeof neurons === 'number' ? neurons : 1; - weights = typeof weights === 'number' ? weights : 1; - - - this.neurons = []; - - for (var n = 0; n < neurons; n++) { - this.neurons.push(new _Neuron(weights)); - } - - }; - - var _sigmoid = function(input, response) { - return (1 / (1 + Math.exp(-1 * input / response))); - }; - - - - /* - * IMPLEMENTATION - */ - - var Composite = function(data) { - - var settings = lychee.assignsafe({ - inputs: 2, - outputs: 2, - layers: 1, - neurons: 4 - }, data); - - - this.layers = []; - - - // Input Layer - this.layers.push(new _Layer(settings.neurons, settings.inputs)); - - // Processing Layers - for (var l = 0; l < layers - 1; l++) { - this.layers.push(new _Layer(settings.neurons, settings.neurons)); - } - - // Output Layer - this.layers.push(new _Layer(settings.outputs, settings.inputs)); - - }; - - - Composite.prototype = { - - update: function(inputs) { - - var outputs = []; - - for (var l = 0; l < this.layers.length; l++) { - - var layer = this.layers[l]; - - if (l > 0) { - inputs = outputs; - outputs = []; - } - - - for (var n = 0; n < layer.neurons.length; n++) { - - var count = 0; - var neuron = layer.neurons[n]; - - var netinput = 0; - var wl = neuron.weights.length; - - for (var w = 0; w < wl - 1; w++) { - netinput += neuron.weights[w] * inputs[count++]; - } - - netinput += neuron.weights[wl - 1] * _BIAS; - - outputs.push(_sigmoid(netinput, _ACTIVATION_RESPONSE)); - - } - - } - - - return outputs; - - }, - - countWeights: function() { - - var amount = 0; - - - var layers = this.layers; - if (layers.length > 0) { - - layers.forEach(function(layer) { - - layer.neurons.forEach(function(neuron) { - amount += neuron.weights.length; - }); - - }); - - } - - - return amount; - - }, - - getWeights: function() { - - var layers = this.layers; - if (layers.length > 0) { - - var weights = []; - - - layers.forEach(function(layer) { - - layer.neurons.forEach(function(neuron) { - - neuron.weights.forEach(function(weight, w) { - weights.push(weight); - }); - - }); - - }); - - - return weights; - - } - - - return null; - - }, - - setWeights: function(weights) { - - var layers = this.layers; - if (layers.length > 0) { - - var index = 0; - - - layers.forEach(function(layer) { - - layer.neurons.forEach(function(neuron) { - - neuron.weights.forEach(function(weight, w) { - neuron.weights[w] = weights[index++]; - }); - - }); - - }); - - - return true; - - } - - - return false; - - } - - }; - - - return Composite; - -}); - diff --git a/libraries/lychee/source/ai/qnn/Brain.js b/libraries/lychee/source/ai/qnn/Brain.js new file mode 100644 index 00000000..d27f9e8b --- /dev/null +++ b/libraries/lychee/source/ai/qnn/Brain.js @@ -0,0 +1,379 @@ + +lychee.define('lychee.ai.qnn.Brain').exports(function(lychee, global, attachments) { + + const _MOMENTUM = 0.3; + const _LEARNING_RATE = 0.3; + + + + /* + * HELPERS + */ + + const _init_network = function() { + + let input_size = this.__sensors_map.reduce(function(a, b) { + return a + b; + }, 0); + + let output_size = this.__controls_map.reduce(function(a, b) { + return a + b; + }, 0); + + + let hidden_size = 1; + + if (input_size > output_size) { + hidden_size = input_size; + } else { + hidden_size = output_size; + } + + + let layer_amount = 6; + + for (let l = 0; l < layer_amount; l++) { + + let prev = hidden_size; + let size = hidden_size; + + if (l === 0) { + prev = 0; + size = input_size; + } else if (l === 1) { + prev = input_size; + size = hidden_size; + } else if (l === layer_amount - 1) { + prev = hidden_size; + size = output_size; + } + + + let layer = new Array(size); + + for (let n = 0, nl = layer.length; n < nl; n++) { + + let neuron = { + bias: (Math.random() * 0.4 - 0.2), + change: 0.0, + delta: 0.0, + weights: [], + output: 0.5 + }; + + for (let p = 0; p < prev; p++) { + neuron.weights.push(Math.random() * 0.4 - 0.2); + } + + layer[n] = neuron; + + } + + this.__layers[l] = layer; + + } + + }; + + const _train_network = function(inputs, outputs) { + + let ll = this.__layers.length; + + for (let l = ll - 1; l >= 0; l--) { + + let layer = this.__layers[l]; + + for (let n = 0, nl = layer.length; n < nl; n++) { + + let neuron = layer[n]; + let value = 0; + + if (l === ll - 1) { + + value = outputs[n] - neuron.output; + + } else { + + let others = this.__layers[l + 1]; + + for (let o = 0, ol = others.length; o < ol; o++) { + + let other = others[o]; + + value += other.delta * other.weights[n]; + + } + + } + + neuron.delta = value * neuron.output * (1 - neuron.output); + + } + + } + + + for (let l = 1; l < ll; l++) { + + let layer = this.__layers[l]; + let prev = this.__layers[l - 1]; + + for (let n = 0, nl = layer.length; n < nl; n++) { + + let neuron = layer[n]; + let delta = neuron.delta; + + for (let p = 0, pl = prev.length; p < pl; p++) { + + let change = (_LEARNING_RATE * delta * prev[p].output) + (_MOMENTUM * neuron.change); + + neuron.change = change; + neuron.weights[p] += change; + + } + + neuron.bias += (_LEARNING_RATE * delta); + + } + + } + + }; + + const _sigmoid = function(value) { + + return (1 / (1 + Math.exp(-1 * value))); + + }; + + + + /* + * IMPLEMENTATION + */ + + let Composite = function(data) { + + let settings = Object.assign({}, data); + + + this.controls = []; + this.sensors = []; + + this.__controls_map = []; + this.__layers = []; + this.__sensors_map = []; + + + this.setSensors(settings.sensors); + this.setControls(settings.controls); + + settings = null; + + }; + + + Composite.prototype = { + + /* + * ENTITY API + */ + + // deserialize: function(blob) {}, + + serialize: function() { + + let settings = {}; + let blob = {}; + + + if (this.controls.length > 0) settings.controls = lychee.serialize(this.controls); + if (this.sensors.length > 0) settings.sensors = lychee.serialize(this.sensors); + + + // TODO: Brain serialization + // in form of Genome (for qnn.Agent mutate / crossover) + + + return { + 'constructor': 'lychee.ai.qnn.Brain', + 'arguments': [ settings ], + 'blob': Object.keys(blob).length > 0 ? blob : null + }; + + }, + + update: function(clock, delta) { + + let controls = this.controls; + let controls_map = this.__controls_map; + let sensors = this.sensors; + let training = { + inputs: null, + outputs: null + }; + + + let inputs = []; + + for (let s = 0, sl = sensors.length; s < sl; s++) { + + let sensor = sensors[s]; + let values = sensor.sensor(); + + inputs.push.apply(inputs, values); + + } + + training.inputs = inputs; + + + let outputs = []; + + for (let l = 0, ll = this.__layers.length; l < ll; l++) { + + let layer = this.__layers[l]; + + if (l > 0 && layer.length > 0) { + inputs = outputs; + outputs = []; + } + + for (let n = 0, nl = layer.length; n < nl; n++) { + + let count = 0; + let neuron = layer[n]; + let value = neuron.bias; + + let wl = neuron.weights.length; + + for (let w = 0; w < wl; w++) { + value += neuron.weights[w] * inputs[count++]; + } + + neuron.output = _sigmoid(value); + + + outputs.push(neuron.output); + + } + + } + + training.outputs = outputs; + + + let offset = 0; + + for (let c = 0, cl = controls_map.length; c < cl; c++) { + + let control = controls[c]; + let length = controls_map[c]; + let values = [].slice.call(outputs, offset, length); + + if (values.length > 0) { + control.control(values); + } + + offset += length; + + } + + + return training; + + }, + + + + /* + * CUSTOM API + */ + + train: function(training) { + + training = training instanceof Object ? training : null; + + + if (training !== null) { + + let iterations = training.iterations || (1 / _LEARNING_RATE) * 30; + let inputs = training.inputs || null; + let outputs = training.outputs || null; + + + if (inputs !== null && outputs !== null) { + + for (let i = 0; i < iterations; i++) { + _train_network.call(this, inputs, outputs); + } + + + return true; + + } + + } + + + return false; + + }, + + setControls: function(controls) { + + controls = controls instanceof Array ? controls : null; + + + if (controls !== null) { + + this.controls = controls; + + this.__controls_map = controls.map(function(control) { + return (control.sensor() || [ 1 ]).length; + }); + + _init_network.call(this); + + + return true; + + } + + + return false; + + }, + + setSensors: function(sensors) { + + sensors = sensors instanceof Array ? sensors : null; + + + if (sensors !== null) { + + this.sensors = sensors; + + this.__sensors_map = sensors.map(function(sensor) { + return (sensor.sensor() || [ 1 ]).length; + }); + + _init_network.call(this); + + + return true; + + } + + + return false; + + } + + }; + + + return Composite; + +}); + diff --git a/libraries/lychee/source/app/Blueprint.js b/libraries/lychee/source/app/Blueprint.js index f9a5b73f..6854b2b3 100644 --- a/libraries/lychee/source/app/Blueprint.js +++ b/libraries/lychee/source/app/Blueprint.js @@ -46,10 +46,9 @@ lychee.define('lychee.app.Blueprint').requires([ let entity = null; let type = this.type; - let x1 = -1/2 * this.width; - let x2 = 1/2 * this.width; - let y1 = -1/2 * this.height; - let y2 = 1/2 * this.height; + let x1 = -1 / 2 * this.width; + let x2 = 1 / 2 * this.width; + let y1 = -1 / 2 * this.height; let off_x = x1 + 32; let off_y = y1 + 32; let pos_x = 0; @@ -92,7 +91,7 @@ lychee.define('lychee.app.Blueprint').requires([ entity.setPosition({ x: pos_x, - y: pos_y - 3/2 * this.height + y: pos_y - 3 / 2 * this.height }); entity.addEffect(new _Position({ @@ -135,7 +134,7 @@ lychee.define('lychee.app.Blueprint').requires([ entity.setPosition({ x: pos_x, - y: pos_y - 3/2 * this.height + y: pos_y - 3 / 2 * this.height }); entity.addEffect(new _Position({ @@ -173,7 +172,7 @@ lychee.define('lychee.app.Blueprint').requires([ entity.setPosition({ x: pos_x, - y: pos_y - 3/2 * this.height + y: pos_y - 3 / 2 * this.height }); entity.addEffect(new _Position({ diff --git a/libraries/lychee/source/app/Element.js b/libraries/lychee/source/app/Element.js index b99693fa..73f76e56 100644 --- a/libraries/lychee/source/app/Element.js +++ b/libraries/lychee/source/app/Element.js @@ -31,10 +31,8 @@ lychee.define('lychee.app.Element').requires([ ]; - let x1 = -1/2 * this.width; - let x2 = 1/2 * this.width; - let y1 = -1/2 * this.height; - let y2 = 1/2 * this.height; + let x1 = -1 / 2 * this.width; + let y1 = -1 / 2 * this.height; if (content.length % 2 === 0) { @@ -53,13 +51,13 @@ lychee.define('lychee.app.Element').requires([ if (label !== null) { - label.position.x = x1 + 16 + label.width / 2; - label.position.y = y1 + offset + label.height / 2; + label.position.x = x1 + 16 + label.width / 2; + label.position.y = y1 + offset + label.height / 2; label.visible = true; - entity.width = 1/2 * (this.width - 32); - entity.position.x = 1/4 * (this.width - 32); - entity.position.y = y1 + offset + entity.height / 2; + entity.width = 1 / 2 * (this.width - 32); + entity.position.x = 1 / 4 * (this.width - 32); + entity.position.y = y1 + offset + entity.height / 2; entity.visible = true; entity.trigger('relayout'); @@ -97,9 +95,7 @@ lychee.define('lychee.app.Element').requires([ } - let entities = this.entities; - let index = -1; - let order_w = 0; + let order_w = 0; entity = layout[0]; diff --git a/libraries/lychee/source/app/Entity.js b/libraries/lychee/source/app/Entity.js index aa8f3dc9..3ab0db60 100644 --- a/libraries/lychee/source/app/Entity.js +++ b/libraries/lychee/source/app/Entity.js @@ -162,11 +162,11 @@ lychee.define('lychee.app.Entity').exports(function(lychee, global, attachments) if (this.depth !== 0) settings.depth = this.depth; if (this.radius !== 0) settings.radius = this.radius; - if (this.alpha !== 1) settings.alpha = this.alpha; + if (this.alpha !== 1) settings.alpha = this.alpha; if (this.collision !== Composite.COLLISION.none) settings.collision = this.collision; if (this.shape !== Composite.SHAPE.rectangle) settings.shape = this.shape; - if (this.state !== 'default') settings.state = this.state; - if (Object.keys(this.__states).length > 1) settings.states = this.__states; + if (this.state !== 'default') settings.state = this.state; + if (Object.keys(this.__states).length > 1) settings.states = this.__states; if (this.position.x !== 0 || this.position.y !== 0 || this.position.z !== 0) { @@ -242,9 +242,9 @@ lychee.define('lychee.app.Entity').exports(function(lychee, global, attachments) let effects = this.effects; - for (let e = 0, el = this.effects.length; e < el; e++) { + for (let e = 0, el = effects.length; e < el; e++) { - let effect = this.effects[e]; + let effect = effects[e]; if (effect.update(this, clock, delta) === false) { this.removeEffect(effect); el--; @@ -269,8 +269,10 @@ lychee.define('lychee.app.Entity').exports(function(lychee, global, attachments) let ax = position.x; let ay = position.y; + let az = position.z; let bx = this.position.x; let by = this.position.y; + let bz = this.position.z; let shape = this.shape; @@ -305,7 +307,7 @@ lychee.define('lychee.app.Entity').exports(function(lychee, global, attachments) let hdepth = this.depth / 2; let colX = (ax >= bx - hwidth) && (ax <= bx + hwidth); let colY = (ay >= by - hheight) && (ay <= by + hheight); - let colZ = (az >= bz - hheight) && (az <= bz + hheight); + let colZ = (az >= bz - hdepth) && (az <= bz + hdepth); return colX && colY && colZ; @@ -366,12 +368,12 @@ lychee.define('lychee.app.Entity').exports(function(lychee, global, attachments) setAlpha: function(alpha) { - alpha = (typeof alpha === 'number' && alpha >= 0 && alpha <= 1) ? alpha : null; + alpha = typeof alpha === 'number' ? alpha : null; if (alpha !== null) { - this.alpha = alpha; + this.alpha = Math.min(Math.max(alpha, 0), 1); return true; diff --git a/libraries/lychee/source/app/Layer.js b/libraries/lychee/source/app/Layer.js index 864ccfb2..e2432993 100644 --- a/libraries/lychee/source/app/Layer.js +++ b/libraries/lychee/source/app/Layer.js @@ -469,9 +469,9 @@ lychee.define('lychee.app.Layer').requires([ } let effects = this.effects; - for (let ef = 0, efl = this.effects.length; ef < efl; ef++) { + for (let ef = 0, efl = effects.length; ef < efl; ef++) { - let effect = this.effects[ef]; + let effect = effects[ef]; if (effect.update(this, clock, delta) === false) { this.removeEffect(effect); efl--; @@ -666,7 +666,7 @@ lychee.define('lychee.app.Layer').requires([ getEntity: function(id, position) { - id = typeof id === 'string' ? id : null; + id = typeof id === 'string' ? id : null; position = position instanceof Object ? position : null; @@ -758,9 +758,12 @@ lychee.define('lychee.app.Layer').requires([ setEntities: function(entities) { + entities = entities instanceof Array ? entities : null; + + let all = true; - if (entities instanceof Array) { + if (entities !== null) { for (let e = 0, el = entities.length; e < el; e++) { diff --git a/libraries/lychee/source/app/Main.js b/libraries/lychee/source/app/Main.js index 6be6ca6c..e76ec89f 100644 --- a/libraries/lychee/source/app/Main.js +++ b/libraries/lychee/source/app/Main.js @@ -627,6 +627,9 @@ lychee.define('lychee.app.Main').requires([ } + + return true; + } else { if (oldstate !== null) { @@ -637,10 +640,15 @@ lychee.define('lychee.app.Main').requires([ } + + if (id === null) { + return true; + } + } - return true; + return false; } diff --git a/libraries/lychee/source/app/State.js b/libraries/lychee/source/app/State.js index e19350f4..eee8be0f 100644 --- a/libraries/lychee/source/app/State.js +++ b/libraries/lychee/source/app/State.js @@ -83,8 +83,8 @@ lychee.define('lychee.app.State').requires([ if (renderer !== null) { let position = { - x: 1/2 * renderer.width, - y: 1/2 * renderer.height + x: 1 / 2 * renderer.width, + y: 1 / 2 * renderer.height }; diff --git a/libraries/lychee/source/app/layer/Table.js b/libraries/lychee/source/app/layer/Table.js index 7fa62279..26f6f240 100644 --- a/libraries/lychee/source/app/layer/Table.js +++ b/libraries/lychee/source/app/layer/Table.js @@ -51,8 +51,8 @@ lychee.define('lychee.app.layer.Table').requires([ let label = this.__label; let type = this.type; let value = this.value; - let x1 = -1/2 * this.width; - let y1 = -1/2 * this.height; + let x1 = -1 / 2 * this.width; + let y1 = -1 / 2 * this.height; let dim_x = 0; let dim_y = 0; let off_x = 0; @@ -329,7 +329,6 @@ lychee.define('lychee.app.layer.Table').requires([ let entities = this.entities; let font = this.font; let label = this.__label; - let model = this.model; let position = this.position; let type = this.type; let value = this.value; diff --git a/libraries/lychee/source/core/Asset.js b/libraries/lychee/source/core/Asset.js index 8ee6bdcc..f9983b64 100644 --- a/libraries/lychee/source/core/Asset.js +++ b/libraries/lychee/source/core/Asset.js @@ -1,11 +1,6 @@ lychee.Asset = typeof lychee.Asset !== 'undefined' ? lychee.Asset : (function(global) { - const lychee = global.lychee; - const console = global.console; - - - /* * HELPERS */ diff --git a/libraries/lychee/source/core/Debugger.js b/libraries/lychee/source/core/Debugger.js index a4b21426..7a7b5225 100644 --- a/libraries/lychee/source/core/Debugger.js +++ b/libraries/lychee/source/core/Debugger.js @@ -196,6 +196,10 @@ lychee.Debugger = typeof lychee.Debugger !== 'undefined' ? lychee.Debugger : (fu if (tmp2.charAt(0) === '(') tmp2 = tmp2.substr(1); if (tmp2.charAt(tmp2.length - 1) === ')') tmp2 = tmp2.substr(0, tmp2.length - 1); + // XXX: Thanks, Blink. Thanks -_- + if (tmp2.substr(0, 4) === 'http') { + tmp2 = '/' + tmp2.split('/').slice(3).join('/'); + } let tmp3 = tmp2.split(':'); @@ -212,7 +216,9 @@ lychee.Debugger = typeof lychee.Debugger !== 'undefined' ? lychee.Debugger : (fu let orig = Error.prepareStackTrace; - Error.prepareStackTrace = function(err, stack) { return stack; }; + Error.prepareStackTrace = function(err, stack) { + return stack; + }; Error.captureStackTrace(new Error()); diff --git a/libraries/lychee/source/core/Definition.js b/libraries/lychee/source/core/Definition.js index c66e131a..168042e3 100644 --- a/libraries/lychee/source/core/Definition.js +++ b/libraries/lychee/source/core/Definition.js @@ -9,33 +9,6 @@ lychee.Definition = typeof lychee.Definition !== 'undefined' ? lychee.Definition * HELPERS */ - const _lint = function(method) { - - let code = method.toString(); - let file = this.__file; - let lines = code.split('\n'); - - - lines.forEach(function(line, l) { - - let curr = line.trim(); - let next = (lines[l + 1] || '').trim(); - - if (curr.substr(0, 2) !== '//') { - - let next_lim = next.substr(0, 1); - - if (curr.substr(curr.length - 1, 1) === ')' && next_lim !== '}' && next_lim !== ']') { - console.warn('lychee.Definition: Missing trailing ";" (' + file + '#L' + l + ')'); - console.warn(curr); - } - - } - - }); - - }; - const _fuzz_asset = function(type) { let asset = { @@ -254,8 +227,7 @@ lychee.Definition = typeof lychee.Definition !== 'undefined' ? lychee.Definition serialize: function() { - let settings = {}; - let blob = {}; + let blob = {}; if (Object.keys(this._attaches).length > 0) { @@ -332,10 +304,7 @@ lychee.Definition = typeof lychee.Definition !== 'undefined' ? lychee.Definition if (callback !== null) { - this._exports = callback; - _lint.call(this, this._exports); - } @@ -404,7 +373,6 @@ lychee.Definition = typeof lychee.Definition !== 'undefined' ? lychee.Definition if (callback !== null) { this._supports = callback; - _lint.call(this, this._supports); } diff --git a/libraries/lychee/source/core/Environment.js b/libraries/lychee/source/core/Environment.js index 52c562cc..9ff774c8 100644 --- a/libraries/lychee/source/core/Environment.js +++ b/libraries/lychee/source/core/Environment.js @@ -101,158 +101,99 @@ lychee.Environment = typeof lychee.Environment !== 'undefined' ? lychee.Environm * HELPERS */ - const _mock_feature = function(name) { - - switch (name) { - - case 'href': - return '1337'; - break; - - case 'innerWidth': - case 'innerHeight': - return 1337; - break; - - case 'addEventListener': - case 'createElement': - case 'on': - case 'querySelectorAll': - case 'read': - case 'requestAnimationFrame': - case 'require': - case 'setInterval': - case 'setTimeout': - case 'write': - case 'CanvasRenderingContext2D': - case 'FileReader': - case 'WebSocket': - case 'XMLHttpRequest': - return function(){}; - break; - - case 'body': - case 'document': - case 'location': - case 'localStorage': - case 'process': - case 'sessionStorage': - case 'stdin': - case 'stdout': - case 'Storage': - return _mock_detector({}); - break; - - default: - break; + const _detect_features = function(source) { + if (typeof Proxy === 'undefined') { + return source; } - console.error('lychee.Environment: Unknown Datatype ("' + name + '")'); + let clone = {}; + let proxy = new Proxy(clone, { - return undefined; + get: function(target, name) { - }; - - const _mock_detector = function(source) { - - if (typeof Proxy !== 'undefined') { + // XXX: Remove this and console will crash your program + if (name === 'splice') return undefined; - let clone = {}; - let proxy = new Proxy(clone, { - get: function(target, name) { - - if (name === 'splice') { - return undefined; - } else if (target[name] !== undefined) { - return target[name]; - } + if (target[name] === undefined) { let type = typeof source[name]; - if (/number|string|function/g.test(type)) { + if (/boolean|number|string|function/g.test(type)) { target[name] = source[name]; } else if (/object/g.test(type)) { - target[name] = _mock_detector(source[name]); + target[name] = _detect_features(source[name]); } else if (/undefined/g.test(type)) { - target[name] = _mock_feature(name); + target[name] = undefined; } - return target[name]; + if (target[name] === undefined) { + console.error('lychee.Environment: Unknown feature (data type) "' + name + '" in bootstrap.js'); + } } - }); - - proxy.toJSON = function() { - let data = {}; + return target[name]; - Object.keys(clone).map(function(key) { + } - let typ = typeof clone[key]; - if (/toJSON/g.test(key)) { - // XXX: Do nothing - } else if (/number|string/g.test(typ)) { - data[key] = typ; - } else if (/object/g.test(typ)) { - data[key] = clone[key]; - } else if (/function/g.test(typ)) { - data[key] = 'function'; - } + }); - }); - return data; + proxy.toJSON = function() { - }; + let data = {}; + Object.keys(clone).forEach(function(key) { - return proxy; + if (/toJSON/g.test(key) === false) { - } + let type = typeof clone[key]; + if (/boolean|number|string|function/g.test(type)) { + data[key] = type; + } else if (/object/g.test(type)) { + data[key] = clone[key]; + } + } - return null; + }); - }; + return data; - const _inject_features = function(source, features) { + }; - let target = this; - let keys = Object.keys(features); - if (keys.length > 0) { + return proxy; - keys.forEach(function(key) { + }; - let type = features[key]; - if (type instanceof Object) { + const _inject_features = function(source, features) { - if (source[key] instanceof Object) { + let target = this; - target[key] = source[key]; - _inject_features.call(target[key], source[key], type); + Object.keys(features).forEach(function(key) { - } + let type = features[key]; + if (/boolean|number|string|function/g.test(type)) { - } else { + target[key] = source[key]; - // XXX: This is pretty much the only Exception -_- - if (key === 'href') return; + } else if (typeof type === 'object') { + if (typeof source[key] === 'object') { - if (/number|string|function/g.test(type)) { - target[key] = source[key]; - } + target[key] = source[key]; + _inject_features.call(target[key], source[key], type); } - }); + } - } + }); }; @@ -270,7 +211,7 @@ lychee.Environment = typeof lychee.Environment !== 'undefined' ? lychee.Environm if (definition._supports !== null) { - let detector = _mock_detector(global); + let detector = _detect_features(Composite.__FEATURES || global); if (detector !== null) { supported = definition._supports.call(detector, lychee, detector); @@ -400,8 +341,7 @@ lychee.Environment = typeof lychee.Environment !== 'undefined' ? lychee.Environm let namespace = _get_namespace.call(this.global, definition.id); - let packageId = definition.packageId; - let classId = definition.classId.split('.').pop(); + let identifier = definition.classId.split('.').pop(); if (this.debug === true) { @@ -418,22 +358,7 @@ lychee.Environment = typeof lychee.Environment !== 'undefined' ? lychee.Environm let template = null; if (definition._exports !== null) { - if (this.debug === true) { - - try { - - template = definition._exports.call( - definition._exports, - this.global.lychee, - this.global, - definition._attaches - ) || null; - - } catch(err) { - lychee.Debugger.report(this, err, definition); - } - - } else { + try { template = definition._exports.call( definition._exports, @@ -442,6 +367,8 @@ lychee.Environment = typeof lychee.Environment !== 'undefined' ? lychee.Environm definition._attaches ) || null; + } catch (err) { + lychee.Debugger.report(this, err, definition); } } @@ -501,8 +428,7 @@ lychee.Environment = typeof lychee.Environment !== 'undefined' ? lychee.Environm } - // Define classId in namespace - Object.defineProperty(namespace, classId, { + Object.defineProperty(namespace, identifier, { value: template, writable: false, enumerable: true, @@ -510,12 +436,13 @@ lychee.Environment = typeof lychee.Environment !== 'undefined' ? lychee.Environm }); - namespace[classId].displayName = definition.id; - namespace[classId].prototype = {}; + namespace[identifier].displayName = definition.id; + namespace[identifier].prototype = {}; + namespace[identifier].prototype.displayName = definition.id; let tplenums = {}; - let tplmethods = [ namespace[classId].prototype ]; + let tplmethods = [ namespace[identifier].prototype ]; for (let i = 0, il = includes.length; i < il; i++) { @@ -564,11 +491,11 @@ lychee.Environment = typeof lychee.Environment !== 'undefined' ? lychee.Environm for (let e in tplenums) { - namespace[classId][e] = tplenums[e]; + namespace[identifier][e] = tplenums[e]; } Object.assign.apply(lychee, tplmethods); - Object.freeze(namespace[classId].prototype); + Object.freeze(namespace[identifier].prototype); /* @@ -577,23 +504,25 @@ lychee.Environment = typeof lychee.Environment !== 'undefined' ? lychee.Environm } else { - namespace[classId] = template; - namespace[classId].displayName = definition.id; + namespace[identifier] = template; + namespace[identifier].displayName = definition.id; if (template instanceof Object) { - Object.freeze(namespace[classId]); + Object.freeze(namespace[identifier]); } } } else { - namespace[classId] = function() {}; - namespace[classId].displayName = definition.id; + namespace[identifier] = function() {}; + namespace[identifier].displayName = definition.id; + namespace[identifier].prototype = {}; + namespace[identifier].prototype.displayName = definition.id; - this.global.console.error('lychee-Environment (' + this.id + '): Invalid Definition "' + definition.id + '", it is a Dummy now.'); + this.global.console.error('lychee-Environment (' + this.id + '): Invalid Definition "' + definition.id + '", it is replaced with a Dummy Composite'); } @@ -914,14 +843,15 @@ lychee.Environment = typeof lychee.Environment !== 'undefined' ? lychee.Environm this.__cache = { - active: false, - start: 0, - end: 0, - retries: 0, - timeout: 0, - load: [], - ready: [], - track: [] + active: false, + assimilations: [], + start: 0, + end: 0, + retries: 0, + timeout: 0, + load: [], + ready: [], + track: [] }; this.__features = {}; @@ -966,6 +896,7 @@ lychee.Environment = typeof lychee.Environment !== 'undefined' ? lychee.Environm * BOOTSTRAP API */ + Composite.__FEATURES = null; Composite.__FILENAME = null; @@ -1161,7 +1092,29 @@ lychee.Environment = typeof lychee.Environment !== 'undefined' ? lychee.Environm } - if (newPackageId !== null && newPackageId !== oldPackageId) { + let assimilation = true; + + for (let p = 0, pl = this.packages.length; p < pl; p++) { + + let id = this.packages[p].id; + if (id === oldPackageId || id === newPackageId) { + assimilation = false; + break; + } + + } + + + if (assimilation === true) { + + if (this.debug === true) { + this.global.console.log('lychee-Environment (' + this.id + '): Assimilating Definition "' + definition.id + '"'); + } + + + this.__cache.assimilations.push(definition.id); + + } else if (newPackageId !== null && newPackageId !== oldPackageId) { if (this.debug === true) { this.global.console.log('lychee-Environment (' + this.id + '): Injecting Definition "' + definition.id + '" as "' + newPackageId + '.' + definition.classId + '"'); @@ -1292,18 +1245,10 @@ lychee.Environment = typeof lychee.Environment !== 'undefined' ? lychee.Environm } - if (this.debug === true) { - - try { - callback.call(this.global, null); - } catch(err) { - lychee.Debugger.report(this, err, null); - } - - } else { - + try { callback.call(this.global, null); - + } catch (err) { + lychee.Debugger.report(this, err, null); } }; @@ -1315,18 +1260,10 @@ lychee.Environment = typeof lychee.Environment !== 'undefined' ? lychee.Environm } - if (this.debug === true) { - - try { - callback.call(this.global, this.global); - } catch(err) { - lychee.Debugger.report(this, err, null); - } - - } else { - + try { callback.call(this.global, this.global); - + } catch (err) { + lychee.Debugger.report(this, err, null); } }; @@ -1347,6 +1284,22 @@ lychee.Environment = typeof lychee.Environment !== 'undefined' ? lychee.Environm } + let assimilations = cache.assimilations; + if (assimilations.length > 0) { + + for (let a = 0, al = assimilations.length; a < al; a++) { + + let identifier = assimilations[a]; + let definition = that.definitions[identifier] || null; + if (definition !== null) { + _export_definition.call(that, definition); + } + + } + + } + + cache.end = Date.now(); diff --git a/libraries/lychee/source/core/Package.js b/libraries/lychee/source/core/Package.js index 7f00ba07..5dd69eac 100644 --- a/libraries/lychee/source/core/Package.js +++ b/libraries/lychee/source/core/Package.js @@ -384,17 +384,9 @@ lychee.Package = typeof lychee.Package !== 'undefined' ? lychee.Package : (funct if (result === true) { - - if (lychee.debug === true) { - console.info('lychee.Package-' + that.id + ': Package at ' + this.url + ' ready'); - } - + console.info('lychee.Package-' + that.id + ': Package at "' + this.url + '" ready.'); } else { - - if (lychee.debug === true) { - console.error('lychee.Package-' + that.id + ': Package at ' + this.url + ' corrupt'); - } - + console.error('lychee.Package-' + that.id + ': Package at "' + this.url + '" corrupt.'); } }; @@ -468,10 +460,8 @@ lychee.Package = typeof lychee.Package !== 'undefined' ? lychee.Package : (funct } else { - if (lychee.debug === true) { - let info = Object.keys(tags).length > 0 ? ('(' + JSON.stringify(tags) + ')') : ''; - console.error('lychee.Package-' + this.id + ': Invalid Definition "' + id + '" ' + info); - } + let info = Object.keys(tags).length > 0 ? ('(' + JSON.stringify(tags) + ')') : ''; + console.error('lychee.Package-' + this.id + ': Invalid Definition "' + id + '" ' + info); return false; diff --git a/libraries/lychee/source/core/lychee.js b/libraries/lychee/source/core/lychee.js index 8bb9b202..2b7efe25 100644 --- a/libraries/lychee/source/core/lychee.js +++ b/libraries/lychee/source/core/lychee.js @@ -1,6 +1,10 @@ lychee = typeof lychee !== 'undefined' ? lychee : (function(global) { + const _INTERFACEOF_CACHE = {}; + + + /* * NAMESPACE */ @@ -15,71 +19,6 @@ lychee = typeof lychee !== 'undefined' ? lychee : (function(global) { * POLYFILLS */ - if (typeof Array.prototype.fill !== 'function') { - - Array.prototype.fill = function(value/*, start = 0, end = this.length */) { - - if (this === null || this === undefined) { - throw new TypeError('Array.prototype.fill called on null or undefined'); - } - - let list = Object(this); - let length = list.length >>> 0; - let start = arguments[1]; - let end = arguments[2]; - let rel_start = start === undefined ? 0 : start >> 0; - let rel_end = end === undefined ? length : end >> 0; - - - let i_start = rel_start < 0 ? Math.max(length + rel_start, 0) : Math.min(rel_start, length); - let i_end = rel_end < 0 ? Math.max(length + rel_end, 0) : Math.min(rel_end, length); - - for (let i = i_start; i < i_end; i++) { - list[i] = value; - } - - - return list; - - }; - - } - - if (typeof Array.prototype.find !== 'function') { - - Array.prototype.find = function(predicate/*, thisArg */) { - - if (this === null || this === undefined) { - throw new TypeError('Array.prototype.find called on null or undefined'); - } - - if (typeof predicate !== 'function') { - throw new TypeError('predicate must be a function'); - } - - - let list = Object(this); - let length = list.length >>> 0; - let thisArg = arguments.length >= 2 ? arguments[1] : void 0; - let value; - - for (let i = 0; i < length; i++) { - - value = list[i]; - - if (predicate.call(thisArg, value, i, list)) { - return value; - } - - } - - - return undefined; - - }; - - } - if (typeof Array.prototype.unique !== 'function') { Array.prototype.unique = function() { @@ -127,12 +66,16 @@ lychee = typeof lychee !== 'undefined' ? lychee : (function(global) { if (isFinite(this.valueOf()) === true) { - return this.getUTCFullYear() + '-' + - _format_date(this.getUTCMonth() + 1) + '-' + - _format_date(this.getUTCDate()) + 'T' + - _format_date(this.getUTCHours()) + ':' + - _format_date(this.getUTCMinutes()) + ':' + - _format_date(this.getUTCSeconds()) + 'Z'; + let str = ''; + + str += this.getUTCFullYear() + '-'; + str += _format_date(this.getUTCMonth() + 1) + '-'; + str += _format_date(this.getUTCDate()) + 'T'; + str += _format_date(this.getUTCHours()) + ':'; + str += _format_date(this.getUTCMinutes()) + ':'; + str += _format_date(this.getUTCSeconds()) + 'Z'; + + return str; } @@ -151,39 +94,6 @@ lychee = typeof lychee !== 'undefined' ? lychee : (function(global) { } - if (typeof Object.assign !== 'function') { - - Object.assign = function(object /*, ... sources */) { - - if (object !== Object(object)) { - throw new TypeError('Object.assign called on a non-object'); - } - - - for (let a = 1, al = arguments.length; a < al; a++) { - - let source = arguments[a]; - if (source != null) { - - for (let key in source) { - - if (Object.prototype.hasOwnProperty.call(source, key) === true) { - object[key] = source[key]; - } - - } - - } - - } - - - return object; - - }; - - } - if (typeof Object.filter !== 'function') { Object.filter = function(object, predicate/*, thisArg */) { @@ -264,31 +174,6 @@ lychee = typeof lychee !== 'undefined' ? lychee : (function(global) { } - if (typeof Object.keys !== 'function') { - - Object.keys = function(object) { - - if (object !== Object(object)) { - throw new TypeError('Object.keys called on a non-object'); - } - - - let keys = []; - - for (let prop in object) { - - if (Object.prototype.hasOwnProperty.call(object, prop)) { - keys.push(prop); - } - - } - - return keys; - - }; - - } - if (typeof Object.map !== 'function') { Object.map = function(object, predicate/*, thisArg */) { @@ -472,14 +357,6 @@ lychee = typeof lychee !== 'undefined' ? lychee : (function(global) { } - if (typeof String.prototype.trim !== 'function') { - - String.prototype.trim = function() { - return this.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, ""); - }; - - } - /* @@ -533,7 +410,7 @@ lychee = typeof lychee !== 'undefined' ? lychee : (function(global) { * IMPLEMENTATION */ - let Module = { + const Module = { debug: true, environment: _environment, @@ -543,7 +420,7 @@ lychee = typeof lychee !== 'undefined' ? lychee : (function(global) { lychee: '/opt/lycheejs', project: null }, - VERSION: "2016-Q3", + VERSION: "2016-Q4", @@ -700,15 +577,46 @@ lychee = typeof lychee !== 'undefined' ? lychee : (function(global) { interfaceof: function(template, instance) { - let valid = false; - let method, property; + if (instance === undefined) { + return false; + } + + + let tname = template.displayName; + let iname = instance.displayName; + let hashable = typeof tname === 'string' && typeof iname === 'string'; + let hashmap = _INTERFACEOF_CACHE; + let valid = false; + + + // 0. Quick validation for identical constructors + if (hashable === true) { + + if (hashmap[tname] !== undefined && hashmap[tname][iname] !== undefined) { + + return hashmap[tname][iname]; + + } else if (tname === iname) { + + if (hashmap[tname] === undefined) { + hashmap[tname] = {}; + } + + hashmap[tname][iname] = true; + + return true; + + } + + } + // 1. Interface validation on Template if (template instanceof Function && template.prototype instanceof Object && instance instanceof Function && instance.prototype instanceof Object) { valid = true; - for (method in template.prototype) { + for (let method in template.prototype) { if (typeof template.prototype[method] !== typeof instance.prototype[method]) { valid = false; @@ -723,7 +631,7 @@ lychee = typeof lychee !== 'undefined' ? lychee : (function(global) { valid = true; - for (method in template.prototype) { + for (let method in template.prototype) { if (typeof template.prototype[method] !== typeof instance[method]) { valid = false; @@ -738,7 +646,7 @@ lychee = typeof lychee !== 'undefined' ? lychee : (function(global) { valid = true; - for (property in template) { + for (let property in template) { if (template.hasOwnProperty(property) && instance.hasOwnProperty(property)) { @@ -754,6 +662,17 @@ lychee = typeof lychee !== 'undefined' ? lychee : (function(global) { } + if (hashable === true) { + + if (hashmap[tname] === undefined) { + hashmap[tname] = {}; + } + + hashmap[tname][iname] = valid; + + } + + return valid; }, @@ -771,7 +690,7 @@ lychee = typeof lychee !== 'undefined' ? lychee : (function(global) { try { data = JSON.parse(JSON.stringify(data)); - } catch(err) { + } catch (err) { data = null; } @@ -828,6 +747,10 @@ lychee = typeof lychee !== 'undefined' ? lychee : (function(global) { } + } else if (data instanceof Object) { + + instance = data; + } @@ -851,9 +774,7 @@ lychee = typeof lychee !== 'undefined' ? lychee : (function(global) { } else { - if (lychee.debug === true) { - console.warn('lychee.deserialize: Require ' + (data.reference || data.constructor) + ' to deserialize it.'); - } + console.info('lychee.deserialize: Require ' + (data.reference || data.constructor) + ' to deserialize it.'); } @@ -881,21 +802,17 @@ lychee = typeof lychee !== 'undefined' ? lychee : (function(global) { } else if (typeof definition.displayName !== 'undefined') { - if (lychee.debug === true) { - - if (definition.prototype instanceof Object) { - console.warn('lychee.deserialize: Define ' + (definition.displayName) + '.prototype.serialize() to serialize it.'); - } else { - console.warn('lychee.deserialize: Define ' + (definition.displayName) + '.serialize() to serialize it.'); - } - + if (definition.prototype instanceof Object) { + console.info('lychee.deserialize: Define ' + (definition.displayName) + '.prototype.serialize() to serialize it.'); + } else { + console.info('lychee.deserialize: Define ' + (definition.displayName) + '.serialize() to serialize it.'); } } else { try { data = JSON.parse(JSON.stringify(definition)); - } catch(err) { + } catch (err) { data = null; } @@ -920,6 +837,55 @@ lychee = typeof lychee !== 'undefined' ? lychee : (function(global) { * CUSTOM API */ + assimilate: function(target) { + + target = typeof target === 'string' ? target : null; + + + if (target !== null) { + + _bootstrap_environment.call(this); + + + let that = this; + + + // XXX: First sandboxed hierarchy + if (that.environment.sandbox === true) { + that = that.environment.global.lychee; + } + + // XXX: Second sandboxed hierarchy + if (that.environment.sandbox === true) { + that = that.environment.global.lychee; + } + + // XXX: Third sandboxed hierarchy + if (that.environment.sandbox === true) { + that = that.environment.global.lychee; + } + + + let asset = new lychee.Asset(target, null, false); + if (asset !== null) { + asset.load(); + } + + + return asset; + + } else { + + console.warn('lychee.assimilate: Invalid target'); + console.info('lychee.assimilate: Use lychee.assimilate(target) where target is a path to an Asset'); + + } + + + return null; + + }, + define: function(identifier) { identifier = typeof identifier === 'string' ? identifier : null; @@ -960,6 +926,11 @@ lychee = typeof lychee !== 'undefined' ? lychee : (function(global) { return definition; + } else { + + console.warn('lychee.define: Invalid identifier'); + console.info('lychee.define: Use lychee.define(id).exports(closure)'); + } @@ -990,6 +961,11 @@ lychee = typeof lychee !== 'undefined' ? lychee : (function(global) { that = that.environment.global.lychee; } + // XXX: Third sandboxed hierarchy + if (that.environment.sandbox === true) { + that = that.environment.global.lychee; + } + let resolved_module = _resolve_reference.call(that.environment.global, reference); if (resolved_module !== null) { @@ -998,11 +974,7 @@ lychee = typeof lychee !== 'undefined' ? lychee : (function(global) { if (instance === null) { - - if (lychee.debug === true) { - console.warn('lychee.deserialize: Require ' + (reference) + ' to import it.'); - } - + console.info('lychee.deserialize: Require ' + (reference) + ' to import it.'); } @@ -1017,6 +989,8 @@ lychee = typeof lychee !== 'undefined' ? lychee : (function(global) { envinit: function(environment, profile) { + let message = environment !== null; + environment = environment instanceof lychee.Environment ? environment : null; profile = profile instanceof Object ? profile : {}; @@ -1070,6 +1044,11 @@ lychee = typeof lychee !== 'undefined' ? lychee : (function(global) { lychee.setEnvironment(environment); environment.init(new Function('sandbox', code)); + } else if (message === true) { + + console.warn('lychee.envinit: Invalid environment'); + console.info('lychee.envinit: Use lychee.envinit(env, profile) where env is a lychee.Environment instance'); + } }, @@ -1139,10 +1118,25 @@ lychee = typeof lychee !== 'undefined' ? lychee : (function(global) { lychee.setEnvironment(environment); environment.init(new Function('sandbox', code)); + } else { + + console.warn('lychee.pkginit: Invalid settings for "' + identifier + '" in lychee.pkg.'); + console.info('lychee.pkginit: Insert settings at "/build/environments/\"' + identifier + '\"" in lychee.pkg.'); + } + } else { + + console.warn('lychee.pkginit: Invalid package at "' + this.url + '".'); + console.info('lychee.pkginit: Replace lychee.pkg with the one from "/projects/boilerplate".'); + } + } else { + + console.warn('lychee.pkginit: Invalid package at "' + this.url + '".'); + console.info('lychee.pkginit: Replace lychee.pkg with the one from "/projects/boilerplate".'); + } }; @@ -1184,9 +1178,8 @@ lychee = typeof lychee !== 'undefined' ? lychee : (function(global) { } else { - if (lychee.debug === true) { - console.warn('lychee.inject: Set Environment to inject another into it.'); - } + console.warn('lychee.inject: Invalid default environment for injection.'); + console.info('lychee.inject: Use lychee.setEnvironment(env) before using lychee.inject(other).'); } diff --git a/libraries/lychee/source/crypto/CRC32.js b/libraries/lychee/source/crypto/CRC32.js index ab047df4..cbbc2d44 100644 --- a/libraries/lychee/source/crypto/CRC32.js +++ b/libraries/lychee/source/crypto/CRC32.js @@ -3,7 +3,7 @@ lychee.define('lychee.crypto.CRC32').exports(function(lychee, global, attachment const _CRC_TABLE = (function(table) { - let value = 0; + let value = 0; for (let t = 0, tl = table.length; t < tl; t++) { @@ -91,9 +91,7 @@ lychee.define('lychee.crypto.CRC32').exports(function(lychee, global, attachment digest: function() { - let crc = this.__crc; let hash = (this.__crc).toString(16); - if (hash.length % 2 === 1) { hash = '0' + hash; } diff --git a/libraries/lychee/source/crypto/MURMUR.js b/libraries/lychee/source/crypto/MURMUR.js new file mode 100644 index 00000000..c305c7f5 --- /dev/null +++ b/libraries/lychee/source/crypto/MURMUR.js @@ -0,0 +1,129 @@ + +lychee.define('lychee.crypto.MURMUR').exports(function(lychee, global, attachments) { + + const _C1 = 0xcc9e2d51; + const _C1B = 0x85ebca6b; + const _C2 = 0x1b873593; + const _C2B = 0xc2b2ae35; + + + + /* + * IMPLEMENTATION + */ + + let Composite = function() { + + this.__hash = 0; + + }; + + + Composite.prototype = { + + /* + * ENTITY API + */ + + // deserialize: function(blob) {}, + + serialize: function() { + + return { + 'constructor': 'lychee.crypto.MURMUR', + 'arguments': [] + }; + + }, + + + + /* + * CRYPTO API + */ + + update: function(data) { + + data = data instanceof Buffer ? data : new Buffer(data, 'utf8'); + + + let remain = data.length % 4; + let bytes = data.length - remain; + + let b = 0; + let h1 = this.__hash; + let h1b = 0; + let k1 = 0; + + + while (b < bytes) { + + k1 = ((data[b] & 0xff)) | ((data[b + 1] & 0xff) << 8) | ((data[b + 2] & 0xff) << 16) | ((data[b + 3] & 0xff) << 24); + k1 = ((((k1 & 0xffff) * _C1) + ((((k1 >>> 16) * _C1) & 0xffff) << 16))) & 0xffffffff; + k1 = (k1 << 15) | (k1 >>> 17); + k1 = ((((k1 & 0xffff) * _C2) + ((((k1 >>> 16) * _C2) & 0xffff) << 16))) & 0xffffffff; + + h1 ^= k1; + h1 = (h1 << 13) | (h1 >>> 19); + h1b = ((((h1 & 0xffff) * 5) + ((((h1 >>> 16) * 5) & 0xffff) << 16))) & 0xffffffff; + h1 = (((h1b & 0xffff) + 0x6b64) + ((((h1b >>> 16) + 0xe654) & 0xffff) << 16)); + + b += 4; + + } + + + k1 = 0; + + + if (remain === 3) { + + k1 ^= (data[b + 2] & 0xff) << 16; + + } else if (remain === 2) { + + k1 ^= (data[b + 1] & 0xff) << 8; + + } else if (remain === 1) { + + k1 ^= (data[b] & 0xff); + + k1 = (((k1 & 0xffff) * _C1) + ((((k1 >>> 16) * _C1) & 0xffff) << 16)) & 0xffffffff; + k1 = (k1 << 15) | (k1 >>> 17); + k1 = (((k1 & 0xffff) * _C2) + ((((k1 >>> 16) * _C2) & 0xffff) << 16)) & 0xffffffff; + h1 ^= k1; + + } + + + h1 ^= data.length; + + h1 ^= h1 >>> 16; + h1 = (((h1 & 0xffff) * _C1B) + ((((h1 >>> 16) * _C1B) & 0xffff) << 16)) & 0xffffffff; + h1 ^= h1 >>> 13; + h1 = (((h1 & 0xffff) * _C2B) + ((((h1 >>> 16) * _C2B) & 0xffff) << 16)) & 0xffffffff; + h1 ^= h1 >>> 16; + + + this.__hash = h1 >>> 0; + + }, + + digest: function() { + + let hash = (this.__hash).toString(16); + if (hash.length % 2 === 1) { + hash = '0' + hash; + } + + return new Buffer(hash, 'hex'); + + } + + }; + + + return Composite; + +}); + diff --git a/libraries/lychee/source/crypto/SHA1.js b/libraries/lychee/source/crypto/SHA1.js index 7e811f8f..5ae13b45 100644 --- a/libraries/lychee/source/crypto/SHA1.js +++ b/libraries/lychee/source/crypto/SHA1.js @@ -239,13 +239,14 @@ lychee.define('lychee.crypto.SHA1').exports(function(lychee, global, attachments buffer[length % 64] = 0x80; - // _write_zero(buffer, length % 64 + 1); - buffer.fill(0, length % 64 + 1); + _write_zero(buffer, length % 64 + 1); + // buffer.fill(0, length % 64 + 1); + if ((length * 8) % (64 * 8) >= (56 * 8)) { _update_chunk.call(this, buffer); - // _write_zero(buffer); - buffer.fill(0); + _write_zero(buffer); + // buffer.fill(0); } diff --git a/libraries/lychee/source/data/HTML.js b/libraries/lychee/source/data/HTML.js deleted file mode 100644 index 8d420dfb..00000000 --- a/libraries/lychee/source/data/HTML.js +++ /dev/null @@ -1,362 +0,0 @@ - -lychee.define('lychee.data.HTML').exports(function(lychee, global, attachments) { - - /* - * HELPERS - */ - - const _Stream = function(buffer, mode) { - - this.__buffer = typeof buffer === 'string' ? buffer : ''; - this.__mode = lychee.enumof(_Stream.MODE, mode) ? mode : 0; - - this.__index = 0; - - }; - - _Stream.MODE = { - read: 0, - write: 1 - }; - - _Stream.prototype = { - - toString: function() { - return this.__buffer; - }, - - pointer: function() { - return this.__index; - }, - - length: function() { - return this.__buffer.length; - }, - - read: function(bytes) { - - var buffer = ''; - - buffer += this.__buffer.substr(this.__index, bytes); - this.__index += bytes; - - return buffer; - - }, - - search: function(array) { - - var bytes = Infinity; - - for (var a = 0, al = array.length; a < al; a++) { - - var token = array[a]; - var size = this.__buffer.indexOf(token, this.__index + 1) - this.__index; - if (size > -1 && size < bytes) { - bytes = size; - } - - } - - - if (bytes === Infinity) { - return -1; - } - - - return bytes; - - }, - - seek: function(bytes) { - return this.__buffer.substr(this.__index, bytes); - }, - - write: function(buffer) { - - this.__buffer += buffer; - this.__index += buffer.length; - - } - - }; - - - - /* - * ENCODER and DECODER - */ - - const _encode_inline = function(entities) { - - var text = ''; - - - entities.forEach(function(entity) { - - if (entity.token === 'Code') { - - text += ' ' + entity.value + ' '; - - } else if (entity.token === 'Text') { - - if (entity.value.match(/\.|\,|\?|\!/g)) { - - text += entity.value; - - } else { - - if (entity.type === 'bold') { - text += ' ' + entity.value + ' '; - } else if (entity.type === 'italic') { - text += ' ' + entity.value + ' '; - } else { - text += ' ' + entity.value; - } - - } - - } else if (entity.token === 'Image') { - - text += ' ' + entity.type + ' '; - - } else if (entity.token === 'Link') { - - text += ' ' + entity.type + ' '; - - } - - }); - - - return text.trim(); - - }; - - const _encode = function(stream, data) { - - var open = false; - - - for (var d = 0, dl = data.length; d < dl; d++) { - - var entity = data[d]; - - if (entity.token === 'Article') { - - if (open === true) { - stream.write(''); - } - - - stream.write('\n'); - stream.write('
'); - stream.write('\n\n'); - - open = true; - - } else if (entity.token === 'Headline') { - - stream.write(''); - stream.write(entity.value); - stream.write(''); - stream.write('\n\n'); - - } else if (entity.token === 'Code') { - - stream.write('
\n');
-				stream.write('\n');
-				stream.write(entity.value);
-				stream.write('\n');
-				stream.write('\n');
-				stream.write('
'); - stream.write('\n\n'); - - } else if (entity.token === 'List') { - - stream.write('
    \n'); - stream.write(entity.value.map(function(val) { - return '\t
  • ' + _encode_inline(val) + '
  • \n'; - }).join('')); - stream.write('
'); - stream.write('\n\n'); - - } else if (entity.token === 'Paragraph') { - - stream.write('

'); - stream.write(_encode_inline(entity.value)); - stream.write('

'); - stream.write('\n\n'); - - } - - } - - - if (open === true) { - stream.write('
\n'); - } - - - }; - - const _decode_inline = function(text) { - -console.info(text); - - return text; - - }; - - const _decode = function(stream) { - - var value = undefined; - var seek = ''; - var size = 0; - var tmp = 0; - var errors = 0; - var check = null; - - - var entity = { - token: null, - type: null, - value: null - }; - - -_COUNT = 0; - - while (errors === 0 && stream.pointer() < stream.length()) { - - size = stream.search('<'); - - if (size !== -1) { - -// content of last entity - tmp = stream.read(size); - - if (entity.token !== null) { - entity.value = tmp.trim(); - } - - - size = stream.search('>'); - stream.read(1); - tmp = stream.read(size - 1); - stream.read(1); - - - check = tmp.substr(0, 1); - - if (check !== '/') { - - seek = tmp.split(' ')[0]; - - if (seek === 'article') { - - entity.token = 'Article'; - entity.value = tmp.split('id=')[1].replace(/"/g, ''); - -// console.log(entity); - - } else if (seek === 'pre') { - } else { - -console.log(seek); - - } - - - -// TODO: Read entity token and type - - } else { - -// TODO: Close last entity - - } - - -// console.log(tmp); - - - } - -_COUNT++; - -if (_COUNT > 200) break; - - } - - - return value; - - }; - - - - /* - * IMPLEMENTATION - */ - - let Module = { - - // deserialize: function(blob) {}, - - serialize: function() { - - return { - 'reference': 'lychee.data.HTML', - 'blob': null - }; - - }, - - encode: function(data) { - - data = data instanceof Object ? data : null; - - - if (data !== null) { - - let stream = new _Stream('', _Stream.MODE.write); - - _encode(stream, data); - - return stream.toString(); - - } - - - return null; - - }, - - decode: function(data) { - - data = typeof data === 'string' ? data : null; - - - if (data !== null) { - - let stream = new _Stream(data, _Stream.MODE.read); - let object = _decode(stream); - if (object !== undefined) { - return object; - } - - } - - - return null; - - } - - }; - - - return Module; - -}); - diff --git a/libraries/lychee/source/data/MD.js b/libraries/lychee/source/data/MD.js deleted file mode 100644 index 450921f2..00000000 --- a/libraries/lychee/source/data/MD.js +++ /dev/null @@ -1,593 +0,0 @@ - -lychee.define('lychee.data.MD').exports(function(lychee, global, attachments) { - - /* - * HELPERS - */ - - const _Stream = function(buffer, mode) { - - this.__buffer = typeof buffer === 'string' ? buffer : ''; - this.__mode = lychee.enumof(_Stream.MODE, mode) ? mode : 0; - - this.__index = 0; - - }; - - _Stream.MODE = { - read: 0, - write: 1 - }; - - _Stream.prototype = { - - toString: function() { - return this.__buffer; - }, - - pointer: function() { - return this.__index; - }, - - length: function() { - return this.__buffer.length; - }, - - read: function(bytes) { - - let buffer = ''; - - buffer += this.__buffer.substr(this.__index, bytes); - this.__index += bytes; - - return buffer; - - }, - - search: function(array) { - - let bytes = Infinity; - - for (let a = 0, al = array.length; a < al; a++) { - - let token = array[a]; - let size = this.__buffer.indexOf(token, this.__index + 1) - this.__index; - if (size > -1 && size < bytes) { - bytes = size; - } - - } - - - if (bytes === Infinity) { - return -1; - } - - - return bytes; - - }, - - seek: function(bytes) { - return this.__buffer.substr(this.__index, bytes); - }, - - write: function(buffer) { - - this.__buffer += buffer; - this.__index += buffer.length; - - } - - }; - - - - /* - * ENCODER and DECODER - */ - - const _encode_inline = function(entities) { - - let text = ''; - - - entities.forEach(function(entity) { - - if (entity.token === 'Code') { - - text += ' `' + entity.value + '`'; - - } else if (entity.token === 'Text') { - - if (entity.value.match(/\.|\,|\?|\!/g)) { - - text += entity.value; - - } else { - - if (entity.type === 'bold') { - text += ' **' + entity.value + '**'; - } else if (entity.type === 'italic') { - text += ' *' + entity.value + '*'; - } else { - text += ' ' + entity.value; - } - - } - - } else if (entity.token === 'Image') { - - text += ' ![' + entity.type + '](' + entity.value + ')'; - - } else if (entity.token === 'Link') { - - text += ' [' + entity.type + '](' + entity.value + ')'; - - } - - }); - - - return text.trim(); - - }; - - const _encode = function(stream, data) { - - for (let d = 0, dl = data.length; d < dl; d++) { - - let entity = data[d]; - - if (entity.token === 'Article') { - - stream.write('\n'); - stream.write('='); - stream.write(' '); - stream.write(entity.value); - stream.write('\n\n'); - - } else if (entity.token === 'Headline') { - - let type = '################'.substr(0, entity.type); - - stream.write(type); - stream.write(' '); - stream.write(entity.value); - stream.write('\n\n'); - - } else if (entity.token === 'Code') { - - stream.write('```'); - stream.write(entity.type || ''); - stream.write('\n'); - stream.write(entity.value); - stream.write('\n'); - stream.write('```'); - stream.write('\n\n'); - - } else if (entity.token === 'List') { - - stream.write(entity.value.map(function(val) { - return '- ' + _encode_inline(val); - }).join('\n')); - stream.write('\n\n'); - - } else if (entity.token === 'Paragraph') { - - stream.write(_encode_inline(entity.value)); - stream.write('\n\n'); - - } - - } - - - }; - - const _decode_inline = function(text) { - - let entities = []; - let last_entity = null; - - - text.match(/(\[[^\)]+\)|[^\s]+)/gi).forEach(function(str) { - - let entity = null; - let suffix = null; - let value = ''; - - - if (str.substr(-1).match(/\.|\,|\?|\!/g)) { - suffix = str.substr(-1); - str = str.substr(0, str.length - 1); - } - - - let b_code = str.substr(0, 1) === '`'; - let e_code = str.substr(-1) === '`'; - let b_bold = str.substr(0, 2) === '**' ; - let e_bold = str.substr(-2) === '**'; - let b_italic = str.substr(0, 1) === '*'; - let e_italic = str.substr(-1) === '*'; - - let i0, i1, i2, i3; - - - if (b_code || e_code) { - - if (b_code && e_code) { - value = str.substr(1, str.length - 2); - } else if (b_code) { - value = str.substr(1); - } else if (e_code) { - value = str.substr(0, str.length - 1); - } - - - entity = { - token: 'Code', - type: 'javascript', - value: value - }; - - - } else if (b_bold || e_bold) { - - if (b_bold && e_bold) { - value = str.substr(2, str.length - 4); - } else if (b_bold) { - value = str.substr(2); - } else if (e_bold) { - value = str.substr(0, str.length - 2); - } - - - entity = { - token: 'Text', - type: 'bold', - value: value - }; - - - } else if (b_italic || e_italic) { - - if (b_italic && e_italic) { - value = str.substr(1, str.length - 2); - } else if (b_italic) { - value = str.substr(1); - } else if (e_italic) { - value = str.substr(0, str.length - 1); - } - - - entity = { - token: 'Text', - type: 'italic', - value: str.substr(1, str.length - 2) - }; - - } else if (str.substr(0, 1) === '!'){ - - i0 = str.indexOf('['); - i1 = str.indexOf(']'); - i2 = str.indexOf('('); - i3 = str.indexOf(')'); - - entity = { - token: 'Image', - type: str.substr(i0 + 1, i1 - i0 - 1), - value: str.substr(i2 + 1, i3 - i2 - 1) - }; - - } else if (str.substr(0, 1) === '[') { - - i0 = str.indexOf('['); - i1 = str.indexOf(']'); - i2 = str.indexOf('('); - i3 = str.indexOf(')'); - - entity = { - token: 'Link', - type: str.substr(i0 + 1, i1 - i0 - 1), - value: str.substr(i2 + 1, i3 - i2 - 1) - }; - - } else { - - entity = { - token: 'Text', - type: 'normal', - value: str - }; - - } - - - if (last_entity !== null) { - - if (last_entity.token === entity.token && last_entity.type === entity.type) { - - last_entity.value += ' ' + entity.value; - - } else { - - entities.push(entity); - last_entity = entity; - - } - - - if (suffix !== null) { - - if (last_entity.token === 'Text' && last_entity.type === 'normal') { - - last_entity.value += suffix; - - } else { - - entity = { - token: 'Text', - type: 'normal', - value: suffix - }; - - entities.push(entity); - last_entity = entity; - - } - - } - - } else { - - entities.push(entity); - last_entity = entity; - - } - - }); - - - return entities; - - }; - - const _decode = function(stream) { - - let value = undefined; - let seek = ''; - let size = 0; - let tmp = 0; - let errors = 0; - let check = null; - - - if (stream.pointer() === 0) { - - seek = stream.seek(1); - - if (seek === '\n') { - - stream.read(1); - - - value = []; - errors = 0; - - while (errors === 0 && stream.pointer() < stream.length()) { - - tmp = _decode(stream); - - if (tmp instanceof Object) { - value.push(tmp); - } else if (tmp === undefined) { - errors++; - } - - } - - } - - } else if (stream.pointer() < stream.length()) { - - seek = stream.seek(1); - - - if (seek === '=') { - - stream.read(1); - - size = stream.search([ '\n' ]); - - if (size !== -1) { - - tmp = stream.read(size).trim(); - value = { - token: 'Article', - type: null, - value: tmp - }; - - stream.read(1); - - } - - - } else if (seek === '#') { - - size = stream.search([ '\n' ]); - - if (size !== -1) { - - tmp = stream.read(size).trim(); - value = { - token: 'Headline', - type: tmp.split(' ')[0].length, - value: tmp.split(' ').slice(1).join(' ') - }; - - stream.read(1); - - } - - - } else if (seek === '`') { - - size = stream.search([ '\n' ]); - tmp = stream.read(size); - - if (size !== -1 && tmp.substr(0, 3) === '```') { - - check = stream.search([ '```' ]); - - if (check !== -1) { - - value = { - token: 'Code', - type: tmp.substr(3).trim(), - value: stream.read(check).trim() - }; - - stream.read(3); - - } - - } - - - } else if (seek === '-') { - - size = stream.search([ '\n\n' ]); - - if (size !== -1) { - - tmp = stream.read(size).trim(); - value = { - token: 'List', - type: null, - value: tmp.split('\n').map(function(val) { - - if (val.substr(0, 1) === '-') { - val = val.substr(1); - } - - return _decode_inline(val.trim()); - - }) - }; - - stream.read(1); - - } - - } else if (seek.match(/[A-Za-z0-9\[\!*]/)) { - - size = stream.search([ '\n\n' ]); - - if (size !== -1) { - - tmp = stream.read(size).trim(); - value = { - token: 'Paragraph', - type: null, - value: _decode_inline(tmp) - }; - - stream.read(1); - - } - - - } else if (seek === '\n') { - - stream.read(1); - value = null; - - - } else { - - size = stream.search([ '\n' ]); - - if (size !== -1) { - stream.read(size); - } - - stream.read(1); - value = null; - - } - - } - - - return value; - - }; - - - - /* - * IMPLEMENTATION - */ - - let Module = { - - // deserialize: function(blob) {}, - - serialize: function() { - - return { - 'reference': 'lychee.data.MD', - 'blob': null - }; - - }, - - encode: function(data) { - - data = data instanceof Object ? data : null; - - - if (data !== null) { - - let stream = new _Stream('', _Stream.MODE.write); - - _encode(stream, data); - - return stream.toString(); - - } - - - return null; - - }, - - decode: function(data) { - - data = typeof data === 'string' ? data : null; - - - if (data !== null) { - - let stream = new _Stream(data, _Stream.MODE.read); - let object = _decode(stream); - if (object !== undefined) { - return object; - } - - } - - - return null; - - } - - }; - - - return Module; - -}); - diff --git a/libraries/lychee/source/effect/Alpha.js b/libraries/lychee/source/effect/Alpha.js index 50186bd3..2a05c344 100644 --- a/libraries/lychee/source/effect/Alpha.js +++ b/libraries/lychee/source/effect/Alpha.js @@ -1,23 +1,6 @@ lychee.define('lychee.effect.Alpha').exports(function(lychee, global, attachments) { - /* - * HELPERS - */ - - const _is_alpha = function(alpha) { - - if (typeof alpha === 'number') { - return alpha >= 0 && alpha <= 1; - } - - - return false; - - }; - - - /* * IMPLEMENTATION */ @@ -35,26 +18,10 @@ lychee.define('lychee.effect.Alpha').exports(function(lychee, global, attachment // No data validation garbage allowed for effects - let type = lychee.enumof(Composite.TYPE, settings.type) ? settings.type : null; - let delay = typeof settings.delay === 'number' ? (settings.delay | 0) : null; - let duration = typeof settings.duration === 'number' ? (settings.duration | 0) : null; - let alpha = _is_alpha(settings.alpha) ? settings.alpha : null; - - if (type !== null) { - this.type = type; - } - - if (delay !== null) { - this.delay = delay; - } - - if (duration !== null) { - this.duration = duration; - } - - if (alpha !== null) { - this.alpha = alpha; - } + this.type = lychee.enumof(Composite.TYPE, settings.type) ? settings.type : Composite.TYPE.easeout; + this.delay = typeof settings.delay === 'number' ? (settings.delay | 0) : 0; + this.duration = typeof settings.duration === 'number' ? (settings.duration | 0) : 250; + this.alpha = typeof settings.alpha === 'number' ? settings.alpha : 1; }; @@ -145,28 +112,28 @@ lychee.define('lychee.effect.Alpha').exports(function(lychee, global, attachment let k = 1 - t; - if ((k /= 1) < ( 1 / 2.75 )) { - f = 1 * ( 7.5625 * Math.pow(k, 2) ); - } else if (k < ( 2 / 2.75 )) { - f = 7.5625 * ( k -= ( 1.5 / 2.75 )) * k + 0.75; - } else if (k < ( 2.5 / 2.75 )) { - f = 7.5625 * ( k -= ( 2.25 / 2.75 )) * k + 0.9375; + if ((k /= 1) < (1 / 2.75)) { + f = 1 * (7.5625 * Math.pow(k, 2)); + } else if (k < (2 / 2.75)) { + f = 7.5625 * (k -= (1.5 / 2.75)) * k + 0.75; + } else if (k < (2.5 / 2.75)) { + f = 7.5625 * (k -= (2.25 / 2.75)) * k + 0.9375; } else { - f = 7.5625 * ( k -= ( 2.625 / 2.75 )) * k + 0.984375; + f = 7.5625 * (k -= (2.625 / 2.75)) * k + 0.984375; } a += (1 - f) * da; } else if (type === Composite.TYPE.bounceeaseout) { - if ((t /= 1) < ( 1 / 2.75 )) { - f = 1 * ( 7.5625 * Math.pow(t, 2) ); - } else if (t < ( 2 / 2.75 )) { - f = 7.5625 * ( t -= ( 1.5 / 2.75 )) * t + 0.75; - } else if (t < ( 2.5 / 2.75 )) { - f = 7.5625 * ( t -= ( 2.25 / 2.75 )) * t + 0.9375; + if ((t /= 1) < (1 / 2.75)) { + f = 1 * (7.5625 * Math.pow(t, 2)); + } else if (t < (2 / 2.75)) { + f = 7.5625 * (t -= (1.5 / 2.75)) * t + 0.75; + } else if (t < (2.5 / 2.75)) { + f = 7.5625 * (t -= (2.25 / 2.75)) * t + 0.9375; } else { - f = 7.5625 * ( t -= ( 2.625 / 2.75 )) * t + 0.984375; + f = 7.5625 * (t -= (2.625 / 2.75)) * t + 0.984375; } a += f * da; diff --git a/libraries/lychee/source/effect/Color.js b/libraries/lychee/source/effect/Color.js index 1fe01eae..896cfb60 100644 --- a/libraries/lychee/source/effect/Color.js +++ b/libraries/lychee/source/effect/Color.js @@ -34,26 +34,10 @@ lychee.define('lychee.effect.Color').exports(function(lychee, global, attachment // No data validation garbage allowed for effects - let type = lychee.enumof(Composite.TYPE, settings.type) ? settings.type : null; - let delay = typeof settings.delay === 'number' ? (settings.delay | 0) : null; - let duration = typeof settings.duration === 'number' ? (settings.duration | 0) : null; - let color = /(#[AaBbCcDdEeFf0-9]{6})/.test(settings.color) ? settings.color : null; - - if (type !== null) { - this.type = type; - } - - if (delay !== null) { - this.delay = delay; - } - - if (duration !== null) { - this.duration = duration; - } - - if (color !== null) { - this.color = color; - } + this.type = lychee.enumof(Composite.TYPE, settings.type) ? settings.type : Composite.TYPE.easeout; + this.delay = typeof settings.delay === 'number' ? (settings.delay | 0) : 0; + this.duration = typeof settings.duration === 'number' ? (settings.duration | 0) : 250; + this.color = /(#[AaBbCcDdEeFf0-9]{6})/.test(settings.color) ? settings.color : '#000000'; }; @@ -163,14 +147,14 @@ lychee.define('lychee.effect.Color').exports(function(lychee, global, attachment let k = 1 - t; - if ((k /= 1) < ( 1 / 2.75 )) { - f = 1 * ( 7.5625 * Math.pow(k, 2) ); - } else if (k < ( 2 / 2.75 )) { - f = 7.5625 * ( k -= ( 1.5 / 2.75 )) * k + 0.75; - } else if (k < ( 2.5 / 2.75 )) { - f = 7.5625 * ( k -= ( 2.25 / 2.75 )) * k + 0.9375; + if ((k /= 1) < (1 / 2.75)) { + f = 1 * (7.5625 * Math.pow(k, 2)); + } else if (k < (2 / 2.75)) { + f = 7.5625 * (k -= (1.5 / 2.75)) * k + 0.75; + } else if (k < (2.5 / 2.75)) { + f = 7.5625 * (k -= (2.25 / 2.75)) * k + 0.9375; } else { - f = 7.5625 * ( k -= ( 2.625 / 2.75 )) * k + 0.984375; + f = 7.5625 * (k -= (2.625 / 2.75)) * k + 0.984375; } r += (1 - f) * dr; @@ -179,14 +163,14 @@ lychee.define('lychee.effect.Color').exports(function(lychee, global, attachment } else if (type === Composite.TYPE.bounceeaseout) { - if ((t /= 1) < ( 1 / 2.75 )) { - f = 1 * ( 7.5625 * Math.pow(t, 2) ); - } else if (t < ( 2 / 2.75 )) { - f = 7.5625 * ( t -= ( 1.5 / 2.75 )) * t + 0.75; - } else if (t < ( 2.5 / 2.75 )) { - f = 7.5625 * ( t -= ( 2.25 / 2.75 )) * t + 0.9375; + if ((t /= 1) < (1 / 2.75)) { + f = 1 * (7.5625 * Math.pow(t, 2)); + } else if (t < (2 / 2.75)) { + f = 7.5625 * (t -= (1.5 / 2.75)) * t + 0.75; + } else if (t < (2.5 / 2.75)) { + f = 7.5625 * (t -= (2.25 / 2.75)) * t + 0.9375; } else { - f = 7.5625 * ( t -= ( 2.625 / 2.75 )) * t + 0.984375; + f = 7.5625 * (t -= (2.625 / 2.75)) * t + 0.984375; } r += f * dr; diff --git a/libraries/lychee/source/effect/Depth.js b/libraries/lychee/source/effect/Depth.js index 936c8812..52e4280f 100644 --- a/libraries/lychee/source/effect/Depth.js +++ b/libraries/lychee/source/effect/Depth.js @@ -20,26 +20,10 @@ lychee.define('lychee.effect.Depth').exports(function(lychee, global, attachment // No data validation garbage allowed for effects - let type = lychee.enumof(Composite.TYPE, settings.type) ? settings.type : null; - let delay = typeof settings.delay === 'number' ? (settings.delay | 0) : null; - let duration = typeof settings.duration === 'number' ? (settings.duration | 0) : null; - let depth = typeof settings.depth === 'number' ? (settings.depth | 0) : null; - - if (type !== null) { - this.type = type; - } - - if (delay !== null) { - this.delay = delay; - } - - if (duration !== null) { - this.duration = duration; - } - - if (depth !== null) { - this.depth = depth; - } + this.type = lychee.enumof(Composite.TYPE, settings.type) ? settings.type : Composite.TYPE.easeout; + this.delay = typeof settings.delay === 'number' ? (settings.delay | 0) : 0; + this.duration = typeof settings.duration === 'number' ? (settings.duration | 0) : 250; + this.depth = typeof settings.depth === 'number' ? (settings.depth | 0) : 0; }; @@ -130,28 +114,28 @@ lychee.define('lychee.effect.Depth').exports(function(lychee, global, attachment let k = 1 - t; - if ((k /= 1) < ( 1 / 2.75 )) { - f = 1 * ( 7.5625 * Math.pow(k, 2) ); - } else if (k < ( 2 / 2.75 )) { - f = 7.5625 * ( k -= ( 1.5 / 2.75 )) * k + 0.75; - } else if (k < ( 2.5 / 2.75 )) { - f = 7.5625 * ( k -= ( 2.25 / 2.75 )) * k + 0.9375; + if ((k /= 1) < (1 / 2.75)) { + f = 1 * (7.5625 * Math.pow(k, 2)); + } else if (k < (2 / 2.75)) { + f = 7.5625 * (k -= (1.5 / 2.75)) * k + 0.75; + } else if (k < (2.5 / 2.75)) { + f = 7.5625 * (k -= (2.25 / 2.75)) * k + 0.9375; } else { - f = 7.5625 * ( k -= ( 2.625 / 2.75 )) * k + 0.984375; + f = 7.5625 * (k -= (2.625 / 2.75)) * k + 0.984375; } d += (1 - f) * dd; } else if (type === Composite.TYPE.bounceeaseout) { - if ((t /= 1) < ( 1 / 2.75 )) { - f = 1 * ( 7.5625 * Math.pow(t, 2) ); - } else if (t < ( 2 / 2.75 )) { - f = 7.5625 * ( t -= ( 1.5 / 2.75 )) * t + 0.75; - } else if (t < ( 2.5 / 2.75 )) { - f = 7.5625 * ( t -= ( 2.25 / 2.75 )) * t + 0.9375; + if ((t /= 1) < (1 / 2.75)) { + f = 1 * (7.5625 * Math.pow(t, 2)); + } else if (t < (2 / 2.75)) { + f = 7.5625 * (t -= (1.5 / 2.75)) * t + 0.75; + } else if (t < (2.5 / 2.75)) { + f = 7.5625 * (t -= (2.25 / 2.75)) * t + 0.9375; } else { - f = 7.5625 * ( t -= ( 2.625 / 2.75 )) * t + 0.984375; + f = 7.5625 * (t -= (2.625 / 2.75)) * t + 0.984375; } d += f * dd; diff --git a/libraries/lychee/source/effect/Event.js b/libraries/lychee/source/effect/Event.js index 61b10816..ec2affb0 100644 --- a/libraries/lychee/source/effect/Event.js +++ b/libraries/lychee/source/effect/Event.js @@ -17,16 +17,8 @@ lychee.define('lychee.effect.Event').exports(function(lychee, global, attachment // No data validation garbage allowed for effects - let delay = typeof settings.delay === 'number' ? (settings.delay | 0) : null; - let event = typeof settings.event === 'string' ? settings.event : null; - - if (delay !== null) { - this.delay = delay; - } - - if (event !== null) { - this.event = event; - } + this.delay = typeof settings.delay === 'number' ? (settings.delay | 0) : 0; + this.event = typeof settings.event === 'string' ? settings.event : null; }; diff --git a/libraries/lychee/source/effect/Height.js b/libraries/lychee/source/effect/Height.js index 4503940c..78947aa0 100644 --- a/libraries/lychee/source/effect/Height.js +++ b/libraries/lychee/source/effect/Height.js @@ -20,26 +20,10 @@ lychee.define('lychee.effect.Height').exports(function(lychee, global, attachmen // No data validation garbage allowed for effects - let type = lychee.enumof(Composite.TYPE, settings.type) ? settings.type : null; - let delay = typeof settings.delay === 'number' ? (settings.delay | 0) : null; - let duration = typeof settings.duration === 'number' ? (settings.duration | 0) : null; - let height = typeof settings.height === 'number' ? (settings.height | 0) : null; - - if (type !== null) { - this.type = type; - } - - if (delay !== null) { - this.delay = delay; - } - - if (duration !== null) { - this.duration = duration; - } - - if (height !== null) { - this.height = height; - } + this.type = lychee.enumof(Composite.TYPE, settings.type) ? settings.type : Composite.TYPE.easeout; + this.delay = typeof settings.delay === 'number' ? (settings.delay | 0) : 0; + this.duration = typeof settings.duration === 'number' ? (settings.duration | 0) : 250; + this.height = typeof settings.height === 'number' ? (settings.height | 0) : 0; }; @@ -130,28 +114,28 @@ lychee.define('lychee.effect.Height').exports(function(lychee, global, attachmen let k = 1 - t; - if ((k /= 1) < ( 1 / 2.75 )) { - f = 1 * ( 7.5625 * Math.pow(k, 2) ); - } else if (k < ( 2 / 2.75 )) { - f = 7.5625 * ( k -= ( 1.5 / 2.75 )) * k + 0.75; - } else if (k < ( 2.5 / 2.75 )) { - f = 7.5625 * ( k -= ( 2.25 / 2.75 )) * k + 0.9375; + if ((k /= 1) < (1 / 2.75)) { + f = 1 * (7.5625 * Math.pow(k, 2)); + } else if (k < (2 / 2.75)) { + f = 7.5625 * (k -= (1.5 / 2.75)) * k + 0.75; + } else if (k < (2.5 / 2.75)) { + f = 7.5625 * (k -= (2.25 / 2.75)) * k + 0.9375; } else { - f = 7.5625 * ( k -= ( 2.625 / 2.75 )) * k + 0.984375; + f = 7.5625 * (k -= (2.625 / 2.75)) * k + 0.984375; } h += (1 - f) * dh; } else if (type === Composite.TYPE.bounceeaseout) { - if ((t /= 1) < ( 1 / 2.75 )) { - f = 1 * ( 7.5625 * Math.pow(t, 2) ); - } else if (t < ( 2 / 2.75 )) { - f = 7.5625 * ( t -= ( 1.5 / 2.75 )) * t + 0.75; - } else if (t < ( 2.5 / 2.75 )) { - f = 7.5625 * ( t -= ( 2.25 / 2.75 )) * t + 0.9375; + if ((t /= 1) < (1 / 2.75)) { + f = 1 * (7.5625 * Math.pow(t, 2)); + } else if (t < (2 / 2.75)) { + f = 7.5625 * (t -= (1.5 / 2.75)) * t + 0.75; + } else if (t < (2.5 / 2.75)) { + f = 7.5625 * (t -= (2.25 / 2.75)) * t + 0.9375; } else { - f = 7.5625 * ( t -= ( 2.625 / 2.75 )) * t + 0.984375; + f = 7.5625 * (t -= (2.625 / 2.75)) * t + 0.984375; } h += f * dh; diff --git a/libraries/lychee/source/effect/Offset.js b/libraries/lychee/source/effect/Offset.js index 62b42d2a..0a66657e 100644 --- a/libraries/lychee/source/effect/Offset.js +++ b/libraries/lychee/source/effect/Offset.js @@ -20,26 +20,14 @@ lychee.define('lychee.effect.Offset').exports(function(lychee, global, attachmen // No data validation garbage allowed for effects - let type = lychee.enumof(Composite.TYPE, settings.type) ? settings.type : null; - let delay = typeof settings.delay === 'number' ? (settings.delay | 0) : null; - let duration = typeof settings.duration === 'number' ? (settings.duration | 0) : null; - let offset = settings.offset instanceof Object ? settings.offset : null; + this.type = lychee.enumof(Composite.TYPE, settings.type) ? settings.type : Composite.TYPE.easeout; + this.delay = typeof settings.delay === 'number' ? (settings.delay | 0) : 0; + this.duration = typeof settings.duration === 'number' ? (settings.duration | 0) : 250; - if (type !== null) { - this.type = type; - } - - if (delay !== null) { - this.delay = delay; - } - - if (duration !== null) { - this.duration = duration; - } - if (offset !== null) { - this.offset.x = typeof offset.x === 'number' ? (offset.x | 0) : null; - this.offset.y = typeof offset.y === 'number' ? (offset.y | 0) : null; + if (settings.offset instanceof Object) { + this.offset.x = typeof settings.offset.x === 'number' ? (settings.offset.x | 0) : null; + this.offset.y = typeof settings.offset.y === 'number' ? (settings.offset.y | 0) : null; } }; @@ -151,14 +139,14 @@ lychee.define('lychee.effect.Offset').exports(function(lychee, global, attachmen let k = 1 - t; - if ((k /= 1) < ( 1 / 2.75 )) { - f = 1 * ( 7.5625 * Math.pow(k, 2) ); - } else if (k < ( 2 / 2.75 )) { - f = 7.5625 * ( k -= ( 1.5 / 2.75 )) * k + 0.75; - } else if (k < ( 2.5 / 2.75 )) { - f = 7.5625 * ( k -= ( 2.25 / 2.75 )) * k + 0.9375; + if ((k /= 1) < (1 / 2.75)) { + f = 1 * (7.5625 * Math.pow(k, 2)); + } else if (k < (2 / 2.75)) { + f = 7.5625 * (k -= (1.5 / 2.75)) * k + 0.75; + } else if (k < (2.5 / 2.75)) { + f = 7.5625 * (k -= (2.25 / 2.75)) * k + 0.9375; } else { - f = 7.5625 * ( k -= ( 2.625 / 2.75 )) * k + 0.984375; + f = 7.5625 * (k -= (2.625 / 2.75)) * k + 0.984375; } x += (1 - f) * dx; @@ -166,14 +154,14 @@ lychee.define('lychee.effect.Offset').exports(function(lychee, global, attachmen } else if (type === Composite.TYPE.bounceeaseout) { - if ((t /= 1) < ( 1 / 2.75 )) { - f = 1 * ( 7.5625 * Math.pow(t, 2) ); - } else if (t < ( 2 / 2.75 )) { - f = 7.5625 * ( t -= ( 1.5 / 2.75 )) * t + 0.75; - } else if (t < ( 2.5 / 2.75 )) { - f = 7.5625 * ( t -= ( 2.25 / 2.75 )) * t + 0.9375; + if ((t /= 1) < (1 / 2.75)) { + f = 1 * (7.5625 * Math.pow(t, 2)); + } else if (t < (2 / 2.75)) { + f = 7.5625 * (t -= (1.5 / 2.75)) * t + 0.75; + } else if (t < (2.5 / 2.75)) { + f = 7.5625 * (t -= (2.25 / 2.75)) * t + 0.9375; } else { - f = 7.5625 * ( t -= ( 2.625 / 2.75 )) * t + 0.984375; + f = 7.5625 * (t -= (2.625 / 2.75)) * t + 0.984375; } x += f * dx; diff --git a/libraries/lychee/source/effect/Position.js b/libraries/lychee/source/effect/Position.js index bb55adcf..ba299507 100644 --- a/libraries/lychee/source/effect/Position.js +++ b/libraries/lychee/source/effect/Position.js @@ -20,27 +20,15 @@ lychee.define('lychee.effect.Position').exports(function(lychee, global, attachm // No data validation garbage allowed for effects - let type = lychee.enumof(Composite.TYPE, settings.type) ? settings.type : null; - let delay = typeof settings.delay === 'number' ? (settings.delay | 0) : null; - let duration = typeof settings.duration === 'number' ? (settings.duration | 0) : null; - let position = settings.position instanceof Object ? settings.position : null; + this.type = lychee.enumof(Composite.TYPE, settings.type) ? settings.type : Composite.TYPE.easeout; + this.delay = typeof settings.delay === 'number' ? (settings.delay | 0) : 0; + this.duration = typeof settings.duration === 'number' ? (settings.duration | 0) : 250; - if (type !== null) { - this.type = type; - } - - if (delay !== null) { - this.delay = delay; - } - - if (duration !== null) { - this.duration = duration; - } - if (position !== null) { - this.position.x = typeof position.x === 'number' ? (position.x | 0) : null; - this.position.y = typeof position.y === 'number' ? (position.y | 0) : null; - this.position.z = typeof position.z === 'number' ? (position.z | 0) : null; + if (settings.position instanceof Object) { + this.position.x = typeof settings.position.x === 'number' ? (settings.position.x | 0) : null; + this.position.y = typeof settings.position.y === 'number' ? (settings.position.y | 0) : null; + this.position.z = typeof settings.position.z === 'number' ? (settings.position.z | 0) : null; } }; @@ -161,14 +149,14 @@ lychee.define('lychee.effect.Position').exports(function(lychee, global, attachm let k = 1 - t; - if ((k /= 1) < ( 1 / 2.75 )) { - f = 1 * ( 7.5625 * Math.pow(k, 2) ); - } else if (k < ( 2 / 2.75 )) { - f = 7.5625 * ( k -= ( 1.5 / 2.75 )) * k + 0.75; - } else if (k < ( 2.5 / 2.75 )) { - f = 7.5625 * ( k -= ( 2.25 / 2.75 )) * k + 0.9375; + if ((k /= 1) < (1 / 2.75)) { + f = 1 * (7.5625 * Math.pow(k, 2)); + } else if (k < (2 / 2.75)) { + f = 7.5625 * (k -= (1.5 / 2.75)) * k + 0.75; + } else if (k < (2.5 / 2.75)) { + f = 7.5625 * (k -= (2.25 / 2.75)) * k + 0.9375; } else { - f = 7.5625 * ( k -= ( 2.625 / 2.75 )) * k + 0.984375; + f = 7.5625 * (k -= (2.625 / 2.75)) * k + 0.984375; } x += (1 - f) * dx; @@ -177,14 +165,14 @@ lychee.define('lychee.effect.Position').exports(function(lychee, global, attachm } else if (type === Composite.TYPE.bounceeaseout) { - if ((t /= 1) < ( 1 / 2.75 )) { - f = 1 * ( 7.5625 * Math.pow(t, 2) ); - } else if (t < ( 2 / 2.75 )) { - f = 7.5625 * ( t -= ( 1.5 / 2.75 )) * t + 0.75; - } else if (t < ( 2.5 / 2.75 )) { - f = 7.5625 * ( t -= ( 2.25 / 2.75 )) * t + 0.9375; + if ((t /= 1) < (1 / 2.75)) { + f = 1 * (7.5625 * Math.pow(t, 2)); + } else if (t < (2 / 2.75)) { + f = 7.5625 * (t -= (1.5 / 2.75)) * t + 0.75; + } else if (t < (2.5 / 2.75)) { + f = 7.5625 * (t -= (2.25 / 2.75)) * t + 0.9375; } else { - f = 7.5625 * ( t -= ( 2.625 / 2.75 )) * t + 0.984375; + f = 7.5625 * (t -= (2.625 / 2.75)) * t + 0.984375; } x += f * dx; diff --git a/libraries/lychee/source/effect/Radius.js b/libraries/lychee/source/effect/Radius.js index 57422e0d..aa521aed 100644 --- a/libraries/lychee/source/effect/Radius.js +++ b/libraries/lychee/source/effect/Radius.js @@ -20,26 +20,10 @@ lychee.define('lychee.effect.Radius').exports(function(lychee, global, attachmen // No data validation garbage allowed for effects - let type = lychee.enumof(Composite.TYPE, settings.type) ? settings.type : null; - let delay = typeof settings.delay === 'number' ? (settings.delay | 0) : null; - let duration = typeof settings.duration === 'number' ? (settings.duration | 0) : null; - let radius = typeof settings.radius === 'number' ? (settings.radius | 0) : null; - - if (type !== null) { - this.type = type; - } - - if (delay !== null) { - this.delay = delay; - } - - if (duration !== null) { - this.duration = duration; - } - - if (radius !== null) { - this.radius = radius; - } + this.type = lychee.enumof(Composite.TYPE, settings.type) ? settings.type : Composite.TYPE.easeout; + this.delay = typeof settings.delay === 'number' ? (settings.delay | 0) : 0; + this.duration = typeof settings.duration === 'number' ? (settings.duration | 0) : 250; + this.radius = typeof settings.radius === 'number' ? (settings.radius | 0) : 0; }; @@ -129,28 +113,28 @@ lychee.define('lychee.effect.Radius').exports(function(lychee, global, attachmen let k = 1 - t; - if ((k /= 1) < ( 1 / 2.75 )) { - f = 1 * ( 7.5625 * Math.pow(k, 2) ); - } else if (k < ( 2 / 2.75 )) { - f = 7.5625 * ( k -= ( 1.5 / 2.75 )) * k + 0.75; - } else if (k < ( 2.5 / 2.75 )) { - f = 7.5625 * ( k -= ( 2.25 / 2.75 )) * k + 0.9375; + if ((k /= 1) < (1 / 2.75)) { + f = 1 * (7.5625 * Math.pow(k, 2)); + } else if (k < (2 / 2.75)) { + f = 7.5625 * (k -= (1.5 / 2.75)) * k + 0.75; + } else if (k < (2.5 / 2.75)) { + f = 7.5625 * (k -= (2.25 / 2.75)) * k + 0.9375; } else { - f = 7.5625 * ( k -= ( 2.625 / 2.75 )) * k + 0.984375; + f = 7.5625 * (k -= (2.625 / 2.75)) * k + 0.984375; } r += (1 - f) * dr; } else if (type === Composite.TYPE.bounceeaseout) { - if ((t /= 1) < ( 1 / 2.75 )) { - f = 1 * ( 7.5625 * Math.pow(t, 2) ); - } else if (t < ( 2 / 2.75 )) { - f = 7.5625 * ( t -= ( 1.5 / 2.75 )) * t + 0.75; - } else if (t < ( 2.5 / 2.75 )) { - f = 7.5625 * ( t -= ( 2.25 / 2.75 )) * t + 0.9375; + if ((t /= 1) < (1 / 2.75)) { + f = 1 * (7.5625 * Math.pow(t, 2)); + } else if (t < (2 / 2.75)) { + f = 7.5625 * (t -= (1.5 / 2.75)) * t + 0.75; + } else if (t < (2.5 / 2.75)) { + f = 7.5625 * (t -= (2.25 / 2.75)) * t + 0.9375; } else { - f = 7.5625 * ( t -= ( 2.625 / 2.75 )) * t + 0.984375; + f = 7.5625 * (t -= (2.625 / 2.75)) * t + 0.984375; } r += f * dr; diff --git a/libraries/lychee/source/effect/Shake.js b/libraries/lychee/source/effect/Shake.js index bdb21eed..b13eb9bb 100644 --- a/libraries/lychee/source/effect/Shake.js +++ b/libraries/lychee/source/effect/Shake.js @@ -20,27 +20,15 @@ lychee.define('lychee.effect.Shake').exports(function(lychee, global, attachment // No data validation garbage allowed for effects - let type = lychee.enumof(Composite.TYPE, settings.type) ? settings.type : null; - let delay = typeof settings.delay === 'number' ? (settings.delay | 0) : null; - let duration = typeof settings.duration === 'number' ? (settings.duration | 0) : null; - let shake = settings.shake instanceof Object ? settings.shake : null; + this.type = lychee.enumof(Composite.TYPE, settings.type) ? settings.type : Composite.TYPE.easeout; + this.delay = typeof settings.delay === 'number' ? (settings.delay | 0) : 0; + this.duration = typeof settings.duration === 'number' ? (settings.duration | 0) : 250; - if (type !== null) { - this.type = type; - } - - if (delay !== null) { - this.delay = delay; - } - - if (duration !== null) { - this.duration = duration; - } - if (shake !== null) { - this.shake.x = typeof shake.x === 'number' ? (shake.x | 0) : null; - this.shake.y = typeof shake.y === 'number' ? (shake.y | 0) : null; - this.shake.z = typeof shake.z === 'number' ? (shake.z | 0) : null; + if (settings.shake instanceof Object) { + this.shake.x = typeof settings.shake.x === 'number' ? (settings.shake.x | 0) : null; + this.shake.y = typeof settings.shake.y === 'number' ? (settings.shake.y | 0) : null; + this.shake.z = typeof settings.shake.z === 'number' ? (settings.shake.z | 0) : null; } }; @@ -162,14 +150,14 @@ lychee.define('lychee.effect.Shake').exports(function(lychee, global, attachment let k = 1 - t; - if ((k /= 1) < ( 1 / 2.75 )) { - f = 1 * ( 7.5625 * Math.pow(k, 2) ); - } else if (k < ( 2 / 2.75 )) { - f = 7.5625 * ( k -= ( 1.5 / 2.75 )) * k + 0.75; - } else if (k < ( 2.5 / 2.75 )) { - f = 7.5625 * ( k -= ( 2.25 / 2.75 )) * k + 0.9375; + if ((k /= 1) < (1 / 2.75)) { + f = 1 * (7.5625 * Math.pow(k, 2)); + } else if (k < (2 / 2.75)) { + f = 7.5625 * (k -= (1.5 / 2.75)) * k + 0.75; + } else if (k < (2.5 / 2.75)) { + f = 7.5625 * (k -= (2.25 / 2.75)) * k + 0.9375; } else { - f = 7.5625 * ( k -= ( 2.625 / 2.75 )) * k + 0.984375; + f = 7.5625 * (k -= (2.625 / 2.75)) * k + 0.984375; } x += Math.sin((1 - f) * pi2) * dx; @@ -178,14 +166,14 @@ lychee.define('lychee.effect.Shake').exports(function(lychee, global, attachment } else if (type === Composite.TYPE.bounceeaseout) { - if ((t /= 1) < ( 1 / 2.75 )) { - f = 1 * ( 7.5625 * Math.pow(t, 2) ); - } else if (t < ( 2 / 2.75 )) { - f = 7.5625 * ( t -= ( 1.5 / 2.75 )) * t + 0.75; - } else if (t < ( 2.5 / 2.75 )) { - f = 7.5625 * ( t -= ( 2.25 / 2.75 )) * t + 0.9375; + if ((t /= 1) < (1 / 2.75)) { + f = 1 * (7.5625 * Math.pow(t, 2)); + } else if (t < (2 / 2.75)) { + f = 7.5625 * (t -= (1.5 / 2.75)) * t + 0.75; + } else if (t < (2.5 / 2.75)) { + f = 7.5625 * (t -= (2.25 / 2.75)) * t + 0.9375; } else { - f = 7.5625 * ( t -= ( 2.625 / 2.75 )) * t + 0.984375; + f = 7.5625 * (t -= (2.625 / 2.75)) * t + 0.984375; } x += Math.sin(f * pi2) * dx; diff --git a/libraries/lychee/source/effect/Sound.js b/libraries/lychee/source/effect/Sound.js index 4b186f23..69a1c3e7 100644 --- a/libraries/lychee/source/effect/Sound.js +++ b/libraries/lychee/source/effect/Sound.js @@ -10,23 +10,15 @@ lychee.define('lychee.effect.Sound').exports(function(lychee, global, attachment let Composite = function(settings) { this.delay = 0; - this.sound = true; + this.sound = null; this.__start = null; // No data validation garbage allowed for effects - let delay = typeof settings.delay === 'number' ? (settings.delay | 0) : null; - let sound = settings.sound instanceof Sound ? settings.sound : null; - - if (delay !== null) { - this.delay = delay; - } - - if (sound !== null) { - this.sound = sound; - } + this.delay = typeof settings.delay === 'number' ? (settings.delay | 0) : 0; + this.sound = settings.sound instanceof Sound ? settings.sound : null; }; diff --git a/libraries/lychee/source/effect/State.js b/libraries/lychee/source/effect/State.js index 0bb46831..9263055f 100644 --- a/libraries/lychee/source/effect/State.js +++ b/libraries/lychee/source/effect/State.js @@ -17,16 +17,8 @@ lychee.define('lychee.effect.State').exports(function(lychee, global, attachment // No data validation garbage allowed for effects - let delay = typeof settings.delay === 'number' ? (settings.delay | 0) : null; - let state = typeof settings.state === 'string' ? settings.state : null; - - if (delay !== null) { - this.delay = delay; - } - - if (state !== null) { - this.state = state; - } + this.delay = typeof settings.delay === 'number' ? (settings.delay | 0) : 0; + this.state = typeof settings.state === 'string' ? settings.state : null; }; diff --git a/libraries/lychee/source/effect/Velocity.js b/libraries/lychee/source/effect/Velocity.js index 7acf5719..09c8065c 100644 --- a/libraries/lychee/source/effect/Velocity.js +++ b/libraries/lychee/source/effect/Velocity.js @@ -20,27 +20,15 @@ lychee.define('lychee.effect.Velocity').exports(function(lychee, global, attachm // No data validation garbage allowed for effects - let type = lychee.enumof(Composite.TYPE, settings.type) ? settings.type : null; - let delay = typeof settings.delay === 'number' ? (settings.delay | 0) : null; - let duration = typeof settings.duration === 'number' ? (settings.duration | 0) : null; - let velocity = settings.velocity instanceof Object ? settings.velocity : null; + this.type = lychee.enumof(Composite.TYPE, settings.type) ? settings.type : Composite.TYPE.easeout; + this.delay = typeof settings.delay === 'number' ? (settings.delay | 0) : 0; + this.duration = typeof settings.duration === 'number' ? (settings.duration | 0) : 250; - if (type !== null) { - this.type = type; - } - - if (delay !== null) { - this.delay = delay; - } - - if (duration !== null) { - this.duration = duration; - } - if (velocity !== null) { - this.velocity.x = typeof velocity.x === 'number' ? (velocity.x | 0) : null; - this.velocity.y = typeof velocity.y === 'number' ? (velocity.y | 0) : null; - this.velocity.z = typeof velocity.z === 'number' ? (velocity.z | 0) : null; + if (settings.velocity instanceof Object) { + this.velocity.x = typeof settings.velocity.x === 'number' ? (settings.velocity.x | 0) : null; + this.velocity.y = typeof settings.velocity.y === 'number' ? (settings.velocity.y | 0) : null; + this.velocity.z = typeof settings.velocity.z === 'number' ? (settings.velocity.z | 0) : null; } }; @@ -161,14 +149,14 @@ lychee.define('lychee.effect.Velocity').exports(function(lychee, global, attachm let k = 1 - t; - if ((k /= 1) < ( 1 / 2.75 )) { - f = 1 * ( 7.5625 * Math.pow(k, 2) ); - } else if (k < ( 2 / 2.75 )) { - f = 7.5625 * ( k -= ( 1.5 / 2.75 )) * k + 0.75; - } else if (k < ( 2.5 / 2.75 )) { - f = 7.5625 * ( k -= ( 2.25 / 2.75 )) * k + 0.9375; + if ((k /= 1) < (1 / 2.75)) { + f = 1 * (7.5625 * Math.pow(k, 2)); + } else if (k < (2 / 2.75)) { + f = 7.5625 * (k -= (1.5 / 2.75)) * k + 0.75; + } else if (k < (2.5 / 2.75)) { + f = 7.5625 * (k -= (2.25 / 2.75)) * k + 0.9375; } else { - f = 7.5625 * ( k -= ( 2.625 / 2.75 )) * k + 0.984375; + f = 7.5625 * (k -= (2.625 / 2.75)) * k + 0.984375; } x += (1 - f) * dx; @@ -177,14 +165,14 @@ lychee.define('lychee.effect.Velocity').exports(function(lychee, global, attachm } else if (type === Composite.TYPE.bounceeaseout) { - if ((t /= 1) < ( 1 / 2.75 )) { - f = 1 * ( 7.5625 * Math.pow(t, 2) ); - } else if (t < ( 2 / 2.75 )) { - f = 7.5625 * ( t -= ( 1.5 / 2.75 )) * t + 0.75; - } else if (t < ( 2.5 / 2.75 )) { - f = 7.5625 * ( t -= ( 2.25 / 2.75 )) * t + 0.9375; + if ((t /= 1) < (1 / 2.75)) { + f = 1 * (7.5625 * Math.pow(t, 2)); + } else if (t < (2 / 2.75)) { + f = 7.5625 * (t -= (1.5 / 2.75)) * t + 0.75; + } else if (t < (2.5 / 2.75)) { + f = 7.5625 * (t -= (2.25 / 2.75)) * t + 0.9375; } else { - f = 7.5625 * ( t -= ( 2.625 / 2.75 )) * t + 0.984375; + f = 7.5625 * (t -= (2.625 / 2.75)) * t + 0.984375; } x += f * dx; diff --git a/libraries/lychee/source/effect/Visible.js b/libraries/lychee/source/effect/Visible.js index f610cc5a..2a5e0c6f 100644 --- a/libraries/lychee/source/effect/Visible.js +++ b/libraries/lychee/source/effect/Visible.js @@ -18,16 +18,8 @@ lychee.define('lychee.effect.Visible').exports(function(lychee, global, attachme // No data validation garbage allowed for effects - let delay = typeof settings.delay === 'number' ? (settings.delay | 0) : null; - let visible = settings.visible === true; - - if (delay !== null) { - this.delay = delay; - } - - if (visible === true || visible === false) { - this.visible = visible; - } + this.delay = typeof settings.delay === 'number' ? (settings.delay | 0) : 0; + this.visible = settings.visible === true; }; diff --git a/libraries/lychee/source/effect/Width.js b/libraries/lychee/source/effect/Width.js index e35da385..45519990 100644 --- a/libraries/lychee/source/effect/Width.js +++ b/libraries/lychee/source/effect/Width.js @@ -20,26 +20,10 @@ lychee.define('lychee.effect.Width').exports(function(lychee, global, attachment // No data validation garbage allowed for effects - let type = lychee.enumof(Composite.TYPE, settings.type) ? settings.type : null; - let delay = typeof settings.delay === 'number' ? (settings.delay | 0) : null; - let duration = typeof settings.duration === 'number' ? (settings.duration | 0) : null; - let width = typeof settings.width === 'number' ? (settings.width | 0) : null; - - if (type !== null) { - this.type = type; - } - - if (delay !== null) { - this.delay = delay; - } - - if (duration !== null) { - this.duration = duration; - } - - if (width !== null) { - this.width = width; - } + this.type = lychee.enumof(Composite.TYPE, settings.type) ? settings.type : Composite.TYPE.easeout; + this.delay = typeof settings.delay === 'number' ? (settings.delay | 0) : 0; + this.duration = typeof settings.duration === 'number' ? (settings.duration | 0) : 250; + this.width = typeof settings.width === 'number' ? (settings.width | 0) : 0; }; @@ -100,7 +84,6 @@ lychee.define('lychee.effect.Width').exports(function(lychee, global, attachment let origin = this.__origin; let width = this.width; - let w = origin; if (t <= 1) { @@ -130,28 +113,28 @@ lychee.define('lychee.effect.Width').exports(function(lychee, global, attachment let k = 1 - t; - if ((k /= 1) < ( 1 / 2.75 )) { - f = 1 * ( 7.5625 * Math.pow(k, 2) ); - } else if (k < ( 2 / 2.75 )) { - f = 7.5625 * ( k -= ( 1.5 / 2.75 )) * k + 0.75; - } else if (k < ( 2.5 / 2.75 )) { - f = 7.5625 * ( k -= ( 2.25 / 2.75 )) * k + 0.9375; + if ((k /= 1) < (1 / 2.75)) { + f = 1 * (7.5625 * Math.pow(k, 2)); + } else if (k < (2 / 2.75)) { + f = 7.5625 * (k -= (1.5 / 2.75)) * k + 0.75; + } else if (k < (2.5 / 2.75)) { + f = 7.5625 * (k -= (2.25 / 2.75)) * k + 0.9375; } else { - f = 7.5625 * ( k -= ( 2.625 / 2.75 )) * k + 0.984375; + f = 7.5625 * (k -= (2.625 / 2.75)) * k + 0.984375; } w += (1 - f) * dw; } else if (type === Composite.TYPE.bounceeaseout) { - if ((t /= 1) < ( 1 / 2.75 )) { - f = 1 * ( 7.5625 * Math.pow(t, 2) ); - } else if (t < ( 2 / 2.75 )) { - f = 7.5625 * ( t -= ( 1.5 / 2.75 )) * t + 0.75; - } else if (t < ( 2.5 / 2.75 )) { - f = 7.5625 * ( t -= ( 2.25 / 2.75 )) * t + 0.9375; + if ((t /= 1) < (1 / 2.75)) { + f = 1 * (7.5625 * Math.pow(t, 2)); + } else if (t < (2 / 2.75)) { + f = 7.5625 * (t -= (1.5 / 2.75)) * t + 0.75; + } else if (t < (2.5 / 2.75)) { + f = 7.5625 * (t -= (2.25 / 2.75)) * t + 0.9375; } else { - f = 7.5625 * ( t -= ( 2.625 / 2.75 )) * t + 0.984375; + f = 7.5625 * (t -= (2.625 / 2.75)) * t + 0.984375; } w += f * dw; diff --git a/libraries/lychee/source/math/Matrix.js b/libraries/lychee/source/math/Matrix.js index bfb4456b..d09c507c 100644 --- a/libraries/lychee/source/math/Matrix.js +++ b/libraries/lychee/source/math/Matrix.js @@ -375,17 +375,17 @@ lychee.define('lychee.math.Matrix').exports(function(lychee, global, attachments // Rotation Matrix - let r00 = x * x * t + c; - let r01 = y * x * t + z * s; - let r02 = z * x * t - y * s; + let r00 = x * x * t + cos; + let r01 = y * x * t + z * sin; + let r02 = z * x * t - y * sin; - let r10 = x * y * t - z * s; - let r11 = y * y * t + c; - let r12 = z * y * t + x * s; + let r10 = x * y * t - z * sin; + let r11 = y * y * t + cos; + let r12 = z * y * t + x * sin; - let r20 = x * z * t + y * s; - let r21 = y * z * t - x * s; - let r22 = z * z * t + c; + let r20 = x * z * t + y * sin; + let r21 = y * z * t - x * sin; + let r22 = z * z * t + cos; d[0] = a00 * r00 + a10 * r01 + a20 * r02; diff --git a/libraries/lychee/source/math/Mersenne.js b/libraries/lychee/source/math/Mersenne.js index 306662d2..d5b9dc23 100644 --- a/libraries/lychee/source/math/Mersenne.js +++ b/libraries/lychee/source/math/Mersenne.js @@ -76,21 +76,19 @@ lychee.define('lychee.math.Mersenne').exports(function(lychee, global, attachmen value = (twister[N - 1] & _UPPER_MASK) | (twister[0] & _LOWER_MASK); twister[N - 1] = twister[M - 1] ^ (value >>> 1) ^ _XOR_MATRIX[value & 0x1]; - index = 0; + this.index = 0; } - this.index = index++; - - - value = twister[index]; + value = twister[this.index++]; value ^= (value >>> 11); value ^= (value << 7) & 0x9d2c5680; value ^= (value << 15) & 0xefc60000; value ^= (value >>> 18); + return value >>> 0; }; @@ -148,7 +146,7 @@ lychee.define('lychee.math.Mersenne').exports(function(lychee, global, attachmen random: function() { - return _random_int32.call(this) * (1.0 / 4294967296.0); + return (_random_int32.call(this) * (1.0 / 4294967296.0)); } diff --git a/libraries/lychee/source/math/Vector3.js b/libraries/lychee/source/math/Vector3.js index 986f152c..5c443f7d 100644 --- a/libraries/lychee/source/math/Vector3.js +++ b/libraries/lychee/source/math/Vector3.js @@ -283,7 +283,7 @@ lychee.define('lychee.math.Vector3').exports(function(lychee, global, attachment interpolateAdd: function(vector, t) { - this.x += t * vector.x; + this.x += t * vector.x; this.y += t * vector.y; this.z += t * vector.z; @@ -326,7 +326,7 @@ lychee.define('lychee.math.Vector3').exports(function(lychee, global, attachment let vy = this.y; let vz = this.z; - let q = quarternion.data; + let q = quaternion.data; let qx = q[0]; let qy = q[1]; let qz = q[2]; diff --git a/libraries/lychee/source/math/Vector4.js b/libraries/lychee/source/math/Vector4.js index 0478dd9e..2fa1fed8 100644 --- a/libraries/lychee/source/math/Vector4.js +++ b/libraries/lychee/source/math/Vector4.js @@ -265,12 +265,10 @@ lychee.define('lychee.math.Vector4').exports(function(lychee, global, attachment let ax = this.x; let ay = this.y; let az = this.z; - let aw = this.w; let bx = this.x; let by = this.y; let bz = this.z; - let bw = this.w; this.x = ay * bz - az * by; @@ -303,7 +301,7 @@ lychee.define('lychee.math.Vector4').exports(function(lychee, global, attachment interpolateAdd: function(vector, t) { - this.x += t * vector.x; + this.x += t * vector.x; this.y += t * vector.y; this.z += t * vector.z; this.w += t * vector.w; @@ -315,7 +313,7 @@ lychee.define('lychee.math.Vector4').exports(function(lychee, global, attachment interpolateSet: function(vector, t) { - this.x = t * vector.x; + this.x = t * vector.x; this.y = t * vector.y; this.z = t * vector.z; this.w = t * vector.w; diff --git a/libraries/lychee/source/net/Service.js b/libraries/lychee/source/net/Service.js index d4b1aa69..c473141e 100644 --- a/libraries/lychee/source/net/Service.js +++ b/libraries/lychee/source/net/Service.js @@ -79,14 +79,9 @@ lychee.define('lychee.net.Service').requires([ let Composite = function(id, tunnel, type) { - id = typeof id === 'string' ? id : null; - tunnel = lychee.interfaceof(lychee.net.Tunnel, tunnel) ? tunnel : null; - type = lychee.enumof(Composite.TYPE, type) ? type : null; - - - this.id = id; - this.tunnel = tunnel; - this.type = type; + this.id = typeof id === 'string' ? id : null; + this.tunnel = lychee.interfaceof(lychee.net.Tunnel, tunnel) ? tunnel : null; + this.type = lychee.enumof(Composite.TYPE, type) ? type : null; this.__multicast = []; diff --git a/libraries/lychee/source/net/client/Debugger.js b/libraries/lychee/source/net/client/Debugger.js index 4ec9aec7..a18b91bc 100644 --- a/libraries/lychee/source/net/client/Debugger.js +++ b/libraries/lychee/source/net/client/Debugger.js @@ -53,10 +53,9 @@ lychee.define('lychee.net.client.Debugger').includes([ if (typeof data.construtor === 'string' || typeof data.reference === 'string') { - let scope = (lychee.environment !== null ? lychee.environment.global : global); let environment = (lychee.environment !== null ? lychee.environment : null); - let definition = lychee.deserialize(data); let value = false; + let definition = lychee.deserialize(data); if (environment !== null) { value = environment.define(definition); @@ -67,7 +66,7 @@ lychee.define('lychee.net.client.Debugger').includes([ this.tunnel.send({ tid: data.receiver, - value: definition !== null + value: value === true }, { id: 'debugger', event: 'define-value' @@ -162,7 +161,7 @@ lychee.define('lychee.net.client.Debugger').includes([ }, this); - this.bind('serialize', function(data) { + this.bind('snapshot', function(data) { if (typeof data.reference === 'string') { @@ -177,7 +176,7 @@ lychee.define('lychee.net.client.Debugger').includes([ value: value }, { id: 'debugger', - event: 'serialize-value' + event: 'snapshot-value' }); } @@ -321,7 +320,7 @@ lychee.define('lychee.net.client.Debugger').includes([ }, - serialize: function(tid, data) { + snapshot: function(tid, data) { tid = typeof tid === 'string' ? tid : null; data = data instanceof Object ? data : null; @@ -334,7 +333,7 @@ lychee.define('lychee.net.client.Debugger').includes([ reference: data.reference || null }, { id: 'debugger', - event: 'serialize' + event: 'snapshot' }); } diff --git a/libraries/lychee/source/net/protocol/HTTP.js b/libraries/lychee/source/net/protocol/HTTP.js index 6701b52b..83ff41b7 100644 --- a/libraries/lychee/source/net/protocol/HTTP.js +++ b/libraries/lychee/source/net/protocol/HTTP.js @@ -133,9 +133,7 @@ lychee.define('lychee.net.protocol.HTTP').exports(function(lychee, global, attac buffer = buffer.toString('utf8'); - let fragment = this.__fragment; - let type = this.type; - let chunk = { + let chunk = { bytes: -1, headers: {}, payload: null @@ -150,12 +148,10 @@ lychee.define('lychee.net.protocol.HTTP').exports(function(lychee, global, attac let headers_length = buffer.indexOf('\r\n\r\n'); let headers_data = buffer.substr(0, headers_length); let payload_data = buffer.substr(headers_length + 4); - let payload_length = buffer.length - headers_length - 4; let i_end = payload_data.indexOf('\r\n\r\n'); if (i_end !== -1) { - payload_data = payload_data.substr(0, i_end); - payload_length = payload_data.length; + payload_data = payload_data.substr(0, i_end); } @@ -320,14 +316,9 @@ lychee.define('lychee.net.protocol.HTTP').exports(function(lychee, global, attac let Composite = function(type) { - type = lychee.enumof(Composite.TYPE, type) ? type : null; - - - this.type = type; - + this.type = lychee.enumof(Composite.TYPE, type) ? type : null; this.__buffer = new Buffer(0); - this.__fragment = { payload: new Buffer(0) }; this.__isClosed = false; diff --git a/libraries/lychee/source/net/protocol/WS.js b/libraries/lychee/source/net/protocol/WS.js index db980de6..58f5b03f 100644 --- a/libraries/lychee/source/net/protocol/WS.js +++ b/libraries/lychee/source/net/protocol/WS.js @@ -212,7 +212,6 @@ lychee.define('lychee.net.protocol.WS').requires([ const _decode_buffer = function(buffer) { let fragment = this.__fragment; - let type = this.type; let chunk = { bytes: -1, headers: {}, @@ -392,11 +391,7 @@ lychee.define('lychee.net.protocol.WS').requires([ let Composite = function(type) { - type = lychee.enumof(Composite.TYPE, type) ? type : null; - - - this.type = type; - + this.type = lychee.enumof(Composite.TYPE, type) ? type : null; this.__buffer = new Buffer(0); this.__fragment = { operator: 0x00, payload: new Buffer(0) }; @@ -587,7 +582,13 @@ lychee.define('lychee.net.protocol.WS').requires([ ping: function() { - return _on_pong_frame.call(this); + let buffer = _on_pong_frame.call(this); + if (buffer !== null) { + return buffer; + } + + + return null; } diff --git a/libraries/lychee/source/net/remote/Chat.js b/libraries/lychee/source/net/remote/Chat.js index 8b084856..d26749c4 100644 --- a/libraries/lychee/source/net/remote/Chat.js +++ b/libraries/lychee/source/net/remote/Chat.js @@ -33,10 +33,6 @@ lychee.define('lychee.net.remote.Chat').includes([ let room = data.room || null; if (user !== null && room !== null) { - - let sync = false; - - // 1. Create Room let chat = _CHATS[room] || null; if (chat === null) { diff --git a/libraries/lychee/source/net/remote/Debugger.js b/libraries/lychee/source/net/remote/Debugger.js index 54b1d0f5..48508043 100644 --- a/libraries/lychee/source/net/remote/Debugger.js +++ b/libraries/lychee/source/net/remote/Debugger.js @@ -113,13 +113,13 @@ lychee.define('lychee.net.remote.Debugger').includes([ _bind_relay.call(this, 'define'); _bind_relay.call(this, 'execute'); _bind_relay.call(this, 'expose'); - _bind_relay.call(this, 'serialize'); + _bind_relay.call(this, 'snapshot'); // Relay events to proper tunnel (data.receiver > data.tid) _bind_console.call(this, 'define-value'); _bind_console.call(this, 'execute-value'); _bind_console.call(this, 'expose-value'); - _bind_console.call(this, 'serialize-value'); + _bind_console.call(this, 'snapshot-value'); }; diff --git a/libraries/lychee/source/platform/html-nwjs/Stash.js b/libraries/lychee/source/platform/html-nwjs/Stash.js index 88cc5cc2..3409d7d1 100644 --- a/libraries/lychee/source/platform/html-nwjs/Stash.js +++ b/libraries/lychee/source/platform/html-nwjs/Stash.js @@ -13,7 +13,7 @@ lychee.define('Stash').tags({ return true; - } catch(err) { + } catch (err) { } @@ -83,7 +83,7 @@ lychee.define('Stash').tags({ const _mkdir_p = function(path, mode) { if (mode === undefined) { - mode = 0777 & (~process.umask()); + mode = 0o777 & (~process.umask()); } @@ -93,7 +93,7 @@ lychee.define('Stash').tags({ is_directory = _fs.lstatSync(path).isDirectory(); - } catch(err) { + } catch (err) { if (err.code === 'ENOENT') { @@ -103,16 +103,15 @@ lychee.define('Stash').tags({ try { is_directory = _fs.lstatSync(path).isDirectory(); - } catch(err) { + } catch (err) { } } - } finally { + } - return is_directory; - } + return is_directory; }; @@ -149,7 +148,7 @@ lychee.define('Stash').tags({ try { _fs.writeFileSync(path, buffer, encoding); result = true; - } catch(err) { + } catch (err) { result = false; } @@ -162,7 +161,7 @@ lychee.define('Stash').tags({ try { _fs.unlinkSync(path); result = true; - } catch(err) { + } catch (err) { result = false; } @@ -202,7 +201,7 @@ lychee.define('Stash').tags({ * HELPERS */ - const _is_asset = function(asset) { + const _validate_asset = function(asset) { if (asset instanceof Object && typeof asset.serialize === 'function') { return true; @@ -658,8 +657,8 @@ lychee.define('Stash').tags({ write: function(id, asset) { - id = typeof id === 'string' ? id : null; - asset = _is_asset(asset) === true ? asset : null; + id = typeof id === 'string' ? id : null; + asset = _validate_asset(asset) === true ? asset : null; if (id !== null && asset !== null) { diff --git a/libraries/lychee/source/platform/html-nwjs/Storage.js b/libraries/lychee/source/platform/html-nwjs/Storage.js index e860e50e..1f032cc1 100644 --- a/libraries/lychee/source/platform/html-nwjs/Storage.js +++ b/libraries/lychee/source/platform/html-nwjs/Storage.js @@ -13,7 +13,7 @@ lychee.define('Storage').tags({ return true; - } catch(err) { + } catch (err) { } @@ -78,7 +78,7 @@ lychee.define('Storage').tags({ let raw = null; try { raw = _fs.readFileSync(url, 'utf8'); - } catch(err) { + } catch (err) { raw = null; } @@ -86,7 +86,7 @@ lychee.define('Storage').tags({ let buffer = null; try { buffer = JSON.parse(raw); - } catch(err) { + } catch (err) { buffer = null; } @@ -122,7 +122,7 @@ lychee.define('Storage').tags({ let result = false; try { result = _fs.writeFileSync(url, buffer, 'utf8'); - } catch(err) { + } catch (err) { result = false; } diff --git a/libraries/lychee/source/platform/html-nwjs/bootstrap.js b/libraries/lychee/source/platform/html-nwjs/bootstrap.js index d093b825..d6eb4d3e 100644 --- a/libraries/lychee/source/platform/html-nwjs/bootstrap.js +++ b/libraries/lychee/source/platform/html-nwjs/bootstrap.js @@ -44,7 +44,10 @@ lychee.ROOT.lychee = selfpath.substr(0, tmp1).substr(tmp2 + 3); } else if (tmp1 !== -1) { lychee.ROOT.lychee = selfpath.substr(0, tmp1); - } else if (typeof process !== 'undefined') { + } + + + if (typeof process !== 'undefined') { cwd = process.cwd() || ''; selfpath = cwd.split('/').slice(0, -1).join('/'); } @@ -77,5 +80,33 @@ }; + + + /* + * FEATURES + */ + + // This is an incremental platform of 'html' + + const _FEATURES = { + + require: function(id) { + + if (id === 'child_process') return {}; + if (id === 'fs') return {}; + if (id === 'http') return {}; + if (id === 'https') return {}; + if (id === 'net') return {}; + if (id === 'path') return {}; + + + throw new Error('Cannot find module \'' + id + '\''); + + } + + }; + + Object.assign(lychee.Environment.__FEATURES, _FEATURES); + })(this.lychee, this); diff --git a/libraries/lychee/source/platform/html-nwjs/net/Server.js b/libraries/lychee/source/platform/html-nwjs/net/Server.js index b520e004..2d8a6584 100644 --- a/libraries/lychee/source/platform/html-nwjs/net/Server.js +++ b/libraries/lychee/source/platform/html-nwjs/net/Server.js @@ -16,7 +16,7 @@ lychee.define('lychee.net.Server').tags({ global.require('net'); return true; - } catch(err) { + } catch (err) { } } diff --git a/libraries/lychee/source/platform/html-nwjs/net/socket/HTTP.js b/libraries/lychee/source/platform/html-nwjs/net/socket/HTTP.js index 0093ecab..6f4b541d 100644 --- a/libraries/lychee/source/platform/html-nwjs/net/socket/HTTP.js +++ b/libraries/lychee/source/platform/html-nwjs/net/socket/HTTP.js @@ -15,7 +15,7 @@ lychee.define('lychee.net.socket.HTTP').tags({ return true; - } catch(err) { + } catch (err) { } } @@ -40,11 +40,15 @@ lychee.define('lychee.net.socket.HTTP').tags({ let that = this; if (that.__connection !== socket) { - socket.on('data', function(blob) { + socket.on('data', function(raw) { // XXX: nwjs has global scope problems // XXX: Internal Buffer is not our global.Buffer interface - blob = new global.Buffer(blob); + + let blob = new Buffer(raw.length); + for (let b = 0; b < blob.length; b++) { + blob[b] = raw[b]; + } let chunks = protocol.receive(blob); @@ -159,7 +163,7 @@ lychee.define('lychee.net.socket.HTTP').tags({ let that = this; - let url = /:/g.test(host) ? ('http://[' + host + ']:' + port) : ('http://' + host + ':' + port); + // let url = /:/g.test(host) ? ('http://[' + host + ']:' + port) : ('http://' + host + ':' + port); let protocol = null; diff --git a/libraries/lychee/source/platform/html-nwjs/net/socket/WS.js b/libraries/lychee/source/platform/html-nwjs/net/socket/WS.js index db5b728c..dbda770d 100644 --- a/libraries/lychee/source/platform/html-nwjs/net/socket/WS.js +++ b/libraries/lychee/source/platform/html-nwjs/net/socket/WS.js @@ -19,7 +19,7 @@ lychee.define('lychee.net.socket.WS').tags({ return true; - } catch(err) { + } catch (err) { } } @@ -29,12 +29,14 @@ lychee.define('lychee.net.socket.WS').tags({ }).exports(function(lychee, global, attachments) { - const _net = global.require('net'); - const _setInterval = global.setInterval; - const _Buffer = global.require('buffer').Buffer; - const _Emitter = lychee.import('lychee.event.Emitter'); - const _Protocol = lychee.import('lychee.net.protocol.WS'); - const _SHA1 = lychee.import('lychee.crypto.SHA1'); + const Buffer = lychee.import('Buffer'); + const _net = global.require('net'); + const _clearInterval = global.clearInterval; + const _setInterval = global.setInterval; + const _Buffer = global.require('buffer').Buffer; + const _Emitter = lychee.import('lychee.event.Emitter'); + const _Protocol = lychee.import('lychee.net.protocol.WS'); + const _SHA1 = lychee.import('lychee.crypto.SHA1'); @@ -47,11 +49,15 @@ lychee.define('lychee.net.socket.WS').tags({ let that = this; if (that.__connection !== socket) { - socket.on('data', function(blob) { + socket.on('data', function(raw) { // XXX: nwjs has global scope problems // XXX: Internal Buffer is not our global.Buffer interface - blob = new global.Buffer(blob); + + let blob = new Buffer(raw.length); + for (let b = 0; b < blob.length; b++) { + blob[b] = raw[b]; + } let chunks = protocol.receive(blob); @@ -213,7 +219,7 @@ lychee.define('lychee.net.socket.WS').tags({ const _upgrade_client = function(host, port, nonce) { - let that = this; + // let that = this; let handshake = ''; let identifier = lychee.ROOT.project; @@ -379,7 +385,7 @@ lychee.define('lychee.net.socket.WS').tags({ let that = this; - let url = /:/g.test(host) ? ('ws://[' + host + ']:' + port) : ('ws://' + host + ':' + port); + // let url = /:/g.test(host) ? ('ws://[' + host + ']:' + port) : ('ws://' + host + ':' + port); if (host !== null && port !== null) { @@ -475,11 +481,22 @@ lychee.define('lychee.net.socket.WS').tags({ socket.removeAllListeners('timeout'); - _setInterval(function() { + let interval_id = _setInterval(function() { + + if (socket.writable) { + + let chunk = protocol.ping(); + if (chunk !== null) { + // XXX: nwjs has global scope problems + // XXX: Internal Buffer is not our global.Buffer interface + socket.write(_Buffer.from(chunk)); + } + + } else { + + _clearInterval(interval_id); + interval_id = null; - let chunk = protocol.ping(); - if (chunk !== null) { - socket.write(chunk); } }.bind(this), 60000); @@ -551,12 +568,12 @@ lychee.define('lychee.net.socket.WS').tags({ if (connection !== null && protocol !== null) { let chunk = protocol.send(payload, headers, binary); - let enc = binary === true ? 'binary' : 'utf8'; + // let enc = binary === true ? 'binary' : 'utf8'; if (chunk !== null) { // XXX: nwjs has global scope problems // XXX: Internal Buffer is not our global.Buffer interface - connection.write(chunk.toString(enc), enc); + connection.write(_Buffer.from(chunk)); } } diff --git a/libraries/lychee/source/platform/html-nwjs/ui/entity/Download.js b/libraries/lychee/source/platform/html-nwjs/ui/entity/Download.js new file mode 100644 index 00000000..115892d0 --- /dev/null +++ b/libraries/lychee/source/platform/html-nwjs/ui/entity/Download.js @@ -0,0 +1,221 @@ + +lychee.define('lychee.ui.entity.Download').tags({ + platform: 'html-nwjs' +}).includes([ + 'lychee.ui.entity.Button' +]).supports(function(lychee, global) { + + if ( + typeof global.require === 'function' + && typeof global.document !== 'undefined' + && typeof global.document.createElement === 'function' + ) { + + try { + + global.require('fs'); + + return true; + + } catch (err) { + + } + + } + + + return false; + +}).exports(function(lychee, global, attachments) { + + // const Buffer = lychee.import('Buffer'); + const _fs = global.require('fs'); + const _Buffer = global.require('buffer').Buffer; + const _Button = lychee.import('lychee.ui.entity.Button'); + + + + /* + * HELPERS + */ + + const _MIME_TYPE = { + 'Config': { name: 'Entity', ext: 'json', mime: 'application/json', enc: 'utf8' }, + 'Font': { name: 'Entity', ext: 'fnt', mime: 'application/json', enc: 'utf8' }, + 'Music': { + 'mp3': { name: 'Entity', ext: 'msc.mp3', mime: 'audio/mp3', enc: 'binary' }, + 'ogg': { name: 'Entity', ext: 'msc.ogg', mime: 'application/ogg', enc: 'binary' } + }, + 'Sound': { + 'mp3': { name: 'Entity', ext: 'snd.mp3', mime: 'audio/mp3', enc: 'binary' }, + 'ogg': { name: 'Entity', ext: 'snd.ogg', mime: 'application/ogg', enc: 'binary' } + }, + 'Texture': { name: 'Entity', ext: 'png', mime: 'image/png', enc: 'binary' }, + 'Stuff': { name: 'Entity', ext: 'stuff', mime: 'application/octet-stream', enc: 'utf8' } + }; + + const _download = function(asset) { + + let data = asset.serialize(); + let url = data.arguments[0]; + let name = url.split('/').pop(); + let mime = _MIME_TYPE[data.constructor] || _MIME_TYPE['Stuff']; + + + if (data.blob !== null) { + + if (/Music|Sound/.test(data.constructor)) { + + for (let ext in mime) { + + let element = global.document.createElement('input'); + + element.setAttribute('type', 'file'); + element.setAttribute('nwsaveas', name + '.' + mime[ext].ext); + + element.onchange = function() { + + let blob = new _Buffer(data.blob.buffer[ext], 'base64'); + let path = this.value; + + _fs.writeFileSync(path, blob, mime[ext].enc); + + }; + + element.click(); + + } + + } else { + + if (url.substr(0, 5) === 'data:') { + name = mime.name + '.' + mime.ext; + } + + let element = global.document.createElement('input'); + + element.setAttribute('type', 'file'); + element.setAttribute('nwsaveas', name); + + element.onchange = function() { + + let blob = new _Buffer(data.blob.buffer, 'base64'); + let path = this.value; + + _fs.writeFileSync(path, blob, mime.enc); + + }; + + element.click(); + + } + + } + + }; + + + + /* + * IMPLEMENTATION + */ + + let Composite = function(data) { + + let settings = Object.assign({ + label: 'DOWNLOAD' + }, data); + + + this.value = []; + + + this.setValue(settings.value); + + delete settings.value; + + + _Button.call(this, settings); + + settings = null; + + + + /* + * INITIALIZATION + */ + + this.unbind('touch'); + this.bind('touch', function() { + + this.value.forEach(function(asset) { + _download(asset); + }); + + }, this); + + }; + + + Composite.prototype = { + + /* + * ENTITY API + */ + + // deserialize: function(blob) {}, + + serialize: function() { + + let data = _Button.prototype.serialize.call(this); + data['constructor'] = 'lychee.ui.entity.Download'; + + + return data; + + }, + + + + /* + * CUSTOM API + */ + + setValue: function(value) { + + value = value instanceof Array ? value : null; + + + if (value !== null) { + + this.value = value.filter(function(asset) { + + if (asset instanceof global.Config) return true; + if (asset instanceof global.Font) return true; + if (asset instanceof global.Music) return true; + if (asset instanceof global.Sound) return true; + if (asset instanceof global.Texture) return true; + if (asset instanceof global.Stuff) return true; + + + return false; + + }); + + + return true; + + } + + + return false; + + } + + }; + + + return Composite; + +}); + diff --git a/libraries/lychee/source/platform/html-nwjs/ui/entity/Helper.js b/libraries/lychee/source/platform/html-nwjs/ui/entity/Helper.js index 7cdc32f5..9003ef19 100644 --- a/libraries/lychee/source/platform/html-nwjs/ui/entity/Helper.js +++ b/libraries/lychee/source/platform/html-nwjs/ui/entity/Helper.js @@ -19,7 +19,7 @@ lychee.define('lychee.ui.entity.Helper').tags({ return true; - } catch(err) { + } catch (err) { } @@ -134,7 +134,7 @@ lychee.define('lychee.ui.entity.Helper').tags({ helper.on('exit', function(code) {}); - } catch(err) { + } catch (err) { helper = null; diff --git a/libraries/lychee/source/platform/html/Renderer.js b/libraries/lychee/source/platform/html/Renderer.js index d6ae8e87..6ea09dcf 100644 --- a/libraries/lychee/source/platform/html/Renderer.js +++ b/libraries/lychee/source/platform/html/Renderer.js @@ -23,8 +23,27 @@ lychee.define('Renderer').tags({ }).exports(function(lychee, global, attachments) { - const _PI2 = Math.PI * 2; - let _id = 0; + const _PI2 = Math.PI * 2; + let _id = 0; + let _body = null; + + + + /* + * FEATURE DETECTION + */ + + (function(global) { + + if (typeof global.document !== 'undefined') { + + if (typeof global.document.body !== 'undefined') { + _body = global.document.body; + } + + } + + })(global); @@ -86,7 +105,10 @@ lychee.define('Renderer').tags({ this.__canvas = global.document.createElement('canvas'); this.__canvas.className = 'lychee-Renderer'; this.__ctx = this.__canvas.getContext('2d'); - global.document.body.appendChild(this.__canvas); + + if (_body !== null) { + _body.appendChild(this.__canvas); + } this.setAlpha(settings.alpha); @@ -590,8 +612,8 @@ lychee.define('Renderer').tags({ y, width, height, - -1/2 * width, - -1/2 * height, + -1 / 2 * width, + -1 / 2 * height, width, height ); diff --git a/libraries/lychee/source/platform/html/Stash.js b/libraries/lychee/source/platform/html/Stash.js index 83e392d7..a826a205 100644 --- a/libraries/lychee/source/platform/html/Stash.js +++ b/libraries/lychee/source/platform/html/Stash.js @@ -72,13 +72,13 @@ lychee.define('Stash').tags({ try { local = 'localStorage' in global; - } catch(err) { + } catch (err) { local = false; } try { session = 'sessionStorage' in global; - } catch(err) { + } catch (err) { session = false; } @@ -134,7 +134,7 @@ lychee.define('Stash').tags({ }; - (function _initialize() { + (function() { let data = _JSON.decode(global.localStorage.getItem('lychee-Stash-PERSISTENT')); if (data !== null) { @@ -174,7 +174,7 @@ lychee.define('Stash').tags({ * HELPERS */ - const _is_asset = function(asset) { + const _validate_asset = function(asset) { if (asset instanceof Object && typeof asset.serialize === 'function') { return true; @@ -629,8 +629,8 @@ lychee.define('Stash').tags({ write: function(id, asset) { - id = typeof id === 'string' ? id : null; - asset = _is_asset(asset) === true ? asset : null; + id = typeof id === 'string' ? id : null; + asset = _validate_asset(asset) === true ? asset : null; if (id !== null && asset !== null) { diff --git a/libraries/lychee/source/platform/html/Storage.js b/libraries/lychee/source/platform/html/Storage.js index 62dbe243..e3c70287 100644 --- a/libraries/lychee/source/platform/html/Storage.js +++ b/libraries/lychee/source/platform/html/Storage.js @@ -53,7 +53,7 @@ lychee.define('Storage').tags({ _TEMPORARY = global.sessionStorage; } - } catch(err) { + } catch (err) { local = false; session = true; diff --git a/libraries/lychee/source/platform/html/Viewport.js b/libraries/lychee/source/platform/html/Viewport.js index f47b795b..c7e4e698 100644 --- a/libraries/lychee/source/platform/html/Viewport.js +++ b/libraries/lychee/source/platform/html/Viewport.js @@ -368,7 +368,7 @@ lychee.define('Viewport').tags({ } else { - orientation = 'landscape'; + orientation = 'landscape'; rotation = 'portrait'; } @@ -393,7 +393,7 @@ lychee.define('Viewport').tags({ } else { - orientation = 'landscape'; + orientation = 'landscape'; rotation = 'portrait'; } diff --git a/libraries/lychee/source/platform/html/bootstrap.js b/libraries/lychee/source/platform/html/bootstrap.js index 89dd2219..834eb317 100644 --- a/libraries/lychee/source/platform/html/bootstrap.js +++ b/libraries/lychee/source/platform/html/bootstrap.js @@ -87,7 +87,7 @@ try { callback.call(scope, xhr.responseText || xhr.responseXML); - } catch(err) { + } catch (err) { lychee.Debugger.report(lychee.environment, err, null); } finally { xhr = null; @@ -99,7 +99,7 @@ try { callback.call(scope, null); - } catch(err) { + } catch (err) { lychee.Debugger.report(lychee.environment, err, null); } finally { xhr = null; @@ -118,6 +118,12 @@ * POLYFILLS */ + let consol = 'console' in global && typeof console !== 'undefined'; + if (consol === false) { + console = {}; + } + + const _clear = console.clear || function() {}; const _log = console.log || function() {}; const _info = console.info || console.log; const _warn = console.warn || console.log; @@ -126,6 +132,10 @@ let _std_err = ''; + console.clear = function() { + _clear.call(console); + }; + console.log = function() { let al = arguments.length; @@ -313,21 +323,11 @@ }; - let consol = 'console' in global && typeof console !== 'undefined'; let audio = 'Audio' in global && typeof Audio !== 'undefined'; let buffer = true; let image = 'Image' in global && typeof Image !== 'undefined'; - if (consol) { - - } else { - - console = {}; - - } - - if (audio) { let audiotest = new Audio(); @@ -427,9 +427,7 @@ }; - if (image) { - - } else { + if (!image) { Image = function() { @@ -567,7 +565,7 @@ try { return decodeURIComponent(str); - } catch(err) { + } catch (err) { return String.fromCharCode(0xFFFD); } @@ -626,7 +624,7 @@ let length = str.length; let placeholders = '=' === str.charAt(length - 2) ? 2 : '=' === str.charAt(length - 1) ? 1 : 0; - let bytes = new Array(length * 3/4 - placeholders); + let bytes = new Array(length * 3 / 4 - placeholders); let l = placeholders > 0 ? str.length - 4 : str.length; let tmp; @@ -704,17 +702,17 @@ tmp = (bytes[bytes.length - 2] << 8) + (bytes[bytes.length - 1]); - str += _encode_base64( tmp >> 10); - str += _encode_base64((tmp >> 4) & 0x3F); - str += _encode_base64((tmp << 2) & 0x3F); + str += _encode_base64(tmp >> 10); + str += _encode_base64((tmp >> 4) & 0x3F); + str += _encode_base64((tmp << 2) & 0x3F); str += '='; } else if (extrabytes === 1) { tmp = bytes[bytes.length - 1]; - str += _encode_base64( tmp >> 2); - str += _encode_base64((tmp << 4) & 0x3F); + str += _encode_base64(tmp >> 2); + str += _encode_base64((tmp << 4) & 0x3F); str += '=='; } @@ -759,7 +757,7 @@ let str = ''; for (let b = start; b < end; b++) { - str += String.fromCharCode(buffer[i]); + str += String.fromCharCode(buffer[b]); } return str; @@ -928,13 +926,23 @@ map: function(callback) { - callback = callback instanceof Function ? callback : function(value) { return value; }; + callback = callback instanceof Function ? callback : null; let clone = new Buffer(this.length); - for (let b = 0; b < this.length; b++) { - clone[b] = callback(this[b], b); + if (callback !== null) { + + for (let b = 0; b < this.length; b++) { + clone[b] = callback(this[b], b); + } + + } else { + + for (let b = 0; b < this.length; b++) { + clone[b] = this[b]; + } + } return clone; @@ -1127,7 +1135,7 @@ let data = null; try { data = JSON.parse(raw); - } catch(err) { + } catch (err) { } @@ -1135,14 +1143,8 @@ this.__load = false; - if (data !== null) { - - } else { - - if (lychee.debug === true) { - console.error('bootstrap.js: Config at "' + this.url + '" is invalid'); - } - + if (data === null) { + console.warn('bootstrap.js: Invalid Config at "' + this.url + '" (No JSON file).'); } @@ -1189,9 +1191,7 @@ } else { - if (lychee.debug === true) { - console.error('bootstrap.js: Font at "' + this.url + '" is invalid (No FNT file)'); - } + console.warn('bootstrap.js: Invalid Font at "' + this.url + '" (No FNT file).'); } @@ -1427,7 +1427,7 @@ let data = null; try { data = JSON.parse(raw); - } catch(err) { + } catch (err) { } @@ -1675,7 +1675,7 @@ try { this.buffer.currentTime = 0; - } catch(err) { + } catch (err) { } if (this.buffer.currentTime === 0) { @@ -1714,7 +1714,7 @@ try { this.buffer.currentTime = 0; - } catch(err) { + } catch (err) { } } @@ -1969,7 +1969,7 @@ try { this.buffer.currentTime = 0; - } catch(err) { + } catch (err) { } if (this.buffer.currentTime === 0) { @@ -2008,7 +2008,7 @@ try { this.buffer.currentTime = 0; - } catch(err) { + } catch (err) { } } @@ -2194,9 +2194,7 @@ } else { - if (lychee.debug === true) { - console.error('bootstrap.js: Texture at "' + url.substr(0, 15) + '" is invalid (no PNG file)'); - } + console.warn('bootstrap.js: Invalid Texture at "' + url.substr(0, 15) + '" (No PNG file).'); if (this.onload instanceof Function) { @@ -2224,7 +2222,7 @@ let is_power_of_two = (this.width & (this.width - 1)) === 0 && (this.height & (this.height - 1)) === 0; if (lychee.debug === true && is_power_of_two === false) { - console.warn('bootstrap.js: Texture at ' + this.url + ' is NOT power-of-two'); + console.warn('bootstrap.js: Texture at "' + this.url + '" is NOT power-of-two'); } @@ -2248,9 +2246,7 @@ } else { - if (lychee.debug === true) { - console.error('bootstrap.js: Texture at "' + this.url + '" is invalid (no PNG file)'); - } + console.warn('bootstrap.js: Invalid Texture at "' + this.url + '" (no PNG file).'); if (this.onload instanceof Function) { @@ -2418,7 +2414,6 @@ }, function(raw) { if (raw !== null) { - // this.buffer = raw.toString('utf8'); this.buffer = raw; } else { this.buffer = ''; @@ -2442,6 +2437,65 @@ + /* + * FEATURES + */ + + const _FEATURES = { + + innerWidth: 1337, + innerHeight: 1337, + + CanvasRenderingContext2D: function() {}, + FileReader: function() {}, + Storage: function() {}, + WebSocket: function() {}, + XMLHttpRequest: function() {}, + + addEventListener: function() {}, + clearInterval: function() {}, + clearTimeout: function() {}, + requestAnimationFrame: function() {}, + setInterval: function() {}, + setTimeout: function() {}, + + document: { + createElement: function() {}, + querySelectorAll: function() {}, + body: { + appendChild: function() {} + } + }, + + location: { + href: 'file:///tmp/index.html' + }, + + localStorage: { + }, + + sessionStorage: { + } + + }; + + _FEATURES.FileReader.prototype.readAsDataURL = function() {}; + + + Object.defineProperty(lychee.Environment, '__FEATURES', { + + get: function() { + return _FEATURES; + }, + + set: function(value) { + return false; + } + + }); + + + /* * EXPORTS */ diff --git a/libraries/lychee/source/platform/html/net/Server.js b/libraries/lychee/source/platform/html/net/Server.js index 3cf54f79..884c3ee2 100644 --- a/libraries/lychee/source/platform/html/net/Server.js +++ b/libraries/lychee/source/platform/html/net/Server.js @@ -149,7 +149,7 @@ lychee.define('lychee.net.Server').tags({ // TODO: Setup HTTP Server - let that = this; + // let that = this; // let server = new _net.Server(); diff --git a/libraries/lychee/source/platform/html/net/socket/HTTP.js b/libraries/lychee/source/platform/html/net/socket/HTTP.js index 2c17ab29..cbbbf970 100644 --- a/libraries/lychee/source/platform/html/net/socket/HTTP.js +++ b/libraries/lychee/source/platform/html/net/socket/HTTP.js @@ -244,7 +244,7 @@ lychee.define('lychee.net.socket.HTTP').tags({ let that = this; - let url = /:/g.test(host) ? ('http://[' + host + ']:' + port) : ('http://' + host + ':' + port); + // let url = /:/g.test(host) ? ('http://[' + host + ']:' + port) : ('http://' + host + ':' + port); let protocol = null; diff --git a/libraries/lychee/source/platform/html/ui/entity/Download.js b/libraries/lychee/source/platform/html/ui/entity/Download.js index 1b02de1b..cd82d98f 100644 --- a/libraries/lychee/source/platform/html/ui/entity/Download.js +++ b/libraries/lychee/source/platform/html/ui/entity/Download.js @@ -30,11 +30,11 @@ lychee.define('lychee.ui.entity.Download').tags({ 'Font': { name: 'Entity', ext: 'fnt', mime: 'application/json' }, 'Music': { 'mp3': { name: 'Entity', ext: 'msc.mp3', mime: 'audio/mp3' }, - 'ogg': { name: 'Entity', ext: 'msc.ogg', mime: 'application/ogg' }, + 'ogg': { name: 'Entity', ext: 'msc.ogg', mime: 'application/ogg' } }, 'Sound': { 'mp3': { name: 'Entity', ext: 'snd.mp3', mime: 'audio/mp3' }, - 'ogg': { name: 'Entity', ext: 'snd.ogg', mime: 'application/ogg' }, + 'ogg': { name: 'Entity', ext: 'snd.ogg', mime: 'application/ogg' } }, 'Texture': { name: 'Entity', ext: 'png', mime: 'image/png' }, 'Stuff': { name: 'Entity', ext: 'stuff', mime: 'application/octet-stream' } @@ -56,7 +56,7 @@ lychee.define('lychee.ui.entity.Download').tags({ let element = global.document.createElement('a'); - element.download = name + '.' + ext; + element.download = name + '.' + mime[ext].ext; element.href = data.blob.buffer[ext]; element.click(); diff --git a/libraries/lychee/source/platform/html/ui/entity/Upload.js b/libraries/lychee/source/platform/html/ui/entity/Upload.js index 4fb9e413..747cc3b2 100644 --- a/libraries/lychee/source/platform/html/ui/entity/Upload.js +++ b/libraries/lychee/source/platform/html/ui/entity/Upload.js @@ -78,7 +78,9 @@ lychee.define('lychee.ui.entity.Upload').tags({ } element._visible = false; - element.setAttribute('accept', allowed.map(function(v) { return '.' + v; }).join(',')); + element.setAttribute('accept', allowed.map(function(v) { + return '.' + v; + }).join(',')); element.setAttribute('type', 'file'); element.setAttribute('multiple', ''); diff --git a/libraries/lychee/source/platform/node/Renderer.js b/libraries/lychee/source/platform/node/Renderer.js index dfccabb4..cc6784b2 100644 --- a/libraries/lychee/source/platform/node/Renderer.js +++ b/libraries/lychee/source/platform/node/Renderer.js @@ -57,10 +57,10 @@ lychee.define('Renderer').tags({ let width = this.width; let height = this.height; - for (let y = 0; y < this.height; y++) { + for (let y = 0; y < height; y++) { - for (let x = 0; x < this.width; x++) { - this.__ctx[y][x] = ' '; + for (let x = 0; x < width; x++) { + ctx[y][x] = ' '; } } @@ -311,11 +311,9 @@ lychee.define('Renderer').tags({ lineWidth = typeof lineWidth === 'number' ? lineWidth : 1; - let ctx = this.__ctx; - let pi2 = Math.PI * 2; - - // TODO: Implement arc-drawing ASCII art algorithm + // let ctx = this.__ctx; + // let pi2 = Math.PI * 2; }, @@ -354,16 +352,24 @@ lychee.define('Renderer').tags({ // top - right - bottom - left y = y1; - for (x = x1 + 1; x < x2; x++) _draw_ctx.call(ctx, x, y, '-'); + for (x = x1 + 1; x < x2; x++) { + _draw_ctx.call(ctx, x, y, '-'); + } x = x2; - for (y = y1 + 1; y < y2; y++) _draw_ctx.call(ctx, x, y, '|'); + for (y = y1 + 1; y < y2; y++) { + _draw_ctx.call(ctx, x, y, '|'); + } y = y2; - for (x = x1 + 1; x < x2; x++) _draw_ctx.call(ctx, x, y, '-'); + for (x = x1 + 1; x < x2; x++) { + _draw_ctx.call(ctx, x, y, '-'); + } x = x1; - for (y = y1 + 1; y < y2; y++) _draw_ctx.call(ctx, x, y, '|'); + for (y = y1 + 1; y < y2; y++) { + _draw_ctx.call(ctx, x, y, '|'); + } }, @@ -384,7 +390,7 @@ lychee.define('Renderer').tags({ for (let y = y1; y < y2; y++) { for (let x = x1; x < x2; x++) { - this.__ctx[y][x] = buffer.__ctx[y - y1][x - x1]; + ctx[y][x] = buffer.__ctx[y - y1][x - x1]; } } @@ -400,10 +406,8 @@ lychee.define('Renderer').tags({ lineWidth = typeof lineWidth === 'number' ? lineWidth : 1; - let ctx = this.__ctx; - - // TODO: Implement circle-drawing ASCII art algorithm + // let ctx = this.__ctx; }, @@ -413,10 +417,8 @@ lychee.define('Renderer').tags({ lineWidth = typeof lineWidth === 'number' ? lineWidth : 1; - let ctx = this.__ctx; - - // TODO: Implement line-drawing ASCII art algorithm + // let ctx = this.__ctx; }, @@ -427,54 +429,50 @@ lychee.define('Renderer').tags({ lineWidth = typeof lineWidth === 'number' ? lineWidth : 1; - let ctx = this.__ctx; - - // TODO: Implement triangle-drawing ASCII art algorithm + // let ctx = this.__ctx; }, // points, x1, y1, [ ... x(a), y(a) ... ], [ color, background, lineWidth ] drawPolygon: function(points, x1, y1) { - let l = arguments.length; + // TODO: Implement polygon-drawing ASCII art algorithm + // let l = arguments.length; - if (points > 3) { + // if (points > 3) { - let optargs = l - (points * 2) - 1; + // let optargs = l - (points * 2) - 1; - let color, background, lineWidth; + // let color, background, lineWidth; - if (optargs === 3) { + // if (optargs === 3) { - color = arguments[l - 3]; - background = arguments[l - 2]; - lineWidth = arguments[l - 1]; + // color = arguments[l - 3]; + // background = arguments[l - 2]; + // lineWidth = arguments[l - 1]; - } else if (optargs === 2) { + // } else if (optargs === 2) { - color = arguments[l - 2]; - background = arguments[l - 1]; + // color = arguments[l - 2]; + // background = arguments[l - 1]; - } else if (optargs === 1) { + // } else if (optargs === 1) { - color = arguments[l - 1]; + // color = arguments[l - 1]; - } - - - color = /(#[AaBbCcDdEeFf0-9]{6})/g.test(color) ? color : '#000000'; - background = background === true; - lineWidth = typeof lineWidth === 'number' ? lineWidth : 1; + // } - let ctx = this.__ctx; + // color = /(#[AaBbCcDdEeFf0-9]{6})/g.test(color) ? color : '#000000'; + // background = background === true; + // lineWidth = typeof lineWidth === 'number' ? lineWidth : 1; - // TODO: Implement polygon-drawing ASCII art algorithm + // let ctx = this.__ctx; - } + // } }, @@ -486,11 +484,12 @@ lychee.define('Renderer').tags({ if (texture !== null) { - if (map === null) { + // TODO: Implement sprite-drawing ASCII art algorithm + // if (map === null) { - } else { + // } else { - } + // } } diff --git a/libraries/lychee/source/platform/node/Stash.js b/libraries/lychee/source/platform/node/Stash.js index a4c08af1..fc829004 100644 --- a/libraries/lychee/source/platform/node/Stash.js +++ b/libraries/lychee/source/platform/node/Stash.js @@ -13,7 +13,7 @@ lychee.define('Stash').tags({ return true; - } catch(err) { + } catch (err) { } @@ -83,7 +83,7 @@ lychee.define('Stash').tags({ const _mkdir_p = function(path, mode) { if (mode === undefined) { - mode = 0777 & (~process.umask()); + mode = 0o777 & (~process.umask()); } @@ -93,7 +93,7 @@ lychee.define('Stash').tags({ is_directory = _fs.lstatSync(path).isDirectory(); - } catch(err) { + } catch (err) { if (err.code === 'ENOENT') { @@ -103,16 +103,15 @@ lychee.define('Stash').tags({ try { is_directory = _fs.lstatSync(path).isDirectory(); - } catch(err) { + } catch (err) { } } - } finally { + } - return is_directory; - } + return is_directory; }; @@ -149,7 +148,7 @@ lychee.define('Stash').tags({ try { _fs.writeFileSync(path, buffer, encoding); result = true; - } catch(err) { + } catch (err) { result = false; } @@ -162,7 +161,7 @@ lychee.define('Stash').tags({ try { _fs.unlinkSync(path); result = true; - } catch(err) { + } catch (err) { result = false; } @@ -202,7 +201,7 @@ lychee.define('Stash').tags({ * HELPERS */ - const _is_asset = function(asset) { + const _validate_asset = function(asset) { if (asset instanceof Object && typeof asset.serialize === 'function') { return true; @@ -658,8 +657,8 @@ lychee.define('Stash').tags({ write: function(id, asset) { - id = typeof id === 'string' ? id : null; - asset = _is_asset(asset) === true ? asset : null; + id = typeof id === 'string' ? id : null; + asset = _validate_asset(asset) === true ? asset : null; if (id !== null && asset !== null) { diff --git a/libraries/lychee/source/platform/node/Storage.js b/libraries/lychee/source/platform/node/Storage.js index 8925d66c..1c64949e 100644 --- a/libraries/lychee/source/platform/node/Storage.js +++ b/libraries/lychee/source/platform/node/Storage.js @@ -13,7 +13,7 @@ lychee.define('Storage').tags({ return true; - } catch(err) { + } catch (err) { } @@ -78,7 +78,7 @@ lychee.define('Storage').tags({ let raw = null; try { raw = _fs.readFileSync(url, 'utf8'); - } catch(err) { + } catch (err) { raw = null; } @@ -86,7 +86,7 @@ lychee.define('Storage').tags({ let buffer = null; try { buffer = JSON.parse(raw); - } catch(err) { + } catch (err) { buffer = null; } @@ -122,7 +122,7 @@ lychee.define('Storage').tags({ let result = false; try { result = _fs.writeFileSync(url, buffer, 'utf8'); - } catch(err) { + } catch (err) { result = false; } diff --git a/libraries/lychee/source/platform/node/bootstrap.js b/libraries/lychee/source/platform/node/bootstrap.js index eb76de5e..24c7c2c6 100644 --- a/libraries/lychee/source/platform/node/bootstrap.js +++ b/libraries/lychee/source/platform/node/bootstrap.js @@ -42,7 +42,7 @@ const _load_asset = function(settings, callback, scope) { let path = lychee.environment.resolve(settings.url); - let encoding = settings.encoding === 'binary' ? 'binary': 'utf8'; + let encoding = settings.encoding === 'binary' ? 'binary' : 'utf8'; _fs.readFile(path, encoding, function(error, buffer) { @@ -54,7 +54,7 @@ try { callback.call(scope, raw); - } catch(err) { + } catch (err) { lychee.Debugger.report(lychee.environment, err, null); } @@ -75,6 +75,15 @@ let _std_out = ''; let _std_err = ''; + console.clear = function() { + + // clear screen + // process.stdout.write('\x1B[2J'); + + // clear screen and reset cursor + process.stdout.write('\x1B[2J\x1B[0f'); + + }; console.log = function() { @@ -209,10 +218,10 @@ let key = { - name: null, - ctrl: false, - meta: false, - shift: false + name: null, + ctrl: false, + meta: false, + shift: false }; @@ -283,26 +292,26 @@ // Parse the key itself switch (code) { - /* xterm ESC O letter */ + // xterm ESC O letter case 'OP': key.name = 'f1'; break; case 'OQ': key.name = 'f2'; break; case 'OR': key.name = 'f3'; break; case 'OS': key.name = 'f4'; break; - /* xterm ESC [ number ~ */ + // xterm ESC [ number ~ case '[11~': key.name = 'f1'; break; case '[12~': key.name = 'f2'; break; case '[13~': key.name = 'f3'; break; case '[14~': key.name = 'f4'; break; - /* Cygwin/libuv */ + // Cygwin/libuv case '[[A': key.name = 'f1'; break; case '[[B': key.name = 'f2'; break; case '[[C': key.name = 'f3'; break; case '[[D': key.name = 'f4'; break; case '[[E': key.name = 'f5'; break; - /* common */ + // common case '[15~': key.name = 'f5'; break; case '[17~': key.name = 'f6'; break; case '[18~': key.name = 'f7'; break; @@ -312,7 +321,7 @@ case '[23~': key.name = 'f11'; break; case '[24~': key.name = 'f12'; break; - /* xterm ESC [ letter */ + // xterm ESC [ letter case '[A': key.name = 'up'; break; case '[B': key.name = 'down'; break; case '[C': key.name = 'right'; break; @@ -321,7 +330,7 @@ case '[F': key.name = 'end'; break; case '[H': key.name = 'home'; break; - /* xterm ESC O letter */ + // xterm ESC O letter case 'OA': key.name = 'up'; break; case 'OB': key.name = 'down'; break; case 'OC': key.name = 'right'; break; @@ -330,7 +339,7 @@ case 'OF': key.name = 'end'; break; case 'OH': key.name = 'home'; break; - /* xterm ESC [ number ~ */ + // xterm ESC [ number ~ case '[1~': key.name = 'home'; break; case '[2~': key.name = 'insert'; break; case '[3~': key.name = 'delete'; break; @@ -338,11 +347,11 @@ case '[5~': key.name = 'pageup'; break; case '[6~': key.name = 'pagedown'; break; - /* Putty */ + // Putty case '[[5~': key.name = 'pageup'; break; case '[[6~': key.name = 'pagedown'; break; - /* misc. */ + // misc. case '[Z': key.name = 'tab'; key.shift = true; break; default: key.name = null; break; @@ -413,13 +422,23 @@ Buffer.prototype.map = function(callback) { - callback = callback instanceof Function ? callback : function(value) { return value; }; + callback = callback instanceof Function ? callback : null; let clone = new Buffer(this.length); - for (let b = 0; b < this.length; b++) { - clone[b] = callback(this[b], b); + if (callback !== null) { + + for (let b = 0; b < this.length; b++) { + clone[b] = callback(this[b], b); + } + + } else { + + for (let b = 0; b < this.length; b++) { + clone[b] = this[b]; + } + } return clone; @@ -524,21 +543,15 @@ let data = null; try { data = JSON.parse(raw); - } catch(err) { + } catch (err) { } this.buffer = data; - if (data !== null) { - - } else { - - if (lychee.debug === true) { - console.error('bootstrap.js: Config at ' + this.url + ' is invalid (No JSON file)'); - } - + if (data === null) { + console.warn('bootstrap.js: Invalid Config at "' + this.url + '" (No JSON file).'); } @@ -585,9 +598,7 @@ } else { - if (lychee.debug === true) { - console.error('bootstrap.js: Font at "' + this.url + '" is invalid (No FNT file)'); - } + console.warn('bootstrap.js: Invalid Font at "' + this.url + '" (No FNT file).'); } @@ -821,7 +832,7 @@ let data = null; try { data = JSON.parse(raw); - } catch(err) { + } catch (err) { } @@ -1321,9 +1332,7 @@ } else { - if (lychee.debug === true) { - console.error('bootstrap.js: Texture at "' + url.substr(0, 15) + '" is invalid (no PNG file)'); - } + console.warn('bootstrap.js: Invalid Texture at "' + url.substr(0, 15) + '" (No PNG file).'); } @@ -1352,9 +1361,9 @@ } - let is_power_of_two = (this.width & (this.width - 1)) === 0 && (this.height & (this.height - 1)) === 0; + let is_power_of_two = (this.width & (this.width - 1)) === 0 && (this.height & (this.height - 1)) === 0; if (lychee.debug === true && is_power_of_two === false) { - console.warn('bootstrap.js: Texture at ' + this.url + ' is NOT power-of-two'); + console.warn('bootstrap.js: Texture at "' + this.url + '" is NOT power-of-two'); } @@ -1367,9 +1376,7 @@ } else { - if (lychee.debug === true) { - console.error('bootstrap.js: Texture at "' + this.url + '" is invalid (no PNG file)'); - } + console.warn('bootstrap.js: Invalid Texture at "' + this.url + '" (No PNG file).'); if (this.onload instanceof Function) { @@ -1420,7 +1427,7 @@ try { require(cid); - } catch(err) { + } catch (err) { lychee.Debugger.report(lychee.environment, err, stuff); } @@ -1550,6 +1557,62 @@ + /* + * FEATURES + */ + + const _FEATURES = { + + require: function(id) { + + if (id === 'child_process') return {}; + if (id === 'fs') return {}; + if (id === 'http') return {}; + if (id === 'https') return {}; + if (id === 'net') return {}; + if (id === 'path') return {}; + + + throw new Error('Cannot find module \'' + id + '\''); + + }, + + process: { + env: { + APPDATA: null, + HOME: '/home/dev' + }, + stdin: { + on: function() {} + }, + stdout: { + on: function() {}, + write: function() {} + } + }, + + clearInterval: function() {}, + clearTimeout: function() {}, + setInterval: function() {}, + setTimeout: function() {} + + }; + + + Object.defineProperty(lychee.Environment, '__FEATURES', { + + get: function() { + return _FEATURES; + }, + + set: function(value) { + return false; + } + + }); + + + /* * EXPORTS */ @@ -1583,7 +1646,6 @@ }); - module.exports = function(root) { let stream = process.stdin; diff --git a/libraries/lychee/source/platform/node/net/Server.js b/libraries/lychee/source/platform/node/net/Server.js index 82840f62..52affa2d 100644 --- a/libraries/lychee/source/platform/node/net/Server.js +++ b/libraries/lychee/source/platform/node/net/Server.js @@ -16,7 +16,7 @@ lychee.define('lychee.net.Server').tags({ global.require('net'); return true; - } catch(err) { + } catch (err) { } } diff --git a/libraries/lychee/source/platform/node/net/socket/HTTP.js b/libraries/lychee/source/platform/node/net/socket/HTTP.js index c240a953..ec1d3bb5 100644 --- a/libraries/lychee/source/platform/node/net/socket/HTTP.js +++ b/libraries/lychee/source/platform/node/net/socket/HTTP.js @@ -15,7 +15,7 @@ lychee.define('lychee.net.socket.HTTP').tags({ return true; - } catch(err) { + } catch (err) { } } @@ -154,7 +154,7 @@ lychee.define('lychee.net.socket.HTTP').tags({ let that = this; - let url = /:/g.test(host) ? ('http://[' + host + ']:' + port) : ('http://' + host + ':' + port); + // let url = /:/g.test(host) ? ('http://[' + host + ']:' + port) : ('http://' + host + ':' + port); let protocol = null; diff --git a/libraries/lychee/source/platform/node/net/socket/WS.js b/libraries/lychee/source/platform/node/net/socket/WS.js index 50e168a1..6642cfbb 100644 --- a/libraries/lychee/source/platform/node/net/socket/WS.js +++ b/libraries/lychee/source/platform/node/net/socket/WS.js @@ -19,7 +19,7 @@ lychee.define('lychee.net.socket.WS').tags({ return true; - } catch(err) { + } catch (err) { } } @@ -29,11 +29,12 @@ lychee.define('lychee.net.socket.WS').tags({ }).exports(function(lychee, global, attachments) { - const _net = global.require('net'); - const _setInterval = global.setInterval; - const _Emitter = lychee.import('lychee.event.Emitter'); - const _Protocol = lychee.import('lychee.net.protocol.WS'); - const _SHA1 = lychee.import('lychee.crypto.SHA1'); + const _net = global.require('net'); + const _clearInterval = global.clearInterval; + const _setInterval = global.setInterval; + const _Emitter = lychee.import('lychee.event.Emitter'); + const _Protocol = lychee.import('lychee.net.protocol.WS'); + const _SHA1 = lychee.import('lychee.crypto.SHA1'); @@ -207,7 +208,7 @@ lychee.define('lychee.net.socket.WS').tags({ const _upgrade_client = function(host, port, nonce) { - let that = this; + // let that = this; let handshake = ''; let identifier = lychee.ROOT.project; @@ -373,7 +374,7 @@ lychee.define('lychee.net.socket.WS').tags({ let that = this; - let url = /:/g.test(host) ? ('ws://[' + host + ']:' + port) : ('ws://' + host + ':' + port); + // let url = /:/g.test(host) ? ('ws://[' + host + ']:' + port) : ('ws://' + host + ':' + port); if (host !== null && port !== null) { @@ -469,11 +470,20 @@ lychee.define('lychee.net.socket.WS').tags({ socket.removeAllListeners('timeout'); - _setInterval(function() { + let interval_id = _setInterval(function() { + + if (socket.writable) { + + let chunk = protocol.ping(); + if (chunk !== null) { + socket.write(chunk); + } + + } else { + + _clearInterval(interval_id); + interval_id = null; - let chunk = protocol.ping(); - if (chunk !== null) { - socket.write(chunk); } }.bind(this), 60000); diff --git a/libraries/lychee/source/platform/node/ui/entity/Download.js b/libraries/lychee/source/platform/node/ui/entity/Download.js index 6fc90c37..b5358697 100644 --- a/libraries/lychee/source/platform/node/ui/entity/Download.js +++ b/libraries/lychee/source/platform/node/ui/entity/Download.js @@ -17,7 +17,7 @@ lychee.define('lychee.ui.entity.Download').tags({ return true; - } catch(err) { + } catch (err) { } @@ -28,6 +28,7 @@ lychee.define('lychee.ui.entity.Download').tags({ }).exports(function(lychee, global, attachments) { + const _fs = global.require('fs'); const _Button = lychee.import('lychee.ui.entity.Button'); const _HOME = (function(env) { @@ -55,11 +56,11 @@ lychee.define('lychee.ui.entity.Download').tags({ 'Font': { name: 'Entity', ext: 'fnt', enc: 'utf8' }, 'Music': { 'mp3': { name: 'Entity', ext: 'msc.mp3', enc: 'binary' }, - 'ogg': { name: 'Entity', ext: 'msc.ogg', enc: 'binary' }, + 'ogg': { name: 'Entity', ext: 'msc.ogg', enc: 'binary' } }, 'Sound': { 'mp3': { name: 'Entity', ext: 'snd.mp3', enc: 'binary' }, - 'ogg': { name: 'Entity', ext: 'snd.ogg', enc: 'binary' }, + 'ogg': { name: 'Entity', ext: 'snd.ogg', enc: 'binary' } }, 'Texture': { name: 'Entity', ext: 'png', enc: 'binary' }, 'Stuff': { name: 'Entity', ext: 'stuff', enc: 'utf8' } @@ -82,7 +83,7 @@ lychee.define('lychee.ui.entity.Download').tags({ let blob = new Buffer(data.blob.buffer[ext], 'base64'); let path = _HOME + '/' + name + '.' + mime[ext].ext; - _fs.writeFileSync(path, buffer, mime[ext].enc); + _fs.writeFileSync(path, blob, mime[ext].enc); } @@ -95,7 +96,7 @@ lychee.define('lychee.ui.entity.Download').tags({ path = _HOME + '/' + mime.name + '.' + mime.ext; } - _fs.writeFileSync(path, buffer, mime.enc); + _fs.writeFileSync(path, blob, mime.enc); } diff --git a/libraries/lychee/source/platform/node/ui/entity/Helper.js b/libraries/lychee/source/platform/node/ui/entity/Helper.js index e4753c9f..d907f42e 100644 --- a/libraries/lychee/source/platform/node/ui/entity/Helper.js +++ b/libraries/lychee/source/platform/node/ui/entity/Helper.js @@ -13,7 +13,7 @@ lychee.define('lychee.ui.entity.Helper').tags({ return true; - } catch(err) { + } catch (err) { } @@ -92,10 +92,10 @@ lychee.define('lychee.ui.entity.Helper').tags({ try { - let helper = _child_process.execFile(_root + '/bin/helper.sh', [ + let helper = _child_process.execFile(_ROOT + '/bin/helper.sh', [ 'lycheejs://' + value ], { - cwd: _root + cwd: _ROOT }, function(error, stdout, stderr) { stderr = (stderr.trim() || '').toString(); @@ -127,7 +127,7 @@ lychee.define('lychee.ui.entity.Helper').tags({ helper.on('exit', function(code) {}); - } catch(err) { + } catch (err) { helper = null; diff --git a/libraries/lychee/source/policy/Position.js b/libraries/lychee/source/policy/Position.js new file mode 100644 index 00000000..d75a555a --- /dev/null +++ b/libraries/lychee/source/policy/Position.js @@ -0,0 +1,94 @@ + +lychee.define('lychee.policy.Position').exports(function(lychee, global, attachments) { + + /* + * IMPLEMENTATION + */ + + let Composite = function(data) { + + let settings = lychee.assignsafe({ + limit: 0xffff + }, data); + + + this.entity = settings.entity || null; + this.limit = settings.limit; + + settings = null; + + }; + + + Composite.prototype = { + + /* + * ENTITY API + */ + + serialize: function() { + + let settings = { + entity: null, + limit: this.limit + }; + + + return { + 'constructor': 'lychee.policy.Position', + 'arguments': [ settings ] + }; + + }, + + + + /* + * CUSTOM API + */ + + sensor: function() { + + let entity = this.entity; + let limit = this.limit; + let values = [ 0.5, 0.5, 0.5 ]; + + if (entity !== null) { + + values[0] = entity.position.x / limit; + values[1] = entity.position.y / limit; + values[2] = entity.position.z / limit; + + } + + + return values; + + }, + + control: function(values) { + + let entity = this.entity; + let limit = this.limit; + let x = values[0] * limit; + let y = values[1] * limit; + let z = values[2] * limit; + + + if (entity !== null) { + + entity.position.x = x; + entity.position.y = y; + entity.position.z = z; + + } + + } + + }; + + + return Composite; + +}); + diff --git a/libraries/lychee/source/policy/Velocity.js b/libraries/lychee/source/policy/Velocity.js new file mode 100644 index 00000000..26681ee7 --- /dev/null +++ b/libraries/lychee/source/policy/Velocity.js @@ -0,0 +1,95 @@ + +lychee.define('lychee.policy.Velocity').exports(function(lychee, global, attachments) { + + /* + * IMPLEMENTATION + */ + + let Composite = function(data) { + + let settings = lychee.assignsafe({ + limit: 0xffff + }, data); + + + this.entity = settings.entity || null; + this.limit = settings.limit; + + settings = null; + + }; + + + Composite.prototype = { + + /* + * ENTITY API + */ + + serialize: function() { + + let settings = { + entity: null, + limit: this.limit + }; + + + return { + 'constructor': 'lychee.policy.Velocity', + 'arguments': [ settings ] + }; + + }, + + + + /* + * CUSTOM API + */ + + sensor: function() { + + let entity = this.entity; + let limit = this.limit; + let values = [ 0.5, 0.5, 0.5 ]; + + + if (entity !== null) { + + values[0] = entity.velocity.x / limit; + values[1] = entity.velocity.y / limit; + values[2] = entity.velocity.z / limit; + + } + + + return values; + + }, + + control: function(values) { + + let entity = this.entity; + let limit = this.limit; + let x = values[0] * limit; + let y = values[1] * limit; + let z = values[2] * limit; + + + if (entity !== null) { + + entity.velocity.x = x; + entity.velocity.y = y; + entity.velocity.z = z; + + } + + } + + }; + + + return Composite; + +}); + diff --git a/libraries/lychee/source/ui/Blueprint.js b/libraries/lychee/source/ui/Blueprint.js index b9b36fe6..797ba0fd 100644 --- a/libraries/lychee/source/ui/Blueprint.js +++ b/libraries/lychee/source/ui/Blueprint.js @@ -49,10 +49,9 @@ lychee.define('lychee.ui.Blueprint').requires([ let entity = null; let other = null; let type = this.type; - let x1 = -1/2 * this.width; - let x2 = 1/2 * this.width; - let y1 = -1/2 * this.height; - let y2 = 1/2 * this.height; + let x1 = -1 / 2 * this.width; + let x2 = 1 / 2 * this.width; + let y1 = -1 / 2 * this.height; let off_x = x1 + 32; let off_y = y1 + 32; let pos_x = 0; @@ -100,7 +99,7 @@ lychee.define('lychee.ui.Blueprint').requires([ entity.setPosition({ x: pos_x, - y: pos_y - 3/2 * this.height + y: pos_y - 3 / 2 * this.height }); entity.addEffect(new _Position({ @@ -147,7 +146,7 @@ lychee.define('lychee.ui.Blueprint').requires([ entity.setPosition({ x: pos_x, - y: pos_y - 3/2 * this.height + y: pos_y - 3 / 2 * this.height }); entity.addEffect(new _Position({ @@ -185,7 +184,7 @@ lychee.define('lychee.ui.Blueprint').requires([ entity.setPosition({ x: pos_x, - y: pos_y - 3/2 * this.height + y: pos_y - 3 / 2 * this.height }); entity.addEffect(new _Position({ @@ -227,7 +226,7 @@ lychee.define('lychee.ui.Blueprint').requires([ entity.setPosition({ x: pos_x, - y: pos_y - 3/2 * this.height + y: pos_y - 3 / 2 * this.height }); entity.addEffect(new _Position({ @@ -279,7 +278,7 @@ lychee.define('lychee.ui.Blueprint').requires([ entity.setPosition({ x: pos_x, - y: pos_y - 3/2 * this.height + y: pos_y - 3 / 2 * this.height }); entity.addEffect(new _Position({ @@ -316,7 +315,7 @@ lychee.define('lychee.ui.Blueprint').requires([ entity.setPosition({ x: pos_x, - y: pos_y - 3/2 * this.height + y: pos_y - 3 / 2 * this.height }); entity.addEffect(new _Position({ @@ -353,7 +352,7 @@ lychee.define('lychee.ui.Blueprint').requires([ entity.setPosition({ x: pos_x, - y: pos_y - 3/2 * this.height + y: pos_y - 3 / 2 * this.height }); entity.addEffect(new _Position({ @@ -390,7 +389,7 @@ lychee.define('lychee.ui.Blueprint').requires([ entity.setPosition({ x: pos_x, - y: pos_y - 3/2 * this.height + y: pos_y - 3 / 2 * this.height }); entity.addEffect(new _Position({ @@ -426,7 +425,7 @@ lychee.define('lychee.ui.Blueprint').requires([ entity.setPosition({ x: pos_x, - y: pos_y - 3/2 * this.height + y: pos_y - 3 / 2 * this.height }); entity.addEffect(new _Position({ @@ -477,9 +476,7 @@ lychee.define('lychee.ui.Blueprint').requires([ if (name === 'tab') { - let e = focus.entity !== null ? entities.indexOf(focus.entity) : 0; - - for (let el = entities.length; e < el; e++) { + for (let e = focus.entity !== null ? entities.indexOf(focus.entity) : 0, el = entities.length; e < el; e++) { let entity = entities[e]; if (entity === focus.entity) { @@ -513,9 +510,7 @@ lychee.define('lychee.ui.Blueprint').requires([ } else if (name === 'shift-tab') { - let e = focus.entity !== null ? entities.indexOf(focus.entity) : entities.length - 1; - - for (let el = entities.length; e >= 0; e--) { + for (let e = focus.entity !== null ? entities.indexOf(focus.entity) : entities.length - 1; e >= 0; e--) { let entity = entities[e]; if (entity === focus.entity) { diff --git a/libraries/lychee/source/ui/Element.js b/libraries/lychee/source/ui/Element.js index 84728127..80fb8e91 100644 --- a/libraries/lychee/source/ui/Element.js +++ b/libraries/lychee/source/ui/Element.js @@ -35,10 +35,10 @@ lychee.define('lychee.ui.Element').requires([ ]; - let x1 = -1/2 * this.width; - let x2 = 1/2 * this.width; - let y1 = -1/2 * this.height; - let y2 = 1/2 * this.height; + let x1 = -1 / 2 * this.width; + let x2 = 1 / 2 * this.width; + let y1 = -1 / 2 * this.height; + let y2 = 1 / 2 * this.height; if (content.length % 2 === 0) { @@ -57,13 +57,13 @@ lychee.define('lychee.ui.Element').requires([ if (label !== null) { - label.position.x = x1 + 16 + label.width / 2; - label.position.y = y1 + offset + label.height / 2; + label.position.x = x1 + 16 + label.width / 2; + label.position.y = y1 + offset + label.height / 2; label.visible = true; - entity.width = 1/2 * (this.width - 32); - entity.position.x = 1/4 * (this.width - 32); - entity.position.y = y1 + offset + entity.height / 2; + entity.width = 1 / 2 * (this.width - 32); + entity.position.x = 1 / 4 * (this.width - 32); + entity.position.y = y1 + offset + entity.height / 2; entity.visible = true; entity.trigger('relayout'); diff --git a/libraries/lychee/source/ui/Entity.js b/libraries/lychee/source/ui/Entity.js index 8ddc163d..48b09e18 100644 --- a/libraries/lychee/source/ui/Entity.js +++ b/libraries/lychee/source/ui/Entity.js @@ -86,7 +86,7 @@ lychee.define('lychee.ui.Entity').includes([ * ENTITY API */ - // deserialize: function(blob) { }, + // deserialize: function(blob) {}, serialize: function() { @@ -102,11 +102,11 @@ lychee.define('lychee.ui.Entity').includes([ if (this.depth !== 0) settings.depth = this.depth; if (this.radius !== 0) settings.radius = this.radius; - if (this.alpha !== 1) settings.alpha = this.alpha; + if (this.alpha !== 1) settings.alpha = this.alpha; if (this.shape !== Composite.SHAPE.rectangle) settings.shape = this.shape; - if (this.state !== 'default') settings.state = this.state; - if (Object.keys(this.__states).length > 0) settings.states = this.__states; - if (this.visible !== true) settings.visible = this.visible; + if (this.state !== 'default') settings.state = this.state; + if (Object.keys(this.__states).length > 0) settings.states = this.__states; + if (this.visible !== true) settings.visible = this.visible; if (this.position.x !== 0 || this.position.y !== 0) { @@ -139,9 +139,9 @@ lychee.define('lychee.ui.Entity').includes([ update: function(clock, delta) { let effects = this.effects; - for (let e = 0, el = this.effects.length; e < el; e++) { + for (let e = 0, el = effects.length; e < el; e++) { - let effect = this.effects[e]; + let effect = effects[e]; if (effect.update(this, clock, delta) === false) { this.removeEffect(effect); el--; @@ -207,12 +207,12 @@ lychee.define('lychee.ui.Entity').includes([ setAlpha: function(alpha) { - alpha = (typeof alpha === 'number' && alpha >= 0 && alpha <= 1) ? alpha : null; + alpha = typeof alpha === 'number' ? alpha : null; if (alpha !== null) { - this.alpha = alpha; + this.alpha = Math.min(Math.max(alpha, 0), 1); return true; diff --git a/libraries/lychee/source/ui/Layer.js b/libraries/lychee/source/ui/Layer.js index d735d63d..a356aaa3 100644 --- a/libraries/lychee/source/ui/Layer.js +++ b/libraries/lychee/source/ui/Layer.js @@ -537,9 +537,9 @@ lychee.define('lychee.ui.Layer').requires([ } let effects = this.effects; - for (let ef = 0, efl = this.effects.length; ef < efl; ef++) { + for (let ef = 0, efl = effects.length; ef < efl; ef++) { - let effect = this.effects[ef]; + let effect = effects[ef]; if (effect.update(this, clock, delta) === false) { this.removeEffect(effect); efl--; @@ -826,9 +826,12 @@ lychee.define('lychee.ui.Layer').requires([ setEntities: function(entities) { + entities = entities instanceof Array ? entities : null; + + let all = true; - if (entities instanceof Array) { + if (entities !== null) { this.entities = []; diff --git a/libraries/lychee/source/ui/Menu.js b/libraries/lychee/source/ui/Menu.js index f2189c37..28b8842a 100644 --- a/libraries/lychee/source/ui/Menu.js +++ b/libraries/lychee/source/ui/Menu.js @@ -70,7 +70,7 @@ lychee.define('lychee.ui.Menu').requires([ this.bind('touch', function(id, position, delta) { - let min_y = -1/2 * this.height + 64; + let min_y = -1 / 2 * this.height + 64; if (min_y > position.y) { if (this.state === 'active') { @@ -201,15 +201,13 @@ lychee.define('lychee.ui.Menu').requires([ } - this.__boundary = -1/2 * width; - this.position.x = -1/2 * width + this.width / 2; + this.__boundary = -1 / 2 * width; + this.position.x = -1 / 2 * width + this.width / 2; let entity = null; - let x1 = -1/2 * this.width; - let y1 = -1/2 * this.height; - let x2 = 1/2 * this.width; - let y2 = 1/2 * this.height; + let y1 = -1 / 2 * this.height; + let y2 = 1 / 2 * this.height; entity = this.getEntity('@label'); diff --git a/libraries/lychee/source/ui/Notice.js b/libraries/lychee/source/ui/Notice.js index 9c9a2923..5922c766 100644 --- a/libraries/lychee/source/ui/Notice.js +++ b/libraries/lychee/source/ui/Notice.js @@ -27,7 +27,7 @@ lychee.define('lychee.ui.Notice').requires([ let button = this.getEntity('@options-next'); let label = this.getEntity('@label'); - let x2 = 1/2 * this.width; + let x2 = 1 / 2 * this.width; if (button.visible === true) { @@ -103,8 +103,8 @@ lychee.define('lychee.ui.Notice').requires([ if (typeof width === 'number' && typeof height === 'number') { - this.__boundary = 1/2 * height; - this.position.y = 1/2 * height + this.height / 2; + this.__boundary = 1 / 2 * height; + this.position.y = 1 / 2 * height + this.height / 2; _on_relayout.call(this); @@ -288,14 +288,14 @@ lychee.define('lychee.ui.Notice').requires([ if (this.options.length === 0) { next.visible = false; - this.trigger('relayout'); + this.trigger('relayout'); } else if (this.options.length === 1) { next.visible = true; next.setLabel(this.options[0]); next.setValue(this.options[0].toLowerCase()); - this.trigger('relayout'); + this.trigger('relayout'); } @@ -314,7 +314,7 @@ lychee.define('lychee.ui.Notice').requires([ id = typeof id === 'string' ? id : null; - if (id !== null && this.__states[id] !== undefined) { + if (id !== null && id !== this.state && this.__states[id] !== undefined) { if (id === 'active') { diff --git a/libraries/lychee/source/ui/State.js b/libraries/lychee/source/ui/State.js index a1b3a3fb..cb2360c9 100644 --- a/libraries/lychee/source/ui/State.js +++ b/libraries/lychee/source/ui/State.js @@ -25,6 +25,7 @@ lychee.define('lychee.ui.State').requires([ const _State = lychee.import('lychee.app.State'); const _Visible = lychee.import('lychee.effect.Visible'); const _BLOB = attachments["json"].buffer; + let _BG = null; const _INSTANCES = []; let _MENU = null; let _NOTICE = null; @@ -66,7 +67,7 @@ lychee.define('lychee.ui.State').requires([ const _on_fade = function(id) { - let fade_offset = -3/2 * this.getLayer('ui').height; + let fade_offset = -3 / 2 * this.getLayer('ui').height; let entity = this.queryLayer('ui', id); let layers = this.getLayer('ui').entities.filter(function(layer) { return layer !== _MENU && layer !== _NOTICE; @@ -230,10 +231,16 @@ lychee.define('lychee.ui.State').requires([ let main = this.main; + let bg = this.getLayer('bg'); let menu = this.queryLayer('ui', 'menu'); let notice = this.queryLayer('ui', 'notice'); + if (main !== null && bg !== null) { + _BG = bg; + } + + if (main !== null && menu !== null) { _MENU = menu; @@ -279,21 +286,33 @@ lychee.define('lychee.ui.State').requires([ if (main !== null && notice !== null) { - _NOTICE = notice; - } + } else { _State.prototype.deserialize.call(this, blob); let main = this.main; + let bg = this.getLayer('bg'); let menu = this.queryLayer('ui', 'menu'); let notice = this.queryLayer('ui', 'notice'); + if (bg !== null && bg !== _BG) { + + // Allow custom bg for each state + + } else if (bg === null) { + + this.setLayer('bg', _BG); + bg = _BG; + + } + + if (menu !== null && menu !== _MENU) { this.getLayer('ui').removeEntity(menu); @@ -392,7 +411,6 @@ lychee.define('lychee.ui.State').requires([ } - if (_MENU !== null) { _MENU.bind('relayout', function() { @@ -468,6 +486,56 @@ lychee.define('lychee.ui.State').requires([ _State.prototype.leave.call(this, oncomplete); }, this); + }, + + render: function(clock, delta, custom) { + + let renderer = this.renderer; + if (renderer !== null) { + + let menu = _MENU; + let notice = _NOTICE; + let layer = this.__layers.ui; + + if (menu !== null) { + menu.visible = false; + } + + if (notice !== null) { + notice.visible = false; + } + + + renderer.clear(); + + _State.prototype.render.call(this, clock, delta, true); + + if (menu !== null) { + + menu.visible = true; + menu.render( + renderer, + layer.position.x + layer.offset.x, + layer.position.y + layer.offset.y + ); + + } + + if (notice !== null) { + + notice.visible = true; + notice.render( + renderer, + layer.position.x + layer.offset.x, + layer.position.y + layer.offset.y + ); + + } + + renderer.flush(); + + } + } }; diff --git a/libraries/lychee/source/ui/State.json b/libraries/lychee/source/ui/State.json index 707a2b8f..010c6add 100644 --- a/libraries/lychee/source/ui/State.json +++ b/libraries/lychee/source/ui/State.json @@ -58,12 +58,10 @@ "constructor": "lychee.ui.Menu", "arguments": [{ "options": [ - "Project", - "Asset", - "Entity", + "Welcome", "Settings" ], - "value": "Project" + "value": "Welcome" }] }, { "constructor": "lychee.ui.Notice", diff --git a/libraries/lychee/source/ui/element/Input.js b/libraries/lychee/source/ui/element/Input.js index b07bf58f..fc43da46 100644 --- a/libraries/lychee/source/ui/element/Input.js +++ b/libraries/lychee/source/ui/element/Input.js @@ -140,6 +140,8 @@ lychee.define('lychee.ui.element.Input').requires([ * ENTITY API */ + // deserialize: function(blob) {}, + serialize: function() { let data = _Element.prototype.serialize.call(this); diff --git a/libraries/lychee/source/ui/element/Jukebox.js b/libraries/lychee/source/ui/element/Jukebox.js index 1a69b6b1..1d9387aa 100644 --- a/libraries/lychee/source/ui/element/Jukebox.js +++ b/libraries/lychee/source/ui/element/Jukebox.js @@ -136,6 +136,8 @@ lychee.define('lychee.ui.element.Jukebox').requires([ * ENTITY API */ + // deserialize: function(blob) {}, + serialize: function() { let data = _Element.prototype.serialize.call(this); diff --git a/libraries/lychee/source/ui/element/Network.js b/libraries/lychee/source/ui/element/Network.js index 3847e581..19fc51d5 100644 --- a/libraries/lychee/source/ui/element/Network.js +++ b/libraries/lychee/source/ui/element/Network.js @@ -252,6 +252,8 @@ lychee.define('lychee.ui.element.Network').requires([ * ENTITY API */ + // deserialize: function(blob) {}, + serialize: function() { let data = _Element.prototype.serialize.call(this); diff --git a/libraries/lychee/source/ui/element/Search.js b/libraries/lychee/source/ui/element/Search.js index e53a255e..f43d1df1 100644 --- a/libraries/lychee/source/ui/element/Search.js +++ b/libraries/lychee/source/ui/element/Search.js @@ -76,7 +76,8 @@ lychee.define('lychee.ui.element.Search').requires([ this.__select = new _Select({ options: this.data, - value: this.data[0] + value: this.data[0], + height: this.height - 128 }); this.__select.bind('change', function(value) { @@ -88,6 +89,11 @@ lychee.define('lychee.ui.element.Search').requires([ }, this); + this.__select.unbind('relayout'); + this.__select.bind('relayout', function() { + this.__select.height = this.height - 128; + }, this); + this.addEntity(this.__search); this.addEntity(this.__select); @@ -100,6 +106,8 @@ lychee.define('lychee.ui.element.Search').requires([ * ENTITY API */ + // deserialize: function(blob) {}, + serialize: function() { let data = _Element.prototype.serialize.call(this); diff --git a/libraries/lychee/source/ui/element/Stash.js b/libraries/lychee/source/ui/element/Stash.js index bb4ce63c..308bb8f4 100644 --- a/libraries/lychee/source/ui/element/Stash.js +++ b/libraries/lychee/source/ui/element/Stash.js @@ -153,6 +153,8 @@ lychee.define('lychee.ui.element.Stash').requires([ * ENTITY API */ + // deserialize: function(blob) {}, + serialize: function() { let data = _Element.prototype.serialize.call(this); diff --git a/libraries/lychee/source/ui/element/Storage.js b/libraries/lychee/source/ui/element/Storage.js index 9f770e94..10893078 100644 --- a/libraries/lychee/source/ui/element/Storage.js +++ b/libraries/lychee/source/ui/element/Storage.js @@ -153,6 +153,8 @@ lychee.define('lychee.ui.element.Storage').requires([ * ENTITY API */ + // deserialize: function(blob) {}, + serialize: function() { let data = _Element.prototype.serialize.call(this); diff --git a/libraries/lychee/source/ui/element/Viewport.js b/libraries/lychee/source/ui/element/Viewport.js index daaafcd2..b097b8cb 100644 --- a/libraries/lychee/source/ui/element/Viewport.js +++ b/libraries/lychee/source/ui/element/Viewport.js @@ -202,6 +202,8 @@ lychee.define('lychee.ui.element.Viewport').requires([ * ENTITY API */ + // deserialize: function(blob) {}, + serialize: function() { let data = _Element.prototype.serialize.call(this); diff --git a/libraries/lychee/source/ui/entity/Input.js b/libraries/lychee/source/ui/entity/Input.js index 6ccfda34..949a85f1 100644 --- a/libraries/lychee/source/ui/entity/Input.js +++ b/libraries/lychee/source/ui/entity/Input.js @@ -246,7 +246,7 @@ lychee.define('lychee.ui.entity.Input').includes([ this.__isDirty = true; } else if (newvalue < this.min) { this.value = this.min; - this.__value = this.min + ''; + this.__value = this.min + ''; this.__isDirty = true; } diff --git a/libraries/lychee/source/ui/entity/Joystick.js b/libraries/lychee/source/ui/entity/Joystick.js index c56d4b45..14134871 100644 --- a/libraries/lychee/source/ui/entity/Joystick.js +++ b/libraries/lychee/source/ui/entity/Joystick.js @@ -122,10 +122,26 @@ lychee.define('lychee.ui.entity.Joystick').includes([ let val = { x: this.value.x, y: this.value.y }; - if (key === 'a' || key === 'arrow-left') { val.x = -1.0; val.y = 0.0; } - if (key === 'd' || key === 'arrow-right') { val.x = 1.0; val.y = 0.0; } - if (key === 'w' || key === 'arrow-up') { val.y = -1.0; val.x = 0.0; } - if (key === 's' || key === 'arrow-down') { val.y = 1.0; val.x = 0.0; } + + if (key === 'a' || key === 'arrow-left') { + val.x = -1.0; + val.y = 0.0; + } + + if (key === 'd' || key === 'arrow-right') { + val.x = 1.0; + val.y = 0.0; + } + + if (key === 'w' || key === 'arrow-up') { + val.y = -1.0; + val.x = 0.0; + } + + if (key === 's' || key === 'arrow-down') { + val.y = 1.0; + val.x = 0.0; + } if (key === 'enter' || key === 'space') { val.x = 0; diff --git a/libraries/lychee/source/ui/entity/Select.js b/libraries/lychee/source/ui/entity/Select.js index 610ba0a1..360dd8fa 100644 --- a/libraries/lychee/source/ui/entity/Select.js +++ b/libraries/lychee/source/ui/entity/Select.js @@ -28,6 +28,7 @@ lychee.define('lychee.ui.entity.Select').includes([ start: null, pingpong: false }; + this.__height = 32; this.__pulse = { active: false, duration: 300, @@ -56,10 +57,12 @@ lychee.define('lychee.ui.entity.Select').includes([ settings = null; - if (this.options.length > 1) { - this.height = this.options.length * this.height; + if (this.height === 32 && this.options.length > 1) { + this.__height = this.height; + this.height = this.options.length * this.__height; } + if (this.value === '') { this.setValue(this.options[0] || null); } @@ -75,7 +78,7 @@ lychee.define('lychee.ui.entity.Select').includes([ if (this.options.length === 0) return; - let lh = this.height / this.options.length; + let lh = this.__height; let pos = (position.y + this.height / 2); let q = (pos / lh) | 0; @@ -126,6 +129,18 @@ lychee.define('lychee.ui.entity.Select').includes([ this.setState('default'); }, this); + this.bind('relayout', function() { + + let lh = this.__height; + + if (this.options.length > 0) { + this.height = lh * this.options.length; + } else { + this.height = lh; + } + + }, this); + settings = null; @@ -237,13 +252,17 @@ lychee.define('lychee.ui.entity.Select').includes([ let x1 = x - hwidth; - let lh = this.height / this.options.length; + let lh = this.__height; for (let o = 0, ol = this.options.length; o < ol; o++) { let option = this.options[o]; let y1 = y - hheight + o * lh; + if (y1 + lh > y + hheight) { + break; + } + if (pulse.active === true) { @@ -401,21 +420,12 @@ lychee.define('lychee.ui.entity.Select').includes([ if (options !== null) { - let height = this.height || null; - if (height !== null) { - - if (this.options.length > 0) { - this.height = (height / this.options.length) * options.length; - } else { - this.height = height * options.length; - } - - } - this.options = options.map(function(option) { return '' + option; }); + this.trigger('relayout'); + if (this.options.indexOf(this.value) === -1) { diff --git a/libraries/lychee/source/ui/entity/Texture.js b/libraries/lychee/source/ui/entity/Texture.js index 0c3c60f6..1b94df32 100644 --- a/libraries/lychee/source/ui/entity/Texture.js +++ b/libraries/lychee/source/ui/entity/Texture.js @@ -3,7 +3,7 @@ lychee.define('lychee.ui.entity.Texture').requires([ 'lychee.ui.entity.Upload', 'lychee.ui.Sprite' ]).includes([ - 'lychee.ui.Entity', + 'lychee.ui.Entity' ]).exports(function(lychee, global, attachments) { const _Entity = lychee.import('lychee.ui.Entity'); @@ -88,10 +88,10 @@ lychee.define('lychee.ui.entity.Texture').requires([ } upload.position.x = 0; - upload.position.y = 1/2 * this.height - 1/2 * upload.height; + upload.position.y = 1 / 2 * this.height - 1 / 2 * upload.height; sprite.position.x = 0; - sprite.position.y = -1/2 * this.height + 1/2 * sprite.height; + sprite.position.y = -1 / 2 * this.height + 1 / 2 * sprite.height; sprite.trigger('relayout'); }, this); @@ -156,7 +156,6 @@ lychee.define('lychee.ui.entity.Texture').requires([ if (this.visible === false) return; - let alpha = this.alpha; let position = this.position; let x = position.x + offsetX; let y = position.y + offsetY; diff --git a/libraries/lychee/source/ui/layer/Table.js b/libraries/lychee/source/ui/layer/Table.js index 46f4694d..186c43b3 100644 --- a/libraries/lychee/source/ui/layer/Table.js +++ b/libraries/lychee/source/ui/layer/Table.js @@ -51,8 +51,8 @@ lychee.define('lychee.ui.layer.Table').requires([ let label = this.__label; let type = this.type; let value = this.value; - let x1 = -1/2 * this.width; - let y1 = -1/2 * this.height; + let x1 = -1 / 2 * this.width; + let y1 = -1 / 2 * this.height; let dim_x = 0; let dim_y = 0; let off_x = 0; @@ -329,7 +329,6 @@ lychee.define('lychee.ui.layer.Table').requires([ let entities = this.entities; let font = this.font; let label = this.__label; - let model = this.model; let position = this.position; let type = this.type; let value = this.value; diff --git a/libraries/lychee/source/ui/sprite/Emblem.js b/libraries/lychee/source/ui/sprite/Emblem.js index 474ed3fc..6bfa0fa8 100644 --- a/libraries/lychee/source/ui/sprite/Emblem.js +++ b/libraries/lychee/source/ui/sprite/Emblem.js @@ -37,7 +37,7 @@ lychee.define('lychee.ui.sprite.Emblem').includes([ */ this.bind('reshape', function(orientation, rotation, width, height) { - this.position.y = 1/2 * height - _CONFIG.height / 2; + this.position.y = 1 / 2 * height - _CONFIG.height / 2; }, this); }; diff --git a/libraries/lychee/source/verlet/Constraint.js b/libraries/lychee/source/verlet/Constraint.js index c1958e11..d65b0f2c 100644 --- a/libraries/lychee/source/verlet/Constraint.js +++ b/libraries/lychee/source/verlet/Constraint.js @@ -14,8 +14,8 @@ lychee.define('lychee.verlet.Constraint').requires([ let Composite = function(a_vector, b_vector, rigidity) { - this.__a_vector = a_vector instanceof _Vector3 ? a_vector : null; - this.__b_vector = b_vector instanceof _Vector3 ? b_vector : null; + this.__a_vector = a_vector instanceof _Vector3 ? a_vector : null; + this.__b_vector = b_vector instanceof _Vector3 ? b_vector : null; this.__distance = 0; this.rigidity = typeof rigidity === 'number' ? rigidity : 1; diff --git a/libraries/lychee/source/verlet/Entity.js b/libraries/lychee/source/verlet/Entity.js index d92b9bb8..e749f144 100644 --- a/libraries/lychee/source/verlet/Entity.js +++ b/libraries/lychee/source/verlet/Entity.js @@ -63,11 +63,10 @@ lychee.define('lychee.verlet.Entity').requires([ } -// TODO: Implement this stuff here - - } else if (shape === Composite.SHAPE.sphere) { - } else if (shape === Composite.SHAPE.rectangle) { - } else if (shape === Composite.SHAPE.cuboid) { + // TODO: Implement this stuff here + // } else if (shape === Composite.SHAPE.sphere) { + // } else if (shape === Composite.SHAPE.rectangle) { + // } else if (shape === Composite.SHAPE.cuboid) { } @@ -125,10 +124,16 @@ lychee.define('lychee.verlet.Entity').requires([ let data = _Entity.prototype.serialize.call(this); data['constructor'] = 'lychee.verlet.Entity'; + let settings = data['arguments'][0]; + let blob = (data['blob'] || {}); + if (this.position.length() > 0) settings.position = lychee.serialize(this.position); + data['blob'] = Object.keys(blob).length > 0 ? blob : null; + + return data; }, diff --git a/libraries/lychee/source/verlet/Layer.js b/libraries/lychee/source/verlet/Layer.js index adca9122..6a09b514 100644 --- a/libraries/lychee/source/verlet/Layer.js +++ b/libraries/lychee/source/verlet/Layer.js @@ -1,7 +1,8 @@ lychee.define('lychee.verlet.Layer').requires([ - 'lychee.app.Layer', 'lychee.math.Vector3' +]).includes([ + 'lychee.app.Layer' ]).exports(function(lychee, global, attachments) { const _Layer = lychee.import('lychee.app.Layer'); @@ -21,7 +22,6 @@ lychee.define('lychee.verlet.Layer').requires([ this.friction = 0.99; this.gravity = new _Vector3({ x: 0, y: 1, z: 0 }); - this.__velocity = new _Vector3(); @@ -60,6 +60,9 @@ lychee.define('lychee.verlet.Layer').requires([ if (this.gravity.length() !== 0) settings.gravity = lychee.serialize(this.gravity); + data['blob'] = Object.keys(blob).length > 0 ? blob : null; + + return data; }, @@ -75,14 +78,13 @@ lychee.define('lychee.verlet.Layer').requires([ let velocity = this.__velocity; - let hwidth = this.width / 2; let hheight = this.height / 2; for (let e = 0, el = entities.length; e < el; e++) { let entity = entities[e]; let position = entity.position.clone(); - let particles = entity.particles; + let particles = entity.particles; for (let p = 0, pl = particles.length; p < pl; p++) { diff --git a/libraries/strainer/lychee.pkg b/libraries/strainer/lychee.pkg index bd065c35..4086a6d3 100644 --- a/libraries/strainer/lychee.pkg +++ b/libraries/strainer/lychee.pkg @@ -34,11 +34,27 @@ "Template": [ "js" ], - "data": { + "api": { + "Callback": [ + "js" + ], + "Composite": [ + "js", + "json" + ], + "Definition": [ + "js" + ], + "Module": [ + "js", + "json" + ] + }, + "plugin": { "API": [ "js" ], - "API__OLD": [ + "ESLINT": [ "js" ] } diff --git a/libraries/strainer/source/Main.js b/libraries/strainer/source/Main.js index 01bb9c3e..9e3701db 100644 --- a/libraries/strainer/source/Main.js +++ b/libraries/strainer/source/Main.js @@ -9,7 +9,7 @@ lychee.define('strainer.Main').requires([ const _lychee = lychee.import('lychee'); const _Emitter = lychee.import('lychee.event.Emitter'); const _Input = lychee.import('lychee.Input'); - const _Template = lychee.import('breeder.Template'); + const _Template = lychee.import('strainer.Template'); @@ -76,15 +76,28 @@ lychee.define('strainer.Main').requires([ }); - if (action === 'stash') { + if (action === 'check') { template.then('read'); - template.then('read-fix'); - template.then('read-api'); -// template.then('stash'); -// template.then('stash-fix'); -// template.then('stash-api'); - template.then('write'); + + template.then('check-eslint'); + template.then('check-api'); + + template.then('write-eslint'); + template.then('write-api'); + + } else if (action === 'stage') { + + template.then('read'); + + template.then('check-eslint'); + template.then('check-api'); + + template.then('write-eslint'); + template.then('write-api'); + + template.then('stage-eslint'); + template.then('stage-api'); } diff --git a/libraries/strainer/source/Template.js b/libraries/strainer/source/Template.js index 20d9f4c3..14df108a 100644 --- a/libraries/strainer/source/Template.js +++ b/libraries/strainer/source/Template.js @@ -1,17 +1,19 @@ lychee.define('strainer.Template').requires([ 'lychee.Stash', - 'strainer.data.API' -// 'strainer.data.FIX' + 'strainer.plugin.API', + 'strainer.plugin.ESLINT' ]).includes([ 'lychee.event.Flow' ]).exports(function(lychee, global, attachments) { - const _API = lychee.import('strainer.data.API'); - const _FIX = lychee.import('strainer.data.FIX'); - const _Flow = lychee.import('lychee.event.Flow'); - const _Stash = lychee.import('lychee.Stash'); - const _STASH = new _Stash({ + const _plugin = { + API: lychee.import('strainer.plugin.API'), + ESLINT: lychee.import('strainer.plugin.ESLINT') + }; + const _Flow = lychee.import('lychee.event.Flow'); + const _Stash = lychee.import('lychee.Stash'); + const _STASH = new _Stash({ type: _Stash.TYPE.persistent }); @@ -88,6 +90,7 @@ lychee.define('strainer.Template').requires([ let settings = Object.assign({}, data); + this.checks = []; this.codes = []; this.configs = []; this.sandbox = ''; @@ -135,7 +138,10 @@ lychee.define('strainer.Template').requires([ stash.bind('batch', function(type, assets) { - this.setCodes(assets); + this.codes = assets.filter(function(asset) { + return asset !== null; + }); + oncomplete(true); }, that, true); @@ -168,50 +174,133 @@ lychee.define('strainer.Template').requires([ }, this); - this.bind('read-fix', function(oncomplete) { + this.bind('check-eslint', function(oncomplete) { - // TODO: Implementation for automated fixes + let eslint = _plugin.ESLINT || null; + let project = this.settings.project; - oncomplete(true); + if (eslint !== null) { + + console.log('strainer: CHECK-ESLINT ' + project); + + + this.checks = this.codes.map(function(asset) { + + let report = _plugin.ESLINT.check(asset); + if (report.length > 0) { + + let result = _plugin.ESLINT.fix(asset, report); + if (result.length > 0) { + return result; + } else { + return []; + } + + } + + + return null; + + }); + + + oncomplete(true); + + } else { + + oncomplete(false); + + } }, this); - this.bind('read-api', function(oncomplete) { + this.bind('write-eslint', function(oncomplete) { + + let project = this.settings.project; + let stash = this.stash; + - let codes = this.codes; - if (codes.length > 0) { + if (project !== null && stash !== null) { - let configs = []; + console.log('strainer: WRITE-ESLINT ' + project); - for (let c = 0, cl = codes.length; c < cl; c++) { - let code = codes[c]; - let url = code.url.replace(/source/, 'api').replace(/\.js$/, '.json'); + // let sandbox = this.sandbox; + let checks = this.checks; + let codes = this.codes.filter(function(code, c) { + return checks[c] !== null && checks[c].length === 0; + }); - if (code.buffer !== null) { - let data = _API.decode(code.buffer); - let config = new lychee.Asset(code.url.replace(/source/, 'api').replace(/\.js$/, '.json'), 'json', true); - if (config !== null) { + if (codes.length > 0) { - config.buffer = data; - configs.push(config); + stash.bind('batch', function(type, assets) { + if (assets.length === codes.length) { + oncomplete(true); } else { + oncomplete(false); + } + + }, this, true); + + stash.batch('write', codes.map(function(code) { + return code.url; + }), codes); + + } else { + + oncomplete(true); + + } + + } else { + + oncomplete(false); + + } - codes.splice(c, 1); - cl--; - c--; + }, this); + + this.bind('stage-eslint', function(oncomplete) { + // TODO: git add (stage) codes + oncomplete(true); + }, this); + + this.bind('check-api', function(oncomplete) { + + let api = _plugin.API || null; + let project = this.settings.project; + + if (api !== null) { + console.log('strainer: CHECK-API ' + project); + + + this.configs = this.codes.map(function(asset) { + + let url = asset.url.replace(/source/, 'api').replace(/\.js$/, '.json'); + let report = _plugin.API.check(asset); + + if (report !== null) { + + if (report.errors.length > 0) { + _plugin.API.fix(asset, report); } + let config = new lychee.Asset(url, 'json', true); + + config.buffer = report; + + return config; + } - } + return null; + + }); - this.setConfigs(configs); - this.setCodes(codes); oncomplete(true); @@ -223,7 +312,7 @@ lychee.define('strainer.Template').requires([ }, this); - this.bind('write', function(oncomplete) { + this.bind('write-api', function(oncomplete) { let project = this.settings.project; let stash = this.stash; @@ -231,28 +320,36 @@ lychee.define('strainer.Template').requires([ if (project !== null && stash !== null) { - console.log('strainer: WRITE ' + project); + console.log('strainer: WRITE-API ' + project); - let sandbox = this.sandbox; - let codes = this.codes; - let configs = this.configs; + // let sandbox = this.sandbox; + let configs = this.configs.filter(function(config, c) { + return config !== null; + }); - stash.bind('batch', function(type, assets) { + if (configs.length > 0) { - if (assets.length === configs.length) { - oncomplete(true); - } else { - oncomplete(false); - } + stash.bind('batch', function(type, assets) { - }, this, true); + if (assets.length === configs.length) { + oncomplete(true); + } else { + oncomplete(false); + } + + }, this, true); + stash.batch('write', configs.map(function(config) { + return config.url; + }), configs); - stash.batch('write', configs.map(function(config) { - return config.url; - }), configs); + } else { + + oncomplete(true); + + } } else { @@ -260,7 +357,12 @@ lychee.define('strainer.Template').requires([ } - }); + }, this); + + this.bind('stage-api', function(oncomplete) { + // TODO: git add (stage) configs + oncomplete(true); + }, this); }; @@ -282,7 +384,11 @@ lychee.define('strainer.Template').requires([ } if (codes.length > 0) { - this.setCodes(codes); + + this.codes = codes.filter(function(asset) { + return asset !== null; + }); + } } @@ -297,7 +403,11 @@ lychee.define('strainer.Template').requires([ } if (configs.length > 0) { - this.setConfigs(configs); + + this.configs = configs.filter(function(asset) { + return asset !== null; + }); + } } @@ -343,60 +453,6 @@ lychee.define('strainer.Template').requires([ * CUSTOM API */ - setCodes: function(codes) { - - codes = codes instanceof Array ? codes : null; - - - if (codes !== null) { - - this.codes = codes.filter(function(asset) { - - if (typeof asset.buffer === 'string' && asset.buffer.length > 0) { - return true; - } - - return false; - - }); - - - return true; - - } - - - return false; - - }, - - setConfigs: function(configs) { - - configs = configs instanceof Array ? configs : null; - - - if (configs !== null) { - - this.configs = configs.filter(function(asset) { - - if (asset.buffer instanceof Object) { - return true; - } - - return false; - - }); - - - return true; - - } - - - return false; - - }, - setSandbox: function(sandbox) { sandbox = typeof sandbox === 'string' ? sandbox : null; diff --git a/libraries/strainer/source/api/Callback.js b/libraries/strainer/source/api/Callback.js new file mode 100644 index 00000000..5a3a87c3 --- /dev/null +++ b/libraries/strainer/source/api/Callback.js @@ -0,0 +1,390 @@ + +lychee.define('strainer.api.Callback').requires([ + 'lychee.crypto.MURMUR' +]).exports(function(lychee, global, attachments) { + + const _MURMUR = lychee.import('lychee.crypto.MURMUR'); + + + + /* + * HELPERS + */ + + const _get_function_hash = function(str) { + + let hash = new _MURMUR(); + + hash.update(str); + + return hash.digest().toString('hex'); + + }; + + const _parse_value = function(str) { + + let val = undefined; + try { + val = eval('(' + str + ')'); + } catch (err) { + } + + return val; + + }; + + const _detect_type = function(str) { + + let type = 'undefined'; + + + if (str === 'undefined') { + type = 'undefined'; + } else if (str === 'null') { + type = 'null'; + } else if (str === 'true' || str === 'false') { + type = 'Boolean'; + } else if (str.includes('===') && !str.includes('?')) { + type = 'Boolean'; + } else if (str === '[]' || str.startsWith('[')) { + type = 'Array'; + } else if (str === '{}' || str.startsWith('{')) { + type = 'Object'; + } else if (str.startsWith('Composite.')) { + type = 'Enum'; + } else if (str.startsWith('new Composite')) { + type = 'Composite'; + } else if (str.startsWith('\'') && str.endsWith('\'')) { + type = 'String'; + } else if (str.startsWith('"') && str.endsWith('"')) { + type = 'String'; + } else if (str.startsWith('\'\' +') || str.startsWith('"" +')) { + type = 'String'; + } else if (str.includes('toString')) { + type = 'String'; + } else if (str.startsWith('0b') || str.startsWith('0x') || str.startsWith('0o') || /^[0-9\.]+$/g.test(str)) { + type = 'Number'; + } else if (str === 'Infinity') { + type = 'Number'; + } else if (str.startsWith('(') && str.endsWith(')')) { + + if (str.includes(' + ') && (str.includes('\'') || str.includes('"'))) { + type = 'String'; + } else if (str.includes(' * ') || str.includes(' / ') || str.includes(' + ') || str.includes(' - ')) { + type = 'Number'; + } + + } else { + + if (str.includes('instanceof') && str.includes('?') && str.includes(':')) { + + let tmp = str.split(/(.*)instanceof\s([A-Za-z_\.]+)([\s]+)(.*)\?/g); + if (tmp.length > 2) { + return tmp[2]; + } + + } else if (str.startsWith('typeof') && str.includes('===') && str.includes('?') && str.includes(':')) { + + // let tmp = str.split(/\(?typeof\s([a-z]+)\s?===\s?("|')(.*)("|')\s\)?\?(.*)/g); + // switch (tmp[3]) ... + let tmp = (str.split('?')[0].split('===')[1] || '').trim(); + if (tmp.startsWith('\'') || tmp.startsWith('\"')) { + tmp = tmp.substr(1, tmp.length - 2); + } + + + switch (tmp) { + case 'undefined': type = 'undefined'; break; + case 'null': type = 'null'; break; + case 'boolean': type = 'Boolean'; break; + case 'number': type = 'Number'; break; + case 'string': type = 'String'; break; + case 'function': type = 'Function'; break; + case 'object': type = 'Object'; break; + default: type = 'undefined'; break; + } + + + if (type === 'undefined') { + + let tmp1 = str.split(':').pop(); + if (tmp1.endsWith(';')) { + tmp1 = tmp1.substr(0, tmp1.length - 1); + } + + return _detect_type(tmp1.trim()); + + } + + } else if (str.includes('!== undefined') && str.includes('?') && str.includes(':')) { + + return 'Object'; + + } else if (str.startsWith('lychee.interfaceof')) { + + let tmp = str.split(/lychee.interfaceof\(([A-Za-z_\.]+),(.*)\)/g); + if (tmp.length > 1) { + return tmp[1]; + } + + } else if (str.startsWith('lychee.enumof')) { + + return 'Enum'; + + } else if (str.startsWith('lychee.assignunlink')) { + + return 'Object'; + + } else if (str.startsWith('lychee.diff')) { + + return 'Object'; + + } + + } + + + return type; + + }; + + const _detect_value = function(str) { + + let value = undefined; + + + if (str === 'undefined') { + value = undefined; + } else if (str === 'null') { + value = null; + } else if (str === 'true' || str === 'false') { + value = str === 'true'; + } else if (str.includes('===') && !str.includes('?')) { + value = true; + } else if (str === '[]' || str.startsWith('[')) { + value = _parse_value(str); + } else if (str === '{}' || str.startsWith('{')) { + value = _parse_value(str); + } else if (str.startsWith('Composite.')) { + value = str; + } else if (str.startsWith('new Composite')) { + value = str; + } else if (str.startsWith('\'') && str.endsWith('\'')) { + value = str.substr(1, str.length - 2); + } else if (str.startsWith('"') && str.endsWith('"')) { + value = str.substr(1, str.length - 2); + } else if (str.includes('toString')) { + value = ""; + } else if (str.startsWith('0b') || str.startsWith('0x') || str.startsWith('0o') || /^[0-9\.]+$/g.test(str)) { + value = _parse_value(str); + } else if (str === 'Infinity') { + value = Infinity; + } else if (str.startsWith('(') && str.endsWith(')')) { + + if (str.includes(' + ') && (str.includes('\'') || str.includes('"'))) { + value = ""; + } else if (str.includes(' * ') || str.includes(' / ') || str.includes(' + ') || str.includes(' - ')) { + value = 1337; + } + + } else { + + if (str.includes('instanceof') && str.includes('?') && str.includes(':')) { + + let tmp = str.split(':').pop(); + if (tmp.endsWith(';')) { + tmp = tmp.substr(0, tmp.length - 1); + } + + return _detect_value(tmp.trim()); + + } else if (str.startsWith('typeof') && str.includes('?') && str.includes(':')) { + + let tmp = str.split(':').pop(); + if (tmp.endsWith(';')) { + tmp = tmp.substr(0, tmp.length - 1); + } + + return _detect_value(tmp.trim()); + + } else if (str.includes('!== undefined') && str.includes('?') && str.includes(':')) { + + return {}; + + } else if (str.startsWith('lychee.interfaceof')) { + + if (str.indexOf(':') !== -1) { + + let tmp = str.split(':').pop(); + if (tmp.endsWith(';')) { + tmp = tmp.substr(0, tmp.length - 1); + } + + return _detect_value(tmp.trim()); + + } else { + + let tmp = str.substr(19, str.indexOf(',') - 19).trim(); + if (tmp.length > 0) { + value = tmp; + } + + } + + } else if (str.startsWith('lychee.enumof')) { + + let tmp = str.split(/lychee\.enumof\(Composite\.([A-Z]+),(.*)\)/g); + if (tmp.length > 2) { + return 'Composite.' + tmp[1]; + } + + } else if (str.startsWith('lychee.assignunlink')) { + + return {}; + + } else if (str.startsWith('lychee.diff')) { + + return {}; + + } + + } + + + return value; + + }; + + const _parse_constructor = function(constructor, stream) { + + let i1 = stream.indexOf('\n\tconst Callback ='); + let i2 = stream.indexOf('\n\t};', i1); + + if (i1 !== -1 && i2 !== -1) { + + let body = stream.substr(i1 + 19, i2 - i1 - 15).trim(); + if (body.length > 0) { + + constructor.body = body; + constructor.hash = _get_function_hash(body); + constructor.parameters = []; + + let tmpa = body.substr(0, body.indexOf('\n')).trim(); + let tmpb = tmpa.split(/function\((.*)\)/g); + if (tmpb.length > 1) { + + let tmpc = tmpb[1].trim(); + if (tmpc.length > 0) { + + constructor.parameters = tmpc.split(',').map(function(val) { + + return { + name: val.trim(), + type: 'undefined', + value: undefined + }; + + }); + + } + + } + + + body.split('\n').filter(function(line, l) { + + let tmp = line.trim(); + if (tmp === '' || tmp.startsWith('//')) { + return false; + } else if (tmp.startsWith('/*') || tmp.startsWith('*/') || tmp.startsWith('*')) { + return false; + } + + return true; + + }).slice(1, -1).forEach(function(line, l) { + + let tmp1 = line.trim(); + + Object.values(constructor.parameters).forEach(function(parameter) { + + if (tmp1.startsWith(parameter.name) && tmp1.includes('=')) { + + let tmp2 = tmp1.substr(tmp1.indexOf('=') + 1).trim(); + let type = _detect_type(tmp2); + let value = _detect_value(tmp2); + + if (type !== 'undefined') { + + if (parameter.type === type) { + + if (parameter.value === undefined) { + parameter.value = value; + } + + } else if (parameter.type === 'undefined') { + + parameter.type = type; + parameter.value = value; + + } + + } + + } + + }); + + }); + + } + + } + + }; + + + + /* + * IMPLEMENTATION + */ + + const Module = { + + // deserialize: function(blob) {}, + + serialize: function() { + + return { + 'reference': 'strainer.api.Callback', + 'arguments': [] + }; + + }, + + check: function(asset) { + + let stream = asset.buffer.toString('utf8'); + let errors = []; + let result = { + constructor: {} + }; + + + _parse_constructor(result.constructor, stream, errors); + + + return { + errors: errors, + result: result + }; + + } + + }; + + + return Module; + +}); + diff --git a/libraries/strainer/source/api/Composite.js b/libraries/strainer/source/api/Composite.js new file mode 100644 index 00000000..391e4874 --- /dev/null +++ b/libraries/strainer/source/api/Composite.js @@ -0,0 +1,923 @@ + +lychee.define('strainer.api.Composite').requires([ + 'lychee.crypto.MURMUR' +]).exports(function(lychee, global, attachments) { + + const _MURMUR = lychee.import('lychee.crypto.MURMUR'); + const _CONFIG = []; + + + + /* + * FEATURE DETECTION + */ + + (function(buffer) { + + if (buffer instanceof Array) { + + buffer.forEach(function(entry) { + _CONFIG.push(entry); + }); + + } + + })(attachments["json"].buffer); + + + + /* + * HELPERS + */ + + const _get_function_body = function(name, stream) { + + let i1 = stream.indexOf('\n\t\t' + name + ': function('); + let i2 = stream.indexOf(':', i1); + let i3 = stream.indexOf('\n\t\t}', i1); + let body = null; + + if (i1 !== -1 && i2 !== -1 && i3 !== -1) { + body = stream.substr(i2 + 1, i3 - i2 + 3).trim(); + } + + return body; + + }; + + const _get_function_hash = function(str) { + + let hash = new _MURMUR(); + + hash.update(str); + + return hash.digest().toString('hex'); + + }; + + const _clone_value = function(data) { + + let clone = undefined; + + if (data !== undefined) { + + try { + data = JSON.parse(JSON.stringify(data)); + } catch (err) { + } + + } + + return clone; + + }; + + const _parse_value = function(str) { + + let val = undefined; + try { + val = eval('(' + str + ')'); + } catch (err) { + } + + return val; + + }; + + const _detect_type = function(str) { + + let type = 'undefined'; + + + if (str === 'undefined') { + type = 'undefined'; + } else if (str === 'null') { + type = 'null'; + } else if (str === 'true' || str === 'false') { + type = 'Boolean'; + } else if (str.includes('===') && !str.includes('?')) { + type = 'Boolean'; + } else if (str === '[]' || str.startsWith('[')) { + type = 'Array'; + } else if (str === '{}' || str.startsWith('{')) { + type = 'Object'; + } else if (str.startsWith('Composite.')) { + type = 'Enum'; + } else if (str.startsWith('new Composite')) { + type = 'Composite'; + } else if (str.startsWith('\'') && str.endsWith('\'')) { + type = 'String'; + } else if (str.startsWith('"') && str.endsWith('"')) { + type = 'String'; + } else if (str.startsWith('\'\' +') || str.startsWith('"" +')) { + type = 'String'; + } else if (str.includes('toString')) { + type = 'String'; + } else if (str.startsWith('0b') || str.startsWith('0x') || str.startsWith('0o') || /^[0-9\.]+$/g.test(str)) { + type = 'Number'; + } else if (str === 'Infinity') { + type = 'Number'; + } else if (str.startsWith('(') && str.endsWith(')')) { + + if (str.includes(' + ') && (str.includes('\'') || str.includes('"'))) { + type = 'String'; + } else if (str.includes(' * ') || str.includes(' / ') || str.includes(' + ') || str.includes(' - ')) { + type = 'Number'; + } + + } else { + + if (str.includes('instanceof') && str.includes('?') && str.includes(':')) { + + let tmp = str.split(/(.*)instanceof\s([A-Za-z_\.]+)([\s]+)(.*)\?/g); + if (tmp.length > 2) { + return tmp[2]; + } + + } else if (str.startsWith('typeof') && str.includes('===') && str.includes('?') && str.includes(':')) { + + let tmp = (str.split('?')[0].split('===')[1] || '').trim(); + if (tmp.startsWith('\'') || tmp.startsWith('\"')) { + tmp = tmp.substr(1, tmp.length - 2); + } + + + switch (tmp) { + case 'undefined': type = 'undefined'; break; + case 'null': type = 'null'; break; + case 'boolean': type = 'Boolean'; break; + case 'number': type = 'Number'; break; + case 'string': type = 'String'; break; + case 'function': type = 'Function'; break; + case 'object': type = 'Object'; break; + default: type = 'undefined'; break; + } + + + if (type === 'undefined') { + + let tmp1 = str.split(':').pop(); + if (tmp1.endsWith(';')) { + tmp1 = tmp1.substr(0, tmp1.length - 1); + } + + return _detect_type(tmp1.trim()); + + } + + } else if (str.includes('!== undefined') && str.includes('?') && str.includes(':')) { + + return 'Object'; + + } else if (str.startsWith('lychee.interfaceof')) { + + let tmp = str.split(/lychee.interfaceof\(([A-Za-z_\.]+),(.*)\)/g); + if (tmp.length > 1) { + return tmp[1]; + } + + } else if (str.startsWith('lychee.enumof')) { + + return 'Enum'; + + } else if (str.startsWith('lychee.assignunlink')) { + + return 'Object'; + + } else if (str.startsWith('lychee.diff')) { + + return 'Object'; + + } else { + + let entry = _CONFIG.find(function(val) { + return str.startsWith(val.name); + }); + + if (entry !== undefined) { + return _clone_value(entry.value); + } + + } + + } + + + return type; + + }; + + const _detect_value = function(str) { + + let value = undefined; + + + if (str === 'undefined') { + value = undefined; + } else if (str === 'null') { + value = null; + } else if (str === 'true' || str === 'false') { + value = str === 'true'; + } else if (str.includes('===') && !str.includes('?')) { + value = true; + } else if (str === '[]' || str.startsWith('[')) { + value = _parse_value(str); + } else if (str === '{}' || str.startsWith('{')) { + value = _parse_value(str); + } else if (str.startsWith('Composite.')) { + value = str; + } else if (str.startsWith('new Composite')) { + value = str; + } else if (str.startsWith('\'') && str.endsWith('\'')) { + value = str.substr(1, str.length - 2); + } else if (str.startsWith('"') && str.endsWith('"')) { + value = str.substr(1, str.length - 2); + } else if (str.includes('toString')) { + value = ""; + } else if (str.startsWith('0b') || str.startsWith('0x') || str.startsWith('0o') || /^[0-9\.]+$/g.test(str)) { + value = _parse_value(str); + } else if (str === 'Infinity') { + value = Infinity; + } else if (str.startsWith('(') && str.endsWith(')')) { + + if (str.includes(' + ') && (str.includes('\'') || str.includes('"'))) { + value = ""; + } else if (str.includes(' * ') || str.includes(' / ') || str.includes(' + ') || str.includes(' - ')) { + value = 1337; + } + + } else { + + if (str.includes('instanceof') && str.includes('?') && str.includes(':')) { + + let tmp = str.split(':').pop(); + if (tmp.endsWith(';')) { + tmp = tmp.substr(0, tmp.length - 1); + } + + return _detect_value(tmp.trim()); + + } else if (str.startsWith('typeof') && str.includes('?') && str.includes(':')) { + + let tmp = str.split(':').pop(); + if (tmp.endsWith(';')) { + tmp = tmp.substr(0, tmp.length - 1); + } + + return _detect_value(tmp.trim()); + + } else if (str.includes('!== undefined') && str.includes('?') && str.includes(':')) { + + return {}; + + } else if (str.startsWith('lychee.interfaceof')) { + + if (str.indexOf(':') !== -1) { + + let tmp = str.split(':').pop(); + if (tmp.endsWith(';')) { + tmp = tmp.substr(0, tmp.length - 1); + } + + return _detect_value(tmp.trim()); + + } else { + + let tmp = str.substr(19, str.indexOf(',') - 19).trim(); + if (tmp.length > 0) { + value = tmp; + } + + } + + } else if (str.startsWith('lychee.enumof')) { + + let tmp = str.split(/lychee\.enumof\(Composite\.([A-Z]+),(.*)\)/g); + if (tmp.length > 2) { + return 'Composite.' + tmp[1]; + } + + } else if (str.startsWith('lychee.assignunlink')) { + + return {}; + + } else if (str.startsWith('lychee.diff')) { + + return {}; + + } else { + + let entry = _CONFIG.find(function(val) { + return str.startsWith(val.name); + }); + + if (entry !== undefined) { + return _clone_value(entry.value); + } + + } + + } + + + return value; + + }; + + const _parse_constructor = function(constructor, stream) { + + let i1 = stream.indexOf('\n\tlet Composite ='); + let i2 = stream.indexOf('\n\t};', i1); + + if (i1 !== -1 && i2 !== -1) { + + let body = stream.substr(i1 + 18, i2 - i1 - 14).trim(); + if (body.length > 0) { + + constructor.body = body; + constructor.hash = _get_function_hash(body); + constructor.parameters = []; + + let tmpa = body.substr(0, body.indexOf('\n')).trim(); + let tmpb = tmpa.split(/function\((.*)\)/g); + if (tmpb.length > 1) { + + let tmpc = tmpb[1].trim(); + if (tmpc.length > 0) { + + constructor.parameters = tmpc.split(',').map(function(val) { + + return { + name: val.trim(), + type: 'undefined', + value: undefined + }; + + }); + + } + + } + + + body.split('\n').filter(function(line, l) { + + let tmp = line.trim(); + if (tmp === '' || tmp.startsWith('//')) { + return false; + } else if (tmp.startsWith('/*') || tmp.startsWith('*/') || tmp.startsWith('*')) { + return false; + } + + return true; + + }).slice(1, -1).forEach(function(line, l) { + + let tmp1 = line.trim(); + + Object.values(constructor.parameters).forEach(function(parameter) { + + if (tmp1.startsWith(parameter.name) && tmp1.includes('=')) { + + let tmp2 = tmp1.substr(tmp1.indexOf('=') + 1).trim(); + let type = _detect_type(tmp2); + let value = _detect_value(tmp2); + + if (type !== 'undefined') { + + if (parameter.type === type) { + + if (parameter.value === undefined) { + parameter.value = value; + } + + } else if (parameter.type === 'undefined') { + + parameter.type = type; + parameter.value = value; + + } + + } + + } + + }); + + }); + + } + + } + + }; + + const _parse_settings = function(settings, stream) { + + let i1 = stream.indexOf('\n\tlet Composite ='); + let i2 = stream.indexOf('\n\t};', i1); + + if (i1 !== -1 && i2 !== -1) { + + stream.substr(i1, i2 - i1 + 4).split('\n').forEach(function(line, l) { + + let tmp1 = line.trim(); + if (tmp1.startsWith('this.set') && tmp1.includes('settings.')) { + + let tmp2 = tmp1.split(/\(settings\.([A-Za-z]+)\);/g); + if (tmp2.pop() === '') { + + // settings['alpha'] = 'setAlpha' + settings[tmp2[1]] = tmp2[0].split('.').pop(); + + } + + } + + }); + + } + + }; + + const _parse_properties = function(properties, stream) { + + let i1 = stream.indexOf('\n\tlet Composite ='); + let i2 = stream.indexOf('\n\t};', i1); + + if (i1 !== -1 && i2 !== -1) { + + stream.substr(i1, i2 - i1 + 4).split('\n').forEach(function(line, l) { + + let tmp1 = line.trim(); + if (tmp1.startsWith('this.') && tmp1.includes('=')) { + + let tmp2 = tmp1.split(/this\.([a-z]+)([\s]+)=([\s]+)(.*);/g); + if (tmp2.pop() === '') { + + // properties['alpha'] = { type: 'Number', value: 1 } + properties[tmp2[1]] = { + type: _detect_type(tmp2[4]), + value: _detect_value(tmp2[4]) + }; + + } + + } + + }); + + } + + }; + + const _parse_enums = function(enums, stream) { + + let i1 = stream.indexOf('\n\t};', stream.indexOf('\n\tlet Composite =')) + 4; + let i2 = stream.indexOf('\n\tComposite.prototype =', i1); + + if (i1 !== -1 && i2 !== -1) { + + let last_enum = null; + + stream.substr(i1, i2 - i1).split('\n').filter(function(line, l) { + + let tmp = line.trim(); + if (tmp === '' || tmp.startsWith('//')) { + return false; + } + + return true; + + }).forEach(function(line, l) { + + let tmp1 = line.trim(); + if (tmp1.startsWith('Composite.') && tmp1.endsWith('= {')) { + + let tmp2 = tmp1.split(/Composite\.([A-Z]+)([\s]+)=([\s]+){/g); + if (tmp2.pop() === '') { + // last_enum = enums['WHATEVER'] = {} + last_enum = enums[tmp2[1]] = {}; + } + + } else if (tmp1.startsWith('};')) { + + last_enum = null; + + } else if (last_enum !== null) { + + if (tmp1.endsWith(',')) { + tmp1 = tmp1.substr(0, tmp1.length - 1); + } + + let tmp2 = tmp1.split(/"?'?([A-Za-z]+)"?'?:([\s]+)(.*)/g); + + // last_enum['whatever'] = { type: 'Number', value: 123 } + last_enum[tmp2[1]] = { + type: 'Number', + value: _detect_value(tmp2[3]) + }; + + } + + + }); + + } + + }; + + const _parse_methods = function(methods, properties, stream, errors) { + + let i1 = stream.indexOf('\n\tComposite.prototype ='); + let i2 = stream.indexOf('\n\t};', i1); + + if (i1 !== -1 && i2 !== -1) { + + let last_line = ''; + let last_name = null; + let last_method = null; + + stream.substr(i1, i2 - i1 + 4).trim().split('\n').filter(function(line, l) { + + let tmp = line.trim(); + if (tmp === '// deserialize: function(blob) {},') { + return true; + } else if (tmp === '' || tmp.startsWith('//')) { + return false; + } else if (tmp.startsWith('/*') || tmp.startsWith('*/') || tmp.startsWith('*')) { + return false; + } + + return true; + + }).slice(1, -1).forEach(function(line, l) { + + if (line.includes('function(')) { + + let tmp1 = line.trim(); + if (tmp1.startsWith('//')) { + tmp1 = tmp1.substr(2).trim(); + } + + let tmp2 = tmp1.split(/"?'?([A-Za-z]+)"?'?:\sfunction\((.*)\)/g); + let tmp3 = tmp2.pop(); + + if (tmp3 === ' {' || tmp3 === ' {},') { + + if (tmp2[1] === 'serialize') { + + methods['serialize'] = { + hash: null, + body: null, + parameters: [], + values: [{ + type: 'SerializationBlob', + value: { + 'constructor': null, + 'arguments': [], + 'blob': null + } + }] + }; + + } else if (tmp2[1] === 'deserialize') { + + methods['deserialize'] = { + hash: null, + body: null, + parameters: [{ + name: 'blob', + type: 'SerializationBlob', + value: {} + }], + values: [{ + type: 'undefined', + value: undefined + }] + }; + + if (tmp1 === 'deserialize: function(blob) {},') { + methods['deserialize'].body = 'function(blob) {}'; + methods['deserialize'].hash = _get_function_hash(methods['deserialize'].body); + } + + } else { + + last_name = tmp2[1]; + + // last_method = methods['setWhatever'] = { parameters: [{ name: 'foo', type: 'String', value: null }] } + last_method = methods[tmp2[1]] = { + hash: null, + body: null, + parameters: [], + values: [] + }; + + + let tmp4 = tmp2[2].trim(); + if (tmp4.length > 0) { + + last_method.parameters = tmp4.split(',').map(function(val) { + + return { + name: val.trim(), + type: 'undefined', + value: undefined + }; + + }); + + } + + } + + } + + } else if (line === '\t\t},' || line === '\t\t}') { + + last_name = null; + last_method = null; + + } else if (last_method !== null) { + + let tmp1 = line.trim(); + if (tmp1.startsWith('return') && tmp1.endsWith('{')) { + + let has_object = last_method.values.find(function(val) { + return val.type === 'Object'; + }); + + if (has_object === undefined) { + last_method.values.push({ + type: 'Object', + value: {} + }); + } + + } else if (tmp1.startsWith('return') && tmp1.endsWith(';')) { + + if ((last_line.includes('function(') || last_line.includes('=>')) && last_line.endsWith('{')) { + return; + } + + + let tmp2 = tmp1.substr(6, tmp1.length - 7).trim(); + if (tmp2.includes('&&') || tmp2.includes('||')) { + + let has_true = last_method.values.find(function(val) { + return val.value === true; + }); + + if (has_true === undefined) { + last_method.values.push({ + type: 'Boolean', + value: true + }); + } + + let has_false = last_method.values.find(function(val) { + return val.value === false; + }); + + if (has_false === undefined) { + last_method.values.push({ + type: 'Boolean', + value: false + }); + } + + } else if (tmp2.length > 0) { + + let type = _detect_type(tmp2); + let value = _detect_value(tmp2); + + // XXX: Keep the non-guessable value + if (type === 'undefined' && value === undefined && tmp2 !== 'undefined') { + + type = 'undefined'; + value = tmp2; + + errors.push({ + ruleId: 'no-return-value', + methodName: last_name, + fileName: null, + message: 'Unguessable return "' + last_name + '()" ("' + tmp2 + '").' + }); + + } + + + let has_already = last_method.values.find(function(val) { + + if (/Array|Object/g.test(val.type)) { + return JSON.stringify(val.value) === JSON.stringify(value); + } else { + return val.type === type && val.value === value; + } + + }); + + if (has_already === undefined && value !== undefined) { + + last_method.values.push({ + type: type, + value: value + }); + + } + + } + + } else { + + Object.values(last_method.parameters).forEach(function(parameter) { + + if (tmp1.startsWith(parameter.name) && tmp1.includes('=')) { + + let tmp2 = tmp1.substr(tmp1.indexOf('=') + 1).trim(); + let type = _detect_type(tmp2); + let value = _detect_value(tmp2); + + if (type !== 'undefined') { + + if (parameter.type === type) { + + if (parameter.value === undefined) { + parameter.value = value; + } + + } else if (parameter.type === 'undefined') { + + parameter.type = type; + parameter.value = value; + + } + + } + + } else if (tmp1.includes(parameter.name)) { + + if (tmp1.startsWith('this\.' + parameter.name)) { + + let property = properties[parameter.name] || null; + if (property !== null) { + + if (parameter.type === 'undefined') { + parameter.type = property.type; + } + + if (parameter.value === null) { + parameter.value = _clone_value(property.value); + } + + } + + } + + } + + }); + + } + + } + + + last_line = line; + + }); + + + for (let name in methods) { + + let method = methods[name]; + if (method.body === null) { + method.body = _get_function_body(name, stream); + } + + if (method.body !== null && method.hash === null) { + method.hash = _get_function_hash(method.body); + } + + if (method.values.length === 0) { + method.values.push({ + type: 'undefined', + value: undefined + }); + } + + } + + } + + }; + + + + /* + * IMPLEMENTATION + */ + + const Module = { + + // deserialize: function(blob) {}, + + serialize: function() { + + return { + 'reference': 'strainer.api.Composite', + 'arguments': [] + }; + + }, + + check: function(asset) { + + let stream = asset.buffer.toString('utf8'); + let errors = []; + let result = { + constructor: {}, + settings: {}, + properties: {}, + enums: {}, + events: {}, + methods: {} + }; + + + _parse_constructor(result.constructor, stream, errors); + _parse_settings(result.settings, stream, errors); + _parse_properties(result.properties, stream, errors); + _parse_enums(result.enums, stream, errors); + // _parse_events(result.events, stream, errors); + _parse_methods(result.methods, result.properties, stream, errors); + + + for (let p in result.properties) { + + let property = result.properties[p]; + if (property.type === 'undefined') { + + let found = _CONFIG.find(function(val) { + return p.startsWith(val.name); + }); + + if (found !== undefined) { + + property.type = found.type; + property.value = _clone_value(found.value); + + } else { + + errors.push({ + ruleId: 'no-property-value', + propertyName: p, + fileName: null, + message: 'Unguessable property "' + p + '" ("' + property.value + '").' + }); + + } + + } + + } + + + if (result.methods['serialize'] === undefined) { + + errors.push({ + ruleId: 'no-serialize', + methodName: 'serialize', + fileName: null, + message: 'No "serialize()" method.' + }); + + } + + if (result.methods['deserialize'] === undefined) { + + errors.push({ + ruleId: 'no-deserialize', + methodName: 'deserialize', + fileName: null, + message: 'No "deserialize()" method.' + }); + + } + + + return { + errors: errors, + result: result + }; + + } + + }; + + + return Module; + +}); + diff --git a/libraries/strainer/source/api/Composite.json b/libraries/strainer/source/api/Composite.json new file mode 100644 index 00000000..2fc3cf48 --- /dev/null +++ b/libraries/strainer/source/api/Composite.json @@ -0,0 +1,277 @@ +[{ + "name": "buffer", + "type": "Buffer", + "value": { + "constructor": "Buffer", + "arguments": [ "" ] + } +}, { + "name": "new Buffer", + "type": "Buffer", + "value": { + "constructor": "Buffer", + "arguments": [ "" ] + } +}, { + "name": "new _Buffer", + "type": "Buffer", + "value": { + "constructor": "Buffer", + "arguments": [ "" ] + } +}, { + "name": "_CONFIG", + "type": "Config", + "value": { + "constructor": "Config", + "arguments": [ "/tmp/Config.json" ] + } +}, { + "name": "_FONT", + "type": "Font", + "value": { + "constructor": "Font", + "arguments": [ "/tmp/Font.fnt" ] + } +}, { + "name": "_CONFIG", + "type": "Config", + "value": { + "constructor": "Config", + "arguments": [ "/tmp/Config.json" ] + } +}, { + "name": "asset", + "type": "lychee.Asset", + "value": { + "constructor": "lychee.Asset", + "arguments": [] + } +}, { + "name": "_validate_asset(asset)", + "type": "lychee.Asset", + "value": { + "constructor": "lychee.Asset", + "arguments": [] + } +}, { + "name": "_validate_brain(brain)", + "type": "lychee.ai.*.Brain", + "value": { + "constructor": "lychee.ai.enn.Brain", + "arguments": [] + } +}, { + "name": "/(#[AaBbCcDdEeFf0-9]{6})/g.test(color)", + "type": "String", + "value": "#d0494b" +}, { + "name": "color", + "type": "String", + "value": "#d0494b" +}, { + "name": "(lychee.interfaceof(_App_layer, layer) || lychee.interfaceof(_Ui_layer, layer))", + "type": "lychee.*.Layer", + "value": { + "constructor": "lychee.app.Layer", + "arguments": [] + } +}, { + "name": "_validate_entity(entity)", + "type": "lychee.*.Entity", + "value": { + "constructor": "lychee.app.Entity", + "arguments": [] + } +}, { + "name": "entity", + "type": "lychee.*.Entity", + "value": { + "constructor": "lychee.app.Entity", + "arguments": [] + } +}, { + "name": "_Entity.SHAPE", + "type": "Enum", + "value": { + "reference": "lychee.app.Entity.SHAPE", + "arguments": [] + } +}, { + "name": "_JSON", + "type": "lychee.codec.*", + "value": { + "reference": "lychee.codec.JSON", + "arguments": [] + } +}, { + "name": "main", + "type": "lychee.app.Main", + "value": { + "constructor": "lychee.app.Main", + "arguments": [] + } +}, { + "name": "input", + "type": "lychee.Input", + "value": { + "constructor": "lychee.Input", + "arguments": [] + } +}, { + "name": "jukebox", + "type": "lychee.app.Jukebox", + "value": { + "constructor": "lychee.app.Jukebox", + "arguments": [] + } +}, { + "name": "renderer", + "type": "lychee.Renderer", + "value": { + "constructor": "lychee.Renderer", + "arguments": [] + } +}, { + "name": "stash", + "type": "lychee.Stash", + "value": { + "constructor": "lychee.Stash", + "arguments": [] + } +}, { + "name": "storage", + "type": "lychee.Storage", + "value": { + "constructor": "lychee.Storage", + "arguments": [] + } +}, { + "name": "viewport", + "type": "lychee.Viewport", + "value": { + "constructor": "lychee.Viewport", + "arguments": [] + } +}, { + "name": "client", + "type": "lychee.net.Client", + "value": { + "constructor": "lychee.net.Client", + "arguments": [] + } +}, { + "name": "remote", + "type": "lychee.net.Remote", + "value": { + "constructor": "lychee.net.Remote", + "arguments": [] + } +}, { + "name": "server", + "type": "lychee.net.Server", + "value": { + "constructor": "lychee.net.Server", + "arguments": [] + } +}, { + "name": "tunnel", + "type": "lychee.net.Tunnel", + "value": { + "constructor": "lychee.net.Tunnel", + "arguments": [] + } +}, { + "name": "id", + "type": "String", + "value": "" +}, { + "name": "this", + "type": "Object", + "value": "this" +}, { + "name": "all", + "type": "Boolean", + "value": true +}, { + "name": "result", + "type": "Boolean", + "value": true +}, { + "name": "found", + "type": "Boolean", + "value": true +}, { + "name": "valid", + "type": "Boolean", + "value": true +}, { + "name": "alpha", + "type": "Number", + "value": 0.5 +}, { + "name": "delay", + "type": "Number", + "value": 1337 +}, { + "name": "duration", + "type": "Number", + "value": 1337 +}, { + "name": "Math.sqrt", + "type": "Number", + "value": 13.37 +}, { + "name": "width", + "type": "Number", + "value": 1337 +}, { + "name": "height", + "type": "Number", + "value": 1337 +}, { + "name": "depth", + "type": "Number", + "value": 1337 +}, { + "name": "radius", + "type": "Number", + "value": 1337 +}, { + "name": "label", + "type": "String", + "value": "