# HG changeset patch # User nickolay # Date 1559756655 -10800 # Node ID 27e8e9e38e073a3764a6c029008586d856357a08 # Parent 8af8e840dd49f31085a8af1fd9cc3b1f1caecb5d# Parent 1dc2fd263b90691e6ecd750c9a330c915f11f423 Слияние diff -r 8af8e840dd49 -r 27e8e9e38e07 .hgignore --- a/.hgignore Wed Jun 05 17:44:17 2019 +0300 +++ b/.hgignore Wed Jun 05 20:44:15 2019 +0300 @@ -1,2 +1,5 @@ .git/ .gitignore/ +syntax: glob +core/build/ +.gradle/ diff -r 8af8e840dd49 -r 27e8e9e38e07 .project --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.project Wed Jun 05 20:44:15 2019 +0300 @@ -0,0 +1,17 @@ + + + implab + Project implab created by Buildship. + + + + + org.eclipse.buildship.core.gradleprojectbuilder + + + + + + org.eclipse.buildship.core.gradleprojectnature + + diff -r 8af8e840dd49 -r 27e8e9e38e07 .settings/org.eclipse.buildship.core.prefs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.settings/org.eclipse.buildship.core.prefs Wed Jun 05 20:44:15 2019 +0300 @@ -0,0 +1,2 @@ +connection.project.dir= +eclipse.preferences.version=1 diff -r 8af8e840dd49 -r 27e8e9e38e07 .vscode/settings.json --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.vscode/settings.json Wed Jun 05 20:44:15 2019 +0300 @@ -0,0 +1,3 @@ +{ + "java.configuration.updateBuildConfiguration": "disabled" +} \ No newline at end of file diff -r 8af8e840dd49 -r 27e8e9e38e07 build.gradle --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/build.gradle Wed Jun 05 20:44:15 2019 +0300 @@ -0,0 +1,11 @@ +version = "${majorVersion}.${minorVersion}.${patchVersion}" +if (suffixVersion) { + version += "-$suffixVersion" +} + +subprojects { + version = rootProject.version +} + +task build(type: Copy) { +} \ No newline at end of file diff -r 8af8e840dd49 -r 27e8e9e38e07 core/.project --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/.project Wed Jun 05 20:44:15 2019 +0300 @@ -0,0 +1,17 @@ + + + core + Project core created by Buildship. + + + + + org.eclipse.buildship.core.gradleprojectbuilder + + + + + + org.eclipse.buildship.core.gradleprojectnature + + diff -r 8af8e840dd49 -r 27e8e9e38e07 core/.settings/org.eclipse.buildship.core.prefs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/.settings/org.eclipse.buildship.core.prefs Wed Jun 05 20:44:15 2019 +0300 @@ -0,0 +1,2 @@ +connection.project.dir=.. +eclipse.preferences.version=1 diff -r 8af8e840dd49 -r 27e8e9e38e07 core/build.gradle --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/build.gradle Wed Jun 05 20:44:15 2019 +0300 @@ -0,0 +1,58 @@ + +println "version: $version" + +String makePackageName(String group, String name, String ver) { + def sb = new StringBuilder(); + if(group) + sb + .append('@') + .append(group) + .append('/'); + + sb.append(name); + + if (ver) + sb.append('@').append(ver); + + return sb.toString(); +} + +configurations { + compile + peer + dev +} + +dependencies { + compile ":eslint:1.x || >=2.5.0 || 5.0.0 - 7.2.3" + compile (name: 'foo') { + ext.location = "http://some/package/location" + } + peer "dojo:core" +} + +task prepare(type: Copy) { + from('src/js/') + from('.') { + include 'readme.md', 'license', 'history.md', 'package.json' + } + into(buildDir) +} + +task installDeps { + configurations.compile.allDependencies.forEach { d -> + println makePackageName(d.group, d.name, d.version); + if(d.hasProperty('location')) { + println d.location + } + } +} + +task build(dependsOn: prepare) { +} + +task pack(dependsOn: build, type: Exec) { + workingDir = buildDir + + commandLine 'npm', 'pack' +} \ No newline at end of file diff -r 8af8e840dd49 -r 27e8e9e38e07 core/gradle.properties diff -r 8af8e840dd49 -r 27e8e9e38e07 core/history.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/history.md Wed Jun 05 20:44:15 2019 +0300 @@ -0,0 +1,12 @@ +HISTORY +======= + +1.0.1 +----- + +First release, intorduces the followinf features + +- `di` - dependency injection conyainer +- `log` - log4 style logging system +- `text` - simple and fast text templating and formatting +- `Uuid` - uuid generation traits \ No newline at end of file diff -r 8af8e840dd49 -r 27e8e9e38e07 core/license diff -r 8af8e840dd49 -r 27e8e9e38e07 core/package.json --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/package.json Wed Jun 05 20:44:15 2019 +0300 @@ -0,0 +1,18 @@ +{ + "name": "@implab/core", + "version": "1.0.1", + "description": "Dependency injection, logging, simple and fast text template engine", + "main": "main.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [ + "di", + "ioc", + "logging", + "template engine", + "dependency injection" + ], + "author": "Sergey Smirnov", + "license": "MIT" +} diff -r 8af8e840dd49 -r 27e8e9e38e07 core/readme.md diff -r 8af8e840dd49 -r 27e8e9e38e07 core/src/js/Deferred.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/js/Deferred.js Wed Jun 05 20:44:15 2019 +0300 @@ -0,0 +1,3 @@ +define(["dojo/Deferred"], function(Deferred) { + return Deferred; +}); \ No newline at end of file diff -r 8af8e840dd49 -r 27e8e9e38e07 core/src/js/Uri.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/js/Uri.js Wed Jun 05 20:44:15 2019 +0300 @@ -0,0 +1,232 @@ +define( + [ "./declare" ], + function(declare) { + function parseURI(uri) { + var schema, host, port, path, query, hash, i; + if (typeof (uri) == "string") { + if ((i = uri.indexOf(":")) >= 0 && + uri.substr(0, i).match(/^\w+$/)) { + schema = uri.substr(0, i); + uri = uri.substr(i + 1); + } + + if (uri.indexOf("//") === 0) { + uri = uri.substr(2); + if ((i = uri.indexOf("/")) >= 0) { + host = uri.substr(0, i); + uri = uri.substr(i); + } else { + host = uri; + uri = ""; + } + } + + if ((i = uri.indexOf("?")) >= 0) { + path = uri.substr(0, i); + uri = uri.substr(i + 1); + + } else { + path = uri; + uri = ""; + + if ((i = path.indexOf("#")) >= 0) { + hash = path.substr(i + 1); + path = path.substr(0, i); + } + } + + if ((i = uri.indexOf("#")) >= 0) { + query = uri.substr(0, i); + hash = uri.substr(i + 1); + } else { + query = uri; + } + } + + if (host && (i = host.lastIndexOf(":")) >= 0) { + port = host.substr(i + 1); + host = host.substr(0, i); + } + + return { + schema : schema, + host : host, + port : port, + path : path, + query : query, + hash : hash + }; + } + + function makeURI(options) { + var uri = []; + + if (options.schema) + uri.push(options.schema, ":"); + if (options.host) + uri.push("//", options.host); + if (options.host && options.port) + uri.push(":", options.port); + + if (options.path) { + if (options.host && options.path[0] != "/") + uri.push("/"); + uri.push(options.path); + } else if (options.host) { + uri.push("/"); + } + + if (options.query) + uri.push("?", options.query); + if (options.hash) + uri.push("#", options.hash); + + return uri.join(""); + } + + function reducePath(parts) { + var balance = 0, result = [], isRoot; + + for (var i = 0; i < parts.length; i++) { + var part = parts[i]; + switch (part) { + case "..": + if (balance > 0) { + result.pop(); + } else { + if (isRoot) + throw new Error("Unbalanced path: " + parts); + + result.push(part); + } + balance--; + break; + case ".": + break; + case "": + if (i === 0) { + isRoot = true; + result.push(part); + } + break; + default: + result.push(part); + balance++; + break; + } + } + + return result.join("/"); + } + + var meta = { + schema : null, + host : null, + port : null, + path : null, + query : null, + hash : null + }; + + var URI = declare(null, { + constructor : function(opts) { + if (typeof (opts) == "string") + opts = parseURI(opts); + for ( var p in meta) + if (p in opts) + this[p] = opts[p]; + }, + + clone : function() { + return new URI(this); + }, + + combine : function(rel) { + var me = this; + + if (typeof (rel) === "string") + rel = new URI(rel); + else + rel = rel.clone(); + + // //some.host:123/path?q=a#123 + if (rel.host) + return rel; + + // /abs/path?q=a#123 + if (rel.path && rel.path[0] == "/") { + if (me.host) { + rel.schema = me.schema; + rel.host = me.host; + rel.port = me.port; + } + return rel; + } + + var base = me.clone(); + + // rel/path?a=b#cd + if (rel.path) { + var segments = base.getSegments(); + segments.pop(); + segments.push.apply(segments, rel.getSegments()); + + base.path = reducePath(segments); + } + + // ?q=a#123 + if (rel.query) + base.query = rel.query; + if (rel.hash) + base.hase = rel.hash; + + return base; + }, + + optimize : function() { + this.path = reducePath(this.getSegments()); + }, + + getSegments : function() { + if (typeof (this.path) === "string") + return this.path.split("/"); + else + return []; + }, + + toString : function() { + var uri = [], me = this; + + if (me.schema) + uri.push(me.schema, ":"); + if (me.host) + uri.push("//", me.host); + if (me.host && me.port) + uri.push(":", me.port); + + if (me.path) { + if (me.host && me.path[0] != "/") + uri.push("/"); + uri.push(me.path); + } else if (me.host) { + uri.push("/"); + } + + if (me.query) + uri.push("?", me.query); + if (me.hash) + uri.push("#", me.hash); + + return uri.join(""); + } + + }); + + URI.combine = function(base, rel) { + if (typeof (base) === "string") + base = new URI(base); + return base.combine(rel).toString(); + }; + + return URI; + }); \ No newline at end of file diff -r 8af8e840dd49 -r 27e8e9e38e07 core/src/js/Uuid.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/js/Uuid.js Wed Jun 05 20:44:15 2019 +0300 @@ -0,0 +1,278 @@ +// uuid.js +// +// Copyright (c) 2010-2012 Robert Kieffer +// MIT License - http://opensource.org/licenses/mit-license.php +define([], function () { + 'use strict'; + + var _window = 'undefined' !== typeof window ? window : null; + + // Unique ID creation requires a high quality random # generator. We + // feature + // detect to determine the best RNG source, normalizing to a function + // that + // returns 128-bits of randomness, since that's what's usually required + var _rng, _mathRNG, _nodeRNG, _whatwgRNG, _previousRoot; + + function setupBrowser() { + // Allow for MSIE11 msCrypto + var _crypto = _window.crypto || _window.msCrypto; + + if (!_rng && _crypto && _crypto.getRandomValues) { + // WHATWG crypto-based RNG - http://wiki.whatwg.org/wiki/Crypto + // + // Moderately fast, high quality + try { + var _rnds8 = new Uint8Array(16); + _whatwgRNG = _rng = function whatwgRNG() { + _crypto.getRandomValues(_rnds8); + return _rnds8; + }; + _rng(); + } catch (e) { /**/ } + } + + if (!_rng) { + // Math.random()-based (RNG) + // + // If all else fails, use Math.random(). It's fast, but is of + // unspecified + // quality. + var _rnds = new Array(16); + _mathRNG = _rng = function () { + for (var i = 0, r; i < 16; i++) { + if ((i & 0x03) === 0) { + r = Math.random() * 0x100000000; + } + _rnds[i] = r >>> ((i & 0x03) << 3) & 0xff; + } + + return _rnds; + }; + if ('undefined' !== typeof console && console.warn) { + console + .warn("[SECURITY] node-uuid: crypto not usable, falling back to insecure Math.random()"); + } + } + } + + function setupNode() { + // Node.js crypto-based RNG - + // http://nodejs.org/docs/v0.6.2/api/crypto.html + // + // Moderately fast, high quality + if ('function' === typeof require) { + try { + var _rb = require('crypto').randomBytes; + _nodeRNG = _rng = _rb && function () { + return _rb(16); + }; + _rng(); + } catch (e) { /**/ } + } + } + + if (_window) { + setupBrowser(); + } else { + setupNode(); + } + + // Buffer class to use + var BufferClass = ('function' === typeof Buffer) ? Buffer : Array; + + // Maps for number <-> hex string conversion + var _byteToHex = []; + var _hexToByte = {}; + for (var i = 0; i < 256; i++) { + _byteToHex[i] = (i + 0x100).toString(16).substr(1); + _hexToByte[_byteToHex[i]] = i; + } + + // **`parse()` - Parse a UUID into it's component bytes** + function parse(s, buf, offset) { + var i = (buf && offset) || 0, + ii = 0; + + buf = buf || []; + s.toLowerCase().replace(/[0-9a-f]{2}/g, function (oct) { + if (ii < 16) { // Don't overflow! + buf[i + ii++] = _hexToByte[oct]; + } + }); + + // Zero out remaining bytes if string was short + while (ii < 16) { + buf[i + ii++] = 0; + } + + return buf; + } + + // **`unparse()` - Convert UUID byte array (ala parse()) into a string** + function unparse(buf, offset) { + var i = offset || 0, + bth = _byteToHex; + return bth[buf[i++]] + bth[buf[i++]] + bth[buf[i++]] + + bth[buf[i++]] + '-' + bth[buf[i++]] + bth[buf[i++]] + '-' + + bth[buf[i++]] + bth[buf[i++]] + '-' + bth[buf[i++]] + + bth[buf[i++]] + '-' + bth[buf[i++]] + bth[buf[i++]] + + bth[buf[i++]] + bth[buf[i++]] + bth[buf[i++]] + bth[buf[i++]]; + } + + // **`v1()` - Generate time-based UUID** + // + // Inspired by https://github.com/LiosK/UUID.js + // and http://docs.python.org/library/uuid.html + + // random #'s we need to init node and clockseq + var _seedBytes = _rng(); + + // Per 4.5, create and 48-bit node id, (47 random bits + multicast bit = + // 1) + var _nodeId = [ + _seedBytes[0] | 0x01, + _seedBytes[1], + _seedBytes[2], + _seedBytes[3], + _seedBytes[4], + _seedBytes[5] + ]; + + // Per 4.2.2, randomize (14 bit) clockseq + var _clockseq = (_seedBytes[6] << 8 | _seedBytes[7]) & 0x3fff; + + // Previous uuid creation time + var _lastMSecs = 0, + _lastNSecs = 0; + + // See https://github.com/broofa/node-uuid for API details + function v1(options, buf, offset) { + var i = buf && offset || 0; + var b = buf || []; + + options = options || {}; + + var clockseq = (options.clockseq != null) ? options.clockseq : _clockseq; + + // UUID timestamps are 100 nano-second units since the Gregorian + // epoch, + // (1582-10-15 00:00). JSNumbers aren't precise enough for this, so + // time is handled internally as 'msecs' (integer milliseconds) and + // 'nsecs' + // (100-nanoseconds offset from msecs) since unix epoch, 1970-01-01 + // 00:00. + var msecs = (options.msecs != null) ? options.msecs : new Date() + .getTime(); + + // Per 4.2.1.2, use count of uuid's generated during the current + // clock + // cycle to simulate higher resolution clock + var nsecs = (options.nsecs != null) ? options.nsecs : _lastNSecs + 1; + + // Time since last uuid creation (in msecs) + var dt = (msecs - _lastMSecs) + (nsecs - _lastNSecs) / 10000; + + // Per 4.2.1.2, Bump clockseq on clock regression + if (dt < 0 && options.clockseq == null) { + clockseq = clockseq + 1 & 0x3fff; + } + + // Reset nsecs if clock regresses (new clockseq) or we've moved onto + // a new + // time interval + if ((dt < 0 || msecs > _lastMSecs) && options.nsecs == null) { + nsecs = 0; + } + + // Per 4.2.1.2 Throw error if too many uuids are requested + if (nsecs >= 10000) { + throw new Error( + 'uuid.v1(): Can\'t create more than 10M uuids/sec'); + } + + _lastMSecs = msecs; + _lastNSecs = nsecs; + _clockseq = clockseq; + + // Per 4.1.4 - Convert from unix epoch to Gregorian epoch + msecs += 12219292800000; + + // `time_low` + var tl = ((msecs & 0xfffffff) * 10000 + nsecs) % 0x100000000; + b[i++] = tl >>> 24 & 0xff; + b[i++] = tl >>> 16 & 0xff; + b[i++] = tl >>> 8 & 0xff; + b[i++] = tl & 0xff; + + // `time_mid` + var tmh = (msecs / 0x100000000 * 10000) & 0xfffffff; + b[i++] = tmh >>> 8 & 0xff; + b[i++] = tmh & 0xff; + + // `time_high_and_version` + b[i++] = tmh >>> 24 & 0xf | 0x10; // include version + b[i++] = tmh >>> 16 & 0xff; + + // `clock_seq_hi_and_reserved` (Per 4.2.2 - include variant) + b[i++] = clockseq >>> 8 | 0x80; + + // `clock_seq_low` + b[i++] = clockseq & 0xff; + + // `node` + var node = options.node || _nodeId; + for (var n = 0; n < 6; n++) { + b[i + n] = node[n]; + } + + return buf ? buf : unparse(b); + } + + // **`v4()` - Generate random UUID** + + // See https://github.com/broofa/node-uuid for API details + function v4(options, buf, offset) { + // Deprecated - 'format' argument, as supported in v1.2 + var i = buf && offset || 0; + + if (typeof (options) === 'string') { + buf = (options === 'binary') ? new BufferClass(16) : null; + options = null; + } + options = options || {}; + + var rnds = options.random || (options.rng || _rng)(); + + // Per 4.4, set bits for version and `clock_seq_hi_and_reserved` + rnds[6] = (rnds[6] & 0x0f) | 0x40; + rnds[8] = (rnds[8] & 0x3f) | 0x80; + + // Copy bytes to buffer, if provided + if (buf) { + for (var ii = 0; ii < 16; ii++) { + buf[i + ii] = rnds[ii]; + } + } + + return buf || unparse(rnds); + } + + // Export public API + var uuid = function () { + return new String(v4()); + }; + uuid.v1 = v1; + uuid.v4 = v4; + uuid.create = v4; + uuid.empty = "00000000-0000-0000-0000-000000000000"; + uuid.parse = parse; + uuid.unparse = unparse; + uuid.BufferClass = BufferClass; + uuid._rng = _rng; + uuid._mathRNG = _mathRNG; + uuid._nodeRNG = _nodeRNG; + uuid._whatwgRNG = _whatwgRNG; + + return uuid; +}); \ No newline at end of file diff -r 8af8e840dd49 -r 27e8e9e38e07 core/src/js/components/ActivationController.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/js/components/ActivationController.js Wed Jun 05 20:44:15 2019 +0300 @@ -0,0 +1,120 @@ +define(["dojo/_base/declare", "../guard", "../safe", "../log/_LogMixin"], function (declare, guard, safe, _LogMixin) { + "use strict"; + return declare([_LogMixin], { + + _current: null, + + _pending: false, + + getCurrent: function () { + return this._current; + }, + + _start: function () { + if (this._pending) + throw new Error("The activation/decativation is already pending"); + this._pending = true; + }, + + _await: function (d) { + var me = this; + return d.then(function (x) { + me._pending = false; + return x; + }, function (e) { + me._pending = false; + throw e; + }); + }, + + activate: function (component) { + safe.argumentNotNull(component, "component"); + var me = this; + if (component.getController() !== this) + throw new Error("The specified component doesn't belong to this controller"); + + return me._await(guard(me, "_start").then(function () { + me._activate(component); + })); + }, + + _activate: function (component) { + var me = this; + if (me._current === component) + return guard(false); + + // before activation hook + return guard(me, "onActivating", [component]).then(function () { + // deactivate curent + if (me._current) + return me._current.deactivate(true).then(function () { + try { + me._current.onDeactivated(); + } catch (err) { + me.error(err); + } + // HACK raise deactivated event + try { + me.onDeactivated(me._current, component); + } catch (err) { + // deactivated shouldn't affect the process + me.error(err); + } + me._current = null; + + }); + }).then(function () { + return component.activate(true); + }).then(function () { + me._current = component; + try { + me.onActivated(component); + } catch (err) { + me.error(err); + } + + }); + + }, + + /** + * Деактивирует текущую компоненту. + * + * @async + * @returns true - компонента была деактивирована, либо нет активной + * компоненты. false - запрос на деактивацию - отклонен. + */ + deactivate: function () { + var me = this; + return me._await(guard(me, "_start").then(function () { + return me._deactivate(); + })); + }, + + _deactivate: function () { + var me = this; + if (!me._current) + return guard(false); + + return guard(me, "onDeactivating").then(function () { + return me._current.deactivate(true); + }).then(function () { + // HACK raise deactivated event + try { + me.onDeactivated(me._current); + } catch (err) { + me.error(err); + } + me._current = null; + }); + }, + + onActivating: function (component) {}, + + onDeactivating: function (component) {}, + + onDeactivated: function (component, next) {}, + + onActivated: function (component) {} + }); +}); \ No newline at end of file diff -r 8af8e840dd49 -r 27e8e9e38e07 core/src/js/components/StateMachine.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/js/components/StateMachine.js Wed Jun 05 20:44:15 2019 +0300 @@ -0,0 +1,34 @@ +define([ "dojo/_base/declare", "../safe", "../text/format" ], function(declare, safe, format) { + return declare(null, { + states : null, + + current : null, + + constructor : function(opts) { + safe.argumentNotNull(opts, "opts"); + safe.argumentNotNull(opts.states, "opts.states"); + safe.argumentNotNull(opts.initial, "opts.initial"); + + this.states = opts.states; + this.current = opts.initial; + + if (safe.isNull(this.states[this.current])) + throw new Error("Invalid initial state " + this.current); + }, + + move : function(input, noThrow) { + safe.argumentNotNull(input, "input"); + + var next = this.states[this.current][input]; + if(safe.isNull(next)) { + if (noThrow) + return false; + else + throw new Error(format("Invalid transition {0}-{1}->?", this.current, input)); + } else { + this.current = next; + return true; + } + } + }); +}); \ No newline at end of file diff -r 8af8e840dd49 -r 27e8e9e38e07 core/src/js/components/_ActivatableMixin.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/js/components/_ActivatableMixin.js Wed Jun 05 20:44:15 2019 +0300 @@ -0,0 +1,153 @@ +define(["dojo/_base/declare", "../guard", "./StateMachine", "../log/_LogMixin", ], function (declare, guard, StateMachine, _LogMixin) { + + var states = { + inactive: { + activate: "activating" + }, + activating: { + success: "active", + failed: "inactive" + }, + active: { + deactivate: "deactivating" + }, + deactivating: { + success: "inactive", + failed: "active" + } + }; + + return declare([_LogMixin], { + _controller: null, + + _active: null, + + constructor: function () { + this._active = new StateMachine({ + states: states, + initial: "inactive" + }); + }, + + /** + * @returns {Object} контроллер для активации текущей компоненты + */ + getController: function () { + return this._controller; + }, + + /** + * @param {Object} + * v Контроллер для активации текущей компоненты + */ + setController: function (v) { + this._controller = v; + }, + + /** + * @returns {Boolean} текущая компонента активна + */ + isActive: function () { + return this._active.current == "active"; + }, + + assertActive: function () { + if (!this.isActive()) + throw new Error("The object must be active to perform the operation"); + }, + + /** + * Активирует текущую компоненту, если у текущей компоненты задан + * контроллер, то активация будет осуществляться через него + * + * @async + * @param{Boolean} + * direct вызов должен осуществится напрямую, без участия + * контроллера. + * @return{Boolean} успешно/неуспешно + */ + activate: function (direct) { + var me = this; + if (!direct && this._controller) + return me._controller.activate(me).then(function () { + me.onActivated(); + }); + + me._active.move("activate"); + return guard(me, "onActivating").then(function () { + me.log("Activated"); + me._active.move("success"); + if (!me._controller) + me.onActivated(); + }, function (err) { + console.error(err); + me.error("Activation failed: {0}", err); + me._active.move("failed"); + throw err; + }); + }, + + /** + * Деактивирует текущую компоненту, если у компоненты задан контроллер, + * то деактивация будет осуществляться через него. + * + * @async + * @param{Boolean} direct вызов должен осуществится напрямую, без + * участия контроллера. + * + */ + deactivate: function (direct) { + var me = this; + if (!direct && me._controller) + return me._controller.deactivate(me).then(function () { + me.onDeactivated(); + }); + + me._active.move("deactivate"); + return guard(me, "onDeactivating").then(function () { + me.log("Deactivated"); + me._active.move("success"); + if (!me._controller) + me.onDeactivated(); + }, function (err) { + console.error(err); + me.error("Deactivation failed: {0}", err); + me.move("failed"); + throw err; + }); + + }, + + toogleActive: function () { + var me = this; + return (me.isActive() ? me.deactivate() : me.activate()).then(function () { + return me.isActive(); + }); + }, + + /** + * Событие вызывается перед активацией текущей компоненты + * + * @returns{Boolean|undefined} если false - активация будет отменена + */ + onActivating: function () {}, + + /** + * Событие вызывается перед деактивацией текущей компоненты + * + * @returns {Boolean|undefined} если false - деактивация будет отменена + */ + onDeactivating: function () {}, + + /** + * Событие вызывается после активации текущей компоненты + */ + onActivated: function () {}, + + /** + * Событие вызывается после деактивации текущей компоненты + */ + onDeactivated: function () {} + + }); +}); \ No newline at end of file diff -r 8af8e840dd49 -r 27e8e9e38e07 core/src/js/data/DataContext.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/js/data/DataContext.js Wed Jun 05 20:44:15 2019 +0300 @@ -0,0 +1,45 @@ +define([ "dojo/_base/declare", "../safe" ], function(declare, safe) { + return declare( + null, + { + _params : null, + + _repositories : null, + + constructor : function(opts) { + this._params = opts || {}; + this._repositories = {}; + }, + + getRepository : function(name) { + safe.argumentNotEmptyString(name, "name"); + var repo = this._repositories[name]; + if (!repo) { + repo = this._params[name]; + if (!repo) + throw new Error("The repository '" + name + + "' isn't found"); + if (repo instanceof Function) + repo = new repo(); // factory method or constructor + if (repo.initialize) { + repo.initialize({ + dataContext : this + }); + } else if (repo.setDataContext) { + repo.setDataContext(this); + } + this._repositories[name] = repo; + } + + return repo; + }, + + dispose : function() { + for( var name in this._repositories) { + var r = this._repositories[name]; + if (r.dispose) + r.dispose(); + } + } + }); +}); \ No newline at end of file diff -r 8af8e840dd49 -r 27e8e9e38e07 core/src/js/data/MapSchema.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/js/data/MapSchema.js Wed Jun 05 20:44:15 2019 +0300 @@ -0,0 +1,67 @@ +define([ "dojo/_base/declare", "../safe" ], function(declare, safe) { + return declare(null, { + /** + * Отображение одного типа объектов в другой. + * + * @remarks Отображения являются односторонними, т.е. позволяют + * перенести часть содержимого одного объекта в другой. Каждая + * схема отображения строится из набора примитивных + * отображений, которые будут применены в произвольном порядке. + */ + _schema : null, + + constructor : function(schema) { + this._schema = schema; + }, + + /** + * Осуществляет отображение одного объекта в другой + * + * @src{Object} Исходный объект из которого будут взяты данные + * @dst{Object} + */ + map : function(src, dst, ctx) { + safe.argumentNotNull(src, "src"); + safe.argumentNotNull(dst, "dst"); + + for ( var p in this._schema) { + var mapper = this._schema[p]; + if (mapper instanceof Function) { + dst[p] = mapper(src[p]); + } else if (mapper && mapper.map) { + mapper.map(src, dst, p, ctx); + } else { + this._defaultMapper(src, dst, p, mapper, ctx); + } + } + }, + + _defaultMapper : function(src, dst, prop, opts) { + if (typeof (opts) == "string") { + if (opts in src) + dst[prop] = src[opts]; + } else if (opts && opts.type instanceof Function) { + if (src[prop] instanceof opts.type) + dst[prop] = src[prop]; + else + dst[prop] = this._isPrimitiveType(opts.type) ? opts.type + .call(null, src[prop]) : new opts.type(src[prop]); + + } else { + if (!(prop in src)) + if (opts && opts.required) + throw new Error("The " + prop + "is missing"); + else + return; + dst[prop] = src[prop]; + } + }, + + _isPrimitiveType : function(type) { + return (type === String || type === Number || type === Boolean + || type === Number || type === Date); + } + + }); + +}); \ No newline at end of file diff -r 8af8e840dd49 -r 27e8e9e38e07 core/src/js/data/ObjectStore.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/js/data/ObjectStore.js Wed Jun 05 20:44:15 2019 +0300 @@ -0,0 +1,174 @@ +define([ "dojo/_base/declare", "dojo/_base/lang", "dojo/_base/array", + "../safe", "dojo/when", "dojo/Deferred", "dojo/store/util/QueryResults" ], function(declare, + lang, array, safe, when, Deferred, QueryResults) { + /** + * @module implab/data/RestStore + * + * Реализует шаблон репозитария dojo/store над уже имеющимся хранилищем. При получении и + * отправке данных в нижележащие хранилище используется implab/data/MapSchema для преобразования + * данных. + */ + return declare(null, { + + model: null, + + mapping: null, + + _dataContext: null, + + _store : null, // backing store + + _cache : null, + + constructor : function(options) { + options = options || {}; + + if (options.store) + this._store = options.store; + + if (options.dataContext) { + this._dataContext = options.dataContext; + } + + if (options.cache === false) { + // no cache at all + } else if (options.cache === "string" && options.dataContext) { + this._cache = this._dataContext.getCache(options.cache); + } else { + this._cache = {}; + } + }, + + getDataContext : function() { + return this._dataContext; + }, + + // READ + get : function(id) { + var me = this; + var cache = me.getCacheEntry(id); + if (cache) + return cache; + else + return when(me._store.get(id), function(data) { + return me._mapToObject(id, data); + }); + }, + + query : function(query, options) { + var me = this; + var d = me._store.query(query, options); + var result = QueryResults(when(d, function(data) { + return array.map(data, function(item) { + return me._mapToObject(me._store.getIdentity(item), item); + }); + })); + result.total = d.total; + return result; + }, + + getIdentity : function(object) { + return object.getId(); + }, + + // UPDATE + put : function(object, directives) { + return this._store.put(this._mapFromObject(object), directives); + }, + + // INSERT + add : function(object, directives) { + var me = this; + // добавляем в хранилище данные, сохраняем в кеше объект с + // полученным идентификатором + return when( + me._store.add(this._mapFromObject(object), directives), + function(id) { + object.attach(id, me); + me.storeCacheEntry(id, object); + return id; + }); + }, + + // DELETE + remove : function(id) { + var me = this; + return when(me._store.remove(id), function() { + me.removeCacheEntry(id); + }); + }, + + _mapToObject : function(id, data) { + var instance = this.createInstance(id); + this.populateInstance(instance, data); + return instance; + }, + + _mapFromObject : function(object) { + return this.serializeInstance(object); + }, + + getCacheEntry : function(id) { + safe.argumentNotNull(id, "id"); + id = id.toString(); + + return this._cache[id]; + }, + + storeCacheEntry : function(id, object) { + safe.argumentNotNull(id, "id"); + id = id.toString(); + + this._cache[id] = object; + }, + + removeCacheEntry : function(id) { + safe.argumentNotNull(id, "id"); + id = id.toString(); + delete this._cache[id]; + }, + + /** Создает экземпляр сущности с указанным идентификатором, либо извлекает из кеша, если таковая уже имеется. + * @remarks + * Технически сюда можно было бы дополнительно передать данные для ининциализации объекта, + * но концептуально это не верно, поскольку процесс чтения объекта состоит из двух этапов: + * 1. Создание пустого объекта (createInstance) + * 2. Заполнение объекта при помощи схемы отображения (populateInstance) + * при этом первый этап может быть выполнен за долго до второго, например, + * при создании заглушек в процессе установления ссылок между объектами. + */ + createInstance : function(id) { + var instance = this.getCacheEntry(id); + if (!instance) { + instance = this.createInstanceImpl(id); + this.storeCacheEntry(id, instance); + } + return instance; + }, + + /** Непосредственно создает экземпляр сущнсти, т.е. является фабричным методом. + * @param {String} id идентификатор создаваемого экземпляра. + */ + createInstanceImpl : function(id) { + var opts = { + dataContext : this.getDataContext(), + id : id + }; + + return new this.itemsType(opts); + }, + + populateInstance : function(instance, data) { + this.mapping.readData(instance, data,this.getDataContext()); + if (instance.onPopulate) + instance.onPopulate(); + }, + + serializeInstance : function(instance) { + var data = {}; + this.mapping.writeData(instance, data, this.getDataContext()); + return data; + } + + }); +}); \ No newline at end of file diff -r 8af8e840dd49 -r 27e8e9e38e07 core/src/js/data/RestStore.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/js/data/RestStore.js Wed Jun 05 20:44:15 2019 +0300 @@ -0,0 +1,166 @@ +define([ "dojo/_base/declare", "dojo/_base/lang", "dojo/_base/array", + "../safe", "dojo/when", "dojo/Deferred", "dojo/store/util/QueryResults" ], function(declare, + lang, array, safe, when, Deferred, QueryResults) { + /** + * @module implab/data/RestStore + * + * Реализует шаблон репозитария dojo/store над уже имеющимся хранилищем. При получении и + * отправке данных в нижележащие хранилище используется implab/data/MapSchema для преобразования + * данных. + */ + return declare(null, { + + itemsType : null, + + _dataContext : null, + + _store : null, // backing store + _cache : null, + + constructor : function(options) { + options = options || {}; + + this._cache = {}; + if (options.store) + this._store = options.store; + if (options.dataContext) + this._dataContext = options.dataContext; + }, + + setDataContext : function(v) { + this._dataContext = v; + }, + + getDataContext : function() { + return this._dataContext; + }, + + // READ + get : function(id) { + var me = this; + var cache = me.getCacheEntry(id); + if (cache) + return cache; + else + return when(me._store.get(id), function(data) { + return me._mapToObject(id, data); + }); + }, + + query : function(query, options) { + var me = this; + var d = me._store.query(query, options); + var result = QueryResults(when(d, function(data) { + return array.map(data, function(item) { + return me._mapToObject(me._store.getIdentity(item), item); + }); + })); + result.total = d.total; + return result; + }, + + getIdentity : function(object) { + return object.getId(); + }, + + // UPDATE + put : function(object, directives) { + return this._store.put(this._mapFromObject(object), directives); + }, + + // INSERT + add : function(object, directives) { + var me = this; + // добавляем в хранилище данные, сохраняем в кеше объект с + // полученным идентификатором + return when( + me._store.add(this._mapFromObject(object), directives), + function(id) { + object.attach(id, me); + me.storeCacheEntry(id, object); + return id; + }); + }, + + // DELETE + remove : function(id) { + var me = this; + return when(me._store.remove(id), function() { + me.removeCacheEntry(id); + }); + }, + + _mapToObject : function(id, data) { + var instance = this.createInstance(id); + this.populateInstance(instance, data); + return instance; + }, + + _mapFromObject : function(object) { + return this.serializeInstance(object); + }, + + getCacheEntry : function(id) { + safe.argumentNotNull(id, "id"); + id = id.toString(); + + return this._cache[id]; + }, + + storeCacheEntry : function(id, object) { + safe.argumentNotNull(id, "id"); + id = id.toString(); + + this._cache[id] = object; + }, + + removeCacheEntry : function(id) { + safe.argumentNotNull(id, "id"); + id = id.toString(); + delete this._cache[id]; + }, + + /** Создает экземпляр сущности с указанным идентификатором, либо извлекает из кеша, если таковая уже имеется. + * @remarks + * Технически сюда можно было бы дополнительно передать данные для ининциализации объекта, + * но концептуально это не верно, поскольку процесс чтения объекта состоит из двух этапов: + * 1. Создание пустого объекта (createInstance) + * 2. Заполнение объекта при помощи схемы отображения (populateInstance) + * при этом первый этап может быть выполнен за долго до второго, например, + * при создании заглушек в процессе установления ссылок между объектами. + */ + createInstance : function(id) { + var instance = this.getCacheEntry(id); + if (!instance) { + instance = this.createInstanceImpl(id); + this.storeCacheEntry(id, instance); + } + return instance; + }, + + /** Непосредственно создает экземпляр сущнсти, т.е. является фабричным методом. + * @param {String} id идентификатор создаваемого экземпляра. + */ + createInstanceImpl : function(id) { + var opts = { + dataContext : this.getDataContext(), + id : id + }; + + return new this.itemsType(opts); + }, + + populateInstance : function(instance, data) { + this.itemsType.readData(instance, data,this.getDataContext()); + if (instance.onPopulate) + instance.onPopulate(); + }, + + serializeInstance : function(instance) { + var data = {}; + this.itemsType.writeData(instance, data, this.getDataContext()); + return data; + } + + }); +}); \ No newline at end of file diff -r 8af8e840dd49 -r 27e8e9e38e07 core/src/js/data/StatefullStoreAdapter.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/js/data/StatefullStoreAdapter.js Wed Jun 05 20:44:15 2019 +0300 @@ -0,0 +1,19 @@ +define(["dojo/_base/declare", "dojo/_base/array", "../safe", "./StoreAdapter"], function(declare, array, safe ,AdapterStore){ + return declare([AdapterStore], { + _attrs : null, + + constructor : function(opts) { + safe.argumentNotEmptyArray(opts.attrs, "opts.attrs"); + this._attrs = opts.attrs; + }, + + mapItem : function(item) { + var result = {}; + array.forEach(this._attrs, function(p) { + result[p] = item.get(p); + }); + return result; + } + }); + +}); \ No newline at end of file diff -r 8af8e840dd49 -r 27e8e9e38e07 core/src/js/data/StoreAdapter.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/js/data/StoreAdapter.js Wed Jun 05 20:44:15 2019 +0300 @@ -0,0 +1,110 @@ +define([ + "dojo/_base/declare", + "../safe", + "dojo/when", + "dojo/store/util/QueryResults" ], + +function(declare, safe, when, QueryResults) { + + "use strict"; + + /** + * Обертка вокруг произвольного хранилища, только для чтения. Используется + * для преобразования данных, например, отображения в списках элементов + * пространственных данных. + */ + return declare(null, { + /** + * @type{String} Свойство, хранящее идентификатор + */ + idProperty : null, + + _store : null, + + /** + * @param{String} opts.idProperty Имя свойства, в которое будет записан + * идентификатор, если не указан, то идентификатор будет + * взят из родительского хранилища или использоваться + * строка id + * @param{dojo.store} opts.store Родительское хранилище + */ + constructor : function(opts) { + safe.argumentNotNull(opts, "opts"); + safe.argumentNotNull(opts.store, "opts.store"); + + this._store = opts.store; + delete opts.store; + declare.safeMixin(this, opts); + this.idProperty = opts.idProperty || this._store.idProperty || "id"; + }, + + getParentStore : function() { + return this._store; + }, + + get : function(id) { + var me = this; + return when(me._store.get(id), function(x) { + var m = me.mapItem(x); + if (!(me.idProperty in m)) + m[me.idProperty] = id; + return m; + }); + }, + + /** + * Выполняет запрос в родительском хранилище, для этого используется + * translateQuery для подготовки запроса, затем, + * mapItem для преобразования результатов. + */ + query : function(q, options) { + var me = this, store = this._store; + return when(store.query(me.translateQuery(q), me + .translateOptions(options)), function(res) { + var total = res.total; + var mapped = res.map(function(x) { + var m = me.mapItem(x); + if (!(me.idProperty in m)) + m[me.idProperty] = store.getIdentity && + store.getIdentity(x); + return m; + }); + mapped.total = total; + var results = new QueryResults(mapped); + console.log(results); + return results; + }); + }, + + getIdentity : function(obj) { + return obj && obj[this.idProperty]; + }, + + /** + * Преобразование запроса в формат родительского хранилища. + * + * @param{Object} q Запрос в формате текущего хранилища + * @returns{Object} Запрос в формате родительского хранилища + */ + translateQuery : function(q) { + return q; + }, + + translateOptions : function(options) { + return options; + }, + + /** + * Преобразование объекта из родительского хранилища. При преобразовании + * в объекте можно задать идентификатор, иначе идентификатор будет + * автоматически получен и присвоен из родительского хранилища + * + * @param{Object} item Объект из родительского хранилища + * @returns{Object} результат преобразования + */ + mapItem : function(item) { + return item; + } + }); + +}); \ No newline at end of file diff -r 8af8e840dd49 -r 27e8e9e38e07 core/src/js/data/_ModelBase.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/js/data/_ModelBase.js Wed Jun 05 20:44:15 2019 +0300 @@ -0,0 +1,37 @@ +define(["dojo/_base/declare"], function(declare) { + + return declare(null, { + dataContext : null, + idField : "id", + loaded : false, + + constructor : function(opts){ + if (opts) { + if(opts.dataContext) + this.dataContext = opts.dataContext; + if(opts.id) + this[this.idField] = opts.id; + } + }, + + getId : function() { + return this[this.idField]; + }, + + attach : function(id, dc) { + if (this.dataContext) + throw new Error("The object is already attached"); + this[this.idField] = id; + this.dataContext = dc; + }, + + isAttached : function() { + return this.dataContext ? true : false; + }, + + onPopulate : function() { + this.loaded = true; + } + + }); +}); \ No newline at end of file diff -r 8af8e840dd49 -r 27e8e9e38e07 core/src/js/data/_StatefulModelMixin.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/js/data/_StatefulModelMixin.js Wed Jun 05 20:44:15 2019 +0300 @@ -0,0 +1,5 @@ +define(["dojo/_base/declare", "dojo/Stateful"], function(declare, Stateful) { + return declare([Stateful], { + + }); +}); \ No newline at end of file diff -r 8af8e840dd49 -r 27e8e9e38e07 core/src/js/data/declare-model.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/js/data/declare-model.js Wed Jun 05 20:44:15 2019 +0300 @@ -0,0 +1,72 @@ +define([ "dojo/_base/declare", "./_ModelBase", "./MapSchema" ], function( + declare, _ModelBase, MapSchema) { + /** + * Создает новый класс, унаследованный от ./ModelBase, с указанной схемой + * отображения данных. + * + * @details Модель представляет собой объект, живущий в рамках контекста + * данных, также имеющий две схемы отображения: из модели хранения + * в источнике данных (toObjectMap) и наооборот в модель хранения в + * источнике данных (fromObjectMap). + * + * Описание схемы выглядит следующим образом + *
+     * {
+     *      name : null, // отображение в обе стороны без преобразования
+     *      
+     *      age : Number,   // при преобразоваении к объекту поле будет преобразовано dst.age = Number(src.age)
+     *                      // обратное преобразование отсутстсвует
+     *      
+     *      age : [Number, null] // тоже самое что и age : Number
+     *      
+     *      date : [Date, function(v) { return v.toString() }] // указывается преобразование в одну и в другую сторону
+     * }
+     * 
+     */
+    return function(schema, mixins, opts) {
+        var fromObjectSchema = {}, toObjectSchema = {};
+        if (schema !== null && schema !== undefined) {
+            for ( var p in schema) {
+                var mapper = schema[p];
+
+                if (mapper instanceof Array) {
+                    toObjectSchema[p] = mapper[0];
+                    fromObjectSchema[p] = mapper[1];
+                } else {
+                    toObjectSchema[p] = mapper;
+                    fromObjectSchema[p] = null;
+                }
+            }
+        }
+
+        if (arguments.length < 3) {
+            opts = mixins;
+            mixins = undefined;
+        }
+
+        var base = [ _ModelBase ];
+        if (mixins) {
+            if (mixins instanceof Array)
+                base = base.concat(mixins);
+            else
+                base.push(mixins);
+        }
+
+        var model = declare(base, opts);
+
+        model.toObjectMap = new MapSchema(toObjectSchema);
+
+        model.fromObjectMap = new MapSchema(fromObjectSchema);
+
+        model.readData = function(that, data, context) {
+            model.toObjectMap.map(data, that, context);
+        };
+
+        model.writeData = function(that, data, context) {
+            data = data || {};
+            model.fromObjectMap.map(that, data, context);
+        };
+
+        return model;
+    };
+});
\ No newline at end of file
diff -r 8af8e840dd49 -r 27e8e9e38e07 core/src/js/declare.js
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/src/js/declare.js	Wed Jun 05 20:44:15 2019 +0300
@@ -0,0 +1,6 @@
+define([
+    './declare/_load!'
+], function(declare) {
+    'use strict';
+    return declare;
+});
\ No newline at end of file
diff -r 8af8e840dd49 -r 27e8e9e38e07 core/src/js/declare/_load.js
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/src/js/declare/_load.js	Wed Jun 05 20:44:15 2019 +0300
@@ -0,0 +1,12 @@
+define([], function () {
+    'use strict';
+
+    return {
+        load: function (id, require, callback) {
+            require(['dojo/_base/declare'], function (declare) {
+                callback(declare);
+            });
+        }
+    };
+
+});
\ No newline at end of file
diff -r 8af8e840dd49 -r 27e8e9e38e07 core/src/js/declare/override.js
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/src/js/declare/override.js	Wed Jun 05 20:44:15 2019 +0300
@@ -0,0 +1,73 @@
+"use strict";
+define([], function () {
+    var slice = Array.prototype.slice;
+    var override = function (method) {
+        var proxy;
+
+        /** @this target object */
+        proxy = function () {
+            var me = this;
+            var inherited = (this.getInherited && this.getInherited(proxy.nom, {
+                callee: proxy
+            })) || function () {};
+
+            return method.apply(me, [function () {
+                return inherited.apply(me, arguments);
+            }].concat(slice.apply(arguments)));
+        };
+
+        proxy.method = method;
+        proxy.overrides = true;
+
+        return proxy;
+    };
+
+    override.before = function (method) {
+        var proxy;
+
+        /** @this target object */
+        proxy = function () {
+            var me = this;
+            var inherited = (this.getInherited && this.getInherited(proxy.nom, {
+                callee: proxy
+            })) || function () {};
+
+
+            method.apply(me, arguments);
+            return inherited.apply(me, arguments);
+        };
+
+        proxy.method = method;
+        proxy.overrides = true;
+
+        return proxy;
+    };
+
+    override.after = function (method) {
+        var proxy;
+
+        /** @this target object */
+        proxy = function () {
+            var me = this;
+            var inherited = (this.getInherited && this.getInherited(proxy.nom, {
+                callee: proxy
+            })) || function () {};
+
+            inherited.apply(me, arguments);
+
+            return method.apply(me, arguments);
+        };
+
+        proxy.method = method;
+        proxy.overrides = true;
+
+        return proxy;
+    };
+
+    override.hide = function (method) {
+        method.overrides = false;
+        return method;
+    };
+
+    return override;
+});
\ No newline at end of file
diff -r 8af8e840dd49 -r 27e8e9e38e07 core/src/js/di/ActivationContext.js
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/src/js/di/ActivationContext.js	Wed Jun 05 20:44:15 2019 +0300
@@ -0,0 +1,138 @@
+define([
+    "../declare",
+    "../safe",
+    "./Descriptor",
+    "./ValueDescriptor",
+    "../log/trace!"
+], function (declare, safe, Descriptor, Value, trace) {
+    var Context = declare(null, {
+
+        _cache: null,
+
+        _services: null,
+
+        _stack: null,
+
+        _visited: null,
+
+        container: null,
+
+        _trace: true,
+
+        constructor: function (container, services, cache, visited) {
+            safe.argumentNotNull(container, "container");
+            safe.argumentNotNull(services, "services");
+
+            this._visited = visited || {};
+            this._stack = [];
+            this._cache = cache || {};
+            this._services = services;
+            this.container = container;
+        },
+
+        getService: function (name, def) {
+            var d = this._services[name];
+
+            if (!d)
+                if (arguments.length > 1)
+                    return def;
+                else
+                    throw new Error("Service '" + name + "' not found");
+
+            return d.activate(this, name);
+        },
+
+        /**
+         * registers services local to the the activation context
+         * 
+         * @name{string} the name of the service
+         * @service{string} the service descriptor to register
+         */
+        register: function (name, service) {
+            safe.argumentNotEmptyString(name, "name");
+
+            if (!(service instanceof Descriptor))
+                service = new Value(service, true);
+            this._services[name] = service;
+        },
+
+        clone: function () {
+            return new Context(
+                this.container,
+                Object.create(this._services),
+                this._cache,
+                this._visited
+            );
+
+        },
+
+        has: function (id) {
+            return id in this._cache;
+        },
+
+        get: function (id) {
+            return this._cache[id];
+        },
+
+        store: function (id, value) {
+            return (this._cache[id] = value);
+        },
+
+        parse: function (data, name) {
+            var me = this;
+            if (safe.isPrimitive(data))
+                return data;
+
+            if (data instanceof Descriptor) {
+                return data.activate(this, name);
+            } else if (data instanceof Array) {
+                me.enter(name);
+                var v = data.map(function (x, i) {
+                    return me.parse(x, "." + i);
+                });
+                me.leave();
+                return v;
+            } else {
+                me.enter(name);
+                var result = {};
+                for (var p in data)
+                    result[p] = me.parse(data[p], "." + p);
+                me.leave();
+                return result;
+            }
+        },
+
+        visit: function (id) {
+            var count = this._visited[id] || 0;
+            this._visited[id] = count + 1;
+            return count;
+        },
+
+        getStack: function () {
+            return this._stack.slice().reverse();
+        },
+
+        enter: function (name, d, localize) {
+            if (this._trace)
+                trace.log("enter " + name + " " + (d || "") +
+                    (localize ? " localize" : ""));
+            this._stack.push({
+                name: name,
+                service: d,
+                scope: this._services
+            });
+            if (localize)
+                this._services = Object.create(this._services);
+        },
+
+        leave: function () {
+            var ctx = this._stack.pop();
+            this._services = ctx.scope;
+
+            if (this._trace)
+                trace.log("leave " + ctx.name + " " + (ctx.service || ""));
+        }
+    });
+
+    return Context;
+});
\ No newline at end of file
diff -r 8af8e840dd49 -r 27e8e9e38e07 core/src/js/di/ActivationError.js
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/src/js/di/ActivationError.js	Wed Jun 05 20:44:15 2019 +0300
@@ -0,0 +1,39 @@
+define([
+    "../declare"
+], function (declare) {
+    return declare(null, {
+        activationStack: null,
+
+        service: null,
+
+        innerException: null,
+
+        message: null,
+
+        constructor: function (service, activationStack, innerException) {
+            this.message = "Failed to activate the service";
+            this.activationStack = activationStack;
+            this.service = service;
+            this.innerException = innerException;
+        },
+
+        toString: function () {
+            var parts = [this.message];
+            if (this.service)
+                parts.push("when activating: " + this.service.toString());
+
+            if (this.innerException)
+                parts.push("caused by: " + this.innerException.toString());
+
+            if (this.activationStack) {
+                parts.push("at");
+                this.activationStack.forEach(function (x) {
+                    parts.push("    " + x.name + " " +
+                        (x.service ? x.service.toString() : ""));
+                });
+            }
+
+            return parts.join("\n");
+        }
+    });
+});
\ No newline at end of file
diff -r 8af8e840dd49 -r 27e8e9e38e07 core/src/js/di/Container.js
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/src/js/di/Container.js	Wed Jun 05 20:44:15 2019 +0300
@@ -0,0 +1,299 @@
+define([
+    "../declare",
+    "../safe",
+    "../Uuid",
+    "../Deferred",
+    "./ActivationContext",
+    "./Descriptor",
+    "./ValueDescriptor",
+    "./ReferenceDescriptor",
+    "./ServiceDescriptor",
+    "./ActivationError"
+], function (
+    declare,
+    safe,
+    Uuid,
+    Deferred,
+    ActivationContext,
+    Descriptor,
+    Value,
+    Reference,
+    Service,
+    ActivationError) {
+    var Container = declare(null, {
+        _services: null,
+        _cache: null,
+        _cleanup: null,
+        _root: null,
+        _parent: null,
+
+        constructor: function (parent) {
+            this._parent = parent;
+            this._services = parent ? Object.create(parent._services) : {};
+            this._cache = {};
+            this._cleanup = [];
+            this._root = parent ? parent.getRootContainer() : this;
+            this._services.container = new Value(this, true);
+        },
+
+        getRootContainer: function () {
+            return this._root;
+        },
+
+        getParent: function () {
+            return this._parent;
+        },
+
+        /**
+         * 
+         */
+        getService: function (name, def) {
+            var d = this._services[name];
+            if (!d)
+                if (arguments.length > 1)
+                    return def;
+                else
+                    throw new Error("Service '" + name + "' isn't found");
+            if (d.isInstanceCreated())
+                return d.getInstance();
+
+            var context = new ActivationContext(this, this._services);
+
+            try {
+                return d.activate(context, name);
+            } catch (error) {
+                throw new ActivationError(name, context.getStack(), error);
+            }
+        },
+
+        register: function (name, service) {
+            if (arguments.length == 1) {
+                var data = name;
+                for (name in data)
+                    this.register(name, data[name]);
+            } else {
+                if (!(service instanceof Descriptor))
+                    service = new Value(service, true);
+                this._services[name] = service;
+            }
+            return this;
+        },
+
+        onDispose: function (callback) {
+            if (!(callback instanceof Function))
+                throw new Error("The callback must be a function");
+            this._cleanup.push(callback);
+        },
+
+        dispose: function () {
+            if (this._cleanup) {
+                for (var i = 0; i < this._cleanup.length; i++)
+                    this._cleanup[i].call(null);
+                this._cleanup = null;
+            }
+        },
+
+        /**
+         * @param{String|Object} config
+         *  The configuration of the contaier. Can be either a string or an object,
+         *  if the configuration is an object it's treated as a collection of
+         *  services which will be registed in the contaier.
+         * 
+         * @param{Function} opts.contextRequire
+         *  The function which will be used to load a configuration or types for services.
+         *  
+         */
+        configure: function (config, opts) {
+            var p, me = this,
+                contextRequire = (opts && opts.contextRequire);
+
+            if (typeof (config) === "string") {
+                p = new Deferred();
+                if (!contextRequire) {
+                    var shim = [config, new Uuid()].join(config.indexOf("/") != -1 ? "-" : "/");
+                    define(shim, ["require", config], function (ctx, data) {
+                        p.resolve([data, {
+                            contextRequire: ctx
+                        }]);
+                    });
+                    require([shim]);
+                } else {
+                    // TODO how to get correct contextRequire for the relative config module?
+                    contextRequire([config], function (data) {
+                        p.resolve([data, {
+                            contextRequire: contextRequire
+                        }]);
+                    });
+                }
+
+                return p.then(function (args) {
+                    return me._configure.apply(me, args);
+                });
+            } else {
+                return me._configure(config, opts);
+            }
+        },
+
+        createChildContainer: function () {
+            return new Container(this);
+        },
+
+        has: function (id) {
+            return id in this._cache;
+        },
+
+        get: function (id) {
+            return this._cache[id];
+        },
+
+        store: function (id, value) {
+            return (this._cache[id] = value);
+        },
+
+        _configure: function (data, opts) {
+            var typemap = {},
+                d = new Deferred(),
+                me = this,
+                p,
+                contextRequire = (opts && opts.contextRequire) || require;
+
+            var services = {};
+
+            for (p in data) {
+                var service = me._parse(data[p], typemap);
+                if (!(service instanceof Descriptor))
+                    service = new Value(service, false);
+                services[p] = service;
+            }
+
+            me.register(services);
+
+            var names = [];
+
+            for (p in typemap)
+                names.push(p);
+
+            if (names.length) {
+                contextRequire(names, function () {
+                    for (var i = 0; i < names.length; i++)
+                        typemap[names[i]] = arguments[i];
+                    d.resolve(me);
+                });
+            } else {
+                d.resolve(me);
+            }
+            return d.promise;
+        },
+
+        _parse: function (data, typemap) {
+            if (safe.isPrimitive(data) || data instanceof Descriptor)
+                return data;
+            if (data.$dependency)
+                return new Reference(
+                    data.$dependency,
+                    data.lazy,
+                    data.optional,
+                    data["default"],
+                    data.services && this._parseObject(data.services, typemap));
+            if (data.$value) {
+                var raw = !data.parse;
+                return new Value(raw ? data.$value : this._parse(
+                    data.$value,
+                    typemap), raw);
+            }
+            if (data.$type || data.$factory)
+                return this._parseService(data, typemap);
+            if (data instanceof Array)
+                return this._parseArray(data, typemap);
+
+            return this._parseObject(data, typemap);
+        },
+
+        _parseService: function (data, typemap) {
+            var me = this,
+                opts = {
+                    owner: this
+                };
+            if (data.$type) {
+
+                opts.type = data.$type;
+
+                if (typeof (data.$type) === "string") {
+                    typemap[data.$type] = null;
+                    opts.typeMap = typemap;
+                }
+            }
+
+            if (data.$factory)
+                opts.factory = data.$factory;
+
+            if (data.services)
+                opts.services = me._parseObject(data.services, typemap);
+            if (data.inject)
+                opts.inject = data.inject instanceof Array ? data.inject.map(function (x) {
+                    return me._parseObject(x, typemap);
+                }) : me._parseObject(data.inject, typemap);
+            if (data.params)
+                opts.params = me._parse(data.params, typemap);
+
+            if (data.activation) {
+                if (typeof (data.activation) === "string") {
+                    switch (data.activation.toLowerCase()) {
+                        case "singleton":
+                            opts.activation = Service.SINGLETON;
+                            break;
+                        case "container":
+                            opts.activation = Service.CONTAINER;
+                            break;
+                        case "hierarchy":
+                            opts.activation = Service.HIERARCHY;
+                            break;
+                        case "context":
+                            opts.activation = Service.CONTEXT;
+                            break;
+                        case "call":
+                            opts.activation = Service.CALL;
+                            break;
+                        default:
+                            throw new Error("Unknown activation type: " +
+                                data.activation);
+                    }
+                } else {
+                    opts.activation = Number(data.activation);
+                }
+            }
+
+            if (data.cleanup)
+                opts.cleanup = data.cleanup;
+
+            return new Service(opts);
+        },
+
+        _parseObject: function (data, typemap) {
+            if (data.constructor &&
+                data.constructor.prototype !== Object.prototype)
+                return new Value(data, true);
+
+            var o = {};
+
+            for (var p in data)
+                o[p] = this._parse(data[p], typemap);
+
+            return o;
+        },
+
+        _parseArray: function (data, typemap) {
+            if (data.constructor &&
+                data.constructor.prototype !== Array.prototype)
+                return new Value(data, true);
+
+            var me = this;
+            return data.map(function (x) {
+                return me._parse(x, typemap);
+            });
+        }
+
+    });
+
+    return Container;
+});
\ No newline at end of file
diff -r 8af8e840dd49 -r 27e8e9e38e07 core/src/js/di/Descriptor.js
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/src/js/di/Descriptor.js	Wed Jun 05 20:44:15 2019 +0300
@@ -0,0 +1,4 @@
+define([], function() {
+    // abstract base type for descriptros
+    return function() {};
+});
\ No newline at end of file
diff -r 8af8e840dd49 -r 27e8e9e38e07 core/src/js/di/ReferenceDescriptor.js
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/src/js/di/ReferenceDescriptor.js	Wed Jun 05 20:44:15 2019 +0300
@@ -0,0 +1,90 @@
+define([
+    "../declare", "../safe", "./Descriptor", "./ActivationError", "./ValueDescriptor"
+],
+
+function(declare, safe, Descriptor, ActivationError, Value) {
+    return declare(Descriptor, {
+        _name : null,
+        _lazy : false,
+        _optional : false,
+        _default : undefined,
+
+        constructor : function(name, lazy, optional, def, services) {
+            safe.argumentNotEmptyString(name, "name");
+            this._name = name;
+            this._lazy = Boolean(lazy);
+            this._optional = Boolean(optional);
+            this._default = def;
+            this._services = services;
+        },
+
+        activate : function(context, name) {
+            var me = this;
+
+            context.enter(name, this, true);
+
+            // добавляем сервисы
+            if (me._services) {
+                for ( var p in me._services) {
+                    var sv = me._services[p];
+                    context.register(p, sv instanceof Descriptor ? sv : new Value(sv, false));
+                }
+            }
+
+            if (me._lazy) {
+                // сохраняем контекст активации
+                context = context.clone();
+                return function(cfg) {
+                    // защищаем контекст на случай исключения в процессе
+                    // активации
+                    var ct = context.clone();
+                    try {
+                        if (cfg)
+                            safe.each(cfg, function(v, k) {
+                                ct.register(k, v instanceof Descriptor ? v : new Value(v, false));
+                            });
+                        return me._optional ? ct.getService(me._name, me._default) : ct
+                            .getService(me._name);
+                    } catch (error) {
+                        throw new ActivationError(me._name, ct.getStack(), error);
+                    }
+                };
+            }
+
+            var v = me._optional ? context.getService(me._name, me._default) : context
+                .getService(me._name);
+            context.leave(me);
+            return v;
+        },
+
+        isInstanceCreated : function() {
+            return false;
+        },
+
+        toString : function() {
+            var opts = [];
+            if (this._optional)
+                opts.push("optional");
+            if (this._lazy)
+                opts.push("lazy");
+
+            var parts = [
+                "@ref "
+            ];
+            if (opts.length) {
+                parts.push("{");
+                parts.push(opts.join());
+                parts.push("} ");
+            }
+
+            parts.push(this._name);
+
+            if (!safe.isNull(this._default)) {
+                parts.push(" = ");
+                parts.push(this._default);
+            }
+
+            return parts.join("");
+        }
+    });
+});
\ No newline at end of file
diff -r 8af8e840dd49 -r 27e8e9e38e07 core/src/js/di/ServiceDescriptor.js
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/src/js/di/ServiceDescriptor.js	Wed Jun 05 20:44:15 2019 +0300
@@ -0,0 +1,289 @@
+define(
+    [
+        "../declare",
+        "../safe",
+        "./Descriptor",
+        "./ValueDescriptor"
+    ],
+
+    function (declare, safe, Descriptor, Value) {
+        var SINGLETON_ACTIVATION = 1,
+            CONTAINER_ACTIVATION = 2,
+            CONTEXT_ACTIVATION = 3,
+            CALL_ACTIVATION = 4,
+            HIERARCHY_ACTIVATION = 5;
+
+        var injectMethod = function (target, method, context, args) {
+            var m = target[method];
+            if (!m)
+                throw new Error("Method '" + method + "' not found");
+
+            if (args instanceof Array)
+                m.apply(target, context.parse(args, "." + method));
+            else
+                m.call(target, context.parse(args, "." + method));
+        };
+
+        var makeClenupCallback = function (target, method) {
+            if (typeof (method) === "string") {
+                return function () {
+                    target[method]();
+                };
+            } else {
+                return function () {
+                    method(target);
+                };
+            }
+        };
+
+        var cacheId = 0;
+
+        var cls = declare(
+            Descriptor, {
+                _instance: null,
+                _hasInstance: false,
+                _activationType: CALL_ACTIVATION,
+                _services: null,
+                _type: null,
+                _typeMap: null,
+                _factory: null,
+                _params: undefined,
+                _inject: null,
+                _cleanup: null,
+                _cacheId: null,
+                _owner: null,
+
+                constructor: function (opts) {
+                    safe.argumentNotNull(opts, "opts");
+                    safe.argumentNotNull(opts.owner, "opts.owner");
+
+                    this._owner = opts.owner;
+
+                    if (!(opts.type || opts.factory))
+                        throw new Error(
+                            "Either a type or a factory must be specified");
+
+                    if (typeof (opts.type) === "string" && !opts.typeMap)
+                        throw new Error(
+                            "The typeMap is required when the type is specified by its name");
+
+                    if (opts.activation)
+                        this._activationType = opts.activation;
+                    if (opts.type)
+                        this._type = opts.type;
+                    if (opts.params)
+                        this._params = opts.params;
+                    if (opts.inject)
+                        this._inject = opts.inject instanceof Array ? opts.inject : [opts.inject];
+                    if (opts.services)
+                        this._services = opts.services;
+                    if (opts.factory)
+                        this._factory = opts.factory;
+                    if (opts.typeMap)
+                        this._typeMap = opts.typeMap;
+                    if (opts.cleanup) {
+                        if (!(typeof (opts.cleanup) === "string" || opts.cleanup instanceof Function))
+                            throw new Error(
+                                "The cleanup parameter must be either a function or a function name");
+
+                        this._cleanup = opts.cleanup;
+                    }
+
+                    this._cacheId = ++cacheId;
+                },
+
+                activate: function (context, name) {
+
+                    // if we have a local service records, register them first
+
+                    var instance;
+
+                    switch (this._activationType) {
+                        case 1: // SINGLETON
+                            // if the value is cached return it
+                            if (this._hasInstance)
+                                return this._instance;
+
+                            var tof = this._type || this._factory;
+
+                            // create the persistent cache identifier for the type
+                            if (safe.isPrimitive(tof))
+                                this._cacheId = this._type;
+                            else
+                                this._cacheId = safe.oid(tof);
+
+                            // singletons are bound to the root container
+                            var container = context.container.getRootContainer();
+
+                            if (container.has(this._cacheId)) {
+                                instance = container.get(this._cacheId);
+                            } else {
+                                instance = this._create(context, name);
+                                container.store(this._cacheId, instance);
+                                if (this._cleanup)
+                                    container.onDispose(
+                                        makeClenupCallback(instance, this._cleanup));
+                            }
+
+                            this._hasInstance = true;
+                            return (this._instance = instance);
+
+                        case 2: // CONTAINER
+                            //return a cached value
+                            if (this._hasInstance)
+                                return this._instance;
+
+                            // create an instance
+                            instance = this._create(context, name);
+
+                            // the instance is bound to the container
+                            if (this._cleanup)
+                                this._owner.onDispose(
+                                    makeClenupCallback(instance, this._cleanup));
+
+                            // cache and return the instance
+                            this._hasInstance = true;
+                            return (this._instance = instance);
+                        case 3: // CONTEXT
+                            //return a cached value if one exists
+                            if (context.has(this._cacheId))
+                                return context.get(this._cacheId);
+                            // context context activated instances are controlled by callers  
+                            return context.store(this._cacheId, this._create(
+                                context,
+                                name));
+                        case 4: // CALL
+                            // per-call created instances are controlled by callers
+                            return this._create(context, name);
+                        case 5: // HIERARCHY
+                            // hierarchy activated instances are behave much like container activated
+                            // except they are created and bound to the child container
+
+                            // return a cached value
+                            if (context.container.has(this._cacheId))
+                                return context.container.get(this._cacheId);
+
+                            instance = this._create(context, name);
+
+                            if (this._cleanup)
+                                context.container.onDispose(makeClenupCallback(
+                                    instance,
+                                    this._cleanup));
+
+                            return context.container.store(this._cacheId, instance);
+                        default:
+                            throw "Invalid activation type: " + this._activationType;
+                    }
+                },
+
+                isInstanceCreated: function () {
+                    return this._hasInstance;
+                },
+
+                getInstance: function () {
+                    return this._instance;
+                },
+
+                _create: function (context, name) {
+                    context.enter(name, this, Boolean(this._services));
+
+                    if (this._activationType != CALL_ACTIVATION &&
+                        context.visit(this._cacheId) > 0)
+                        throw new Error("Recursion detected");
+
+                    if (this._services) {
+                        for (var p in this._services) {
+                            var sv = this._services[p];
+                            context.register(p, sv instanceof Descriptor ? sv : new Value(sv, false));
+                        }
+                    }
+
+                    var instance;
+
+                    if (!this._factory) {
+                        var ctor, type = this._type;
+
+                        if (typeof (type) === "string") {
+                            ctor = this._typeMap[type];
+                            if (!ctor)
+                                throw new Error("Failed to resolve the type '" +
+                                    type + "'");
+                        } else {
+                            ctor = type;
+                        }
+
+                        if (this._params === undefined) {
+                            this._factory = function () {
+                                return new ctor();
+                            };
+                        } else if (this._params instanceof Array) {
+                            this._factory = function () {
+                                var inst = Object.create(ctor.prototype);
+                                var ret = ctor.apply(inst, arguments);
+                                return typeof (ret) === "object" ? ret : inst;
+                            };
+                        } else {
+                            this._factory = function (param) {
+                                return new ctor(param);
+                            };
+                        }
+                    }
+
+                    if (this._params === undefined) {
+                        instance = this._factory();
+                    } else if (this._params instanceof Array) {
+                        instance = this._factory.apply(this, context.parse(
+                            this._params,
+                            ".params"));
+                    } else {
+                        instance = this._factory(context.parse(
+                            this._params,
+                            ".params"));
+                    }
+
+                    if (this._inject) {
+                        this._inject.forEach(function (spec) {
+                            for (var m in spec)
+                                injectMethod(instance, m, context, spec[m]);
+                        });
+                    }
+
+                    context.leave();
+
+                    return instance;
+                },
+
+                // @constructor {singleton} foo/bar/Baz
+                // @factory {singleton}
+                toString: function () {
+                    var parts = [];
+
+                    parts.push(this._type ? "@constructor" : "@factory");
+
+                    parts.push(activationNames[this._activationType]);
+
+                    if (typeof (this._type) === "string")
+                        parts.push(this._type);
+
+                    return parts.join(" ");
+                }
+
+            });
+
+        cls.SINGLETON = SINGLETON_ACTIVATION;
+        cls.CONTAINER = CONTAINER_ACTIVATION;
+        cls.CONTEXT = CONTEXT_ACTIVATION;
+        cls.CALL = CALL_ACTIVATION;
+        cls.HIERARCHY = HIERARCHY_ACTIVATION;
+
+        var activationNames = [
+            "",
+            "{singleton}",
+            "{container}",
+            "{context}",
+            "{call}",
+            "{hierarchy}"
+        ];
+
+        return cls;
+    });
\ No newline at end of file
diff -r 8af8e840dd49 -r 27e8e9e38e07 core/src/js/di/ValueDescriptor.js
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/src/js/di/ValueDescriptor.js	Wed Jun 05 20:44:15 2019 +0300
@@ -0,0 +1,38 @@
+define([ "../declare", "./Descriptor", "../safe" ],
+
+function(declare, Descriptor, safe) {
+    return declare(Descriptor, {
+        _value : undefined,
+        _raw : false,
+        constructor : function(value, raw) {
+            this._value = value;
+            this._raw = Boolean(raw);
+        },
+
+        activate : function(context, name) {
+            context.enter(name, this);
+            var v = this._raw ? this._value : context.parse(
+                this._value,
+                ".params");
+            context.leave(this);
+            return v;
+        },
+
+        isInstanceCreated : function() {
+            return this._raw;
+        },
+
+        getInstance : function() {
+            if (!this._raw)
+                throw new Error("The instance isn't constructed");
+            return this._value;
+        },
+
+        toString : function() {
+            if (this._raw)
+                return "@value {raw}";
+            else
+                return safe.isNull(this._value) ? "@value " : "@value";
+        }
+    });
+});
\ No newline at end of file
diff -r 8af8e840dd49 -r 27e8e9e38e07 core/src/js/log/ConsoleLogChannel.js
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/src/js/log/ConsoleLogChannel.js	Wed Jun 05 20:44:15 2019 +0300
@@ -0,0 +1,30 @@
+define(
+    [ "dojo/_base/declare", "../text/format" ],
+    function(declare, format) {
+        return declare(
+            null,
+            {
+                name : null,
+
+                constructor : function(name) {
+                    this.name = name;
+                },
+
+                log : function() {
+                    console.log(this._makeMsg(arguments));
+                },
+
+                warn : function() {
+                    console.warn(this._makeMsg(arguments));
+                },
+
+                error : function() {
+                    console.error(this._makeMsg(arguments));
+                },
+
+                _makeMsg : function(args) {
+                    return this.name ? this.name + " " +
+                        format.apply(null, args) : format.apply(null, args);
+                }
+            });
+    });
\ No newline at end of file
diff -r 8af8e840dd49 -r 27e8e9e38e07 core/src/js/log/_LogMixin.js
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/src/js/log/_LogMixin.js	Wed Jun 05 20:44:15 2019 +0300
@@ -0,0 +1,67 @@
+define([ "dojo/_base/declare" ],
+
+function(declare) {
+    var cls = declare(null, {
+        _logChannel : null,
+
+        _logLevel : 1,
+
+        constructor : function(opts) {
+            if (typeof opts == "object") {
+                if ("logChannel" in opts)
+                    this._logChannel = opts.logChannel;
+                if ("logLevel" in opts)
+                    this._logLevel = opts.logLevel;
+            }
+        },
+
+        getLogChannel : function() {
+            return this._logChannel;
+        },
+
+        setLogChannel : function(v) {
+            this._logChannel = v;
+        },
+
+        getLogLevel : function() {
+            return this._logLevel;
+        },
+
+        setLogLevel : function(v) {
+            this._logLevel = v;
+        },
+
+        log : function(format) {
+            if (this._logChannel && this._logLevel > 2)
+                this._logChannel.log.apply(this._logChannel, arguments);
+        },
+        warn : function(format) {
+            if (this._logChannel && this._logLevel > 1)
+                this._logChannel.warn.apply(this._logChannel, arguments);
+        },
+        error : function(format) {
+            if (this._logChannel && this._logLevel > 0)
+                this._logChannel.error.apply(this._logChannel, arguments);
+        },
+
+        /**
+         * Used to by widgets
+         */
+        startup : function() {
+            var me = this, parent;
+            if (!me.getLogChannel()) {
+                parent = me;
+                while (parent = parent.getParent()) {
+                    if (parent.getLogChannel) {
+                        me.setLogChannel(parent.getLogChannel());
+                        if(parent.getLogLevel)
+                            me.setLogLevel(parent.getLogLevel());
+                        break;
+                    }
+                }
+            }
+            this.inherited(arguments);
+        }
+    });
+    return cls;
+});
\ No newline at end of file
diff -r 8af8e840dd49 -r 27e8e9e38e07 core/src/js/log/listeners/console.js
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/src/js/log/listeners/console.js	Wed Jun 05 20:44:15 2019 +0300
@@ -0,0 +1,25 @@
+define([], function () {
+    if (console && console.log)
+        return function (ch, name, msg) {
+            
+            var args = [ch + ":"];
+
+            switch (name) {
+                case "warn":
+                case "error":
+                case "log":
+                    break;
+                default:
+                    args.push(name + ":");
+                    name = "log";
+            }
+
+
+            if (msg instanceof Array)
+                args.push.apply(args, msg);
+            else
+                args.push(msg);
+
+            console[name].apply(console, args);
+        };
+});
\ No newline at end of file
diff -r 8af8e840dd49 -r 27e8e9e38e07 core/src/js/log/trace.js
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/src/js/log/trace.js	Wed Jun 05 20:44:15 2019 +0300
@@ -0,0 +1,116 @@
+define(["../text/format"], function (format) {
+    'use strict';
+
+    var listeners = [];
+    var channels = {};
+
+    var Trace = function (name) {
+        this.name = name;
+        this._subscribers = [];
+    };
+
+    Trace.prototype.debug = function () {
+        if (Trace.level >= 4)
+            this.notify("debug", format.apply(null, arguments));
+    };
+
+    Trace.prototype.log = function () {
+        if (Trace.level >= 3)
+            this.notify("log", format.apply(null, arguments));
+    };
+
+    Trace.prototype.warn = function () {
+        if (Trace.level >= 2)
+            this.notify("warn", format.apply(null, arguments));
+
+    };
+
+    Trace.prototype.error = function () {
+        if (Trace.level >= 1)
+            this.notify("error", format.apply(null, arguments));
+    };
+
+    Trace.prototype.notify = function (name, msg) {
+        var me = this;
+        me._subscribers.forEach(function (cb) {
+            cb(me, name, msg);
+        });
+    };
+
+    Trace.prototype.subscribe = function (cb) {
+        this._subscribers.push(cb);
+    };
+
+    Trace.prototype.toString = function () {
+        return this.name;
+    };
+
+    Trace.createChannel = function (type, name, cb) {
+        var chId = name;
+        if (channels[chId])
+            return channels[chId];
+
+        var channel = new type(chId);
+        channels[chId] = channel;
+
+        Trace._onNewChannel(chId, channel);
+        cb(channel);
+    };
+
+    Trace._onNewChannel = function (chId, ch) {
+        listeners.forEach(function (listener) {
+            listener(chId, ch);
+        });
+    };
+
+    Trace.on = function (filter, cb) {
+        if (arguments.length == 1) {
+            cb = filter;
+            filter = undefined;
+        }
+        var d, test;
+        if (filter instanceof RegExp) {
+            test = function (chId) {
+                return filter.test(chId);
+            };
+        } else if (filter instanceof Function) {
+            test = filter;
+        } else if (filter) {
+            test = function (chId) {
+                return chId == filter;
+            };
+        }
+
+        if (test) {
+            d = function(chId, ch) {
+                if(test(chId))
+                    ch.subscribe(cb);
+            };
+        } else {
+            d = function(chId, ch) {
+                ch.subscribe(cb);
+            };
+        }
+        listeners.push(d);
+
+        for(var chId in channels)
+            d(chId,channels[chId]);
+    };
+
+    Trace.load = function (id, require, cb) {
+        if (id)
+            Trace.createChannel(Trace, id, cb);
+        else if (require.module && require.module.mid)
+            Trace.createChannel(Trace, require.module.mid, cb);
+        else
+            require(['module'], function (module) {
+                Trace.createChannel(Trace, module && module.id, cb);
+            });
+    };
+
+    Trace.dynamic = true;
+
+    Trace.level = 4;
+
+    return Trace;
+});
\ No newline at end of file
diff -r 8af8e840dd49 -r 27e8e9e38e07 core/src/js/main.js
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/src/js/main.js	Wed Jun 05 20:44:15 2019 +0300
@@ -0,0 +1,3 @@
+declare([], function(){
+    // does nothing yet...
+});
\ No newline at end of file
diff -r 8af8e840dd49 -r 27e8e9e38e07 core/src/js/messaging/Client.js
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/src/js/messaging/Client.js	Wed Jun 05 20:44:15 2019 +0300
@@ -0,0 +1,61 @@
+define(
+    [ "dojo/_base/declare", "dojo/_base/lang", "dojo/Evented", "../log/_LogMixin" ],
+
+    function(declare, lang, Evented, _LogMixin) {
+        return declare([ Evented, _LogMixin ], {
+            _session : null,
+            _destination : null,
+            _id : null,
+
+            constructor : function(session, destination, options) {
+                this._destination = destination;
+                this._session = session;
+            },
+
+            getDestination : function() {
+                return this._destination;
+            },
+
+            start : function() {
+                var me = this;
+                return me._session.createClient(me.prepareOptions({})).then(
+                    function(id) {
+                        me._id = id;
+                        return me;
+                    });
+            },
+
+            prepareOptions : function(options) {
+                var me = this;
+                options.mode = me.getMode();
+                options.destination = me.getDestination();
+                options.client = function(msg) {
+                    me.process(msg);
+                };
+                return options;
+            },
+
+            process : function(msg) {
+                this.warn("Messages are not acceped by this client");
+            },
+
+            stop : function() {
+                var me = this;
+                if (me._id) {
+                    me.log("stop");
+                    return me._session.deleteClient({'clientId': me._id}).then(function() {
+                        me._id = null;
+                        return me;
+                    });
+                }
+            },
+
+            toString : function() {
+                return "["
+                    + [
+                        this.getMode().toUpperCase(),
+                        this.getDestination(),
+                        this._id ].join(',') + "]";
+            }
+        });
+    });
\ No newline at end of file
diff -r 8af8e840dd49 -r 27e8e9e38e07 core/src/js/messaging/Destination.js
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/src/js/messaging/Destination.js	Wed Jun 05 20:44:15 2019 +0300
@@ -0,0 +1,34 @@
+define([ "dojo/_base/declare", "./Listener" ],
+
+function(declare, Listener) {
+    return declare(null, {
+        _session : null,
+        _destination : null,
+        _listenerClass : null,
+
+        constructor : function(session, destination, options) {
+            if (!session)
+                throw new Error("A session is required");
+            if (!destination)
+                throw new Error("A destination is required");
+
+            this._session = session;
+            this._destination = destination;
+            if (options) {
+                if (options.listenerClass)
+                    this._listenerClass = options.listenerClass;
+            }
+        },
+
+        listen : function(callback) {
+            var factory = this._listenerClass || Listener;
+            var listener = new factory(this._session, this._destination, {
+                listener : callback
+            });
+            listener.start();
+
+            return listener;
+        }
+
+    });
+});
diff -r 8af8e840dd49 -r 27e8e9e38e07 core/src/js/messaging/Listener.js
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/src/js/messaging/Listener.js	Wed Jun 05 20:44:15 2019 +0300
@@ -0,0 +1,64 @@
+define([ "dojo/_base/declare", "dojo/_base/lang", "./Client" ],
+
+function(declare, lang, Client) {
+    return declare([ Client ], {
+        _listener : null,
+
+        constructor : function(session, destination, options) {
+            if (!options || !options.listener)
+                throw new Error("A listener is required");
+            this._listener = options.listener;
+            if (options.transform)
+                this._transform = options.transform;
+        },
+
+        getMode : function() {
+            return "listener";
+        },
+
+        process : function(result) {
+            switch (result.type) {
+            case "message":
+                try {
+                    this._handleMessage(result.message);
+                } catch (ex) {
+                    var err = new Error("Failed to handle message");
+                    err.envelope = result.message;
+                    err.innerException = ex;
+                    this._handleError(err);
+                }
+                break;
+            case "error":
+                this._handleError(result.error);
+                break;
+            }
+
+        },
+
+        _transform : function(envelope) {
+            return envelope;
+        },
+
+        _handleMessage : function(envelope) {
+            this.log(
+                "MESSAGE type = ${0}, headers = ${2}: ${1}",
+                envelope.bodyType,
+                envelope.body,
+                JSON.stringify(envelope.headers));
+            var data = this._transform(envelope);
+            this._listener(data);
+            this.emit("message", data);
+        },
+
+        _handleError : function(ex) {
+            if (ex.innerException)
+                this.error(
+                    "ERROR: ${0} -> ${1}",
+                    ex.message,
+                    ex.innerException.message);
+            else
+                this.error("ERROR: ${0}", ex.message);
+            this.emit("error", ex);
+        }
+    });
+});
\ No newline at end of file
diff -r 8af8e840dd49 -r 27e8e9e38e07 core/src/js/messaging/Session.js
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/src/js/messaging/Session.js	Wed Jun 05 20:44:15 2019 +0300
@@ -0,0 +1,217 @@
+define(
+    [
+        "dojo/_base/declare",
+        "dojo/_base/lang",
+        "dojo/request",
+        "./Destination",
+        "dojo/Evented",
+        "dojo/Deferred",
+        "../log/_LogMixin" ],
+
+    function(declare, lang, request, Destination, Evented, Deferred, _LogMixin) {
+
+        var cls = declare(
+            [ Evented, _LogMixin ],
+            {
+                _id : null,
+                _baseUrl : null,
+                _destinations : null,
+                _timeout : 100000,
+                _clients : null,
+                _started : null,
+                _starting : false,
+
+                constructor : function(baseUrl, options) {
+                    if (!baseUrl)
+                        throw new Error("baseUrl is required");
+                    options = options || {};
+
+                    this._baseUrl = baseUrl.replace(/\/*$/, "");
+                    this._destinations = {};
+                    this._pending = [];
+                    this._clients = {};
+                    if (options.timeout)
+                        this._timeout = options.timeout;
+
+                    this._started = new Deferred();
+                },
+
+                start : function() {
+                    if (this._starting)
+                        return this._started;
+                    this._starting = true;
+
+                    var me = this;
+                    me.log("START");
+                    request(this._baseUrl, {
+                        method : "POST",
+                        handleAs : "json"
+                    }).then(function(result) {
+                        me._id = result;
+                        me._emitConnected();
+                        me._poll();
+                        me._started.resolve(me);
+                    }, function(error) {
+                        me._emitError(error);
+                        me._started.reject(me);
+                    });
+                    return me._started.promise;
+                },
+
+                createClient : function(options) {
+                    if (!options || !options.destination || !options.mode)
+                        throw new Error("Invalid argument");
+
+                    var me = this;
+
+                    return me._started
+                        .then(function() {
+                            var url = me._makeUrl(me._id);
+                            me.log(
+                                "CREATE mode=${0}, destination=${1}",
+                                options.mode,
+                                options.destination);
+
+                            return request(url, {
+                                method : "POST",
+                                data : {
+                                    mode : options.mode,
+                                    destination : options.destination
+                                },
+                                handleAs : 'json'
+                            })
+                                .then(
+                                    function(id) {
+                                        me
+                                            .log(
+                                                "CLIENT id=${0}, mode=${1}, destination=${2}",
+                                                id,
+                                                options.mode,
+                                                options.destination);
+                                        me._clients[id] = options.client
+                                            ? options.client
+                                            : function(msg) {
+                                                me
+                                                    .warn(
+                                                        "The client id=${0}, mode=${1}, destination=${2} isn't accepting mesages",
+                                                        id,
+                                                        options.mode,
+                                                        options.destination);
+                                            };
+                                        return id;
+                                    });
+                        });
+
+                },
+
+                deleteClient : function(options) {
+                    if (!options || !options.clientId)
+                        throw new Error("Invalid argument");
+
+                    var me = this, id = options.clientId;
+
+                    return me._started.then(function() {
+                        var url = me._makeUrl(me._id, options.clientId);
+
+                        me.log("DELETE CLIENT ${0}", options.clientId);
+
+                        return request(url, {
+                            method : "DELETE",
+                            handleAs : 'json'
+                        }).then(function() {
+                            me.log("CLIENT DELETED ${0}", options.clientId);
+                            me._clients[id] = undefined;
+                        });
+                    });
+                },
+
+                _poll : function() {
+                    var me = this, url = this._makeUrl(this._id);
+                    me.log("POLL timeout=${0}", me._timeout);
+                    request(url, {
+                        method : "GET",
+                        handleAs : "json",
+                        query : {
+                            timeout : me._timeout
+                        }
+                    }).then(function(response) {
+                        me._handlePoll(response);
+                        me._poll();
+                    }, function(err) {
+                        me.error("POLL faield with ${0}", err);
+                        me._emitError(err);
+                    });
+                },
+
+                _handlePoll : function(response) {
+                    if (!response) {
+                        this.log("POLL response undefined, looks like a bug");
+                        return;
+                    }
+                    if (!response.results || !response.results.length) {
+                        this.log("POLL response is empty");
+                        return;
+                    }
+
+                    var results = response.results;
+                    this.log("POLL got ${0} results", results.length);
+
+                    for (var i = 0; i < results.length; i++) {
+                        var result = results[i];
+                        var client = this._clients[result.clientId];
+                        if (!client) {
+                            // TODO this could happen due to client isn't
+                            // registered yet
+                            this.error("Unknown client ${0}", result.clientId);
+                            continue;
+                        }
+                        client.call(this, result);
+                    }
+                },
+
+                _emitError : function(err) {
+                    this.emit("error", err);
+                },
+
+                _emitConnected : function() {
+                    var me = this;
+                    me.log("CONNECTED");
+                    me.emit("connected");
+                },
+
+                _makeUrl : function() {
+                    var parts = [ this._baseUrl ];
+                    for (var i = 0; i < arguments.length; i++)
+                        parts.push(arguments[i].replace(/\/*$/, ""));
+                    return parts.join('/');
+                },
+
+                queue : function(name) {
+                    return this._getDestination("queue://" + name);
+                },
+
+                topic : function(name) {
+                    return this._getDestination("topic://" + name);
+                },
+
+                _getDestination : function(uri) {
+                    if (uri in this._destinations)
+                        return this._destinations[uri];
+
+                    var dest = new Destination(this, uri);
+                    this._destinations[uri] = dest;
+                    return dest;
+                },
+
+                toString : function() {
+                    return [ "[", "SESSION ", this._id, "]" ].join(" ");
+                }
+            });
+
+        cls.connect = function(url, options) {
+            var session = new cls(url, options);
+            return session.start();
+        };
+
+        return cls;
+    });
diff -r 8af8e840dd49 -r 27e8e9e38e07 core/src/js/safe.js
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/src/js/safe.js	Wed Jun 05 20:44:15 2019 +0300
@@ -0,0 +1,325 @@
+define([],
+
+    function () {
+        var _create = Object.create,
+            _keys = Object.keys;
+
+        var safe = null;
+        safe = {
+            argumentNotNull: function (arg, name) {
+                if (arg === null || arg === undefined)
+                    throw new Error("The argument " + name + " can't be null or undefined");
+            },
+
+            argumentNotEmptyString: function (arg, name) {
+                if (typeof (arg) !== "string" || !arg.length)
+                    throw new Error("The argument '" + name + "' must be a not empty string");
+            },
+
+            argumentNotEmptyArray: function (arg, name) {
+                if (!(arg instanceof Array) || !arg.length)
+                    throw new Error("The argument '" + name + "' must be a not empty array");
+            },
+
+            argumentOfType: function (arg, type, name) {
+                if (!(arg instanceof type))
+                    throw new Error("The argument '" + name + "' type doesn't match");
+            },
+
+            isNull: function (arg) {
+                return (arg === null || arg === undefined);
+            },
+
+            isPrimitive: function (arg) {
+                return (arg === null || arg === undefined || typeof (arg) === "string" ||
+                    typeof (arg) === "number" || typeof (arg) === "boolean");
+            },
+
+            isInteger: function (arg) {
+                return parseInt(arg) == arg;
+            },
+
+            isNumber: function (arg) {
+                return parseFloat(arg) == arg;
+            },
+
+            isString: function (val) {
+                return typeof (val) == "string" || val instanceof String;
+            },
+
+            isNullOrEmptyString: function (str) {
+                if (str === null || str === undefined ||
+                    ((typeof (str) == "string" || str instanceof String) && str.length === 0))
+                    return true;
+            },
+
+            isNotEmptyArray: function (arg) {
+                return (arg instanceof Array && arg.length > 0);
+            },
+
+            /**
+             * Выполняет метод для каждого элемента массива, останавливается, когда
+             * либо достигнут конец массива, либо функция cb вернула
+             * значение.
+             * 
+             * @param{Array | Object} obj массив элементов для просмотра
+             * @param{Function} cb функция, вызываемая для каждого элемента
+             * @param{Object} thisArg значение, которое будет передано в качестве
+             *                this в cb.
+             * @returns Результат вызова функции cb, либо undefined
+             *          если достигнут конец массива.
+             */
+            each: function (obj, cb, thisArg) {
+                safe.argumentNotNull(cb, "cb");
+                var i, x;
+                if (obj instanceof Array) {
+                    for (i = 0; i < obj.length; i++) {
+                        x = cb.call(thisArg, obj[i], i);
+                        if (x !== undefined)
+                            return x;
+                    }
+                } else {
+                    var keys = _keys(obj);
+                    for (i = 0; i < keys.length; i++) {
+                        var k = keys[i];
+                        x = cb.call(thisArg, obj[k], k);
+                        if (x !== undefined)
+                            return x;
+                    }
+                }
+            },
+
+            /**
+             * Копирует свойства одного объекта в другой.
+             * 
+             * @param{Any} dest объект в который нужно скопировать значения
+             * @param{Any} src источник из которого будут копироваться значения
+             * @tmpl{Object|Array} tmpl шаблон по которому будет происходить
+             *                     копирование. Если шаблон является массивом
+             *                     (список свойств), тогда значения этого массива
+             *                     являются именами свойсвт которые будут
+             *                     скопированы. Если шаблон является объектом (карта
+             *                     преобразования имен свойств src->dst), тогда
+             *                     копирование будет осуществляться только
+             *                     собственных свойств источника, присутсвующих в
+             *                     шаблоне, при этом значение свойства шаблона
+             *                     является именем свойства в которое будет
+             *                     произведено коприрование
+             */
+            mixin: function (dest, src, tmpl) {
+                safe.argumentNotNull(dest, "dest");
+                if (!src)
+                    return dest;
+
+                var keys, i, p;
+                if (arguments.length < 3) {
+                    keys = _keys(src);
+                    for (i = 0; i < keys.length; i++) {
+                        p = keys[i];
+                        dest[p] = src[p];
+                    }
+                } else {
+                    if (tmpl instanceof Array) {
+                        for (i = 0; i < tmpl.length; i++) {
+                            p = tmpl[i];
+                            if (p in src)
+                                dest[p] = src[p];
+                        }
+
+                    } else {
+                        keys = _keys(src);
+                        for (i = 0; i < keys.length; i++) {
+                            p = keys[i];
+                            if (p in tmpl)
+                                dest[tmpl[p]] = src[p];
+                        }
+                    }
+                }
+                return dest;
+            },
+
+            /** Wraps the specified function to emulate an asynchronous execution.
+             * @param{Object} thisArg [Optional] Object which will be passed as 'this' to the function.
+             * @param{Function|String} fn [Required] Function wich will be wrapped.
+             */
+            async: function (fn, thisArg) {
+                if (arguments.length == 2 && !(fn instanceof Function))
+                    fn = thisArg[fn];
+
+                if (fn == null)
+                    throw new Error("The function must be specified");
+
+                function wrapresult(x, e) {
+                    if (e) {
+                        return {
+                            then: function (cb, eb) {
+                                try {
+                                    return eb ? wrapresult(eb(e)) : this;
+                                } catch (e2) {
+                                    return wrapresult(null, e2);
+                                }
+                            }
+                        };
+                    } else {
+                        if (x && x.then)
+                            return x;
+                        return {
+                            then: function (cb) {
+                                try {
+                                    return cb ? wrapresult(cb(x)) : this;
+                                } catch (e2) {
+                                    return wrapresult(e2);
+                                }
+                            }
+                        };
+                    }
+                }
+
+                return function () {
+                    try {
+                        return wrapresult(fn.apply(thisArg, arguments));
+                    } catch (e) {
+                        return wrapresult(null, e);
+                    }
+                };
+            },
+
+            create: function () {
+                if (console && console.warn)
+                    console.warn("implab/safe::create is deprecated use Object.create instead");
+                _create.apply(this, arguments);
+            },
+
+            delegate: function (target, method) {
+                if (!(method instanceof Function)) {
+                    this.argumentNotNull(target, "target");
+                    method = target[method];
+                }
+
+                if (!(method instanceof Function))
+                    throw new Error("'method' argument must be a Function or a method name");
+
+                return function () {
+                    return method.apply(target, arguments);
+                };
+            },
+
+            /**
+             * Для каждого элемента массива вызывает указанную функцию и сохраняет
+             * возвращенное значение в массиве результатов.
+             * 
+             * @remarks cb может выполняться асинхронно, при этом одновременно будет
+             *          только одна операция.
+             * 
+             * @async
+             */
+            pmap: function (items, cb) {
+                safe.argumentNotNull(cb, "cb");
+
+                if (items && items.then instanceof Function)
+                    return items.then(function (data) {
+                        return safe.pmap(data, cb);
+                    });
+
+                if (safe.isNull(items) || !items.length)
+                    return items;
+
+                var i = 0,
+                    result = [];
+
+                function next() {
+                    var r, ri;
+
+                    function chain(x) {
+                        result[ri] = x;
+                        return next();
+                    }
+
+                    while (i < items.length) {
+                        r = cb(items[i], i);
+                        ri = i;
+                        i++;
+                        if (r && r.then) {
+                            return r.then(chain);
+                        } else {
+                            result[ri] = r;
+                        }
+                    }
+                    return result;
+                }
+
+                return next();
+            },
+
+            /**
+             * Для каждого элемента массива вызывает указанную функцию, результаты
+             * не сохраняются
+             * 
+             * @remarks cb может выполняться асинхронно, при этом одновременно будет
+             *          только одна операция.
+             * @async
+             */
+            pfor: function (items, cb) {
+                safe.argumentNotNull(cb, "cb");
+
+                if (items && items.then instanceof Function)
+                    return items.then(function (data) {
+                        return safe.pmap(data, cb);
+                    });
+
+                if (safe.isNull(items) || !items.length)
+                    return items;
+
+                var i = 0;
+
+                function next() {
+                    while (i < items.length) {
+                        var r = cb(items[i], i);
+                        i++;
+                        if (r && r.then)
+                            return r.then(next);
+                    }
+                }
+
+                return next();
+            },
+
+            /**
+             * Выбирает первый элемент из последовательности, или обещания, если в
+             * качестве параметра используется обещание, оно должно вернуть массив.
+             * 
+             * @param{Function} cb обработчик результата, ему будет передан первый
+             *                  элемент последовательности в случае успеха
+             * @param{Fucntion} err обработчик исключения, если массив пустой, либо
+             *                  не массив
+             * 
+             * @remarks Если не указаны ни cb ни err, тогда функция вернет либо
+             *          обещание, либо первый элемент.
+             * @async
+             */
+            first: function (sequence, cb, err) {
+                if (sequence) {
+                    if (sequence.then instanceof Function) {
+                        return sequence.then(function (res) {
+                            return safe.first(res, cb, err);
+                        }, err);
+                    } else if (sequence && "length" in sequence) {
+                        if (sequence.length === 0) {
+                            if (err)
+                                return err(new Error("The sequence is empty"));
+                            else
+                                throw new Error("The sequence is empty");
+                        }
+                        return cb ? cb(sequence[0]) : sequence[0];
+                    }
+                }
+
+                if (err)
+                    return err(new Error("The sequence is required"));
+                else
+                    throw new Error("The sequence is required");
+            }
+        };
+
+        return safe;
+    });
\ No newline at end of file
diff -r 8af8e840dd49 -r 27e8e9e38e07 core/src/js/text/format-compile.js
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/src/js/text/format-compile.js	Wed Jun 05 20:44:15 2019 +0300
@@ -0,0 +1,101 @@
+define(
+    [],
+    function() {
+        var map = {
+            "\\{" : "&curlopen;",
+            "\\}" : "&curlclose;",
+            "&" : "&",
+            "\\:" : ":"
+        };
+
+        var rev = {
+            curlopen : "{",
+            curlclose : "}",
+            amp : "&",
+            colon : ":"
+        };
+
+        var espaceString = function(s) {
+            if (!s)
+                return s;
+            return "'" + s.replace(/('|\\)/g, "\\$1") + "'";
+        };
+
+        var encode = function(s) {
+            if (!s)
+                return s;
+            return s.replace(/\\{|\\}|&|\\:/g, function(m) {
+                return map[m] || m;
+            });
+        };
+
+        var decode = function(s) {
+            if (!s)
+                return s;
+            return s.replace(/&(\w+);/g, function(m, $1) {
+                return rev[$1] || m;
+            });
+        };
+
+        var subst = function(s) {
+            var i = s.indexOf(":"), name, pattern;
+            if (i >= 0) {
+                name = s.substr(0, i);
+                pattern = s.substr(i + 1);
+            } else {
+                name = s;
+            }
+
+            if (pattern)
+                return [
+                    espaceString(decode(name)),
+                    espaceString(decode(pattern)) ];
+            else
+                return [ espaceString(decode(name)) ];
+        };
+
+        var compile = function(str) {
+            if (!str)
+                return function() {};
+
+            var chunks = encode(str).split("{"), chunk;
+
+            var code = [ "var result=[];" ];
+
+            for (var i = 0; i < chunks.length; i++) {
+                chunk = chunks[i];
+
+                if (i === 0) {
+                    if (chunk)
+                        code.push("result.push(" + espaceString(decode(chunk)) +
+                            ");");
+                } else {
+                    var len = chunk.indexOf("}");
+                    if (len < 0)
+                        throw new Error("Unbalanced substitution #" + i);
+
+                    code.push("result.push(subst(" +
+                        subst(chunk.substr(0, len)).join(",") + "));");
+                    if (chunk.length > len + 1)
+                        code.push("result.push(" +
+                            espaceString(decode(chunk.substr(len + 1))) + ");");
+                }
+            }
+
+            code.push("return result.join('');");
+
+            /* jshint -W054 */
+            return new Function("subst", code.join("\n"));
+        };
+
+        var cache = {};
+
+        return function(template) {
+            var compiled = cache[template];
+            if (!compiled) {
+                compiled = compile(template);
+                cache[template] = compiled;
+            }
+            return compiled;
+        };
+    });
\ No newline at end of file
diff -r 8af8e840dd49 -r 27e8e9e38e07 core/src/js/text/format.js
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/src/js/text/format.js	Wed Jun 05 20:44:15 2019 +0300
@@ -0,0 +1,87 @@
+define([
+    "../safe",
+    "./format-compile",
+    "dojo/number",
+    "dojo/date/locale",
+    "dojo/_base/array" ], function(safe, compile, number, date, array) {
+
+    // {short,medium,full,long}-{date,time}
+    var convert = function(value, pattern) {
+        if (!pattern)
+            return value.toString();
+
+        if (pattern.toLocaleLowerCase() == "json") {
+            var cache = [];
+            return JSON.stringify(value, function(k, v) {
+                if (!safe.isPrimitive(v)) {
+                    var id = array.indexOf(cache, v);
+                    if (id >= 0)
+                        return "@ref-" + id;
+                    else
+                        return v;
+                } else {
+                    return v;
+                }
+            },2);
+        }
+
+        if (safe.isNumber(value)) {
+            var nopt = {};
+            if (pattern.indexOf("!") === 0) {
+                nopt.round = -1;
+                pattern = pattern.substr(1);
+            }
+            nopt.pattern = pattern;
+            return number.format(value, nopt);
+        } else if (value instanceof Date) {
+            var m = pattern.match(/^(\w+)-(\w+)$/);
+            if (m)
+                return date.format(value, {
+                    selector : m[2],
+                    formatLength : m[1]
+                });
+            else if (pattern == "iso")
+                return value.toISOString();
+            else
+                return date.format(value, {
+                    selector : "date",
+                    datePattern : pattern
+                });
+        } else {
+            return value.toString(pattern);
+        }
+    };
+
+    function formatter(format) {
+        var data;
+
+        if (arguments.length <= 1)
+            return format;
+
+        data = Array.prototype.slice.call(arguments, 1);
+
+        var template = compile(format);
+
+        return template(function(name, pattern) {
+            var value = data[name];
+            return !safe.isNull(value) ? convert(value, pattern) : "";
+        });
+    }
+
+    formatter.compile = function(format) {
+        var template = compile(format);
+
+        return function() {
+            var data = arguments;
+
+            return template(function(name, pattern) {
+                var value = data[name];
+                return !safe.isNull(value) ? convert(value, pattern) : "";
+            });
+        };
+    };
+
+    formatter.convert = convert;
+
+    return formatter;
+});
\ No newline at end of file
diff -r 8af8e840dd49 -r 27e8e9e38e07 core/src/js/text/template-compile.js
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/src/js/text/template-compile.js	Wed Jun 05 20:44:15 2019 +0300
@@ -0,0 +1,134 @@
+define(
+    ["dojo/request", "./format", "../log/trace!"],
+    function (request, format, trace) {
+
+        // разбивает строку шаблона на токены, возвращает контекст для
+        // дальнейшей обработки в visitTemplate
+        var parseTemplate = function (str) {
+            var tokens = str.split(/(<%=|\[%=|<%|\[%|%\]|%>)/);
+            var pos = -1;
+            var data = [],
+                code = [];
+
+            return {
+                next: function () {
+                    pos++;
+                    return pos < tokens.length;
+                },
+                token: function () {
+                    return tokens[pos];
+                },
+                pushData: function () {
+                    var i = data.length;
+                    data.push.apply(data, arguments);
+                    return i;
+                },
+                pushCode : function() {
+                    var i = code.length;
+                    code.push.apply(code, arguments);
+                    return i;
+                },
+                compile: function () {
+                    var text = "var $p = [];\n" +
+                        "var print = function(){\n" +
+                        "   $p.push(format.apply(null,arguments));\n" +
+                        "};\n" +
+                        // Introduce the data as local variables using with(){}
+                        "with(obj){\n" +
+                        code.join("\n") +
+                        "}\n" +
+                        "return $p.join('');";
+                    
+                    try {
+                        var compiled = new Function("obj, format, $data", text);
+                        /**
+                         * Функция форматирования по шаблону
+                         * 
+                         * @type{Function}
+                         * @param{Object} obj объект с параметрами для подстановки
+                         */
+                        return function (obj) {
+                            return compiled(obj || {}, format, data);
+                        };
+                    } catch (e) {
+                        trace.error([e]);
+                        trace.log([text, data]);
+                        throw e;
+                    }
+                }
+            }
+        };
+
+        function visitTemplate(context) {
+            while (context.next()) {
+                switch (context.token()) {
+                    case "<%":
+                    case "[%":
+                        visitCode(context);
+                        break;
+                    case "<%=":
+                    case "[%=":
+                        visitInline(context);
+                        break;
+                    default:
+                        visitTextFragment(context);
+                        break;
+                }
+            }
+        }
+
+        function visitInline(context) {
+            var code = ["$p.push("];
+            while (context.next()) {
+                if (context.token() == "%>" || context.token() == "%]")
+                    break;
+                code.push(context.token());
+            }
+            code.push(");");
+            context.pushCode(code.join(''));
+        }
+
+        function visitCode(context) {
+            var code = [];
+            while (context.next()) {
+                if (context.token() == "%>" || context.token() == "%]")
+                    break;
+                code.push(context.token());
+            }
+            context.pushCode(code.join(''));
+        }
+
+        function visitTextFragment(context) {
+            var i = context.pushData(context.token());
+            context.pushCode("$p.push($data["+i+"]);");
+        }
+
+        var compile = function (str) {
+            if (!str)
+                return function() { return "";};
+
+            var ctx = parseTemplate(str);
+            visitTemplate(ctx);
+            return ctx.compile();
+        };
+
+        var cache = {};
+
+        compile.load = function (id, require, callback) {
+            var url = require.toUrl(id);
+            if (url in cache) {
+                callback(cache[url]);
+            } else {
+                request(url).then(compile).then(function (tc) {
+                    callback(cache[url] = tc);
+                }, function (err) {
+                    require.signal("error", [{
+                        error: err,
+                        src: 'implab/text/template-compile'
+                    }]);
+                });
+            }
+        };
+
+        return compile;
+    });
\ No newline at end of file
diff -r 8af8e840dd49 -r 27e8e9e38e07 dom/.project
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dom/.project	Wed Jun 05 20:44:15 2019 +0300
@@ -0,0 +1,17 @@
+
+
+	dom
+	Project dom created by Buildship.
+	
+	
+	
+		
+			org.eclipse.buildship.core.gradleprojectbuilder
+			
+			
+		
+	
+	
+		org.eclipse.buildship.core.gradleprojectnature
+	
+
diff -r 8af8e840dd49 -r 27e8e9e38e07 dom/.settings/org.eclipse.buildship.core.prefs
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dom/.settings/org.eclipse.buildship.core.prefs	Wed Jun 05 20:44:15 2019 +0300
@@ -0,0 +1,2 @@
+connection.project.dir=..
+eclipse.preferences.version=1
diff -r 8af8e840dd49 -r 27e8e9e38e07 dom/build.gradle
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dom/build.gradle	Wed Jun 05 20:44:15 2019 +0300
@@ -0,0 +1,2 @@
+task build(type: Copy) {
+}
\ No newline at end of file
diff -r 8af8e840dd49 -r 27e8e9e38e07 dom/package.json
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dom/package.json	Wed Jun 05 20:44:15 2019 +0300
@@ -0,0 +1,18 @@
+{
+  "name": "@implab/dom",
+  "version": "1.0.1",
+  "description": "Dependency injection, logging, simple and fast text template engine",
+  "main": "index.js",
+  "scripts": {
+    "test": "echo \"Error: no test specified\" && exit 1"
+  },
+  "keywords": [
+    "di",
+    "ioc",
+    "logging",
+    "template engine",
+    "dependency injection"
+  ],
+  "author": "Sergey Smirnov",
+  "license": "MIT"
+}
diff -r 8af8e840dd49 -r 27e8e9e38e07 dom/src/js/css.js
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dom/src/js/css.js	Wed Jun 05 20:44:15 2019 +0300
@@ -0,0 +1,10 @@
+define(["./inject"], function (inject) {
+    return {
+        load: function (id, require, cb) {
+            var url = require.toUrl(id);
+            inject.injectStylesheet(url).then(function () {
+                cb();
+            });
+        }
+    };
+});
\ No newline at end of file
diff -r 8af8e840dd49 -r 27e8e9e38e07 dom/src/js/inject.js
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dom/src/js/inject.js	Wed Jun 05 20:44:15 2019 +0300
@@ -0,0 +1,86 @@
+define(["../Deferred", "../log/trace!"], function (Deferred, trace) {
+    function on(node, eventName, handler) {
+        // Add an event listener to a DOM node
+        node.addEventListener(eventName, handler, false);
+
+        return function () {
+            node.removeEventListener(eventName, handler, false);
+        };
+    }
+
+    return {
+        injectionPoint: document.head,
+        injectBefore: document.head.firstChild,
+
+        _map: {},
+
+        _inject: function (name, attr) {
+            var node = document.createElement(name),
+                d = new Deferred(),
+
+                cleanup = function () {
+                    noerr();
+                    noload();
+                },
+
+                noload = on(node, "load", function () {
+                    d.resolve({
+                        node: node
+                    });
+                    cleanup();
+                }, true),
+
+                noerr = on(node, "error", function (e) {
+                    d.reject({
+                        erorr: e,
+                        node: node
+                    });
+                    cleanup();
+                }, true);
+
+            for (var p in attr)
+                node[p] = attr[p];
+
+            this.injectionPoint.insertBefore(node, this.injectBefore);
+            return d;
+        },
+
+        injectScript: function (url) {
+            var d = this._map[url];
+            if (!d) {
+                trace.log("js {0}", url);
+                d = this._inject("script", {
+                    type: "text/javascript",
+                    charset: "utf-8",
+                    src: url
+                });
+                d.then(function () {
+                    trace.log("done {0}", url);
+                }, function (e) {
+                    trace.err([url, e]);
+                });
+                this._map[url] = d;
+            }
+            return d;
+        },
+
+        injectStylesheet: function (url) {
+            var d = this._map[url];
+            if (!d) {
+                trace.log("css {0}", url);
+                d = this._inject("link", {
+                    type: "text/css",
+                    rel: "stylesheet",
+                    href: url
+                });
+                d.then(function () {
+                    trace.log("done {0}", url);
+                }, function (e) {
+                    trace.error([url, e]);
+                });
+                this._map[url] = d;
+            }
+            return d;
+        }
+    };
+});
\ No newline at end of file
diff -r 8af8e840dd49 -r 27e8e9e38e07 gradle.properties
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gradle.properties	Wed Jun 05 20:44:15 2019 +0300
@@ -0,0 +1,4 @@
+majorVersion=1
+minorVersion=0
+patchVersion=0
+suffixVersion=snap
\ No newline at end of file
diff -r 8af8e840dd49 -r 27e8e9e38e07 gradle/wrapper/gradle-wrapper.jar
Binary file gradle/wrapper/gradle-wrapper.jar has changed
diff -r 8af8e840dd49 -r 27e8e9e38e07 gradle/wrapper/gradle-wrapper.properties
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gradle/wrapper/gradle-wrapper.properties	Wed Jun 05 20:44:15 2019 +0300
@@ -0,0 +1,5 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.7-bin.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff -r 8af8e840dd49 -r 27e8e9e38e07 gradlew
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gradlew	Wed Jun 05 20:44:15 2019 +0300
@@ -0,0 +1,172 @@
+#!/usr/bin/env sh
+
+##############################################################################
+##
+##  Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+    ls=`ls -ld "$PRG"`
+    link=`expr "$ls" : '.*-> \(.*\)$'`
+    if expr "$link" : '/.*' > /dev/null; then
+        PRG="$link"
+    else
+        PRG=`dirname "$PRG"`"/$link"
+    fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+    echo "$*"
+}
+
+die () {
+    echo
+    echo "$*"
+    echo
+    exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+  CYGWIN* )
+    cygwin=true
+    ;;
+  Darwin* )
+    darwin=true
+    ;;
+  MINGW* )
+    msys=true
+    ;;
+  NONSTOP* )
+    nonstop=true
+    ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+        # IBM's JDK on AIX uses strange locations for the executables
+        JAVACMD="$JAVA_HOME/jre/sh/java"
+    else
+        JAVACMD="$JAVA_HOME/bin/java"
+    fi
+    if [ ! -x "$JAVACMD" ] ; then
+        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+    fi
+else
+    JAVACMD="java"
+    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+    MAX_FD_LIMIT=`ulimit -H -n`
+    if [ $? -eq 0 ] ; then
+        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+            MAX_FD="$MAX_FD_LIMIT"
+        fi
+        ulimit -n $MAX_FD
+        if [ $? -ne 0 ] ; then
+            warn "Could not set maximum file descriptor limit: $MAX_FD"
+        fi
+    else
+        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+    fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+    JAVACMD=`cygpath --unix "$JAVACMD"`
+
+    # We build the pattern for arguments to be converted via cygpath
+    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+    SEP=""
+    for dir in $ROOTDIRSRAW ; do
+        ROOTDIRS="$ROOTDIRS$SEP$dir"
+        SEP="|"
+    done
+    OURCYGPATTERN="(^($ROOTDIRS))"
+    # Add a user-defined pattern to the cygpath arguments
+    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+    fi
+    # Now convert the arguments - kludge to limit ourselves to /bin/sh
+    i=0
+    for arg in "$@" ; do
+        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
+
+        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
+            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+        else
+            eval `echo args$i`="\"$arg\""
+        fi
+        i=$((i+1))
+    done
+    case $i in
+        (0) set -- ;;
+        (1) set -- "$args0" ;;
+        (2) set -- "$args0" "$args1" ;;
+        (3) set -- "$args0" "$args1" "$args2" ;;
+        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+    esac
+fi
+
+# Escape application args
+save () {
+    for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+    echo " "
+}
+APP_ARGS=$(save "$@")
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+  cd "$(dirname "$0")"
+fi
+
+exec "$JAVACMD" "$@"
diff -r 8af8e840dd49 -r 27e8e9e38e07 gradlew.bat
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gradlew.bat	Wed Jun 05 20:44:15 2019 +0300
@@ -0,0 +1,84 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem  Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff -r 8af8e840dd49 -r 27e8e9e38e07 settings.gradle
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/settings.gradle	Wed Jun 05 20:44:15 2019 +0300
@@ -0,0 +1,18 @@
+/*
+ * This settings file was generated by the Gradle 'init' task.
+ *
+ * The settings file is used to specify which projects to include in your build.
+ * In a single project build this file can be empty or even removed.
+ *
+ * Detailed information about configuring a multi-project build in Gradle can be found
+ * in the user guide at https://docs.gradle.org/3.5/userguide/multi_project_builds.html
+ */
+
+// To declare projects as part of a multi-project build use the 'include' method
+
+//include 'sub-project-name'
+
+include 'core'
+include 'dom'
+
+rootProject.name = 'implab'
\ No newline at end of file
diff -r 8af8e840dd49 -r 27e8e9e38e07 src/djol/BaseLayer.js
--- a/src/djol/BaseLayer.js	Wed Jun 05 17:44:17 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,44 +0,0 @@
-define([
-    "implab/text/template-compile",
-    "dojo/_base/declare",
-    "dojo/_base/lang",
-    "ol"],
-    function (compile, declare, lang, ol) {
-        return declare([ol.layer.Layer], {            
-
-            name: null,
-
-            displayName: null,
-
-            identifyResultTemplate: null,
-
-            searchResultTemplate: null,
-
-            constructor: function () {
-                lang.mixin(this, arguments[0]);
-                var identifyCompiledTemplate = null, searchCompiledTemplate = null;
-                if (this.identifyResultTemplate) {
-                    identifyCompiledTemplate = compile(this.identifyResultTemplate);
-                }
-                if (this.searchResultTemplate) {
-                    searchCompiledTemplate = compile(this.searchResultTemplate);
-                }
-            },
-
-            /** Возвращает массив строк, каждая строка - результат поиска  приведенный к шаблонному виду
-                @options {Object}
-                    @str {String} поисковая строка
-                    @bbox {Object} bound box, в рамках которого осуществлять поиск
-            */
-            getSearchResult: function (options) {
-                console.warn("Метод необходимо переопределить для для слоя конкретного типа!");
-            },
-            /** Возвращает массив строк, каждая строка - результат идентификации приведенный к шаблонному виду
-                @options {Object}
-                    @coordinates {Array} массив описывающий координаты точки идентификации                    
-            */
-            getItentifyResult: function (coordinates) {
-                console.warn("Метод необходимо переопределить для для слоя конкретного типа!");
-            }
-        });
-    })
\ No newline at end of file
diff -r 8af8e840dd49 -r 27e8e9e38e07 src/djol/ClearTool.js
--- a/src/djol/ClearTool.js	Wed Jun 05 17:44:17 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,19 +0,0 @@
-define (["dojo/_base/declare", "./_OneshotTool", "implab/safe"] , function(declare, _OneshotTool, safe) {
-    return declare([_OneshotTool], {
-        tools : null,
-        
-        constructor : function(opts) {
-            safe.mixin(this,opts, ["tools"]);
-        },
-        
-        invoke : function() {
-            if (this.tools) {
-                this.log("Clear {0} tools", this.tools.length);
-                safe.each(this.tools, function(tool) {
-                    if (tool.clear)
-                        tool.clear();
-                });
-            }
-        }
-    });
-});
\ No newline at end of file
diff -r 8af8e840dd49 -r 27e8e9e38e07 src/djol/CoordPickerTool.js
--- a/src/djol/CoordPickerTool.js	Wed Jun 05 17:44:17 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,24 +0,0 @@
-define (["dojo/_base/declare", "./_OneshotTool", "implab/safe", "dojo/when"] , function(declare, _OneshotTool, safe, when) {
-    return declare([_OneshotTool], {
-        _map : null,
-        _proj : null,
-        
-        constructor : function(opts) {
-            safe.argumentNotNull(opts && opts.map, "opts.map");
-
-            this._map = opts.map;
-            this._proj = opts.proj;
-        },
-        
-        invoke : function() {
-            var me = this;
-
-            return when(me._map.awaitMapEvent('singleclick'), function(evt){
-                if (me._proj) {
-                    // тут можно преобразовать проекции
-                }
-                return evt;
-            });
-        }
-    });
-});
\ No newline at end of file
diff -r 8af8e840dd49 -r 27e8e9e38e07 src/djol/DeactivationTool.js
--- a/src/djol/DeactivationTool.js	Wed Jun 05 17:44:17 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,14 +0,0 @@
-define(["dojo/_base/declare", "./_ToolBase"],function(declare, _ToolBase) {
-    
-    // Инструмент, выключает текущий активный инструмент
-    // Данный инструмент ничго не делает, но при его активации будет
-    // деактивирован предыдущий инструмент
-    return declare([_ToolBase],  {
-
-        // данный инструмент не может быть активным, поэтому данный метод
-        // переопределяется и возвращает всегда false
-        onActivating : function() {
-            return false;
-        }
-    });  
-});
\ No newline at end of file
diff -r 8af8e840dd49 -r 27e8e9e38e07 src/djol/DistanceMeasureTool.js
--- a/src/djol/DistanceMeasureTool.js	Wed Jun 05 17:44:17 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,63 +0,0 @@
-define([
-    "dojo/_base/declare",
-    "implab/safe",
-    "./MeasureToolBase",
-    "implab/text/format",
-    "dojo/i18n!./format/nls/units",
-    "ol" ],
-
-function(declare, safe, MeasureToolBase, format, units, ol) {
-    return declare([ MeasureToolBase ], {
-
-        isGeodesic : true,
-
-        units : 'metric',
-        
-        constructor : function(opts) {
-            if (opts)
-                safe.mixin(this,opts,["isGeodesic", "units"]);
-        },
-
-        _createDraw : function(source) {
-            return new ol.interaction.Draw(
-                {
-                    source : source,
-                    type : "LineString",
-                    style : this.drawStyle
-                });
-        },
-
-        _formatTooltip : function(sketch, proj) {
-            var length = 0;
-            if (this.isGeodesic) {
-                var points = sketch.getGeometry().getCoordinates();
-                var t = ol.proj.getTransform(proj, "EPSG:4326");
-                for (var i = 0; i < points.length - 1; i++) {
-                    length += this.wgs84Sphere.haversineDistance(
-                        t(points[i]),
-                        t(points[i + 1]));
-                }
-            } else {
-                length = sketch.getGeometry().getLength();
-            }
-
-            var mpu, unitName;
-            switch (this.units) {
-                case "nautical":
-                    mpu = 1852;
-                    unitName = units.nmiles;
-                    break;
-                default:
-                    mpu = 1000;
-                    unitName = units.kilometers;
-            }
-
-            if (length >= mpu) {
-                return format("{0:#.0#}{1}", length / mpu, unitName);
-            } else {
-                return format("{0:#0.0#}{1}", length, units.meters);
-            }
-        }
-
-    });
-});
\ No newline at end of file
diff -r 8af8e840dd49 -r 27e8e9e38e07 src/djol/DynamicStyle.js
--- a/src/djol/DynamicStyle.js	Wed Jun 05 17:44:17 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,119 +0,0 @@
-define([ "./declare-style", "dojo/_base/declare", "ol", "implab/safe" ],
-
-function(declare, dojoDeclare, ol, safe) {
-    return declare([], {
-        _cache : null,
-        _getKey : null,
-        _getZoom : null,
-        
-        defaultStyle : null,
-        
-        style : null,
-        
-        styleFunction : null,
-        
-        filter : null,
-
-        constructor : function(opts) {
-            if (opts)
-                dojoDeclare.safeMixin(this, opts);
-
-            this._cache = {};
-
-            if (this.zoom) {
-                if (this.zoom instanceof Function) {
-                    this._getZoom = this.zoom;
-                } else {
-                    var levels = [], max = "max";
-                    for ( var p in this.zoom) {
-                        if (safe.isNumber(this.zoom[p]))
-                            levels.push({
-                                name : p,
-                                zoom : Number(this.zoom[p])
-                            });
-                        else if (this.zoom[p] == "max")
-                            max = p;
-                    }
-
-                    levels.sort(function(x, y) {
-                        return x.zoom - y.zoom;
-                    });
-
-                    this.zoomMax = max;
-                    this.zoomLevels = levels;
-
-                    this._getZoom = function(z) {
-                        for (var i = 0; i < levels.length; i++) {
-                            if (z <= levels[i].zoom)
-                                return levels[i].name;
-                        }
-                        return max;
-                    };
-                }
-            } else {
-                this._getZoom = function(z) {
-                    return "max";
-                };
-            }
-
-            if (this.key) {
-                if (this.key instanceof Function) {
-                    this._getKey = this.key;
-                } else if (typeof this.key === "string") {
-                    this._getKey = function(ft) {
-                        return ft.get(this.key);
-                    };
-                } else {
-                    this._getKey = function(ft, z) {
-                        var k = this.key[z];
-                        if (k instanceof Function)
-                            return k.call(this, ft, z);
-                        else if (typeof k == "string")
-                            return ft.get(k);
-                        else
-                            return this.defaultStyle;
-                    };
-                }
-            } else {
-                this._getKey = function() {
-                    return this.defaultStyle;
-                };
-            }
-
-            if (this.style) {
-                if (this.style instanceof Function) {
-                    this._style = this.style;
-                } else {
-                    this._style = function(ft, res, key, zoom) {
-                        var s = this.style[zoom];
-                        return s && (s instanceof Function) ? s.apply(
-                            this,
-                            arguments) : s;
-                    };
-                }
-            }
-        },
-
-        getFeatureStyle : function(ft, res) {
-            safe.argumentNotNull(ft, "ft");
-            
-            if (this.filter && this.filter(ft) === false)
-                return null;
-
-            var z = this._getZoom(res);
-            var k = this._getKey(ft, z);
-
-            var cid = [ k, z ].join('-');
-
-            var style = this._cache[cid];
-            if (!style) {
-                style = this._style ? this._style(ft, res, k, z) : null;
-                this._cache[cid] = style;
-            }
-
-
-            return safe.isNull(style) || style instanceof Array ? style : [ style ];
-        }
-
-    });
-});
\ No newline at end of file
diff -r 8af8e840dd49 -r 27e8e9e38e07 src/djol/IdentificationTool.js
--- a/src/djol/IdentificationTool.js	Wed Jun 05 17:44:17 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,246 +0,0 @@
-define([
-        "dijit/layout/ContentPane",
-        "dojo/_base/declare",
-        "dojo/Deferred",
-        "dojo/dom-construct",
-        "dojo/dom-class",
-        "dojo/on",
-        "dojo/promise/all",
-        "dojo/when",
-        "implab/safe",
-        "ol",
-        "./listen",
-        "./IdentifyGroup",
-        "./_ToolBase",
-        "./PopupContainer"
-    ],
-
-    function (
-        ContentPane,
-        declare,
-        Deffered,
-        domConstruct,
-        domClass,
-        on,
-        promiseAll,
-        when,
-        safe,
-        ol,
-        listen,
-        IdentifyGroup,
-        _ToolBase,
-        PopupContainer) {
-        return declare([_ToolBase], {
-            /**
-             * массив обработчиков openLayers, которые необходимо удалить при
-             * деактивации
-             */
-            _handlers: null,
-            /**
-             * widget карты
-             */
-            _map: null,
-            /**
-             * openLayers map
-             */
-            _olMap: null,
-            /**
-             * Массив overlays содержащих popupContainers
-             */
-            _popupOverlays: null,
-            /**
-             * Массив popups контейнеров
-             */
-            _popupContainers: null,
-            /**
-             * Режим работы инструмента идентификации
-             * 
-             * @value {String} "single"||"multiple"
-             */
-            mode: null,
-            /**
-             * Режимы
-             */
-            appManager: null,
-
-            constructor: function (options) {
-                safe.argumentNotNull(options, "options");
-                safe.argumentNotNull(options.map, "options.map");
-                safe.argumentNotNull(options.appManager, "options.appManager");
-
-                this._map = options.map;
-                this._olMap = options.map.olMap;
-                this._popupContainers = [];
-                this._popupOverlays = [];
-                this._handlers = [];
-
-                this.appManager = options.appManager;
-                this.mode = options.mode || "single";
-            },
-            /** 
-             */
-            createPopupContent: function (groupWidgets) {
-                var contentWidget = new ContentPane();
-                groupWidgets.forEach(function (groupWidget) {
-                    if (groupWidget && !groupWidget.isEmpty()) {
-                        contentWidget.addChild(groupWidget);
-                    }
-                });
-                return contentWidget;
-            },
-
-            /**
-             * Возвращает обещание на получение объекта с результатом идентификации
-             * по всем видимым режимам и информационным слоям @ options {Object} @ pixel
-             * {Object} - информация о точке идентификации @ coordinate {Array} -
-             * координаты точки иденификации
-             */
-            getGroupsFromVisibleModules: function (options) {
-                var promises = [];
-                var modules = this.appManager.getVisibleModules();
-                modules.forEach(function (module) {
-                    promises.push.apply(promises, module
-                        .getIdentifyResult(options));
-                });
-
-                return promiseAll(promises).then(
-                    function (results) {
-                        console.log("promise all groups = ", results);
-                        return results;
-                    });
-            },
-
-            identifyPosition: function (position) {
-                var me = this, i;
-                var popupContainer = null,
-                    popupOverlay = null;
-                if (me.mode == "multiple") {
-                    // TODO: создать popupContainer и popupOverlay
-                    popupContainer = new PopupContainer({
-                        map: me._olMap
-                    });
-                    on(popupContainer, "close", function () {
-                        var index = me._popupContainers.indexOf(me);
-                        me._popupContainers.splice(index, 1);
-
-                    });
-                    me._popupContainers.push(popupContainer);
-
-                    popupOverlay = new ol.Overlay({
-                        element: popupContainer.domNode,
-                        autoPan: true,
-                        autoPanAnimation: {
-                            duration: 250
-                        }
-                    });
-                    me._popupOverlays.push(popupOverlay);
-                    me._olMap.addOverlay(popupOverlay);
-
-                } else {
-                    if (me._popupContainers.length > 0) {
-                        // Берем первый
-                        popupContainer = me._popupContainers[0];
-                        // Все остальные удалить
-                        if (me._popupContainers.length > 1) {
-                            for (i = 1; i < me._popupContainers.length; i++) {
-                                me._popupContainers[i].destroyRecursive();
-                            }
-                            me._popupContainers.splice(
-                                1,
-                                me._popupContainers.length - 1);
-                        }
-                    } else {
-                        // Создаем новый
-                        popupContainer = new PopupContainer({
-                            map: me._olMap
-                        });
-                        on(popupContainer, "close", function () {
-                            var index = me._popupContainers.indexOf(me);
-                            me._popupContainers.splice(index, 1);
-
-                        });
-                        me._popupContainers.push(popupContainer);
-                    }
-                    if (me._popupOverlays.length > 0) {
-                        // Берем первый и помещаем в него popup
-                        popupOverlay = me._popupOverlays[0];
-                        popupOverlay.setElement(popupContainer.domNode);
-                        // Все остальные удалить
-                        if (me._popupOverlays.length > 1) {
-                            for (i = 1; i < me._popupOverlays.length; i++) {
-                                me._olMap.removeOverlay(me._popupOverlays[i]);
-                            }
-                            me._popupOverlays.splice(
-                                1,
-                                me._popupOverlays.length - 1)
-                        }
-                    } else {
-                        // Создаем новый и помещаем в него popup
-                        popupOverlay = new ol.Overlay({
-                            element: popupContainer.domNode,
-                            autoPan: true,
-                            autoPanAnimation: {
-                                duration: 250
-                            }
-                        });
-                        me._popupOverlays.push(popupOverlay);
-                        me._olMap.addOverlay(popupOverlay);
-                    }
-                }
-
-                popupContainer.destroyDescendants();
-
-                popupOverlay.setPosition(position.coordinate);
-
-                popupContainer.showOverlay();
-
-                when(me.getGroupsFromVisibleModules(position), function (data) {
-                    var contentWidget = me.createPopupContent(data);
-                    popupContainer.show(contentWidget, "only");
-                    popupContainer.hideOverlay();
-                });
-            },
-            /**
-             * Скрыть все popups
-             */
-            hideAllPopups: function () {
-                var me = this, i;
-                for (i = 0; i < this._popupContainers.length; i++) {
-                    this._popupContainers[i].destroyRecursive();
-                }
-                this._popupContainers.splice(0, this._popupContainers.length);
-
-                for (i = 0; i < this._popupOverlays.length; i++) {
-                    this._olMap.removeOverlay(this._popupOverlays[i]);
-                }
-                this._popupOverlays.splice(0, this._popupOverlays.length)
-            },
-
-            onActivating: function () {
-                var me = this;
-                // Обработчик для события "singleclick" по карте
-                var handler = listen(this._olMap, 'singleclick', function (evt) {
-                    if (evt.originalEvent.ctrlKey) {
-                        me.mode = "multiple";
-                    } else {
-                        me.mode = "single";
-                    }
-                    me.identifyPosition({
-                        pixel: evt.pixel,
-                        coordinate: evt.coordinate
-                    });
-                });
-                this._handlers.push(handler);
-            },
-
-            onDeactivating: function () {
-                var me = this;
-                me._handlers.forEach(function (handler) {
-                    if (handler.remove)
-                        handler.remove();
-
-                });
-                this.hideAllPopups();
-            },
-        })
-    });
\ No newline at end of file
diff -r 8af8e840dd49 -r 27e8e9e38e07 src/djol/IdentifyGroup.js
--- a/src/djol/IdentifyGroup.js	Wed Jun 05 17:44:17 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,89 +0,0 @@
-define(
-    [
-        "implab/safe",
-        'dijit/_WidgetBase',
-        'dijit/_TemplatedMixin',
-        "dijit/_WidgetsInTemplateMixin",
-        "dijit/layout/_LayoutWidget",
-        "dijit/layout/ContentPane",
-        "dojo/_base/declare",
-        "dojo/dom-construct",
-        "dojo/on",
-        "ol3/IdentifyItem" ],
-    function(
-        safe,
-        _WidgetBase,
-        _TemplatedMixin,
-        _WidgetsInTemplateMixin,
-        _LayoutWidget,
-        ContentPane,
-        declare,
-        domConstruct,
-        on,
-        IdentifyItem) {
-
-        return declare(
-            [ _LayoutWidget, _TemplatedMixin, _WidgetsInTemplateMixin ],
-            {
-
-                /**
-                 */
-                _empty : true,
-                /**
-                 */
-                layerName : null,
-                /**
-                 * Шаблон всего widget
-                 */
-                templateString : "
", - - itemTemplate : "", - - title : null, - - /** - * Метод из widget.lifecycle - */ - postCreate : function() { - var me = this; - if (typeof this.title == "string") { - this.identifyItemGroupTitle.innerHTML = me.title; - } else if (me.title && me.title.placeAt) { - me.title.placeAt(me.identifyItemGroupTitle, "only"); - } else { - domConstruct.place( - me.title, - me.identifyItemGroupTitle, - "only"); - } - on(this.domNode, "click", function() { - if ("function" == typeof me.callback) { - me.callback(); - } - }); - }, - - addItem : function(options) { - safe.argumentNotNull(options, "options"); - safe.argumentNotNull(options.model, "options.model"); - - if (options.model) { - - var item = new IdentifyItem({ - title : options.title || this.itemTemplate, - model : options.model, - callback : options.callback - }); - this.addChild(item); - this._empty = false; - } else { - console - .error("Не задано необходимое свойство layerFeature"); - } - }, - - isEmpty : function() { - return this._empty; - } - }); - }); \ No newline at end of file diff -r 8af8e840dd49 -r 27e8e9e38e07 src/djol/IdentifyItem.js --- a/src/djol/IdentifyItem.js Wed Jun 05 17:44:17 2019 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,62 +0,0 @@ -define([ - 'dijit/_WidgetBase', - 'dijit/_TemplatedMixin', - "dijit/Tooltip", - "dojo/_base/declare", - "dojo/date/locale", - "dojo/dom-construct", - "dojo/on" ], function(_WidgetBase, _TemplatedMixin, Tooltip, declare, - dateLocale, domConstruct, on) { - var empty = {}; - return declare([ _WidgetBase, _TemplatedMixin ], { - - callback : null, - - dateLocale : dateLocale, - - baseClass : 'identify-item', - - feature : null, - - model : empty, - - title : null, - - templateString : "
", - - constructor : function(options) { - option = options || {}; - if (options.title) - this.title = options.title; - if (options.model) - this.model = options.model; - if (options.callback) - this.callback = options.callback; - - }, - - /** - * Метод из widget.lifecycle - */ - postCreate : function() { - var me = this; - - var content = me.title instanceof Function ? me.title(me) - : me.title; - - if (typeof content == "string") { - me.domNode.innerHTML = content; - } else if (content && content.placeAt) { - content.placeAt(me.domNode, "only"); - } else { - domConstruct.place(content, me.domNode, "only"); - } - - on(me.domNode, "click", function() { - if (typeof me.callback == "function") { - me.callback(me.model); - } - }); - }, - }); -}); \ No newline at end of file diff -r 8af8e840dd49 -r 27e8e9e38e07 src/djol/ImageLayer.js --- a/src/djol/ImageLayer.js Wed Jun 05 17:44:17 2019 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3 +0,0 @@ -define(["ol"], function(ol) { - return ol.layer.Image -}) \ No newline at end of file diff -r 8af8e840dd49 -r 27e8e9e38e07 src/djol/ImageWMSSource.js --- a/src/djol/ImageWMSSource.js Wed Jun 05 17:44:17 2019 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3 +0,0 @@ -define(["ol"], function(ol) { - return ol.source.ImageWMS; -}) \ No newline at end of file diff -r 8af8e840dd49 -r 27e8e9e38e07 src/djol/LayerCheckBox.js --- a/src/djol/LayerCheckBox.js Wed Jun 05 17:44:17 2019 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,49 +0,0 @@ -define([ - "dojo/_base/declare", - "dijit/_WidgetBase", - "dijit/_TemplatedMixin", - "dijit/_WidgetsInTemplateMixin", - "dojo/text!./resources/LayerCheckBoxTemplate.html", - "dijit/form/CheckBox" ], function(declare, _WidgetBase, _TemplatedMixin, - _WidgetsInTemplateMixin, templateString) { - return declare([ _WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin ], { - templateString : templateString, - labelNode : null, - checkBox : null, - - label : "", - _setLabelAttr : { - node : "labelNode", - type : "innerHTML" - }, - - name : "layer", - - _layer : null, - - constructor : function(options) { - options = options || {}; - - if (!options.layer) - throw new Error("The layer is required"); - - this._layer = options.layer; - this.label = options.layer.get("label") || "unnamed"; - }, - - postCreate : function() { - var me = this; - me.inherited(arguments); - - me.checkBox.set('name', me.name); - me.checkBox.set('value', me._layer.getVisible()); - this.checkBox.on("change", function(value) { - me._changed(value); - }); - }, - - _changed : function(visible) { - this._layer.setVisible(visible); - } - }); -}); \ No newline at end of file diff -r 8af8e840dd49 -r 27e8e9e38e07 src/djol/LayerRadioButton.js --- a/src/djol/LayerRadioButton.js Wed Jun 05 17:44:17 2019 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,50 +0,0 @@ -define([ - "dojo/_base/declare", - "dijit/_WidgetBase", - "dijit/_TemplatedMixin", - "dijit/_WidgetsInTemplateMixin", - "dojo/text!./resources/LayerRadioButtonTemplate.html", - "dijit/form/RadioButton" ], function(declare, _WidgetBase, _TemplatedMixin, - _WidgetsInTemplateMixin, templateString) { - return declare([ _WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin ], { - templateString : templateString, - - labelNode : null, - radioButton : null, - - label : "", - _setLabelAttr : { - node : "labelNode", - type : "innerHTML" - }, - - name : "layers", - - _layer : null, - - constructor : function(options) { - options = options || {}; - - if (!options.layer) - throw new Error("The layer is required"); - - this._layer = options.layer; - this.label = options.layer.get("label") || "unnamed"; - }, - - postCreate : function() { - var me = this; - me.inherited(arguments); - - me.radioButton.set('name', me.name); - me.radioButton.set('value', me._layer.getVisible()); - this.radioButton.on("change", function(value) { - me._changed(value); - }); - }, - - _changed : function(visible) { - this._layer.setVisible(visible); - } - }); -}); \ No newline at end of file diff -r 8af8e840dd49 -r 27e8e9e38e07 src/djol/LayerSwitcher.js --- a/src/djol/LayerSwitcher.js Wed Jun 05 17:44:17 2019 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,81 +0,0 @@ -define([ - "dojo/_base/declare", - "require", - "dijit/_WidgetBase", - "dijit/_TemplatedMixin", - "dijit/_WidgetsInTemplateMixin", - "dojo/text!./resources/LayerSwitcherTemplate.html", - "./LayerCheckBox", - "./LayerRadioButton", - "app/view/Container" ], - -function(declare, require, _WidgetBase, _TemplatedMixin, - _WidgetsInTemplateMixin, templateString, LayerCheckBox, LayerRadioButton) { - - return declare([ _WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin ], { - templateString : templateString, - requireScope : require, - _layers : null, - _map : null, - - infoLayersLabel : "Layers", - _setInfoLayersLabelAttr : { - node : "infoLayersLabelNode", - type : "innerHTML" - }, - - baseLayersLabel : "Base", - _setBaseLayersLabelAttr : { - node : "baseLayersLabelNode", - type : "innerHTML" - }, - - constructor : function(options) { - options = options || {}; - - if (!options.map) - throw new Error("The map is required"); - - this._map = options.map; - - if (options.layers && options.layers instanceof Array) - this._layers = options.layers; - else - this._layers = []; - - // this.baseLayersLabel = "Base"; - - }, - - postCreate : function() { - this.inherited(arguments); - - var pending = []; - - for ( var i in this._layers) { - if (this._layers[i].get("layerType") != "base") - pending.push(this._layers[i]); - else - this._addLayer(this._layers[i]); - } - - for ( var i in pending) - this._addLayer(pending[i]); - }, - - _addLayer : function(layer) { - this._map.addLayer(layer); - - if (layer.get("layerType") === "base") { - this.baseLayersContainer.addChild(new LayerRadioButton({ - layer : layer - })); - } else { - this.infoLayersContainer.addChild(new LayerCheckBox({ - layer : layer - })); - } - }, - - }); -}); \ No newline at end of file diff -r 8af8e840dd49 -r 27e8e9e38e07 src/djol/Map.js --- a/src/djol/Map.js Wed Jun 05 17:44:17 2019 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,176 +0,0 @@ -define([ - "dijit/registry", - "dojo/_base/declare", - "dijit/_WidgetBase", - "dojo/dom-construct", - "./PopupContainer", - "dojo/_base/array", - "ol", - "ol3/listen", - "dojo/Deferred", - "implab/safe" -], function (registry, declare, _WidgetBase, dom, PopupContainer, array, ol, listen, Deferred, safe) { - - return declare([_WidgetBase], { - popupOverlays: null, - olMap: null, - - _pending: null, - - constructor: function () { - this._pending = {}; - }, - - buildRendering: function () { - this.domNode = dom.create("div"); - }, - - postCreate: function () { - this.inherited(arguments); - this.popupOverlays = {}; - this.olMap = new ol.Map({ - target: this.domNode, - layers: this.layers, - view: this.view, - controls: this.controls || [], - }); - }, - - getProjection : function() { - return this.view.getProjection(); - }, - - addInteraction: function (value) { - this.olMap.addInteraction(value); - }, - - addLayer: function (layer) { - if (layer) { - if (layer.get("layerType") == "base") - this.olMap.getLayers().insertAt(0, layer); - else - this.olMap.addLayer(layer); - } - }, - - removeLayer: function(layer) { - this.olMap.removeLayer(layer); - }, - - startup: function () { - this.inherited(arguments); - - this.olMap.updateSize(); - }, - - showPopup: function (contentWidget, position, opts) { - // Скрыть popups указанной в opts.role роли, если (opts.hint == - // "replace") - // Если не задан opts или opta.hint скрывать все popup - - var me = this; - - if ((!opts) || (!opts.hint)) { - this.closeAllPopups(); - } else if ((opts.hint) && (opts.hint == "replace")) { - if (opts.role) { - this.closePopupsByRole(opts.role); - } else { - this.closeAllPopups(); - } - } - var overlay = new ol.Overlay({}); - - if (opts && (opts.role)) { - if (this.popupOverlays[opts.role]) { - this.popupOverlays[opts.role].push(overlay); - } else { - this.popupOverlays[opts.role] = [overlay]; - } - } - - // Отображение popUp start - this.olMap.addOverlay(overlay); - var popup = new PopupContainer({ - overlay: overlay, - map: this.olMap, - onClose: function () { - // registry.byNode(overlay.getElement()).destroyRecursive(); - array.forEach(me.popupOverlays[opts.role], function (o) { - if (o === overlay) { - var index = me.popupOverlays[opts.role].indexOf(o); - if (index > -1) { - me.popupOverlays[opts.role].splice(index, 1); - } - } - }); - } - }); - overlay.setElement(popup.domNode); - popup.show(contentWidget); - overlay.setPosition(position); - popup.hideOverlay(); - // end - return popup; - }, - - closeAllPopups: function () { - var overlays = this.olMap.getOverlays(); - overlays.forEach(function (elenemt, index) { - registry.byNode(elenemt.getElement()).destroyRecursive(); - }, this); - this.popupOverlays = {}; - }, - - closePopupsByRole: function (role) { - if (this.popupOverlays[role]) { - array.forEach(this.popupOverlays[role], function (overlay) { - registry.byNode(overlay.getElement()).destroyRecursive(); - }); - this.popupOverlays[role] = []; - } - }, - - /** - * Подписывается на событие карты - * - * @param {String} - * name Имя события - * @param {function(evt)} - * filter Фильтр того, что событие нужное - * - * @returns {ol.ObjectEvent | ol.MapBroeserEvent | ol.MapEvent} Событие - * на которое подписались. - */ - awaitMapEvent: function (name, filter) { - safe.argumentNotEmptyString(name, "name"); - var map = this.olMap, - handle, d, me = this; - - if (me._pending[name]) - throw new Error("An event is already pending: " + name); - - me._pending[name] = d = new Deferred(function () { - handle.remove(); - }); - - handle = listen.once(map, name, function (evt) { - if (!filter || filter(evt)) - d.resolve(evt); - }); - - return d.then(function (evt) { - delete me._pending[name]; - return evt; - }, function (err) { - delete me._pending[name]; - throw err; - }); - }, - - cancelPendingEvents: function () { - for (var name in this._pending) - this._pending[name].cancel(); - } - }); -}); \ No newline at end of file diff -r 8af8e840dd49 -r 27e8e9e38e07 src/djol/MeasureToolBase.js --- a/src/djol/MeasureToolBase.js Wed Jun 05 17:44:17 2019 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,181 +0,0 @@ -define([ - "dojo/_base/declare", - "implab/safe", - "ol", - "./listen", - "./_ToolBase", - "dojo/dom-construct", - "dojo/dom-class" -], function (declare, safe, ol, listen, _ToolBase, dconstruct, dclass) { - return declare([_ToolBase], { - _draw: null, - - drawStyle: new ol.style.Style({ - fill: new ol.style.Fill({ - color: 'rgba(255, 255, 255, 0.2)' - }), - stroke: new ol.style.Stroke({ - color: 'rgba(230, 126, 34, 0.7)', - lineDash: [10, 10], - width: 2 - }), - image: new ol.style.Circle({ - radius: 5, - stroke: new ol.style.Stroke({ - color: 'rgba(0, 0, 0, 0.7)' - }), - fill: new ol.style.Fill({ - color: 'rgba(255, 255, 255, 0.2)' - }) - }) - }), - - vectorStyle: new ol.style.Style({ - fill: new ol.style.Fill({ - color: 'rgba(255, 255, 255, 0.2)' - }), - stroke: new ol.style.Stroke({ - color: '#ffcc33', - width: 2 - }), - image: new ol.style.Circle({ - radius: 7, - fill: new ol.style.Fill({ - color: '#ffcc33' - }) - }) - }), - - _map: null, - - _olMap: null, - - _measureTooltipElement: null, - /** - * Overlay to show the measurement. - * - * @type {ol.Overlay} - */ - _measureTooltip: null, - - _pointermoveKey: null, - - _sketch: null, - - _overlays: null, - - _vector: null, - - wgs84Sphere: new ol.Sphere(6378137), - - constructor: function (options) { - safe.argumentNotNull(options, "options"); - safe.argumentNotNull(options.map, "map"); - - this._map = options.map; - this._olMap = options.map.olMap; - this._overlays = []; - }, - - init: function () { - if (this._draw) - return; - - var source = new ol.source.Vector(); - - this._vector = new ol.layer.Vector({ - source: source, - style: this.vectorStyle - }); - this._map.addLayer(this._vector); - - this._draw = this._createDraw(source); - this._draw.on('drawstart', this._onDrawStart, this); - this._draw.on('drawend', this._onDrawEnd, this); - - }, - - onActivating: function () { - this.init(); - - this._pointermoveKey = listen(this._olMap, 'pointermove', safe.delegate(this, "_onPointerMove")); - this._olMap.addInteraction(this._draw); - - return this.inherited(arguments); - }, - - onDeactivating: function () { - // отключаем рисование и получение сообщений - if (this._pointermoveKey) - this._pointermoveKey.remove(); - this._olMap.removeInteraction(this._draw); - - // если был активен инструмент - if (this._sketch) { - // убиваем подсказку и сбрасываем текущее рисование - this._sketch = null; - this._measureTooltipElement = null; - this._olMap.removeOverlay(this._measureTooltip); - } - - return this.inherited(arguments); - }, - - clear: function () { - var me = this; - me.log("clear"); - if (me._vector) { - me._vector.getSource().clear(); - me._overlays.forEach(function (x) { - me._olMap.removeOverlay(x); - }); - } - }, - - _createMeasureTooltip: function () { - this._measureTooltipElement = dconstruct.create("div", { - "class": 'tooltip poisk-measure-tooltip' - }); - this._measureTooltip = new ol.Overlay({ - element: this._measureTooltipElement, - offset: [0, -15], - positioning: 'bottom-center' - }); - this._olMap.addOverlay(this._measureTooltip); - - }, - - _onDrawStart: function (evt) { - this._sketch = evt.feature; - this._createMeasureTooltip(); - }, - - _onDrawEnd: function (evt) { - - this._measureTooltip.setOffset([0, -7]); - - dclass.remove(this._measureTooltipElement, "tooltip"); - dclass.add(this._measureTooltipElement, "tooltip-static"); - - this._overlays.push(this._measureTooltip); - - this._sketch = null; - this._measureTooltip = null; - this._measureTooltipElement = null; - }, - - _onPointerMove: function (evt) { - if (this._sketch && !evt.dragging) { - this._measureTooltip.setPosition(evt.coordinate); - this._measureTooltipElement.innerHTML = this._formatTooltip( - this._sketch, - this._olMap.getView().getProjection()); - } - }, - - _formatTooltip: function (sketch, proj) { - - } - }); - -}); \ No newline at end of file diff -r 8af8e840dd49 -r 27e8e9e38e07 src/djol/OSMSource.js --- a/src/djol/OSMSource.js Wed Jun 05 17:44:17 2019 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3 +0,0 @@ -define(["ol"], function(ol) { - return ol.source.OSM; -}); \ No newline at end of file diff -r 8af8e840dd49 -r 27e8e9e38e07 src/djol/OlTool.js --- a/src/djol/OlTool.js Wed Jun 05 17:44:17 2019 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,21 +0,0 @@ -define(["dojo/_base/declare", "dojo/_base/lang", "implab/safe", "dojo/dom-class", "dojo/dom-construct", "dijit/_TemplatedMixin", "dijit/_WidgetBase"], - function (declare, lang, safe, domClass, domConstruct, _TemplatedMixin, _WidgetBase) { - return declare([_WidgetBase, _TemplatedMixin], { - map : null, - control : null, - elementName : "div", - - constructor: function () { - lang.mixin(this, arguments[0]); - safe.argumentNotNull(this.map, "map"); - safe.argumentNotNull(this.control, "control"); - }, - - buildRendering : function() { - this.domNode = domConstruct.create(this.elementName); - domClass.add(this.domNode, this.baseClass); - this.control.setTarget(this.domNode); - this.control.setMap(this.map.olMap || this.map); - } - }); -}); \ No newline at end of file diff -r 8af8e840dd49 -r 27e8e9e38e07 src/djol/PopupContainer.js --- a/src/djol/PopupContainer.js Wed Jun 05 17:44:17 2019 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,60 +0,0 @@ -define([ - "dijit/_WidgetBase", - "dijit/_TemplatedMixin", - "dijit/_WidgetsInTemplateMixin", - "dijit/_Container", - "dojo/_base/declare", - "dojo/Evented", - "dojo/dom-class", - "dojo/on", - "dojo/text!./resources/PopupContainerTemplate.html", - "ol" -], - function (_WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin, _Container, declare, Evented, domClass, on, templateString, ol) { - return declare([_WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin, _Container/*, Evented*/], { - - templateString: templateString, - - overlay: null, - - map : null, - - constructor: function (options) { - options = options || {}; - }, - - postCreate: function () { - var me = this; - this.inherited(arguments); - on(this.popupCloser, "click", function () { - me.destroyRecursive(); - me.onClose(); - }); - }, - - show: function (widget, opts) { - opts = opts || "only"; - if (widget) { - widget.placeAt(this.popupContent, opts); - } - }, - - hideOverlay: function () { - domClass.add(this.popupOverlay, "hidden") - }, - - showOverlay: function () { - domClass.remove(this.popupOverlay, "hidden") - }, - - destroy : function() { - this.map.removeOverlay(this.overlay); - this.inherited(arguments); - }, - - onClose: function () { - this.emit("close"); - } - - }); - }); \ No newline at end of file diff -r 8af8e840dd49 -r 27e8e9e38e07 src/djol/SquareMeasureTool.js --- a/src/djol/SquareMeasureTool.js Wed Jun 05 17:44:17 2019 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,61 +0,0 @@ -define([ - "dojo/_base/declare", - "implab/safe", - "./MeasureToolBase", - "implab/text/format", - "dojo/i18n!./format/nls/units", - "ol" ], - -function(declare, safe, MeasureToolBase, format, units, ol) { - return declare([ MeasureToolBase ], { - - isGeodesic : true, - - units : 'metric', - - constructor : function(opts) { - if (opts) - safe.mixin(this,opts,["isGeodesic", "units"]); - }, - - _createDraw : function(source) { - return new ol.interaction.Draw({ - source : source, - type : "Polygon", - style : this.drawStyle - }); - }, - - _formatTooltip : function(sketch, proj) { - var area; - if (this.isGeodesic) { - var geom = sketch.getGeometry().clone().transform(proj, 'EPSG:4326'); - var coordinates = geom.getLinearRing(0).getCoordinates(); - area = Math.abs(this.wgs84Sphere.geodesicArea(coordinates)); - } else { - area = sketch.getGeometry().getArea(); - } - - var mpu, unitName; - switch (this.units) { - case "nautical": - mpu = 1852*1852; - unitName = units.nmiles2; - break; - default: - mpu = 1852*1852; - unitName = units.kilometers2; - } - - if (area > mpu/10) { - return format( - "{0:#0.##} {1}", - area / mpu, - unitName); - } else { - return format("{0:#0.##} {1}", area, units.meters2); - } - } - - }); -}); \ No newline at end of file diff -r 8af8e840dd49 -r 27e8e9e38e07 src/djol/TileLayer.js --- a/src/djol/TileLayer.js Wed Jun 05 17:44:17 2019 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3 +0,0 @@ -define(["ol"], function(ol) { - return ol.layer.Tile; -}); \ No newline at end of file diff -r 8af8e840dd49 -r 27e8e9e38e07 src/djol/TileWMSSource.js --- a/src/djol/TileWMSSource.js Wed Jun 05 17:44:17 2019 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3 +0,0 @@ -define(["ol"], function(ol) { - return ol.source.TileWMS; -}); \ No newline at end of file diff -r 8af8e840dd49 -r 27e8e9e38e07 src/djol/ToolBoxController.js --- a/src/djol/ToolBoxController.js Wed Jun 05 17:44:17 2019 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,43 +0,0 @@ -define([ - "dojo/_base/declare", - "implab/safe", - "implab/components/ActivationController", - "./ToolType" ], - -function(declare, safe, ActivationController, ToolType) { - return declare([ ActivationController ], { - _stack : null, - _tools : null, - - constructor : function() { - this._stack = new Array(); - this._tools = new Array(); - }, - - activate : function(tool) { - safe.argumentNotNull(tool, "tool"); - - var me = this, current = me.getCurrent(); - - return this.inherited(arguments).then(function(success) { - if (success) { - if (tool.toolType == ToolType.Oneshot && current) - me._stack.push(current); - else - me._stack = []; - } - return success; - }); - }, - - deactivate : function() { - var me = this; - return me.inherited(arguments).then(function(success) { - if (success && me._stack.length) - return me.activate(me._stack.pop()); - - return success; - }); - } - }); -}); \ No newline at end of file diff -r 8af8e840dd49 -r 27e8e9e38e07 src/djol/ToolType.js --- a/src/djol/ToolType.js Wed Jun 05 17:44:17 2019 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,6 +0,0 @@ -define([], function(){ - return { - Activatable : 1, - Oneshot : 2 - }; -}); \ No newline at end of file diff -r 8af8e840dd49 -r 27e8e9e38e07 src/djol/VectorLayer.js --- a/src/djol/VectorLayer.js Wed Jun 05 17:44:17 2019 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,68 +0,0 @@ -define([ - "implab/guard", - "implab/text/template-compile", - "dojo/_base/declare", - "dojo/_base/lang", - "dojo/Deferred", - "ol"], - function (guard, compile, declare, lang, Deferred, ol) { - return declare([ol.layer.Vector], { - - map: null, - - _olMap: null, - - name: null, - - displayName: null, - - identifyResultTemplate: null, - - identifyCompiledTemplate:null, - - searchResultTemplate: null, - - searchCompiledTemplate: null, - - constructor: function () { - lang.mixin(this, arguments[0]); - this._olMap = this.map.olMap; - var identifyCompiledTemplate = null, searchCompiledTemplate = null; - if (this.identifyResultTemplate) { - this.identifyCompiledTemplate = compile(this.identifyResultTemplate); - } - if (this.searchResultTemplate) { - this.searchCompiledTemplate = compile(this.searchResultTemplate); - } - }, - - /** Возвращает массив строк, каждая строка - результат поиска приведенный к шаблонному виду - @options {Object} - @str {String} поисковая строка - @bbox {Object} bound box, в рамках которого осуществлять поиск - */ - getSearchResult: function (options) { - return null; - }, - - _getIdentifyResult: function (options) { - var me = this; - var features = []; - //TODO: добавить фильтр по layer равный ему самому - this._olMap.forEachFeatureAtPixel(options.pixel, function (feature, layer) { - features.push({ feature: feature, layer: layer }); - }, null, function (layer) { - return layer == me; - }); - console.log(features); - return features; - }, - /** Возвращает массив строк, каждая строка - результат идентификации приведенный к шаблонному виду - @options {Object} - @coordinates {Array} массив описывающий координаты точки идентификации - */ - getIdentifyResult: function (coordinates) { - return guard(this, "_getIdentifyResult", [coordinates]); - } - }); - }) \ No newline at end of file diff -r 8af8e840dd49 -r 27e8e9e38e07 src/djol/VectorStore.js --- a/src/djol/VectorStore.js Wed Jun 05 17:44:17 2019 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,289 +0,0 @@ -define( - [ - "dojo/_base/declare", - "dojo/_base/array", - "implab/safe", - "implab/Uuid", - "ol", - "ol3/listen", - "./VectorStoreQuery", - "dojo/store/util/QueryResults" - ], - function (declare, array, safe, UUID, ol, listen, VectorStoreQuery, QueryResults) { - function createPaginator(opts) { - return (opts.count || opts.start) && - function (results) { - var total = results.length; - results = results.slice(opts.start || 0, (opts.start || 0) + - (opts.count || Infinity)); - results.total = total; - - return results; - }; - } - - /** - * Обертка вокруг векторного источника данных ol.source.Vector, - * реализует dojo/store а также notify, что делает возможным наблюдение - * за хранилищем при помощи dojo/store/Observable. - * - * @disposable - */ - return declare( - null, { - _source: null, // ol3.source.Vector - - _projection: null, - - _subscriptions: null, - - constructor: function (opts) { - safe.argumentNotNull(opts, "opts"); - safe.argumentOfType( - opts.source, - ol.source.Vector, - "opts.source"); - - var me = this; - - me._source = opts.source; - if (opts.projection) - me._projection = ol.proj.get(opts.projection); - }, - - getSource: function () { - return this._source; - }, - - getProjection: function() { - return this._projection; - }, - - get: function (id) { - return this._source.getFeatureById(id); - }, - - /** - * @param{Object|Function} q предикат для выбора объекта - * @param{Object} opts параметры выполнения (start,count,sort) - * @return{Function} filter(data) filter.matches - * filter.matches.predicate - * filter.matches.extent filter.sort - * filter.sort.compare - */ - queryEngine: function (q, opts) { - opts = opts || {}; - - // строим функцию для фильтрации - var filter; - if (q instanceof Function) { - // если передали уже готовую функцию, испольуем ее - filter = new VectorStoreQuery(q, q.extent); - } else { - // если передали объект - var extent; - // вытаскиваем из него extent - if (q && 'extent' in q) { - extent = q.extent; - delete q.extent; - } - - // строим новую функцию фильтрации - filter = new VectorStoreQuery(q, extent); - } - - // строим функцию сортировки - var sort = opts.sort && this.sortEngine(opts.sort); - - var paginate = createPaginator(opts); - - // строим функцию выполнения запроса - var execute = function (data) { - var results = array.filter(data, filter); - - if (sort) - sort(results); - - if (paginate) - results = paginate(results); - return results; - }; - - execute.matches = filter; - execute.sort = sort; - execute.paginate = paginate; - return execute; - }, - - sortEngine: function (options) { - var cmp = function (a, b) { - for (var sort, i = 0; - (sort = options[i]); i++) { - var aValue = a.get(sort.attribute); - var bValue = b.get(sort.attribute); - if (aValue != bValue) { - return Boolean(sort.descending) == aValue > bValue ? -1 : 1; - } - } - return 0; - }; - - var execute = function (data) { - return data.sort(cmp); - }; - - execute.compare = cmp; - return execute; - }, - - /** - * Запрашивает объекты со слоя - * - * @param{object|VectorStoreQuery|Function} query - * - *
-                 * {
-                 *     extent : ol3.Extent,
-                 * }
-                 * 
- */ - query: function (q, options) { - var me = this; - var filter = this.queryEngine(q, options); - - if (this.notify && !this.hasOwnProperty("_subscriptions")) { - me._subscriptions = []; - - var sc = function (evt, handler) { - me._subscriptions.push(listen(me._source, evt, safe.delegate(me, handler))); - } - - sc("addfeature", "_onAdd"); - sc("changefeature", "_onUpdate"); - sc("removefeature", "_onRemove"); - } - - var predicate, data, extent = filter.matches && - filter.matches.extent; - // если это запрос с указанием области - if (extent) { - predicate = filter.matches.predicate; - - data = this._source.getFeaturesInExtent(extent); - - if (predicate) - data = array.filter(data, predicate); - - if (filter.sort) - filter.sort(data); - - if (filter.paginate) - data = filter.paginate(data); - } else { - // любой другой запрос - data = filter(this._source.getFeatures()); - } - - return new QueryResults(data); - }, - - put: function (obj, options) { - safe.argumentOfType(obj, ol.Feature, "obj"); - if (!options) - options = {}; - - if (options.id) - obj.setId(options.id); - - var id = obj.getId() || new UUID(); - - var prev = this.get(id); - - if ('overwrite' in options) { - // overwrite=true указан, но перезаписывать нечего - if (!prev && options.overwrite) - throw new Error("The specified feature with id '" + - id + "' doesn't exist in the store"); - - // overwrite=false указан, но объект уже существует - if (prev && !options.overwrite) - throw new Error("The specified feature with id '" + - id + "' already exists in the store"); - } - - // ok - if (prev) { - var data = obj.getProperties(); - prev.setProperties(data); - } else { - this._source.addFeature(obj); - } - - return id; - }, - - add: function (obj, options) { - safe.argumentOfType(obj, ol.Feature, "obj"); - - if (!options) - options = {}; - - if (options.id) - obj.setId(options.id); - - var id = obj.getId() || new UUID(); - - var prev = this.get(id); - - if (prev) - throw new Error("The specified feature with id '" + id + - "' already exists in the store"); - - this._source.addFeature(obj); - }, - - remove: function (id) { - var me = this; - - var ft = me.get(id); - if (ft) - me._source.removeFeature(ft); - }, - - getIdentity: function (obj) { - if (safe.isNull(obj)) - return undefined; - if (!(obj instanceof ol.Feature)) - throw new Error("A feature is expected"); - - return obj.getId(); - }, - - _onAdd: function (ev) { - this.notify(ev.feature); - }, - - _onRemove: function (ev) { - var id = ev.feature.getId(); - if (!safe.isNull(id)) - this.notify(undefined, id); - }, - - _onUpdate: function (ev) { - var id = ev.feature.getId(); - if (!safe.isNull(id)) - this.notify(ev.feature, id); - }, - - dispose: function () { - var me = this; - if (me._subscriptions) - me._subscriptions.forEach(function (sc) { - sc.remove(); - }); - - me._source = null; - me._subscriptions = null; - } - }); - }); \ No newline at end of file diff -r 8af8e840dd49 -r 27e8e9e38e07 src/djol/VectorStoreQuery.js --- a/src/djol/VectorStoreQuery.js Wed Jun 05 17:44:17 2019 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,67 +0,0 @@ -define([ "ol" ], function(ol) { - - function buildFilter(filter) { - if (filter instanceof Function) - return filter; - if (filter) { - var match = function(str) { - return { - test : function(x) { - if (x === null || x === undefined) - return false; - return x.toString().startsWith(str); - } - }; - }; - - for ( var p in filter) { - if (typeof (filter[p]) == "string" && filter[p].endsWith("*")) - filter[p] = match(filter[p].substr(0, filter[p].length)); - } - return function(ft) { - for ( var p in filter) { - if (filter[p] && filter[p].test ? !filter[p] - .test(ft.get(p)) : ft.get(p) != filter[p]) - return false; - } - return true; - }; - } - throw new Error("Unsupported filter"); - } - - /** - * @constructor - * @example - * - *
-     * var store = new VectorStore({
-     *     source : vectorSource
-     * });
-     * 
-     * var req = new VectorStoreQuery({
-     *     city : "Moscow"
-     * }, [ 30, 50, 40, 60 ]);
-     * 
-     * store.query(req).then(showResults);
-     * 
- */ - return function(filter, extent) { - var match = filter && buildFilter(filter); - - var query = function(ft) { - if (extent) { - var g = gt.getGeometry(); - if (!g || !ol.extent.intersects(extent, g.getExtent())) - return false; - } - - return !match || match(ft); - }; - - query.extent = extent; - query.predicate = match; - - return query; - }; -}); \ No newline at end of file diff -r 8af8e840dd49 -r 27e8e9e38e07 src/djol/WFSSource.js --- a/src/djol/WFSSource.js Wed Jun 05 17:44:17 2019 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,123 +0,0 @@ -define([ - "ol", - "dojo/request", - "dojo/_base/array", - "implab/safe", - "implab/log/trace!" -], function (ol, - request, - array, - safe, - trace -) { - return function (wfs, featurePrefix, featureType, featureNS, queryArgs) { - if (arguments.length == 1) { - featurePrefix = wfs.featurePrefix; - featureType = wfs.featureType; - featureNS = wfs.featureNS; - wfs = wfs.wfsURL; - queryArgs = wfs.queryArgs; - } - - safe.argumentNotNull(wfs, "wfsURL"); - safe.argumentNotEmptyString(featurePrefix, "featurePrefix"); - safe.argumentNotEmptyString(featureNS, "featureNS"); - safe.argumentNotEmptyString(featureType, "featureType"); - - var format = new ol.format.WFS({ - featureNS: featureNS, - featureType: featureType - }); - - var layerName = featurePrefix + ":" + featureType; - - function loader(extent, resolution, projection) { - var query = { - service: 'WFS', - version: '1.1.0', - request: 'GetFeature', - typename: layerName, - srsname: projection.getCode() - }; - safe.mixin(query, queryArgs); - - if (extent && isFinite(extent[0])) - query.bbox = extent.join(',') + "," + projection.getCode(); - - return request(wfs, { - query: query, - handleAs: 'xml' - }).then(function (data) { - // в загрузчике нельзя вызывать метод source.clear() поскольку - // это приводит к рекурсии - var features = format.readFeatures(data); - - var map = {}, - del = [], - add = []; - - array.forEach(features, function (x) { - // HACK исправляем идентификаторы, чтобы они совпадали с - // реальными - - var id = x.get("id"); - if (id) - x.setId(id); - else - id = x.getId(); - - map[id] = x; - - // нужно проверить, была ли фича на карте - var prev = source.getFeatureById(id); - if (prev) { - // если да, то обновить ее. - var data = x.getProperties(); - prev.setProperties(data); - } else { - // иначе добавить - add.push(x); - } - }); - - source.forEachFeatureInExtent(extent, function (x) { - if (!(x.getId() in map)) - del.push(x); - }); - - source.addFeatures(add); - - array.forEach(del, function (x) { - source.removeFeature(x); - }); - - //revision = revision + 1; - - source.set("revision", ++revision); - - }); - } - - var cls = ol.source.ServerVector || ol.source.Vector; - var revision = 0; - var source = new cls({ - loader: loader, - //revision: revision - wrapX: false - // , - // strategy : options.strategy || ol.loadingstrategy.all, - // projection : options.projection - }); - source.set("revision", revision); - source.reload = function (extent, resolution, projection, q) { - if (arguments.length >= 4) - queryArgs = q; - if (!extent) - extent = [-Infinity, -Infinity, Infinity, Infinity]; - return loader(extent, resolution, projection); - }; - - trace.log("{0} -> {1}", layerName, wfs); - return source; - }; -}); \ No newline at end of file diff -r 8af8e840dd49 -r 27e8e9e38e07 src/djol/_OneshotTool.js --- a/src/djol/_OneshotTool.js Wed Jun 05 17:44:17 2019 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,63 +0,0 @@ -define(["dojo/_base/declare", "implab/safe", "implab/guard", "ol3/_ToolBase", "ol3/ToolType"], - - function (declare, safe, guard, _ToolBase, ToolType) { - return declare([_ToolBase], { - _pending: null, - - _lastResult: null, - - toolType: ToolType.Oneshot, - - invoke: function () { - }, - - onActivating: function () { - var me = this; - - // start the operation - me._lastResult = me._pending = guard(me, "invoke"); - - return this.inherited(arguments); - }, - - onActivated: function () { - var me = this; - - // fire the activate event - this.inherited(arguments); - - me._pending.then(function () { - if (me._pending) { - me.log("Operation finished, deactivating."); - me._pending = null; - me.deactivate(); - } - }, function (ex) { - if (me._pending) { - me.error("Operation failed, deactivating: {0}", ex); - me._pending = null; - me.deactivate(); - } - }); - }, - - onDeactivated: function () { - var d = this._pending; - if (d) { - this.log("Cancelling pending operation"); - this._pending = null; - d.cancel(); - } - - return this.inherited(arguments); - }, - - run: function () { - var me = this; - - return me.activate().then(function () { - return me._lastResult; - }); - } - }); - }); \ No newline at end of file diff -r 8af8e840dd49 -r 27e8e9e38e07 src/djol/_ToolBase.js --- a/src/djol/_ToolBase.js Wed Jun 05 17:44:17 2019 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,46 +0,0 @@ -define([ - "dojo/_base/declare", - "dojo/when", - "implab/safe", - "implab/guard", - "implab/components/_ActivatableMixin", - "implab/log/_LogMixin", - "dojo/Evented", - "./ToolType" ], - -function(declare, when, safe, guard, _ActivatableMixin, _LogMixin, Evented, ToolType) { - return declare([ _ActivatableMixin, Evented ], { - toolType : ToolType.Activatable, - - module : null, - - constructor : function(opts) { - if (opts) { - if (opts.controller) - this.setController(opts.controller); - } - }, - - onActivating : function() { - var me = this, inherited = this.getInherited(arguments); - if (me.module && !me.module.isActive()) - return me.module.activate().then(function(active) { - return active ? inherited.apply(me) : false; - }); - else - return inherited.apply(me); - }, - - onActivated : function() { - this.emit("active", true); - }, - - onDeactivated : function() { - this.emit("active", false); - }, - - destroy : function() { - - } - }); -}); \ No newline at end of file diff -r 8af8e840dd49 -r 27e8e9e38e07 src/djol/declare-style.js --- a/src/djol/declare-style.js Wed Jun 05 17:44:17 2019 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,20 +0,0 @@ -define(["dojo/_base/declare","implab/safe"],function(declare, safe){ - return function(base, proto){ - var cls = declare(base,proto); - - var factory = /** @this */ function() { - var me = this; - cls.apply(me,arguments); - var fn = function() { - return me.getFeatureStyle.apply(me,arguments); - }; - fn.style = me; - fn.styleFunction = fn; - return fn; - }; - - factory.styleClass = cls; - factory.prototype = cls.prototype; - return factory; - }; -}); \ No newline at end of file diff -r 8af8e840dd49 -r 27e8e9e38e07 src/djol/format/coords.js --- a/src/djol/format/coords.js Wed Jun 05 17:44:17 2019 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,71 +0,0 @@ -define( - [ "dojo/i18n!./nls/coords", "implab/text/format", "implab/safe" ], - - function(nls, format, safe) { - - var formatDMS = function(coord) { - return formatSD(coord, nls.dmsPattern); - }; - - var formatDM = function(coord) { - return formatSD(coord, nls.dmPattern); - }; - - var formatD = function(coord) { - return formatSD(coord, nls.dPattern); - }; - - /** - * pattern: - * - * {0} - signed floating point number - latitude - * - * {1} - positive floating point number - minutes part of latitude - * - * {2} - positive floating point number - seconds part of latitude - * - * {3} - localized hemisphere sign: north or south - * - * {4} - signed floating point number - longitude - * - * {5} - positive floating point number - minutes part of longitude - * - * {6} - positive floating point number - seconds part of longitude - * - * {7} - localized hemisphere sign: east or west - */ - var formatSD = function(coord, pattern) { - safe.argumentNotNull(coord, "coord"); - if (!pattern) - pattern = nls.sdPattern; - var x = (coord[0] % 360 + 540) % 360 - 180, y = (coord[1] % 180 + 270) % 180 - 90; - - return format(pattern, y, Math.abs((y * 60) % 60), Math - .abs((y * 3600) % 60), y >= 0 ? nls.north : nls.south, x, Math - .abs((x * 60) % 60), Math.abs((x * 3600) % 60), x >= 0 - ? nls.east - : nls.west); - }; - - var cls = function(fmt) { - switch (fmt) { - case "DMS": - return formatDMS; - case "DM": - return formatDM; - case "D": - return formatD; - case "SD": - return formatSD; - default: - if (!fmt) - return formatSD; - else - return function(coord) { - return formatSD(coord, fmt); - } - } - }; - - return cls; - }); \ No newline at end of file diff -r 8af8e840dd49 -r 27e8e9e38e07 src/djol/format/nls/coords.js --- a/src/djol/format/nls/coords.js Wed Jun 05 17:44:17 2019 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,14 +0,0 @@ -define({ - root : { - // lat lon - dmsPattern : "{0:!00;00}\u00b0{1:!00}\u2032{2:00}\u2033{3} {4:!000;000}\u00b0{5:!00}\u2032{6:00}\u2033{7}", - dmPattern : "{0:!00;00}\u00b0{1:00.0000}\u2032{3} {4:000;000}\u00b0{5:!00.0000}\u2032{7}", - dPattern : "{0:00.000000;00.000000}\u00b0{3} {4:000.000000;000.000000}\u00b0{7}", - sdPattern : "{0:#0.000000}, {4:#0.000000}", - north : "N", - south : "S", - west : "W", - east : "E" - }, - ru : true -}); \ No newline at end of file diff -r 8af8e840dd49 -r 27e8e9e38e07 src/djol/format/nls/ru/coords.js --- a/src/djol/format/nls/ru/coords.js Wed Jun 05 17:44:17 2019 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,6 +0,0 @@ -define({ - north : "С", - south : "Ю", - west : "З", - east : "В" -}); \ No newline at end of file diff -r 8af8e840dd49 -r 27e8e9e38e07 src/djol/format/nls/ru/units.js --- a/src/djol/format/nls/ru/units.js Wed Jun 05 17:44:17 2019 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,11 +0,0 @@ -define({ - kmph : "км/ч", - mps : "м/с", - knots : "уз", - meters : "м", - kilometers : "км", - meters2 : "м2", - kilometers2 : "км2", - nmiles : "миль", - nmiles2 : "миль2" -}); \ No newline at end of file diff -r 8af8e840dd49 -r 27e8e9e38e07 src/djol/format/nls/units.js --- a/src/djol/format/nls/units.js Wed Jun 05 17:44:17 2019 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,14 +0,0 @@ -define({ - root : { - kmph: "km/h", - mps: "m/s", - knots : "kn", - meters : "m", - kilometers : "km", - meters2 : "m2", - kilometers2 : "m2", - nmiles : "nmi", - nmiles2 : "nmi2" - }, - ru : true -}); \ No newline at end of file diff -r 8af8e840dd49 -r 27e8e9e38e07 src/djol/interaction/FeatureDrag.js --- a/src/djol/interaction/FeatureDrag.js Wed Jun 05 17:44:17 2019 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,123 +0,0 @@ -define([ "dojo/_base/declare", "ol", "dojo/Evented" ], function(declare, ol, - Evented) { - - var peekFirstFeature = function(map, coordinate, pixel) { - return map.forEachFeatureAtPixel(function(ft, layer) { - return ft; - }); - }; - - var cls = declare([ ol.interaction.Pointer ], { - "-chains-" : { - constructor : "manual" - }, - - _peek : null, - - _feature : null, - - _coordinate : null, - - cursor : "pointer", - - _oldCursor : undefined, - - /** - * Создает новый объект - * - * @param {Object} - * opts опции - * @param {Function} - * opts.peek Функция выбора фичи для перетаскивания - * function(map,coordinate,pixel), возвращает фичу - * @param {String} - * opts.cursor css курсор который будет использован при - * наведении и перетаскивании фичи - * - */ - constructor : function(opts) { - - ol.interaction.Pointer.apply(this, [{ - handleDownEvent : this.handleDownEvent, - handleDragEvent : this.handleDragEvent, - handleMoveEvent : this.handleMoveEvent, - handleUpEvent : this.handleUpEvent - }]); - Evented.apply(this); - - if (opts) { - if (opts.peek) { - this._peek = opts.peek; - } else { - this._peek = peekFirstFeature; - } - if ("cursor" in opts) - this.cursor = opts.cursor; - } - }, - - handleDownEvent : function(evt) { - var c = evt.coordinate; - - var ft = this._peek(evt.map, c, evt.pixel); - - if (ft) { - this._feature = ft; - this._coordinate = c; - this._emit("dragbegin", { feature : ft }); - return true; - } - - return false; - }, - - handleDragEvent : function(evt) { - var c1 = this._coordinate, c2 = evt.coordinate; - - var dx = c2[0] - c1[0]; - var dy = c2[1] - c1[1]; - - this._emit("dragging", { feature : this._feature, fromCoord : c1, toCoord : c2 }); - - this._feature.getGeometry().translate(dx, dy); - - this._coordinate = c2; - }, - - handleUpEvent : function(evt) { - if (this._feature) - this._emit("dragend", { feature : this._feature }); - - this._feature = null; - this._coordinate = null; - return false; - }, - - handleMoveEvent : function(evt) { - if (this.cursor) { - var ft = this._feature || this._peek(evt.map, evt.coordinate , evt.pixel); - - var element = evt.map.getTargetElement(); - if (ft) { - if (element.style.cursor != this.cursor) { - this._oldCursor = element.style.cursor; - element.style.cursor = this.cursor; - } - } else if (this._oldCursor !== undefined) { - element.style.cursor = this._oldCursor; - this._oldCursor = undefined; - } - } - }, - - _emit : function(name, data) { - var evt = new ol.source.VectorEvent(name,this); - - for(var p in data) - evt[p] = data[p]; - this.dispatchEvent(evt); - } - }); - - return cls; -}); \ No newline at end of file diff -r 8af8e840dd49 -r 27e8e9e38e07 src/djol/listen.js --- a/src/djol/listen.js Wed Jun 05 17:44:17 2019 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,22 +0,0 @@ -define(["ol"], function(ol) { - - var listen = function(target, event, callback) { - var key = target.on(event, callback); - return { - remove : function() { - ol.Observable.unByKey(key); - } - }; - }; - - listen.once = function(target, event, callback) { - var key = target.once(event, callback); - return { - remove : function() { - ol.Observable.unByKey(key); - } - }; - }; - - return listen; -}); \ No newline at end of file diff -r 8af8e840dd49 -r 27e8e9e38e07 src/djol/main.js --- a/src/djol/main.js Wed Jun 05 17:44:17 2019 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,6 +0,0 @@ -define([ "ol" ], function(ol) { - // вспомогательный класс для получения ol в виде зависимости - return function() { - return ol; - }; -}); \ No newline at end of file diff -r 8af8e840dd49 -r 27e8e9e38e07 src/djol/ol-stub.js --- a/src/djol/ol-stub.js Wed Jun 05 17:44:17 2019 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4 +0,0 @@ -var ol; -define([], function() { - return ol; -}); \ No newline at end of file diff -r 8af8e840dd49 -r 27e8e9e38e07 src/djol/resources/LayerCheckBoxTemplate.html --- a/src/djol/resources/LayerCheckBoxTemplate.html Wed Jun 05 17:44:17 2019 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4 +0,0 @@ -
- -
\ No newline at end of file diff -r 8af8e840dd49 -r 27e8e9e38e07 src/djol/resources/LayerRadioButtonTemplate.html --- a/src/djol/resources/LayerRadioButtonTemplate.html Wed Jun 05 17:44:17 2019 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,5 +0,0 @@ -
- -
\ No newline at end of file diff -r 8af8e840dd49 -r 27e8e9e38e07 src/djol/resources/LayerSwitcherTemplate.html --- a/src/djol/resources/LayerSwitcherTemplate.html Wed Jun 05 17:44:17 2019 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,6 +0,0 @@ -
-

-
-

-
-
\ No newline at end of file diff -r 8af8e840dd49 -r 27e8e9e38e07 src/djol/resources/PopupContainerTemplate.html --- a/src/djol/resources/PopupContainerTemplate.html Wed Jun 05 17:44:17 2019 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,8 +0,0 @@ -
- -
- -
\ No newline at end of file diff -r 8af8e840dd49 -r 27e8e9e38e07 src/djol/resources/mapToolCheckBox.html --- a/src/djol/resources/mapToolCheckBox.html Wed Jun 05 17:44:17 2019 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3 +0,0 @@ -
-
-
\ No newline at end of file diff -r 8af8e840dd49 -r 27e8e9e38e07 src/implab/Deferred.js --- a/src/implab/Deferred.js Wed Jun 05 17:44:17 2019 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3 +0,0 @@ -define(["dojo/Deferred"], function(Deferred) { - return Deferred; -}); \ No newline at end of file diff -r 8af8e840dd49 -r 27e8e9e38e07 src/implab/Uri.js --- a/src/implab/Uri.js Wed Jun 05 17:44:17 2019 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,232 +0,0 @@ -define( - [ "./declare" ], - function(declare) { - function parseURI(uri) { - var schema, host, port, path, query, hash, i; - if (typeof (uri) == "string") { - if ((i = uri.indexOf(":")) >= 0 && - uri.substr(0, i).match(/^\w+$/)) { - schema = uri.substr(0, i); - uri = uri.substr(i + 1); - } - - if (uri.indexOf("//") === 0) { - uri = uri.substr(2); - if ((i = uri.indexOf("/")) >= 0) { - host = uri.substr(0, i); - uri = uri.substr(i); - } else { - host = uri; - uri = ""; - } - } - - if ((i = uri.indexOf("?")) >= 0) { - path = uri.substr(0, i); - uri = uri.substr(i + 1); - - } else { - path = uri; - uri = ""; - - if ((i = path.indexOf("#")) >= 0) { - hash = path.substr(i + 1); - path = path.substr(0, i); - } - } - - if ((i = uri.indexOf("#")) >= 0) { - query = uri.substr(0, i); - hash = uri.substr(i + 1); - } else { - query = uri; - } - } - - if (host && (i = host.lastIndexOf(":")) >= 0) { - port = host.substr(i + 1); - host = host.substr(0, i); - } - - return { - schema : schema, - host : host, - port : port, - path : path, - query : query, - hash : hash - }; - } - - function makeURI(options) { - var uri = []; - - if (options.schema) - uri.push(options.schema, ":"); - if (options.host) - uri.push("//", options.host); - if (options.host && options.port) - uri.push(":", options.port); - - if (options.path) { - if (options.host && options.path[0] != "/") - uri.push("/"); - uri.push(options.path); - } else if (options.host) { - uri.push("/"); - } - - if (options.query) - uri.push("?", options.query); - if (options.hash) - uri.push("#", options.hash); - - return uri.join(""); - } - - function reducePath(parts) { - var balance = 0, result = [], isRoot; - - for (var i = 0; i < parts.length; i++) { - var part = parts[i]; - switch (part) { - case "..": - if (balance > 0) { - result.pop(); - } else { - if (isRoot) - throw new Error("Unbalanced path: " + parts); - - result.push(part); - } - balance--; - break; - case ".": - break; - case "": - if (i === 0) { - isRoot = true; - result.push(part); - } - break; - default: - result.push(part); - balance++; - break; - } - } - - return result.join("/"); - } - - var meta = { - schema : null, - host : null, - port : null, - path : null, - query : null, - hash : null - }; - - var URI = declare(null, { - constructor : function(opts) { - if (typeof (opts) == "string") - opts = parseURI(opts); - for ( var p in meta) - if (p in opts) - this[p] = opts[p]; - }, - - clone : function() { - return new URI(this); - }, - - combine : function(rel) { - var me = this; - - if (typeof (rel) === "string") - rel = new URI(rel); - else - rel = rel.clone(); - - // //some.host:123/path?q=a#123 - if (rel.host) - return rel; - - // /abs/path?q=a#123 - if (rel.path && rel.path[0] == "/") { - if (me.host) { - rel.schema = me.schema; - rel.host = me.host; - rel.port = me.port; - } - return rel; - } - - var base = me.clone(); - - // rel/path?a=b#cd - if (rel.path) { - var segments = base.getSegments(); - segments.pop(); - segments.push.apply(segments, rel.getSegments()); - - base.path = reducePath(segments); - } - - // ?q=a#123 - if (rel.query) - base.query = rel.query; - if (rel.hash) - base.hase = rel.hash; - - return base; - }, - - optimize : function() { - this.path = reducePath(this.getSegments()); - }, - - getSegments : function() { - if (typeof (this.path) === "string") - return this.path.split("/"); - else - return []; - }, - - toString : function() { - var uri = [], me = this; - - if (me.schema) - uri.push(me.schema, ":"); - if (me.host) - uri.push("//", me.host); - if (me.host && me.port) - uri.push(":", me.port); - - if (me.path) { - if (me.host && me.path[0] != "/") - uri.push("/"); - uri.push(me.path); - } else if (me.host) { - uri.push("/"); - } - - if (me.query) - uri.push("?", me.query); - if (me.hash) - uri.push("#", me.hash); - - return uri.join(""); - } - - }); - - URI.combine = function(base, rel) { - if (typeof (base) === "string") - base = new URI(base); - return base.combine(rel).toString(); - }; - - return URI; - }); \ No newline at end of file diff -r 8af8e840dd49 -r 27e8e9e38e07 src/implab/Uuid.js --- a/src/implab/Uuid.js Wed Jun 05 17:44:17 2019 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,278 +0,0 @@ -// uuid.js -// -// Copyright (c) 2010-2012 Robert Kieffer -// MIT License - http://opensource.org/licenses/mit-license.php -define([], function () { - 'use strict'; - - var _window = 'undefined' !== typeof window ? window : null; - - // Unique ID creation requires a high quality random # generator. We - // feature - // detect to determine the best RNG source, normalizing to a function - // that - // returns 128-bits of randomness, since that's what's usually required - var _rng, _mathRNG, _nodeRNG, _whatwgRNG, _previousRoot; - - function setupBrowser() { - // Allow for MSIE11 msCrypto - var _crypto = _window.crypto || _window.msCrypto; - - if (!_rng && _crypto && _crypto.getRandomValues) { - // WHATWG crypto-based RNG - http://wiki.whatwg.org/wiki/Crypto - // - // Moderately fast, high quality - try { - var _rnds8 = new Uint8Array(16); - _whatwgRNG = _rng = function whatwgRNG() { - _crypto.getRandomValues(_rnds8); - return _rnds8; - }; - _rng(); - } catch (e) { /**/ } - } - - if (!_rng) { - // Math.random()-based (RNG) - // - // If all else fails, use Math.random(). It's fast, but is of - // unspecified - // quality. - var _rnds = new Array(16); - _mathRNG = _rng = function () { - for (var i = 0, r; i < 16; i++) { - if ((i & 0x03) === 0) { - r = Math.random() * 0x100000000; - } - _rnds[i] = r >>> ((i & 0x03) << 3) & 0xff; - } - - return _rnds; - }; - if ('undefined' !== typeof console && console.warn) { - console - .warn("[SECURITY] node-uuid: crypto not usable, falling back to insecure Math.random()"); - } - } - } - - function setupNode() { - // Node.js crypto-based RNG - - // http://nodejs.org/docs/v0.6.2/api/crypto.html - // - // Moderately fast, high quality - if ('function' === typeof require) { - try { - var _rb = require('crypto').randomBytes; - _nodeRNG = _rng = _rb && function () { - return _rb(16); - }; - _rng(); - } catch (e) { /**/ } - } - } - - if (_window) { - setupBrowser(); - } else { - setupNode(); - } - - // Buffer class to use - var BufferClass = ('function' === typeof Buffer) ? Buffer : Array; - - // Maps for number <-> hex string conversion - var _byteToHex = []; - var _hexToByte = {}; - for (var i = 0; i < 256; i++) { - _byteToHex[i] = (i + 0x100).toString(16).substr(1); - _hexToByte[_byteToHex[i]] = i; - } - - // **`parse()` - Parse a UUID into it's component bytes** - function parse(s, buf, offset) { - var i = (buf && offset) || 0, - ii = 0; - - buf = buf || []; - s.toLowerCase().replace(/[0-9a-f]{2}/g, function (oct) { - if (ii < 16) { // Don't overflow! - buf[i + ii++] = _hexToByte[oct]; - } - }); - - // Zero out remaining bytes if string was short - while (ii < 16) { - buf[i + ii++] = 0; - } - - return buf; - } - - // **`unparse()` - Convert UUID byte array (ala parse()) into a string** - function unparse(buf, offset) { - var i = offset || 0, - bth = _byteToHex; - return bth[buf[i++]] + bth[buf[i++]] + bth[buf[i++]] + - bth[buf[i++]] + '-' + bth[buf[i++]] + bth[buf[i++]] + '-' + - bth[buf[i++]] + bth[buf[i++]] + '-' + bth[buf[i++]] + - bth[buf[i++]] + '-' + bth[buf[i++]] + bth[buf[i++]] + - bth[buf[i++]] + bth[buf[i++]] + bth[buf[i++]] + bth[buf[i++]]; - } - - // **`v1()` - Generate time-based UUID** - // - // Inspired by https://github.com/LiosK/UUID.js - // and http://docs.python.org/library/uuid.html - - // random #'s we need to init node and clockseq - var _seedBytes = _rng(); - - // Per 4.5, create and 48-bit node id, (47 random bits + multicast bit = - // 1) - var _nodeId = [ - _seedBytes[0] | 0x01, - _seedBytes[1], - _seedBytes[2], - _seedBytes[3], - _seedBytes[4], - _seedBytes[5] - ]; - - // Per 4.2.2, randomize (14 bit) clockseq - var _clockseq = (_seedBytes[6] << 8 | _seedBytes[7]) & 0x3fff; - - // Previous uuid creation time - var _lastMSecs = 0, - _lastNSecs = 0; - - // See https://github.com/broofa/node-uuid for API details - function v1(options, buf, offset) { - var i = buf && offset || 0; - var b = buf || []; - - options = options || {}; - - var clockseq = (options.clockseq != null) ? options.clockseq : _clockseq; - - // UUID timestamps are 100 nano-second units since the Gregorian - // epoch, - // (1582-10-15 00:00). JSNumbers aren't precise enough for this, so - // time is handled internally as 'msecs' (integer milliseconds) and - // 'nsecs' - // (100-nanoseconds offset from msecs) since unix epoch, 1970-01-01 - // 00:00. - var msecs = (options.msecs != null) ? options.msecs : new Date() - .getTime(); - - // Per 4.2.1.2, use count of uuid's generated during the current - // clock - // cycle to simulate higher resolution clock - var nsecs = (options.nsecs != null) ? options.nsecs : _lastNSecs + 1; - - // Time since last uuid creation (in msecs) - var dt = (msecs - _lastMSecs) + (nsecs - _lastNSecs) / 10000; - - // Per 4.2.1.2, Bump clockseq on clock regression - if (dt < 0 && options.clockseq == null) { - clockseq = clockseq + 1 & 0x3fff; - } - - // Reset nsecs if clock regresses (new clockseq) or we've moved onto - // a new - // time interval - if ((dt < 0 || msecs > _lastMSecs) && options.nsecs == null) { - nsecs = 0; - } - - // Per 4.2.1.2 Throw error if too many uuids are requested - if (nsecs >= 10000) { - throw new Error( - 'uuid.v1(): Can\'t create more than 10M uuids/sec'); - } - - _lastMSecs = msecs; - _lastNSecs = nsecs; - _clockseq = clockseq; - - // Per 4.1.4 - Convert from unix epoch to Gregorian epoch - msecs += 12219292800000; - - // `time_low` - var tl = ((msecs & 0xfffffff) * 10000 + nsecs) % 0x100000000; - b[i++] = tl >>> 24 & 0xff; - b[i++] = tl >>> 16 & 0xff; - b[i++] = tl >>> 8 & 0xff; - b[i++] = tl & 0xff; - - // `time_mid` - var tmh = (msecs / 0x100000000 * 10000) & 0xfffffff; - b[i++] = tmh >>> 8 & 0xff; - b[i++] = tmh & 0xff; - - // `time_high_and_version` - b[i++] = tmh >>> 24 & 0xf | 0x10; // include version - b[i++] = tmh >>> 16 & 0xff; - - // `clock_seq_hi_and_reserved` (Per 4.2.2 - include variant) - b[i++] = clockseq >>> 8 | 0x80; - - // `clock_seq_low` - b[i++] = clockseq & 0xff; - - // `node` - var node = options.node || _nodeId; - for (var n = 0; n < 6; n++) { - b[i + n] = node[n]; - } - - return buf ? buf : unparse(b); - } - - // **`v4()` - Generate random UUID** - - // See https://github.com/broofa/node-uuid for API details - function v4(options, buf, offset) { - // Deprecated - 'format' argument, as supported in v1.2 - var i = buf && offset || 0; - - if (typeof (options) === 'string') { - buf = (options === 'binary') ? new BufferClass(16) : null; - options = null; - } - options = options || {}; - - var rnds = options.random || (options.rng || _rng)(); - - // Per 4.4, set bits for version and `clock_seq_hi_and_reserved` - rnds[6] = (rnds[6] & 0x0f) | 0x40; - rnds[8] = (rnds[8] & 0x3f) | 0x80; - - // Copy bytes to buffer, if provided - if (buf) { - for (var ii = 0; ii < 16; ii++) { - buf[i + ii] = rnds[ii]; - } - } - - return buf || unparse(rnds); - } - - // Export public API - var uuid = function () { - return new String(v4()); - }; - uuid.v1 = v1; - uuid.v4 = v4; - uuid.create = v4; - uuid.empty = "00000000-0000-0000-0000-000000000000"; - uuid.parse = parse; - uuid.unparse = unparse; - uuid.BufferClass = BufferClass; - uuid._rng = _rng; - uuid._mathRNG = _mathRNG; - uuid._nodeRNG = _nodeRNG; - uuid._whatwgRNG = _whatwgRNG; - - return uuid; -}); \ No newline at end of file diff -r 8af8e840dd49 -r 27e8e9e38e07 src/implab/components/ActivationController.js --- a/src/implab/components/ActivationController.js Wed Jun 05 17:44:17 2019 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,120 +0,0 @@ -define(["dojo/_base/declare", "../guard", "../safe", "../log/_LogMixin"], function (declare, guard, safe, _LogMixin) { - "use strict"; - return declare([_LogMixin], { - - _current: null, - - _pending: false, - - getCurrent: function () { - return this._current; - }, - - _start: function () { - if (this._pending) - throw new Error("The activation/decativation is already pending"); - this._pending = true; - }, - - _await: function (d) { - var me = this; - return d.then(function (x) { - me._pending = false; - return x; - }, function (e) { - me._pending = false; - throw e; - }); - }, - - activate: function (component) { - safe.argumentNotNull(component, "component"); - var me = this; - if (component.getController() !== this) - throw new Error("The specified component doesn't belong to this controller"); - - return me._await(guard(me, "_start").then(function () { - me._activate(component); - })); - }, - - _activate: function (component) { - var me = this; - if (me._current === component) - return guard(false); - - // before activation hook - return guard(me, "onActivating", [component]).then(function () { - // deactivate curent - if (me._current) - return me._current.deactivate(true).then(function () { - try { - me._current.onDeactivated(); - } catch (err) { - me.error(err); - } - // HACK raise deactivated event - try { - me.onDeactivated(me._current, component); - } catch (err) { - // deactivated shouldn't affect the process - me.error(err); - } - me._current = null; - - }); - }).then(function () { - return component.activate(true); - }).then(function () { - me._current = component; - try { - me.onActivated(component); - } catch (err) { - me.error(err); - } - - }); - - }, - - /** - * Деактивирует текущую компоненту. - * - * @async - * @returns true - компонента была деактивирована, либо нет активной - * компоненты. false - запрос на деактивацию - отклонен. - */ - deactivate: function () { - var me = this; - return me._await(guard(me, "_start").then(function () { - return me._deactivate(); - })); - }, - - _deactivate: function () { - var me = this; - if (!me._current) - return guard(false); - - return guard(me, "onDeactivating").then(function () { - return me._current.deactivate(true); - }).then(function () { - // HACK raise deactivated event - try { - me.onDeactivated(me._current); - } catch (err) { - me.error(err); - } - me._current = null; - }); - }, - - onActivating: function (component) {}, - - onDeactivating: function (component) {}, - - onDeactivated: function (component, next) {}, - - onActivated: function (component) {} - }); -}); \ No newline at end of file diff -r 8af8e840dd49 -r 27e8e9e38e07 src/implab/components/StateMachine.js --- a/src/implab/components/StateMachine.js Wed Jun 05 17:44:17 2019 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,34 +0,0 @@ -define([ "dojo/_base/declare", "../safe", "../text/format" ], function(declare, safe, format) { - return declare(null, { - states : null, - - current : null, - - constructor : function(opts) { - safe.argumentNotNull(opts, "opts"); - safe.argumentNotNull(opts.states, "opts.states"); - safe.argumentNotNull(opts.initial, "opts.initial"); - - this.states = opts.states; - this.current = opts.initial; - - if (safe.isNull(this.states[this.current])) - throw new Error("Invalid initial state " + this.current); - }, - - move : function(input, noThrow) { - safe.argumentNotNull(input, "input"); - - var next = this.states[this.current][input]; - if(safe.isNull(next)) { - if (noThrow) - return false; - else - throw new Error(format("Invalid transition {0}-{1}->?", this.current, input)); - } else { - this.current = next; - return true; - } - } - }); -}); \ No newline at end of file diff -r 8af8e840dd49 -r 27e8e9e38e07 src/implab/components/_ActivatableMixin.js --- a/src/implab/components/_ActivatableMixin.js Wed Jun 05 17:44:17 2019 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,153 +0,0 @@ -define(["dojo/_base/declare", "../guard", "./StateMachine", "../log/_LogMixin", ], function (declare, guard, StateMachine, _LogMixin) { - - var states = { - inactive: { - activate: "activating" - }, - activating: { - success: "active", - failed: "inactive" - }, - active: { - deactivate: "deactivating" - }, - deactivating: { - success: "inactive", - failed: "active" - } - }; - - return declare([_LogMixin], { - _controller: null, - - _active: null, - - constructor: function () { - this._active = new StateMachine({ - states: states, - initial: "inactive" - }); - }, - - /** - * @returns {Object} контроллер для активации текущей компоненты - */ - getController: function () { - return this._controller; - }, - - /** - * @param {Object} - * v Контроллер для активации текущей компоненты - */ - setController: function (v) { - this._controller = v; - }, - - /** - * @returns {Boolean} текущая компонента активна - */ - isActive: function () { - return this._active.current == "active"; - }, - - assertActive: function () { - if (!this.isActive()) - throw new Error("The object must be active to perform the operation"); - }, - - /** - * Активирует текущую компоненту, если у текущей компоненты задан - * контроллер, то активация будет осуществляться через него - * - * @async - * @param{Boolean} - * direct вызов должен осуществится напрямую, без участия - * контроллера. - * @return{Boolean} успешно/неуспешно - */ - activate: function (direct) { - var me = this; - if (!direct && this._controller) - return me._controller.activate(me).then(function () { - me.onActivated(); - }); - - me._active.move("activate"); - return guard(me, "onActivating").then(function () { - me.log("Activated"); - me._active.move("success"); - if (!me._controller) - me.onActivated(); - }, function (err) { - console.error(err); - me.error("Activation failed: {0}", err); - me._active.move("failed"); - throw err; - }); - }, - - /** - * Деактивирует текущую компоненту, если у компоненты задан контроллер, - * то деактивация будет осуществляться через него. - * - * @async - * @param{Boolean} direct вызов должен осуществится напрямую, без - * участия контроллера. - * - */ - deactivate: function (direct) { - var me = this; - if (!direct && me._controller) - return me._controller.deactivate(me).then(function () { - me.onDeactivated(); - }); - - me._active.move("deactivate"); - return guard(me, "onDeactivating").then(function () { - me.log("Deactivated"); - me._active.move("success"); - if (!me._controller) - me.onDeactivated(); - }, function (err) { - console.error(err); - me.error("Deactivation failed: {0}", err); - me.move("failed"); - throw err; - }); - - }, - - toogleActive: function () { - var me = this; - return (me.isActive() ? me.deactivate() : me.activate()).then(function () { - return me.isActive(); - }); - }, - - /** - * Событие вызывается перед активацией текущей компоненты - * - * @returns{Boolean|undefined} если false - активация будет отменена - */ - onActivating: function () {}, - - /** - * Событие вызывается перед деактивацией текущей компоненты - * - * @returns {Boolean|undefined} если false - деактивация будет отменена - */ - onDeactivating: function () {}, - - /** - * Событие вызывается после активации текущей компоненты - */ - onActivated: function () {}, - - /** - * Событие вызывается после деактивации текущей компоненты - */ - onDeactivated: function () {} - - }); -}); \ No newline at end of file diff -r 8af8e840dd49 -r 27e8e9e38e07 src/implab/data/DataContext.js --- a/src/implab/data/DataContext.js Wed Jun 05 17:44:17 2019 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,45 +0,0 @@ -define([ "dojo/_base/declare", "../safe" ], function(declare, safe) { - return declare( - null, - { - _params : null, - - _repositories : null, - - constructor : function(opts) { - this._params = opts || {}; - this._repositories = {}; - }, - - getRepository : function(name) { - safe.argumentNotEmptyString(name, "name"); - var repo = this._repositories[name]; - if (!repo) { - repo = this._params[name]; - if (!repo) - throw new Error("The repository '" + name + - "' isn't found"); - if (repo instanceof Function) - repo = new repo(); // factory method or constructor - if (repo.initialize) { - repo.initialize({ - dataContext : this - }); - } else if (repo.setDataContext) { - repo.setDataContext(this); - } - this._repositories[name] = repo; - } - - return repo; - }, - - dispose : function() { - for( var name in this._repositories) { - var r = this._repositories[name]; - if (r.dispose) - r.dispose(); - } - } - }); -}); \ No newline at end of file diff -r 8af8e840dd49 -r 27e8e9e38e07 src/implab/data/MapSchema.js --- a/src/implab/data/MapSchema.js Wed Jun 05 17:44:17 2019 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,67 +0,0 @@ -define([ "dojo/_base/declare", "../safe" ], function(declare, safe) { - return declare(null, { - /** - * Отображение одного типа объектов в другой. - * - * @remarks Отображения являются односторонними, т.е. позволяют - * перенести часть содержимого одного объекта в другой. Каждая - * схема отображения строится из набора примитивных - * отображений, которые будут применены в произвольном порядке. - */ - _schema : null, - - constructor : function(schema) { - this._schema = schema; - }, - - /** - * Осуществляет отображение одного объекта в другой - * - * @src{Object} Исходный объект из которого будут взяты данные - * @dst{Object} - */ - map : function(src, dst, ctx) { - safe.argumentNotNull(src, "src"); - safe.argumentNotNull(dst, "dst"); - - for ( var p in this._schema) { - var mapper = this._schema[p]; - if (mapper instanceof Function) { - dst[p] = mapper(src[p]); - } else if (mapper && mapper.map) { - mapper.map(src, dst, p, ctx); - } else { - this._defaultMapper(src, dst, p, mapper, ctx); - } - } - }, - - _defaultMapper : function(src, dst, prop, opts) { - if (typeof (opts) == "string") { - if (opts in src) - dst[prop] = src[opts]; - } else if (opts && opts.type instanceof Function) { - if (src[prop] instanceof opts.type) - dst[prop] = src[prop]; - else - dst[prop] = this._isPrimitiveType(opts.type) ? opts.type - .call(null, src[prop]) : new opts.type(src[prop]); - - } else { - if (!(prop in src)) - if (opts && opts.required) - throw new Error("The " + prop + "is missing"); - else - return; - dst[prop] = src[prop]; - } - }, - - _isPrimitiveType : function(type) { - return (type === String || type === Number || type === Boolean - || type === Number || type === Date); - } - - }); - -}); \ No newline at end of file diff -r 8af8e840dd49 -r 27e8e9e38e07 src/implab/data/ObjectStore.js --- a/src/implab/data/ObjectStore.js Wed Jun 05 17:44:17 2019 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,174 +0,0 @@ -define([ "dojo/_base/declare", "dojo/_base/lang", "dojo/_base/array", - "../safe", "dojo/when", "dojo/Deferred", "dojo/store/util/QueryResults" ], function(declare, - lang, array, safe, when, Deferred, QueryResults) { - /** - * @module implab/data/RestStore - * - * Реализует шаблон репозитария dojo/store над уже имеющимся хранилищем. При получении и - * отправке данных в нижележащие хранилище используется implab/data/MapSchema для преобразования - * данных. - */ - return declare(null, { - - model: null, - - mapping: null, - - _dataContext: null, - - _store : null, // backing store - - _cache : null, - - constructor : function(options) { - options = options || {}; - - if (options.store) - this._store = options.store; - - if (options.dataContext) { - this._dataContext = options.dataContext; - } - - if (options.cache === false) { - // no cache at all - } else if (options.cache === "string" && options.dataContext) { - this._cache = this._dataContext.getCache(options.cache); - } else { - this._cache = {}; - } - }, - - getDataContext : function() { - return this._dataContext; - }, - - // READ - get : function(id) { - var me = this; - var cache = me.getCacheEntry(id); - if (cache) - return cache; - else - return when(me._store.get(id), function(data) { - return me._mapToObject(id, data); - }); - }, - - query : function(query, options) { - var me = this; - var d = me._store.query(query, options); - var result = QueryResults(when(d, function(data) { - return array.map(data, function(item) { - return me._mapToObject(me._store.getIdentity(item), item); - }); - })); - result.total = d.total; - return result; - }, - - getIdentity : function(object) { - return object.getId(); - }, - - // UPDATE - put : function(object, directives) { - return this._store.put(this._mapFromObject(object), directives); - }, - - // INSERT - add : function(object, directives) { - var me = this; - // добавляем в хранилище данные, сохраняем в кеше объект с - // полученным идентификатором - return when( - me._store.add(this._mapFromObject(object), directives), - function(id) { - object.attach(id, me); - me.storeCacheEntry(id, object); - return id; - }); - }, - - // DELETE - remove : function(id) { - var me = this; - return when(me._store.remove(id), function() { - me.removeCacheEntry(id); - }); - }, - - _mapToObject : function(id, data) { - var instance = this.createInstance(id); - this.populateInstance(instance, data); - return instance; - }, - - _mapFromObject : function(object) { - return this.serializeInstance(object); - }, - - getCacheEntry : function(id) { - safe.argumentNotNull(id, "id"); - id = id.toString(); - - return this._cache[id]; - }, - - storeCacheEntry : function(id, object) { - safe.argumentNotNull(id, "id"); - id = id.toString(); - - this._cache[id] = object; - }, - - removeCacheEntry : function(id) { - safe.argumentNotNull(id, "id"); - id = id.toString(); - delete this._cache[id]; - }, - - /** Создает экземпляр сущности с указанным идентификатором, либо извлекает из кеша, если таковая уже имеется. - * @remarks - * Технически сюда можно было бы дополнительно передать данные для ининциализации объекта, - * но концептуально это не верно, поскольку процесс чтения объекта состоит из двух этапов: - * 1. Создание пустого объекта (createInstance) - * 2. Заполнение объекта при помощи схемы отображения (populateInstance) - * при этом первый этап может быть выполнен за долго до второго, например, - * при создании заглушек в процессе установления ссылок между объектами. - */ - createInstance : function(id) { - var instance = this.getCacheEntry(id); - if (!instance) { - instance = this.createInstanceImpl(id); - this.storeCacheEntry(id, instance); - } - return instance; - }, - - /** Непосредственно создает экземпляр сущнсти, т.е. является фабричным методом. - * @param {String} id идентификатор создаваемого экземпляра. - */ - createInstanceImpl : function(id) { - var opts = { - dataContext : this.getDataContext(), - id : id - }; - - return new this.itemsType(opts); - }, - - populateInstance : function(instance, data) { - this.mapping.readData(instance, data,this.getDataContext()); - if (instance.onPopulate) - instance.onPopulate(); - }, - - serializeInstance : function(instance) { - var data = {}; - this.mapping.writeData(instance, data, this.getDataContext()); - return data; - } - - }); -}); \ No newline at end of file diff -r 8af8e840dd49 -r 27e8e9e38e07 src/implab/data/RestStore.js --- a/src/implab/data/RestStore.js Wed Jun 05 17:44:17 2019 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,166 +0,0 @@ -define([ "dojo/_base/declare", "dojo/_base/lang", "dojo/_base/array", - "../safe", "dojo/when", "dojo/Deferred", "dojo/store/util/QueryResults" ], function(declare, - lang, array, safe, when, Deferred, QueryResults) { - /** - * @module implab/data/RestStore - * - * Реализует шаблон репозитария dojo/store над уже имеющимся хранилищем. При получении и - * отправке данных в нижележащие хранилище используется implab/data/MapSchema для преобразования - * данных. - */ - return declare(null, { - - itemsType : null, - - _dataContext : null, - - _store : null, // backing store - _cache : null, - - constructor : function(options) { - options = options || {}; - - this._cache = {}; - if (options.store) - this._store = options.store; - if (options.dataContext) - this._dataContext = options.dataContext; - }, - - setDataContext : function(v) { - this._dataContext = v; - }, - - getDataContext : function() { - return this._dataContext; - }, - - // READ - get : function(id) { - var me = this; - var cache = me.getCacheEntry(id); - if (cache) - return cache; - else - return when(me._store.get(id), function(data) { - return me._mapToObject(id, data); - }); - }, - - query : function(query, options) { - var me = this; - var d = me._store.query(query, options); - var result = QueryResults(when(d, function(data) { - return array.map(data, function(item) { - return me._mapToObject(me._store.getIdentity(item), item); - }); - })); - result.total = d.total; - return result; - }, - - getIdentity : function(object) { - return object.getId(); - }, - - // UPDATE - put : function(object, directives) { - return this._store.put(this._mapFromObject(object), directives); - }, - - // INSERT - add : function(object, directives) { - var me = this; - // добавляем в хранилище данные, сохраняем в кеше объект с - // полученным идентификатором - return when( - me._store.add(this._mapFromObject(object), directives), - function(id) { - object.attach(id, me); - me.storeCacheEntry(id, object); - return id; - }); - }, - - // DELETE - remove : function(id) { - var me = this; - return when(me._store.remove(id), function() { - me.removeCacheEntry(id); - }); - }, - - _mapToObject : function(id, data) { - var instance = this.createInstance(id); - this.populateInstance(instance, data); - return instance; - }, - - _mapFromObject : function(object) { - return this.serializeInstance(object); - }, - - getCacheEntry : function(id) { - safe.argumentNotNull(id, "id"); - id = id.toString(); - - return this._cache[id]; - }, - - storeCacheEntry : function(id, object) { - safe.argumentNotNull(id, "id"); - id = id.toString(); - - this._cache[id] = object; - }, - - removeCacheEntry : function(id) { - safe.argumentNotNull(id, "id"); - id = id.toString(); - delete this._cache[id]; - }, - - /** Создает экземпляр сущности с указанным идентификатором, либо извлекает из кеша, если таковая уже имеется. - * @remarks - * Технически сюда можно было бы дополнительно передать данные для ининциализации объекта, - * но концептуально это не верно, поскольку процесс чтения объекта состоит из двух этапов: - * 1. Создание пустого объекта (createInstance) - * 2. Заполнение объекта при помощи схемы отображения (populateInstance) - * при этом первый этап может быть выполнен за долго до второго, например, - * при создании заглушек в процессе установления ссылок между объектами. - */ - createInstance : function(id) { - var instance = this.getCacheEntry(id); - if (!instance) { - instance = this.createInstanceImpl(id); - this.storeCacheEntry(id, instance); - } - return instance; - }, - - /** Непосредственно создает экземпляр сущнсти, т.е. является фабричным методом. - * @param {String} id идентификатор создаваемого экземпляра. - */ - createInstanceImpl : function(id) { - var opts = { - dataContext : this.getDataContext(), - id : id - }; - - return new this.itemsType(opts); - }, - - populateInstance : function(instance, data) { - this.itemsType.readData(instance, data,this.getDataContext()); - if (instance.onPopulate) - instance.onPopulate(); - }, - - serializeInstance : function(instance) { - var data = {}; - this.itemsType.writeData(instance, data, this.getDataContext()); - return data; - } - - }); -}); \ No newline at end of file diff -r 8af8e840dd49 -r 27e8e9e38e07 src/implab/data/StatefullStoreAdapter.js --- a/src/implab/data/StatefullStoreAdapter.js Wed Jun 05 17:44:17 2019 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,19 +0,0 @@ -define(["dojo/_base/declare", "dojo/_base/array", "../safe", "./StoreAdapter"], function(declare, array, safe ,AdapterStore){ - return declare([AdapterStore], { - _attrs : null, - - constructor : function(opts) { - safe.argumentNotEmptyArray(opts.attrs, "opts.attrs"); - this._attrs = opts.attrs; - }, - - mapItem : function(item) { - var result = {}; - array.forEach(this._attrs, function(p) { - result[p] = item.get(p); - }); - return result; - } - }); - -}); \ No newline at end of file diff -r 8af8e840dd49 -r 27e8e9e38e07 src/implab/data/StoreAdapter.js --- a/src/implab/data/StoreAdapter.js Wed Jun 05 17:44:17 2019 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,110 +0,0 @@ -define([ - "dojo/_base/declare", - "../safe", - "dojo/when", - "dojo/store/util/QueryResults" ], - -function(declare, safe, when, QueryResults) { - - "use strict"; - - /** - * Обертка вокруг произвольного хранилища, только для чтения. Используется - * для преобразования данных, например, отображения в списках элементов - * пространственных данных. - */ - return declare(null, { - /** - * @type{String} Свойство, хранящее идентификатор - */ - idProperty : null, - - _store : null, - - /** - * @param{String} opts.idProperty Имя свойства, в которое будет записан - * идентификатор, если не указан, то идентификатор будет - * взят из родительского хранилища или использоваться - * строка id - * @param{dojo.store} opts.store Родительское хранилище - */ - constructor : function(opts) { - safe.argumentNotNull(opts, "opts"); - safe.argumentNotNull(opts.store, "opts.store"); - - this._store = opts.store; - delete opts.store; - declare.safeMixin(this, opts); - this.idProperty = opts.idProperty || this._store.idProperty || "id"; - }, - - getParentStore : function() { - return this._store; - }, - - get : function(id) { - var me = this; - return when(me._store.get(id), function(x) { - var m = me.mapItem(x); - if (!(me.idProperty in m)) - m[me.idProperty] = id; - return m; - }); - }, - - /** - * Выполняет запрос в родительском хранилище, для этого используется - * translateQuery для подготовки запроса, затем, - * mapItem для преобразования результатов. - */ - query : function(q, options) { - var me = this, store = this._store; - return when(store.query(me.translateQuery(q), me - .translateOptions(options)), function(res) { - var total = res.total; - var mapped = res.map(function(x) { - var m = me.mapItem(x); - if (!(me.idProperty in m)) - m[me.idProperty] = store.getIdentity && - store.getIdentity(x); - return m; - }); - mapped.total = total; - var results = new QueryResults(mapped); - console.log(results); - return results; - }); - }, - - getIdentity : function(obj) { - return obj && obj[this.idProperty]; - }, - - /** - * Преобразование запроса в формат родительского хранилища. - * - * @param{Object} q Запрос в формате текущего хранилища - * @returns{Object} Запрос в формате родительского хранилища - */ - translateQuery : function(q) { - return q; - }, - - translateOptions : function(options) { - return options; - }, - - /** - * Преобразование объекта из родительского хранилища. При преобразовании - * в объекте можно задать идентификатор, иначе идентификатор будет - * автоматически получен и присвоен из родительского хранилища - * - * @param{Object} item Объект из родительского хранилища - * @returns{Object} результат преобразования - */ - mapItem : function(item) { - return item; - } - }); - -}); \ No newline at end of file diff -r 8af8e840dd49 -r 27e8e9e38e07 src/implab/data/_ModelBase.js --- a/src/implab/data/_ModelBase.js Wed Jun 05 17:44:17 2019 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,37 +0,0 @@ -define(["dojo/_base/declare"], function(declare) { - - return declare(null, { - dataContext : null, - idField : "id", - loaded : false, - - constructor : function(opts){ - if (opts) { - if(opts.dataContext) - this.dataContext = opts.dataContext; - if(opts.id) - this[this.idField] = opts.id; - } - }, - - getId : function() { - return this[this.idField]; - }, - - attach : function(id, dc) { - if (this.dataContext) - throw new Error("The object is already attached"); - this[this.idField] = id; - this.dataContext = dc; - }, - - isAttached : function() { - return this.dataContext ? true : false; - }, - - onPopulate : function() { - this.loaded = true; - } - - }); -}); \ No newline at end of file diff -r 8af8e840dd49 -r 27e8e9e38e07 src/implab/data/_StatefulModelMixin.js --- a/src/implab/data/_StatefulModelMixin.js Wed Jun 05 17:44:17 2019 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,5 +0,0 @@ -define(["dojo/_base/declare", "dojo/Stateful"], function(declare, Stateful) { - return declare([Stateful], { - - }); -}); \ No newline at end of file diff -r 8af8e840dd49 -r 27e8e9e38e07 src/implab/data/declare-model.js --- a/src/implab/data/declare-model.js Wed Jun 05 17:44:17 2019 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,72 +0,0 @@ -define([ "dojo/_base/declare", "./_ModelBase", "./MapSchema" ], function( - declare, _ModelBase, MapSchema) { - /** - * Создает новый класс, унаследованный от ./ModelBase, с указанной схемой - * отображения данных. - * - * @details Модель представляет собой объект, живущий в рамках контекста - * данных, также имеющий две схемы отображения: из модели хранения - * в источнике данных (toObjectMap) и наооборот в модель хранения в - * источнике данных (fromObjectMap). - * - * Описание схемы выглядит следующим образом - *
-     * {
-     *      name : null, // отображение в обе стороны без преобразования
-     *      
-     *      age : Number,   // при преобразоваении к объекту поле будет преобразовано dst.age = Number(src.age)
-     *                      // обратное преобразование отсутстсвует
-     *      
-     *      age : [Number, null] // тоже самое что и age : Number
-     *      
-     *      date : [Date, function(v) { return v.toString() }] // указывается преобразование в одну и в другую сторону
-     * }
-     * 
-     */
-    return function(schema, mixins, opts) {
-        var fromObjectSchema = {}, toObjectSchema = {};
-        if (schema !== null && schema !== undefined) {
-            for ( var p in schema) {
-                var mapper = schema[p];
-
-                if (mapper instanceof Array) {
-                    toObjectSchema[p] = mapper[0];
-                    fromObjectSchema[p] = mapper[1];
-                } else {
-                    toObjectSchema[p] = mapper;
-                    fromObjectSchema[p] = null;
-                }
-            }
-        }
-
-        if (arguments.length < 3) {
-            opts = mixins;
-            mixins = undefined;
-        }
-
-        var base = [ _ModelBase ];
-        if (mixins) {
-            if (mixins instanceof Array)
-                base = base.concat(mixins);
-            else
-                base.push(mixins);
-        }
-
-        var model = declare(base, opts);
-
-        model.toObjectMap = new MapSchema(toObjectSchema);
-
-        model.fromObjectMap = new MapSchema(fromObjectSchema);
-
-        model.readData = function(that, data, context) {
-            model.toObjectMap.map(data, that, context);
-        };
-
-        model.writeData = function(that, data, context) {
-            data = data || {};
-            model.fromObjectMap.map(that, data, context);
-        };
-
-        return model;
-    };
-});
\ No newline at end of file
diff -r 8af8e840dd49 -r 27e8e9e38e07 src/implab/declare.js
--- a/src/implab/declare.js	Wed Jun 05 17:44:17 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,6 +0,0 @@
-define([
-    './declare/_load!'
-], function(declare) {
-    'use strict';
-    return declare;
-});
\ No newline at end of file
diff -r 8af8e840dd49 -r 27e8e9e38e07 src/implab/declare/_load.js
--- a/src/implab/declare/_load.js	Wed Jun 05 17:44:17 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,12 +0,0 @@
-define([], function () {
-    'use strict';
-
-    return {
-        load: function (id, require, callback) {
-            require(['dojo/_base/declare'], function (declare) {
-                callback(declare);
-            });
-        }
-    };
-
-});
\ No newline at end of file
diff -r 8af8e840dd49 -r 27e8e9e38e07 src/implab/declare/override.js
--- a/src/implab/declare/override.js	Wed Jun 05 17:44:17 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,73 +0,0 @@
-"use strict";
-define([], function () {
-    var slice = Array.prototype.slice;
-    var override = function (method) {
-        var proxy;
-
-        /** @this target object */
-        proxy = function () {
-            var me = this;
-            var inherited = (this.getInherited && this.getInherited(proxy.nom, {
-                callee: proxy
-            })) || function () {};
-
-            return method.apply(me, [function () {
-                return inherited.apply(me, arguments);
-            }].concat(slice.apply(arguments)));
-        };
-
-        proxy.method = method;
-        proxy.overrides = true;
-
-        return proxy;
-    };
-
-    override.before = function (method) {
-        var proxy;
-
-        /** @this target object */
-        proxy = function () {
-            var me = this;
-            var inherited = (this.getInherited && this.getInherited(proxy.nom, {
-                callee: proxy
-            })) || function () {};
-
-
-            method.apply(me, arguments);
-            return inherited.apply(me, arguments);
-        };
-
-        proxy.method = method;
-        proxy.overrides = true;
-
-        return proxy;
-    };
-
-    override.after = function (method) {
-        var proxy;
-
-        /** @this target object */
-        proxy = function () {
-            var me = this;
-            var inherited = (this.getInherited && this.getInherited(proxy.nom, {
-                callee: proxy
-            })) || function () {};
-
-            inherited.apply(me, arguments);
-
-            return method.apply(me, arguments);
-        };
-
-        proxy.method = method;
-        proxy.overrides = true;
-
-        return proxy;
-    };
-
-    override.hide = function (method) {
-        method.overrides = false;
-        return method;
-    };
-
-    return override;
-});
\ No newline at end of file
diff -r 8af8e840dd49 -r 27e8e9e38e07 src/implab/di/ActivationContext.js
--- a/src/implab/di/ActivationContext.js	Wed Jun 05 17:44:17 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,138 +0,0 @@
-define([
-    "../declare",
-    "../safe",
-    "./Descriptor",
-    "./ValueDescriptor",
-    "../log/trace!"
-], function (declare, safe, Descriptor, Value, trace) {
-    var Context = declare(null, {
-
-        _cache: null,
-
-        _services: null,
-
-        _stack: null,
-
-        _visited: null,
-
-        container: null,
-
-        _trace: true,
-
-        constructor: function (container, services, cache, visited) {
-            safe.argumentNotNull(container, "container");
-            safe.argumentNotNull(services, "services");
-
-            this._visited = visited || {};
-            this._stack = [];
-            this._cache = cache || {};
-            this._services = services;
-            this.container = container;
-        },
-
-        getService: function (name, def) {
-            var d = this._services[name];
-
-            if (!d)
-                if (arguments.length > 1)
-                    return def;
-                else
-                    throw new Error("Service '" + name + "' not found");
-
-            return d.activate(this, name);
-        },
-
-        /**
-         * registers services local to the the activation context
-         * 
-         * @name{string} the name of the service
-         * @service{string} the service descriptor to register
-         */
-        register: function (name, service) {
-            safe.argumentNotEmptyString(name, "name");
-
-            if (!(service instanceof Descriptor))
-                service = new Value(service, true);
-            this._services[name] = service;
-        },
-
-        clone: function () {
-            return new Context(
-                this.container,
-                Object.create(this._services),
-                this._cache,
-                this._visited
-            );
-
-        },
-
-        has: function (id) {
-            return id in this._cache;
-        },
-
-        get: function (id) {
-            return this._cache[id];
-        },
-
-        store: function (id, value) {
-            return (this._cache[id] = value);
-        },
-
-        parse: function (data, name) {
-            var me = this;
-            if (safe.isPrimitive(data))
-                return data;
-
-            if (data instanceof Descriptor) {
-                return data.activate(this, name);
-            } else if (data instanceof Array) {
-                me.enter(name);
-                var v = data.map(function (x, i) {
-                    return me.parse(x, "." + i);
-                });
-                me.leave();
-                return v;
-            } else {
-                me.enter(name);
-                var result = {};
-                for (var p in data)
-                    result[p] = me.parse(data[p], "." + p);
-                me.leave();
-                return result;
-            }
-        },
-
-        visit: function (id) {
-            var count = this._visited[id] || 0;
-            this._visited[id] = count + 1;
-            return count;
-        },
-
-        getStack: function () {
-            return this._stack.slice().reverse();
-        },
-
-        enter: function (name, d, localize) {
-            if (this._trace)
-                trace.log("enter " + name + " " + (d || "") +
-                    (localize ? " localize" : ""));
-            this._stack.push({
-                name: name,
-                service: d,
-                scope: this._services
-            });
-            if (localize)
-                this._services = Object.create(this._services);
-        },
-
-        leave: function () {
-            var ctx = this._stack.pop();
-            this._services = ctx.scope;
-
-            if (this._trace)
-                trace.log("leave " + ctx.name + " " + (ctx.service || ""));
-        }
-    });
-
-    return Context;
-});
\ No newline at end of file
diff -r 8af8e840dd49 -r 27e8e9e38e07 src/implab/di/ActivationError.js
--- a/src/implab/di/ActivationError.js	Wed Jun 05 17:44:17 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,39 +0,0 @@
-define([
-    "../declare"
-], function (declare) {
-    return declare(null, {
-        activationStack: null,
-
-        service: null,
-
-        innerException: null,
-
-        message: null,
-
-        constructor: function (service, activationStack, innerException) {
-            this.message = "Failed to activate the service";
-            this.activationStack = activationStack;
-            this.service = service;
-            this.innerException = innerException;
-        },
-
-        toString: function () {
-            var parts = [this.message];
-            if (this.service)
-                parts.push("when activating: " + this.service.toString());
-
-            if (this.innerException)
-                parts.push("caused by: " + this.innerException.toString());
-
-            if (this.activationStack) {
-                parts.push("at");
-                this.activationStack.forEach(function (x) {
-                    parts.push("    " + x.name + " " +
-                        (x.service ? x.service.toString() : ""));
-                });
-            }
-
-            return parts.join("\n");
-        }
-    });
-});
\ No newline at end of file
diff -r 8af8e840dd49 -r 27e8e9e38e07 src/implab/di/Container.js
--- a/src/implab/di/Container.js	Wed Jun 05 17:44:17 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,299 +0,0 @@
-define([
-    "../declare",
-    "../safe",
-    "../Uuid",
-    "../Deferred",
-    "./ActivationContext",
-    "./Descriptor",
-    "./ValueDescriptor",
-    "./ReferenceDescriptor",
-    "./ServiceDescriptor",
-    "./ActivationError"
-], function (
-    declare,
-    safe,
-    Uuid,
-    Deferred,
-    ActivationContext,
-    Descriptor,
-    Value,
-    Reference,
-    Service,
-    ActivationError) {
-    var Container = declare(null, {
-        _services: null,
-        _cache: null,
-        _cleanup: null,
-        _root: null,
-        _parent: null,
-
-        constructor: function (parent) {
-            this._parent = parent;
-            this._services = parent ? Object.create(parent._services) : {};
-            this._cache = {};
-            this._cleanup = [];
-            this._root = parent ? parent.getRootContainer() : this;
-            this._services.container = new Value(this, true);
-        },
-
-        getRootContainer: function () {
-            return this._root;
-        },
-
-        getParent: function () {
-            return this._parent;
-        },
-
-        /**
-         * 
-         */
-        getService: function (name, def) {
-            var d = this._services[name];
-            if (!d)
-                if (arguments.length > 1)
-                    return def;
-                else
-                    throw new Error("Service '" + name + "' isn't found");
-            if (d.isInstanceCreated())
-                return d.getInstance();
-
-            var context = new ActivationContext(this, this._services);
-
-            try {
-                return d.activate(context, name);
-            } catch (error) {
-                throw new ActivationError(name, context.getStack(), error);
-            }
-        },
-
-        register: function (name, service) {
-            if (arguments.length == 1) {
-                var data = name;
-                for (name in data)
-                    this.register(name, data[name]);
-            } else {
-                if (!(service instanceof Descriptor))
-                    service = new Value(service, true);
-                this._services[name] = service;
-            }
-            return this;
-        },
-
-        onDispose: function (callback) {
-            if (!(callback instanceof Function))
-                throw new Error("The callback must be a function");
-            this._cleanup.push(callback);
-        },
-
-        dispose: function () {
-            if (this._cleanup) {
-                for (var i = 0; i < this._cleanup.length; i++)
-                    this._cleanup[i].call(null);
-                this._cleanup = null;
-            }
-        },
-
-        /**
-         * @param{String|Object} config
-         *  The configuration of the contaier. Can be either a string or an object,
-         *  if the configuration is an object it's treated as a collection of
-         *  services which will be registed in the contaier.
-         * 
-         * @param{Function} opts.contextRequire
-         *  The function which will be used to load a configuration or types for services.
-         *  
-         */
-        configure: function (config, opts) {
-            var p, me = this,
-                contextRequire = (opts && opts.contextRequire);
-
-            if (typeof (config) === "string") {
-                p = new Deferred();
-                if (!contextRequire) {
-                    var shim = [config, new Uuid()].join(config.indexOf("/") != -1 ? "-" : "/");
-                    define(shim, ["require", config], function (ctx, data) {
-                        p.resolve([data, {
-                            contextRequire: ctx
-                        }]);
-                    });
-                    require([shim]);
-                } else {
-                    // TODO how to get correct contextRequire for the relative config module?
-                    contextRequire([config], function (data) {
-                        p.resolve([data, {
-                            contextRequire: contextRequire
-                        }]);
-                    });
-                }
-
-                return p.then(function (args) {
-                    return me._configure.apply(me, args);
-                });
-            } else {
-                return me._configure(config, opts);
-            }
-        },
-
-        createChildContainer: function () {
-            return new Container(this);
-        },
-
-        has: function (id) {
-            return id in this._cache;
-        },
-
-        get: function (id) {
-            return this._cache[id];
-        },
-
-        store: function (id, value) {
-            return (this._cache[id] = value);
-        },
-
-        _configure: function (data, opts) {
-            var typemap = {},
-                d = new Deferred(),
-                me = this,
-                p,
-                contextRequire = (opts && opts.contextRequire) || require;
-
-            var services = {};
-
-            for (p in data) {
-                var service = me._parse(data[p], typemap);
-                if (!(service instanceof Descriptor))
-                    service = new Value(service, false);
-                services[p] = service;
-            }
-
-            me.register(services);
-
-            var names = [];
-
-            for (p in typemap)
-                names.push(p);
-
-            if (names.length) {
-                contextRequire(names, function () {
-                    for (var i = 0; i < names.length; i++)
-                        typemap[names[i]] = arguments[i];
-                    d.resolve(me);
-                });
-            } else {
-                d.resolve(me);
-            }
-            return d.promise;
-        },
-
-        _parse: function (data, typemap) {
-            if (safe.isPrimitive(data) || data instanceof Descriptor)
-                return data;
-            if (data.$dependency)
-                return new Reference(
-                    data.$dependency,
-                    data.lazy,
-                    data.optional,
-                    data["default"],
-                    data.services && this._parseObject(data.services, typemap));
-            if (data.$value) {
-                var raw = !data.parse;
-                return new Value(raw ? data.$value : this._parse(
-                    data.$value,
-                    typemap), raw);
-            }
-            if (data.$type || data.$factory)
-                return this._parseService(data, typemap);
-            if (data instanceof Array)
-                return this._parseArray(data, typemap);
-
-            return this._parseObject(data, typemap);
-        },
-
-        _parseService: function (data, typemap) {
-            var me = this,
-                opts = {
-                    owner: this
-                };
-            if (data.$type) {
-
-                opts.type = data.$type;
-
-                if (typeof (data.$type) === "string") {
-                    typemap[data.$type] = null;
-                    opts.typeMap = typemap;
-                }
-            }
-
-            if (data.$factory)
-                opts.factory = data.$factory;
-
-            if (data.services)
-                opts.services = me._parseObject(data.services, typemap);
-            if (data.inject)
-                opts.inject = data.inject instanceof Array ? data.inject.map(function (x) {
-                    return me._parseObject(x, typemap);
-                }) : me._parseObject(data.inject, typemap);
-            if (data.params)
-                opts.params = me._parse(data.params, typemap);
-
-            if (data.activation) {
-                if (typeof (data.activation) === "string") {
-                    switch (data.activation.toLowerCase()) {
-                        case "singleton":
-                            opts.activation = Service.SINGLETON;
-                            break;
-                        case "container":
-                            opts.activation = Service.CONTAINER;
-                            break;
-                        case "hierarchy":
-                            opts.activation = Service.HIERARCHY;
-                            break;
-                        case "context":
-                            opts.activation = Service.CONTEXT;
-                            break;
-                        case "call":
-                            opts.activation = Service.CALL;
-                            break;
-                        default:
-                            throw new Error("Unknown activation type: " +
-                                data.activation);
-                    }
-                } else {
-                    opts.activation = Number(data.activation);
-                }
-            }
-
-            if (data.cleanup)
-                opts.cleanup = data.cleanup;
-
-            return new Service(opts);
-        },
-
-        _parseObject: function (data, typemap) {
-            if (data.constructor &&
-                data.constructor.prototype !== Object.prototype)
-                return new Value(data, true);
-
-            var o = {};
-
-            for (var p in data)
-                o[p] = this._parse(data[p], typemap);
-
-            return o;
-        },
-
-        _parseArray: function (data, typemap) {
-            if (data.constructor &&
-                data.constructor.prototype !== Array.prototype)
-                return new Value(data, true);
-
-            var me = this;
-            return data.map(function (x) {
-                return me._parse(x, typemap);
-            });
-        }
-
-    });
-
-    return Container;
-});
\ No newline at end of file
diff -r 8af8e840dd49 -r 27e8e9e38e07 src/implab/di/Descriptor.js
--- a/src/implab/di/Descriptor.js	Wed Jun 05 17:44:17 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,4 +0,0 @@
-define([], function() {
-    // abstract base type for descriptros
-    return function() {};
-});
\ No newline at end of file
diff -r 8af8e840dd49 -r 27e8e9e38e07 src/implab/di/ReferenceDescriptor.js
--- a/src/implab/di/ReferenceDescriptor.js	Wed Jun 05 17:44:17 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,90 +0,0 @@
-define([
-    "../declare", "../safe", "./Descriptor", "./ActivationError", "./ValueDescriptor"
-],
-
-function(declare, safe, Descriptor, ActivationError, Value) {
-    return declare(Descriptor, {
-        _name : null,
-        _lazy : false,
-        _optional : false,
-        _default : undefined,
-
-        constructor : function(name, lazy, optional, def, services) {
-            safe.argumentNotEmptyString(name, "name");
-            this._name = name;
-            this._lazy = Boolean(lazy);
-            this._optional = Boolean(optional);
-            this._default = def;
-            this._services = services;
-        },
-
-        activate : function(context, name) {
-            var me = this;
-
-            context.enter(name, this, true);
-
-            // добавляем сервисы
-            if (me._services) {
-                for ( var p in me._services) {
-                    var sv = me._services[p];
-                    context.register(p, sv instanceof Descriptor ? sv : new Value(sv, false));
-                }
-            }
-
-            if (me._lazy) {
-                // сохраняем контекст активации
-                context = context.clone();
-                return function(cfg) {
-                    // защищаем контекст на случай исключения в процессе
-                    // активации
-                    var ct = context.clone();
-                    try {
-                        if (cfg)
-                            safe.each(cfg, function(v, k) {
-                                ct.register(k, v instanceof Descriptor ? v : new Value(v, false));
-                            });
-                        return me._optional ? ct.getService(me._name, me._default) : ct
-                            .getService(me._name);
-                    } catch (error) {
-                        throw new ActivationError(me._name, ct.getStack(), error);
-                    }
-                };
-            }
-
-            var v = me._optional ? context.getService(me._name, me._default) : context
-                .getService(me._name);
-            context.leave(me);
-            return v;
-        },
-
-        isInstanceCreated : function() {
-            return false;
-        },
-
-        toString : function() {
-            var opts = [];
-            if (this._optional)
-                opts.push("optional");
-            if (this._lazy)
-                opts.push("lazy");
-
-            var parts = [
-                "@ref "
-            ];
-            if (opts.length) {
-                parts.push("{");
-                parts.push(opts.join());
-                parts.push("} ");
-            }
-
-            parts.push(this._name);
-
-            if (!safe.isNull(this._default)) {
-                parts.push(" = ");
-                parts.push(this._default);
-            }
-
-            return parts.join("");
-        }
-    });
-});
\ No newline at end of file
diff -r 8af8e840dd49 -r 27e8e9e38e07 src/implab/di/ServiceDescriptor.js
--- a/src/implab/di/ServiceDescriptor.js	Wed Jun 05 17:44:17 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,289 +0,0 @@
-define(
-    [
-        "../declare",
-        "../safe",
-        "./Descriptor",
-        "./ValueDescriptor"
-    ],
-
-    function (declare, safe, Descriptor, Value) {
-        var SINGLETON_ACTIVATION = 1,
-            CONTAINER_ACTIVATION = 2,
-            CONTEXT_ACTIVATION = 3,
-            CALL_ACTIVATION = 4,
-            HIERARCHY_ACTIVATION = 5;
-
-        var injectMethod = function (target, method, context, args) {
-            var m = target[method];
-            if (!m)
-                throw new Error("Method '" + method + "' not found");
-
-            if (args instanceof Array)
-                m.apply(target, context.parse(args, "." + method));
-            else
-                m.call(target, context.parse(args, "." + method));
-        };
-
-        var makeClenupCallback = function (target, method) {
-            if (typeof (method) === "string") {
-                return function () {
-                    target[method]();
-                };
-            } else {
-                return function () {
-                    method(target);
-                };
-            }
-        };
-
-        var cacheId = 0;
-
-        var cls = declare(
-            Descriptor, {
-                _instance: null,
-                _hasInstance: false,
-                _activationType: CALL_ACTIVATION,
-                _services: null,
-                _type: null,
-                _typeMap: null,
-                _factory: null,
-                _params: undefined,
-                _inject: null,
-                _cleanup: null,
-                _cacheId: null,
-                _owner: null,
-
-                constructor: function (opts) {
-                    safe.argumentNotNull(opts, "opts");
-                    safe.argumentNotNull(opts.owner, "opts.owner");
-
-                    this._owner = opts.owner;
-
-                    if (!(opts.type || opts.factory))
-                        throw new Error(
-                            "Either a type or a factory must be specified");
-
-                    if (typeof (opts.type) === "string" && !opts.typeMap)
-                        throw new Error(
-                            "The typeMap is required when the type is specified by its name");
-
-                    if (opts.activation)
-                        this._activationType = opts.activation;
-                    if (opts.type)
-                        this._type = opts.type;
-                    if (opts.params)
-                        this._params = opts.params;
-                    if (opts.inject)
-                        this._inject = opts.inject instanceof Array ? opts.inject : [opts.inject];
-                    if (opts.services)
-                        this._services = opts.services;
-                    if (opts.factory)
-                        this._factory = opts.factory;
-                    if (opts.typeMap)
-                        this._typeMap = opts.typeMap;
-                    if (opts.cleanup) {
-                        if (!(typeof (opts.cleanup) === "string" || opts.cleanup instanceof Function))
-                            throw new Error(
-                                "The cleanup parameter must be either a function or a function name");
-
-                        this._cleanup = opts.cleanup;
-                    }
-
-                    this._cacheId = ++cacheId;
-                },
-
-                activate: function (context, name) {
-
-                    // if we have a local service records, register them first
-
-                    var instance;
-
-                    switch (this._activationType) {
-                        case 1: // SINGLETON
-                            // if the value is cached return it
-                            if (this._hasInstance)
-                                return this._instance;
-
-                            var tof = this._type || this._factory;
-
-                            // create the persistent cache identifier for the type
-                            if (safe.isPrimitive(tof))
-                                this._cacheId = this._type;
-                            else
-                                this._cacheId = safe.oid(tof);
-
-                            // singletons are bound to the root container
-                            var container = context.container.getRootContainer();
-
-                            if (container.has(this._cacheId)) {
-                                instance = container.get(this._cacheId);
-                            } else {
-                                instance = this._create(context, name);
-                                container.store(this._cacheId, instance);
-                                if (this._cleanup)
-                                    container.onDispose(
-                                        makeClenupCallback(instance, this._cleanup));
-                            }
-
-                            this._hasInstance = true;
-                            return (this._instance = instance);
-
-                        case 2: // CONTAINER
-                            //return a cached value
-                            if (this._hasInstance)
-                                return this._instance;
-
-                            // create an instance
-                            instance = this._create(context, name);
-
-                            // the instance is bound to the container
-                            if (this._cleanup)
-                                this._owner.onDispose(
-                                    makeClenupCallback(instance, this._cleanup));
-
-                            // cache and return the instance
-                            this._hasInstance = true;
-                            return (this._instance = instance);
-                        case 3: // CONTEXT
-                            //return a cached value if one exists
-                            if (context.has(this._cacheId))
-                                return context.get(this._cacheId);
-                            // context context activated instances are controlled by callers  
-                            return context.store(this._cacheId, this._create(
-                                context,
-                                name));
-                        case 4: // CALL
-                            // per-call created instances are controlled by callers
-                            return this._create(context, name);
-                        case 5: // HIERARCHY
-                            // hierarchy activated instances are behave much like container activated
-                            // except they are created and bound to the child container
-
-                            // return a cached value
-                            if (context.container.has(this._cacheId))
-                                return context.container.get(this._cacheId);
-
-                            instance = this._create(context, name);
-
-                            if (this._cleanup)
-                                context.container.onDispose(makeClenupCallback(
-                                    instance,
-                                    this._cleanup));
-
-                            return context.container.store(this._cacheId, instance);
-                        default:
-                            throw "Invalid activation type: " + this._activationType;
-                    }
-                },
-
-                isInstanceCreated: function () {
-                    return this._hasInstance;
-                },
-
-                getInstance: function () {
-                    return this._instance;
-                },
-
-                _create: function (context, name) {
-                    context.enter(name, this, Boolean(this._services));
-
-                    if (this._activationType != CALL_ACTIVATION &&
-                        context.visit(this._cacheId) > 0)
-                        throw new Error("Recursion detected");
-
-                    if (this._services) {
-                        for (var p in this._services) {
-                            var sv = this._services[p];
-                            context.register(p, sv instanceof Descriptor ? sv : new Value(sv, false));
-                        }
-                    }
-
-                    var instance;
-
-                    if (!this._factory) {
-                        var ctor, type = this._type;
-
-                        if (typeof (type) === "string") {
-                            ctor = this._typeMap[type];
-                            if (!ctor)
-                                throw new Error("Failed to resolve the type '" +
-                                    type + "'");
-                        } else {
-                            ctor = type;
-                        }
-
-                        if (this._params === undefined) {
-                            this._factory = function () {
-                                return new ctor();
-                            };
-                        } else if (this._params instanceof Array) {
-                            this._factory = function () {
-                                var inst = Object.create(ctor.prototype);
-                                var ret = ctor.apply(inst, arguments);
-                                return typeof (ret) === "object" ? ret : inst;
-                            };
-                        } else {
-                            this._factory = function (param) {
-                                return new ctor(param);
-                            };
-                        }
-                    }
-
-                    if (this._params === undefined) {
-                        instance = this._factory();
-                    } else if (this._params instanceof Array) {
-                        instance = this._factory.apply(this, context.parse(
-                            this._params,
-                            ".params"));
-                    } else {
-                        instance = this._factory(context.parse(
-                            this._params,
-                            ".params"));
-                    }
-
-                    if (this._inject) {
-                        this._inject.forEach(function (spec) {
-                            for (var m in spec)
-                                injectMethod(instance, m, context, spec[m]);
-                        });
-                    }
-
-                    context.leave();
-
-                    return instance;
-                },
-
-                // @constructor {singleton} foo/bar/Baz
-                // @factory {singleton}
-                toString: function () {
-                    var parts = [];
-
-                    parts.push(this._type ? "@constructor" : "@factory");
-
-                    parts.push(activationNames[this._activationType]);
-
-                    if (typeof (this._type) === "string")
-                        parts.push(this._type);
-
-                    return parts.join(" ");
-                }
-
-            });
-
-        cls.SINGLETON = SINGLETON_ACTIVATION;
-        cls.CONTAINER = CONTAINER_ACTIVATION;
-        cls.CONTEXT = CONTEXT_ACTIVATION;
-        cls.CALL = CALL_ACTIVATION;
-        cls.HIERARCHY = HIERARCHY_ACTIVATION;
-
-        var activationNames = [
-            "",
-            "{singleton}",
-            "{container}",
-            "{context}",
-            "{call}",
-            "{hierarchy}"
-        ];
-
-        return cls;
-    });
\ No newline at end of file
diff -r 8af8e840dd49 -r 27e8e9e38e07 src/implab/di/ValueDescriptor.js
--- a/src/implab/di/ValueDescriptor.js	Wed Jun 05 17:44:17 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,38 +0,0 @@
-define([ "../declare", "./Descriptor", "../safe" ],
-
-function(declare, Descriptor, safe) {
-    return declare(Descriptor, {
-        _value : undefined,
-        _raw : false,
-        constructor : function(value, raw) {
-            this._value = value;
-            this._raw = Boolean(raw);
-        },
-
-        activate : function(context, name) {
-            context.enter(name, this);
-            var v = this._raw ? this._value : context.parse(
-                this._value,
-                ".params");
-            context.leave(this);
-            return v;
-        },
-
-        isInstanceCreated : function() {
-            return this._raw;
-        },
-
-        getInstance : function() {
-            if (!this._raw)
-                throw new Error("The instance isn't constructed");
-            return this._value;
-        },
-
-        toString : function() {
-            if (this._raw)
-                return "@value {raw}";
-            else
-                return safe.isNull(this._value) ? "@value " : "@value";
-        }
-    });
-});
\ No newline at end of file
diff -r 8af8e840dd49 -r 27e8e9e38e07 src/implab/dom/css.js
--- a/src/implab/dom/css.js	Wed Jun 05 17:44:17 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,10 +0,0 @@
-define(["./inject"], function (inject) {
-    return {
-        load: function (id, require, cb) {
-            var url = require.toUrl(id);
-            inject.injectStylesheet(url).then(function () {
-                cb();
-            });
-        }
-    };
-});
\ No newline at end of file
diff -r 8af8e840dd49 -r 27e8e9e38e07 src/implab/dom/inject.js
--- a/src/implab/dom/inject.js	Wed Jun 05 17:44:17 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,86 +0,0 @@
-define(["../Deferred", "../log/trace!"], function (Deferred, trace) {
-    function on(node, eventName, handler) {
-        // Add an event listener to a DOM node
-        node.addEventListener(eventName, handler, false);
-
-        return function () {
-            node.removeEventListener(eventName, handler, false);
-        };
-    }
-
-    return {
-        injectionPoint: document.head,
-        injectBefore: document.head.firstChild,
-
-        _map: {},
-
-        _inject: function (name, attr) {
-            var node = document.createElement(name),
-                d = new Deferred(),
-
-                cleanup = function () {
-                    noerr();
-                    noload();
-                },
-
-                noload = on(node, "load", function () {
-                    d.resolve({
-                        node: node
-                    });
-                    cleanup();
-                }, true),
-
-                noerr = on(node, "error", function (e) {
-                    d.reject({
-                        erorr: e,
-                        node: node
-                    });
-                    cleanup();
-                }, true);
-
-            for (var p in attr)
-                node[p] = attr[p];
-
-            this.injectionPoint.insertBefore(node, this.injectBefore);
-            return d;
-        },
-
-        injectScript: function (url) {
-            var d = this._map[url];
-            if (!d) {
-                trace.log("js {0}", url);
-                d = this._inject("script", {
-                    type: "text/javascript",
-                    charset: "utf-8",
-                    src: url
-                });
-                d.then(function () {
-                    trace.log("done {0}", url);
-                }, function (e) {
-                    trace.err([url, e]);
-                });
-                this._map[url] = d;
-            }
-            return d;
-        },
-
-        injectStylesheet: function (url) {
-            var d = this._map[url];
-            if (!d) {
-                trace.log("css {0}", url);
-                d = this._inject("link", {
-                    type: "text/css",
-                    rel: "stylesheet",
-                    href: url
-                });
-                d.then(function () {
-                    trace.log("done {0}", url);
-                }, function (e) {
-                    trace.error([url, e]);
-                });
-                this._map[url] = d;
-            }
-            return d;
-        }
-    };
-});
\ No newline at end of file
diff -r 8af8e840dd49 -r 27e8e9e38e07 src/implab/guard.js
--- a/src/implab/guard.js	Wed Jun 05 17:44:17 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,55 +0,0 @@
-define([ "./Deferred" ], function(Deferred) {
-    var toPromise = function(d) {
-        if (d && d.then)
-            return d;
-        var d2 = new Deferred();
-        d2.resolve(d);
-        return d2;
-    };
-
-    /**
-     * функция для асинхронного выполнения метода
-     * 
-     * @async
-     * @param{Object} o Объект, который будет использован в качестве
-     *                this, если не указан, будет
-     *                null
-     * @param{Function|String} m Функция или имя метода, обязательный параметр.
-     *                         Если указано имя, тогда параметр o
-     *                         также должен быть задан
-     * @param{Array} args Параметры для вызова метода, не обязательно.
-     * @returns{dojo/promise}
-     * @deprecated use safe.async() + when() instead.
-     */
-    return function(o, m, args) {
-        if (arguments.length == 1) {
-            m = o;
-            o = null;
-        } else if (arguments.length == 2 && o instanceof Function &&
-            m instanceof Array) {
-            args = m;
-            m = o;
-            o = null;
-        }
-
-        try {
-            if (!(m instanceof Function)) {
-                if (o)
-                    m = o[m];
-                else if (arguments.length == 1)
-                    return toPromise(m);
-                else
-                    throw new Error("The target object must be specified");
-            }
-
-            if (!m)
-                throw new Error("Method not found");
-
-            return toPromise(m.apply(o, args));
-        } catch (err) {
-            var d = new Deferred();
-            d.reject(err);
-            return d;
-        }
-    };
-});
\ No newline at end of file
diff -r 8af8e840dd49 -r 27e8e9e38e07 src/implab/log/ConsoleLogChannel.js
--- a/src/implab/log/ConsoleLogChannel.js	Wed Jun 05 17:44:17 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,30 +0,0 @@
-define(
-    [ "dojo/_base/declare", "../text/format" ],
-    function(declare, format) {
-        return declare(
-            null,
-            {
-                name : null,
-
-                constructor : function(name) {
-                    this.name = name;
-                },
-
-                log : function() {
-                    console.log(this._makeMsg(arguments));
-                },
-
-                warn : function() {
-                    console.warn(this._makeMsg(arguments));
-                },
-
-                error : function() {
-                    console.error(this._makeMsg(arguments));
-                },
-
-                _makeMsg : function(args) {
-                    return this.name ? this.name + " " +
-                        format.apply(null, args) : format.apply(null, args);
-                }
-            });
-    });
\ No newline at end of file
diff -r 8af8e840dd49 -r 27e8e9e38e07 src/implab/log/_LogMixin.js
--- a/src/implab/log/_LogMixin.js	Wed Jun 05 17:44:17 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,67 +0,0 @@
-define([ "dojo/_base/declare" ],
-
-function(declare) {
-    var cls = declare(null, {
-        _logChannel : null,
-
-        _logLevel : 1,
-
-        constructor : function(opts) {
-            if (typeof opts == "object") {
-                if ("logChannel" in opts)
-                    this._logChannel = opts.logChannel;
-                if ("logLevel" in opts)
-                    this._logLevel = opts.logLevel;
-            }
-        },
-
-        getLogChannel : function() {
-            return this._logChannel;
-        },
-
-        setLogChannel : function(v) {
-            this._logChannel = v;
-        },
-
-        getLogLevel : function() {
-            return this._logLevel;
-        },
-
-        setLogLevel : function(v) {
-            this._logLevel = v;
-        },
-
-        log : function(format) {
-            if (this._logChannel && this._logLevel > 2)
-                this._logChannel.log.apply(this._logChannel, arguments);
-        },
-        warn : function(format) {
-            if (this._logChannel && this._logLevel > 1)
-                this._logChannel.warn.apply(this._logChannel, arguments);
-        },
-        error : function(format) {
-            if (this._logChannel && this._logLevel > 0)
-                this._logChannel.error.apply(this._logChannel, arguments);
-        },
-
-        /**
-         * Used to by widgets
-         */
-        startup : function() {
-            var me = this, parent;
-            if (!me.getLogChannel()) {
-                parent = me;
-                while (parent = parent.getParent()) {
-                    if (parent.getLogChannel) {
-                        me.setLogChannel(parent.getLogChannel());
-                        if(parent.getLogLevel)
-                            me.setLogLevel(parent.getLogLevel());
-                        break;
-                    }
-                }
-            }
-            this.inherited(arguments);
-        }
-    });
-    return cls;
-});
\ No newline at end of file
diff -r 8af8e840dd49 -r 27e8e9e38e07 src/implab/log/listeners/console.js
--- a/src/implab/log/listeners/console.js	Wed Jun 05 17:44:17 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,25 +0,0 @@
-define([], function () {
-    if (console && console.log)
-        return function (ch, name, msg) {
-            
-            var args = [ch + ":"];
-
-            switch (name) {
-                case "warn":
-                case "error":
-                case "log":
-                    break;
-                default:
-                    args.push(name + ":");
-                    name = "log";
-            }
-
-
-            if (msg instanceof Array)
-                args.push.apply(args, msg);
-            else
-                args.push(msg);
-
-            console[name].apply(console, args);
-        };
-});
\ No newline at end of file
diff -r 8af8e840dd49 -r 27e8e9e38e07 src/implab/log/trace.js
--- a/src/implab/log/trace.js	Wed Jun 05 17:44:17 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,116 +0,0 @@
-define(["../text/format"], function (format) {
-    'use strict';
-
-    var listeners = [];
-    var channels = {};
-
-    var Trace = function (name) {
-        this.name = name;
-        this._subscribers = [];
-    };
-
-    Trace.prototype.debug = function () {
-        if (Trace.level >= 4)
-            this.notify("debug", format.apply(null, arguments));
-    };
-
-    Trace.prototype.log = function () {
-        if (Trace.level >= 3)
-            this.notify("log", format.apply(null, arguments));
-    };
-
-    Trace.prototype.warn = function () {
-        if (Trace.level >= 2)
-            this.notify("warn", format.apply(null, arguments));
-
-    };
-
-    Trace.prototype.error = function () {
-        if (Trace.level >= 1)
-            this.notify("error", format.apply(null, arguments));
-    };
-
-    Trace.prototype.notify = function (name, msg) {
-        var me = this;
-        me._subscribers.forEach(function (cb) {
-            cb(me, name, msg);
-        });
-    };
-
-    Trace.prototype.subscribe = function (cb) {
-        this._subscribers.push(cb);
-    };
-
-    Trace.prototype.toString = function () {
-        return this.name;
-    };
-
-    Trace.createChannel = function (type, name, cb) {
-        var chId = name;
-        if (channels[chId])
-            return channels[chId];
-
-        var channel = new type(chId);
-        channels[chId] = channel;
-
-        Trace._onNewChannel(chId, channel);
-        cb(channel);
-    };
-
-    Trace._onNewChannel = function (chId, ch) {
-        listeners.forEach(function (listener) {
-            listener(chId, ch);
-        });
-    };
-
-    Trace.on = function (filter, cb) {
-        if (arguments.length == 1) {
-            cb = filter;
-            filter = undefined;
-        }
-        var d, test;
-        if (filter instanceof RegExp) {
-            test = function (chId) {
-                return filter.test(chId);
-            };
-        } else if (filter instanceof Function) {
-            test = filter;
-        } else if (filter) {
-            test = function (chId) {
-                return chId == filter;
-            };
-        }
-
-        if (test) {
-            d = function(chId, ch) {
-                if(test(chId))
-                    ch.subscribe(cb);
-            };
-        } else {
-            d = function(chId, ch) {
-                ch.subscribe(cb);
-            };
-        }
-        listeners.push(d);
-
-        for(var chId in channels)
-            d(chId,channels[chId]);
-    };
-
-    Trace.load = function (id, require, cb) {
-        if (id)
-            Trace.createChannel(Trace, id, cb);
-        else if (require.module && require.module.mid)
-            Trace.createChannel(Trace, require.module.mid, cb);
-        else
-            require(['module'], function (module) {
-                Trace.createChannel(Trace, module && module.id, cb);
-            });
-    };
-
-    Trace.dynamic = true;
-
-    Trace.level = 4;
-
-    return Trace;
-});
\ No newline at end of file
diff -r 8af8e840dd49 -r 27e8e9e38e07 src/implab/messaging/Client.js
--- a/src/implab/messaging/Client.js	Wed Jun 05 17:44:17 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,61 +0,0 @@
-define(
-    [ "dojo/_base/declare", "dojo/_base/lang", "dojo/Evented", "../log/_LogMixin" ],
-
-    function(declare, lang, Evented, _LogMixin) {
-        return declare([ Evented, _LogMixin ], {
-            _session : null,
-            _destination : null,
-            _id : null,
-
-            constructor : function(session, destination, options) {
-                this._destination = destination;
-                this._session = session;
-            },
-
-            getDestination : function() {
-                return this._destination;
-            },
-
-            start : function() {
-                var me = this;
-                return me._session.createClient(me.prepareOptions({})).then(
-                    function(id) {
-                        me._id = id;
-                        return me;
-                    });
-            },
-
-            prepareOptions : function(options) {
-                var me = this;
-                options.mode = me.getMode();
-                options.destination = me.getDestination();
-                options.client = function(msg) {
-                    me.process(msg);
-                };
-                return options;
-            },
-
-            process : function(msg) {
-                this.warn("Messages are not acceped by this client");
-            },
-
-            stop : function() {
-                var me = this;
-                if (me._id) {
-                    me.log("stop");
-                    return me._session.deleteClient({'clientId': me._id}).then(function() {
-                        me._id = null;
-                        return me;
-                    });
-                }
-            },
-
-            toString : function() {
-                return "["
-                    + [
-                        this.getMode().toUpperCase(),
-                        this.getDestination(),
-                        this._id ].join(',') + "]";
-            }
-        });
-    });
\ No newline at end of file
diff -r 8af8e840dd49 -r 27e8e9e38e07 src/implab/messaging/Destination.js
--- a/src/implab/messaging/Destination.js	Wed Jun 05 17:44:17 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,34 +0,0 @@
-define([ "dojo/_base/declare", "./Listener" ],
-
-function(declare, Listener) {
-    return declare(null, {
-        _session : null,
-        _destination : null,
-        _listenerClass : null,
-
-        constructor : function(session, destination, options) {
-            if (!session)
-                throw new Error("A session is required");
-            if (!destination)
-                throw new Error("A destination is required");
-
-            this._session = session;
-            this._destination = destination;
-            if (options) {
-                if (options.listenerClass)
-                    this._listenerClass = options.listenerClass;
-            }
-        },
-
-        listen : function(callback) {
-            var factory = this._listenerClass || Listener;
-            var listener = new factory(this._session, this._destination, {
-                listener : callback
-            });
-            listener.start();
-
-            return listener;
-        }
-
-    });
-});
diff -r 8af8e840dd49 -r 27e8e9e38e07 src/implab/messaging/Listener.js
--- a/src/implab/messaging/Listener.js	Wed Jun 05 17:44:17 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,64 +0,0 @@
-define([ "dojo/_base/declare", "dojo/_base/lang", "./Client" ],
-
-function(declare, lang, Client) {
-    return declare([ Client ], {
-        _listener : null,
-
-        constructor : function(session, destination, options) {
-            if (!options || !options.listener)
-                throw new Error("A listener is required");
-            this._listener = options.listener;
-            if (options.transform)
-                this._transform = options.transform;
-        },
-
-        getMode : function() {
-            return "listener";
-        },
-
-        process : function(result) {
-            switch (result.type) {
-            case "message":
-                try {
-                    this._handleMessage(result.message);
-                } catch (ex) {
-                    var err = new Error("Failed to handle message");
-                    err.envelope = result.message;
-                    err.innerException = ex;
-                    this._handleError(err);
-                }
-                break;
-            case "error":
-                this._handleError(result.error);
-                break;
-            }
-
-        },
-
-        _transform : function(envelope) {
-            return envelope;
-        },
-
-        _handleMessage : function(envelope) {
-            this.log(
-                "MESSAGE type = ${0}, headers = ${2}: ${1}",
-                envelope.bodyType,
-                envelope.body,
-                JSON.stringify(envelope.headers));
-            var data = this._transform(envelope);
-            this._listener(data);
-            this.emit("message", data);
-        },
-
-        _handleError : function(ex) {
-            if (ex.innerException)
-                this.error(
-                    "ERROR: ${0} -> ${1}",
-                    ex.message,
-                    ex.innerException.message);
-            else
-                this.error("ERROR: ${0}", ex.message);
-            this.emit("error", ex);
-        }
-    });
-});
\ No newline at end of file
diff -r 8af8e840dd49 -r 27e8e9e38e07 src/implab/messaging/Session.js
--- a/src/implab/messaging/Session.js	Wed Jun 05 17:44:17 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,217 +0,0 @@
-define(
-    [
-        "dojo/_base/declare",
-        "dojo/_base/lang",
-        "dojo/request",
-        "./Destination",
-        "dojo/Evented",
-        "dojo/Deferred",
-        "../log/_LogMixin" ],
-
-    function(declare, lang, request, Destination, Evented, Deferred, _LogMixin) {
-
-        var cls = declare(
-            [ Evented, _LogMixin ],
-            {
-                _id : null,
-                _baseUrl : null,
-                _destinations : null,
-                _timeout : 100000,
-                _clients : null,
-                _started : null,
-                _starting : false,
-
-                constructor : function(baseUrl, options) {
-                    if (!baseUrl)
-                        throw new Error("baseUrl is required");
-                    options = options || {};
-
-                    this._baseUrl = baseUrl.replace(/\/*$/, "");
-                    this._destinations = {};
-                    this._pending = [];
-                    this._clients = {};
-                    if (options.timeout)
-                        this._timeout = options.timeout;
-
-                    this._started = new Deferred();
-                },
-
-                start : function() {
-                    if (this._starting)
-                        return this._started;
-                    this._starting = true;
-
-                    var me = this;
-                    me.log("START");
-                    request(this._baseUrl, {
-                        method : "POST",
-                        handleAs : "json"
-                    }).then(function(result) {
-                        me._id = result;
-                        me._emitConnected();
-                        me._poll();
-                        me._started.resolve(me);
-                    }, function(error) {
-                        me._emitError(error);
-                        me._started.reject(me);
-                    });
-                    return me._started.promise;
-                },
-
-                createClient : function(options) {
-                    if (!options || !options.destination || !options.mode)
-                        throw new Error("Invalid argument");
-
-                    var me = this;
-
-                    return me._started
-                        .then(function() {
-                            var url = me._makeUrl(me._id);
-                            me.log(
-                                "CREATE mode=${0}, destination=${1}",
-                                options.mode,
-                                options.destination);
-
-                            return request(url, {
-                                method : "POST",
-                                data : {
-                                    mode : options.mode,
-                                    destination : options.destination
-                                },
-                                handleAs : 'json'
-                            })
-                                .then(
-                                    function(id) {
-                                        me
-                                            .log(
-                                                "CLIENT id=${0}, mode=${1}, destination=${2}",
-                                                id,
-                                                options.mode,
-                                                options.destination);
-                                        me._clients[id] = options.client
-                                            ? options.client
-                                            : function(msg) {
-                                                me
-                                                    .warn(
-                                                        "The client id=${0}, mode=${1}, destination=${2} isn't accepting mesages",
-                                                        id,
-                                                        options.mode,
-                                                        options.destination);
-                                            };
-                                        return id;
-                                    });
-                        });
-
-                },
-
-                deleteClient : function(options) {
-                    if (!options || !options.clientId)
-                        throw new Error("Invalid argument");
-
-                    var me = this, id = options.clientId;
-
-                    return me._started.then(function() {
-                        var url = me._makeUrl(me._id, options.clientId);
-
-                        me.log("DELETE CLIENT ${0}", options.clientId);
-
-                        return request(url, {
-                            method : "DELETE",
-                            handleAs : 'json'
-                        }).then(function() {
-                            me.log("CLIENT DELETED ${0}", options.clientId);
-                            me._clients[id] = undefined;
-                        });
-                    });
-                },
-
-                _poll : function() {
-                    var me = this, url = this._makeUrl(this._id);
-                    me.log("POLL timeout=${0}", me._timeout);
-                    request(url, {
-                        method : "GET",
-                        handleAs : "json",
-                        query : {
-                            timeout : me._timeout
-                        }
-                    }).then(function(response) {
-                        me._handlePoll(response);
-                        me._poll();
-                    }, function(err) {
-                        me.error("POLL faield with ${0}", err);
-                        me._emitError(err);
-                    });
-                },
-
-                _handlePoll : function(response) {
-                    if (!response) {
-                        this.log("POLL response undefined, looks like a bug");
-                        return;
-                    }
-                    if (!response.results || !response.results.length) {
-                        this.log("POLL response is empty");
-                        return;
-                    }
-
-                    var results = response.results;
-                    this.log("POLL got ${0} results", results.length);
-
-                    for (var i = 0; i < results.length; i++) {
-                        var result = results[i];
-                        var client = this._clients[result.clientId];
-                        if (!client) {
-                            // TODO this could happen due to client isn't
-                            // registered yet
-                            this.error("Unknown client ${0}", result.clientId);
-                            continue;
-                        }
-                        client.call(this, result);
-                    }
-                },
-
-                _emitError : function(err) {
-                    this.emit("error", err);
-                },
-
-                _emitConnected : function() {
-                    var me = this;
-                    me.log("CONNECTED");
-                    me.emit("connected");
-                },
-
-                _makeUrl : function() {
-                    var parts = [ this._baseUrl ];
-                    for (var i = 0; i < arguments.length; i++)
-                        parts.push(arguments[i].replace(/\/*$/, ""));
-                    return parts.join('/');
-                },
-
-                queue : function(name) {
-                    return this._getDestination("queue://" + name);
-                },
-
-                topic : function(name) {
-                    return this._getDestination("topic://" + name);
-                },
-
-                _getDestination : function(uri) {
-                    if (uri in this._destinations)
-                        return this._destinations[uri];
-
-                    var dest = new Destination(this, uri);
-                    this._destinations[uri] = dest;
-                    return dest;
-                },
-
-                toString : function() {
-                    return [ "[", "SESSION ", this._id, "]" ].join(" ");
-                }
-            });
-
-        cls.connect = function(url, options) {
-            var session = new cls(url, options);
-            return session.start();
-        };
-
-        return cls;
-    });
diff -r 8af8e840dd49 -r 27e8e9e38e07 src/implab/safe.js
--- a/src/implab/safe.js	Wed Jun 05 17:44:17 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,325 +0,0 @@
-define([],
-
-    function () {
-        var _create = Object.create,
-            _keys = Object.keys;
-
-        var safe = null;
-        safe = {
-            argumentNotNull: function (arg, name) {
-                if (arg === null || arg === undefined)
-                    throw new Error("The argument " + name + " can't be null or undefined");
-            },
-
-            argumentNotEmptyString: function (arg, name) {
-                if (typeof (arg) !== "string" || !arg.length)
-                    throw new Error("The argument '" + name + "' must be a not empty string");
-            },
-
-            argumentNotEmptyArray: function (arg, name) {
-                if (!(arg instanceof Array) || !arg.length)
-                    throw new Error("The argument '" + name + "' must be a not empty array");
-            },
-
-            argumentOfType: function (arg, type, name) {
-                if (!(arg instanceof type))
-                    throw new Error("The argument '" + name + "' type doesn't match");
-            },
-
-            isNull: function (arg) {
-                return (arg === null || arg === undefined);
-            },
-
-            isPrimitive: function (arg) {
-                return (arg === null || arg === undefined || typeof (arg) === "string" ||
-                    typeof (arg) === "number" || typeof (arg) === "boolean");
-            },
-
-            isInteger: function (arg) {
-                return parseInt(arg) == arg;
-            },
-
-            isNumber: function (arg) {
-                return parseFloat(arg) == arg;
-            },
-
-            isString: function (val) {
-                return typeof (val) == "string" || val instanceof String;
-            },
-
-            isNullOrEmptyString: function (str) {
-                if (str === null || str === undefined ||
-                    ((typeof (str) == "string" || str instanceof String) && str.length === 0))
-                    return true;
-            },
-
-            isNotEmptyArray: function (arg) {
-                return (arg instanceof Array && arg.length > 0);
-            },
-
-            /**
-             * Выполняет метод для каждого элемента массива, останавливается, когда
-             * либо достигнут конец массива, либо функция cb вернула
-             * значение.
-             * 
-             * @param{Array | Object} obj массив элементов для просмотра
-             * @param{Function} cb функция, вызываемая для каждого элемента
-             * @param{Object} thisArg значение, которое будет передано в качестве
-             *                this в cb.
-             * @returns Результат вызова функции cb, либо undefined
-             *          если достигнут конец массива.
-             */
-            each: function (obj, cb, thisArg) {
-                safe.argumentNotNull(cb, "cb");
-                var i, x;
-                if (obj instanceof Array) {
-                    for (i = 0; i < obj.length; i++) {
-                        x = cb.call(thisArg, obj[i], i);
-                        if (x !== undefined)
-                            return x;
-                    }
-                } else {
-                    var keys = _keys(obj);
-                    for (i = 0; i < keys.length; i++) {
-                        var k = keys[i];
-                        x = cb.call(thisArg, obj[k], k);
-                        if (x !== undefined)
-                            return x;
-                    }
-                }
-            },
-
-            /**
-             * Копирует свойства одного объекта в другой.
-             * 
-             * @param{Any} dest объект в который нужно скопировать значения
-             * @param{Any} src источник из которого будут копироваться значения
-             * @tmpl{Object|Array} tmpl шаблон по которому будет происходить
-             *                     копирование. Если шаблон является массивом
-             *                     (список свойств), тогда значения этого массива
-             *                     являются именами свойсвт которые будут
-             *                     скопированы. Если шаблон является объектом (карта
-             *                     преобразования имен свойств src->dst), тогда
-             *                     копирование будет осуществляться только
-             *                     собственных свойств источника, присутсвующих в
-             *                     шаблоне, при этом значение свойства шаблона
-             *                     является именем свойства в которое будет
-             *                     произведено коприрование
-             */
-            mixin: function (dest, src, tmpl) {
-                safe.argumentNotNull(dest, "dest");
-                if (!src)
-                    return dest;
-
-                var keys, i, p;
-                if (arguments.length < 3) {
-                    keys = _keys(src);
-                    for (i = 0; i < keys.length; i++) {
-                        p = keys[i];
-                        dest[p] = src[p];
-                    }
-                } else {
-                    if (tmpl instanceof Array) {
-                        for (i = 0; i < tmpl.length; i++) {
-                            p = tmpl[i];
-                            if (p in src)
-                                dest[p] = src[p];
-                        }
-
-                    } else {
-                        keys = _keys(src);
-                        for (i = 0; i < keys.length; i++) {
-                            p = keys[i];
-                            if (p in tmpl)
-                                dest[tmpl[p]] = src[p];
-                        }
-                    }
-                }
-                return dest;
-            },
-
-            /** Wraps the specified function to emulate an asynchronous execution.
-             * @param{Object} thisArg [Optional] Object which will be passed as 'this' to the function.
-             * @param{Function|String} fn [Required] Function wich will be wrapped.
-             */
-            async: function (fn, thisArg) {
-                if (arguments.length == 2 && !(fn instanceof Function))
-                    fn = thisArg[fn];
-
-                if (fn == null)
-                    throw new Error("The function must be specified");
-
-                function wrapresult(x, e) {
-                    if (e) {
-                        return {
-                            then: function (cb, eb) {
-                                try {
-                                    return eb ? wrapresult(eb(e)) : this;
-                                } catch (e2) {
-                                    return wrapresult(null, e2);
-                                }
-                            }
-                        };
-                    } else {
-                        if (x && x.then)
-                            return x;
-                        return {
-                            then: function (cb) {
-                                try {
-                                    return cb ? wrapresult(cb(x)) : this;
-                                } catch (e2) {
-                                    return wrapresult(e2);
-                                }
-                            }
-                        };
-                    }
-                }
-
-                return function () {
-                    try {
-                        return wrapresult(fn.apply(thisArg, arguments));
-                    } catch (e) {
-                        return wrapresult(null, e);
-                    }
-                };
-            },
-
-            create: function () {
-                if (console && console.warn)
-                    console.warn("implab/safe::create is deprecated use Object.create instead");
-                _create.apply(this, arguments);
-            },
-
-            delegate: function (target, method) {
-                if (!(method instanceof Function)) {
-                    this.argumentNotNull(target, "target");
-                    method = target[method];
-                }
-
-                if (!(method instanceof Function))
-                    throw new Error("'method' argument must be a Function or a method name");
-
-                return function () {
-                    return method.apply(target, arguments);
-                };
-            },
-
-            /**
-             * Для каждого элемента массива вызывает указанную функцию и сохраняет
-             * возвращенное значение в массиве результатов.
-             * 
-             * @remarks cb может выполняться асинхронно, при этом одновременно будет
-             *          только одна операция.
-             * 
-             * @async
-             */
-            pmap: function (items, cb) {
-                safe.argumentNotNull(cb, "cb");
-
-                if (items && items.then instanceof Function)
-                    return items.then(function (data) {
-                        return safe.pmap(data, cb);
-                    });
-
-                if (safe.isNull(items) || !items.length)
-                    return items;
-
-                var i = 0,
-                    result = [];
-
-                function next() {
-                    var r, ri;
-
-                    function chain(x) {
-                        result[ri] = x;
-                        return next();
-                    }
-
-                    while (i < items.length) {
-                        r = cb(items[i], i);
-                        ri = i;
-                        i++;
-                        if (r && r.then) {
-                            return r.then(chain);
-                        } else {
-                            result[ri] = r;
-                        }
-                    }
-                    return result;
-                }
-
-                return next();
-            },
-
-            /**
-             * Для каждого элемента массива вызывает указанную функцию, результаты
-             * не сохраняются
-             * 
-             * @remarks cb может выполняться асинхронно, при этом одновременно будет
-             *          только одна операция.
-             * @async
-             */
-            pfor: function (items, cb) {
-                safe.argumentNotNull(cb, "cb");
-
-                if (items && items.then instanceof Function)
-                    return items.then(function (data) {
-                        return safe.pmap(data, cb);
-                    });
-
-                if (safe.isNull(items) || !items.length)
-                    return items;
-
-                var i = 0;
-
-                function next() {
-                    while (i < items.length) {
-                        var r = cb(items[i], i);
-                        i++;
-                        if (r && r.then)
-                            return r.then(next);
-                    }
-                }
-
-                return next();
-            },
-
-            /**
-             * Выбирает первый элемент из последовательности, или обещания, если в
-             * качестве параметра используется обещание, оно должно вернуть массив.
-             * 
-             * @param{Function} cb обработчик результата, ему будет передан первый
-             *                  элемент последовательности в случае успеха
-             * @param{Fucntion} err обработчик исключения, если массив пустой, либо
-             *                  не массив
-             * 
-             * @remarks Если не указаны ни cb ни err, тогда функция вернет либо
-             *          обещание, либо первый элемент.
-             * @async
-             */
-            first: function (sequence, cb, err) {
-                if (sequence) {
-                    if (sequence.then instanceof Function) {
-                        return sequence.then(function (res) {
-                            return safe.first(res, cb, err);
-                        }, err);
-                    } else if (sequence && "length" in sequence) {
-                        if (sequence.length === 0) {
-                            if (err)
-                                return err(new Error("The sequence is empty"));
-                            else
-                                throw new Error("The sequence is empty");
-                        }
-                        return cb ? cb(sequence[0]) : sequence[0];
-                    }
-                }
-
-                if (err)
-                    return err(new Error("The sequence is required"));
-                else
-                    throw new Error("The sequence is required");
-            }
-        };
-
-        return safe;
-    });
\ No newline at end of file
diff -r 8af8e840dd49 -r 27e8e9e38e07 src/implab/text/format-compile.js
--- a/src/implab/text/format-compile.js	Wed Jun 05 17:44:17 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,101 +0,0 @@
-define(
-    [],
-    function() {
-        var map = {
-            "\\{" : "&curlopen;",
-            "\\}" : "&curlclose;",
-            "&" : "&",
-            "\\:" : ":"
-        };
-
-        var rev = {
-            curlopen : "{",
-            curlclose : "}",
-            amp : "&",
-            colon : ":"
-        };
-
-        var espaceString = function(s) {
-            if (!s)
-                return s;
-            return "'" + s.replace(/('|\\)/g, "\\$1") + "'";
-        };
-
-        var encode = function(s) {
-            if (!s)
-                return s;
-            return s.replace(/\\{|\\}|&|\\:/g, function(m) {
-                return map[m] || m;
-            });
-        };
-
-        var decode = function(s) {
-            if (!s)
-                return s;
-            return s.replace(/&(\w+);/g, function(m, $1) {
-                return rev[$1] || m;
-            });
-        };
-
-        var subst = function(s) {
-            var i = s.indexOf(":"), name, pattern;
-            if (i >= 0) {
-                name = s.substr(0, i);
-                pattern = s.substr(i + 1);
-            } else {
-                name = s;
-            }
-
-            if (pattern)
-                return [
-                    espaceString(decode(name)),
-                    espaceString(decode(pattern)) ];
-            else
-                return [ espaceString(decode(name)) ];
-        };
-
-        var compile = function(str) {
-            if (!str)
-                return function() {};
-
-            var chunks = encode(str).split("{"), chunk;
-
-            var code = [ "var result=[];" ];
-
-            for (var i = 0; i < chunks.length; i++) {
-                chunk = chunks[i];
-
-                if (i === 0) {
-                    if (chunk)
-                        code.push("result.push(" + espaceString(decode(chunk)) +
-                            ");");
-                } else {
-                    var len = chunk.indexOf("}");
-                    if (len < 0)
-                        throw new Error("Unbalanced substitution #" + i);
-
-                    code.push("result.push(subst(" +
-                        subst(chunk.substr(0, len)).join(",") + "));");
-                    if (chunk.length > len + 1)
-                        code.push("result.push(" +
-                            espaceString(decode(chunk.substr(len + 1))) + ");");
-                }
-            }
-
-            code.push("return result.join('');");
-
-            /* jshint -W054 */
-            return new Function("subst", code.join("\n"));
-        };
-
-        var cache = {};
-
-        return function(template) {
-            var compiled = cache[template];
-            if (!compiled) {
-                compiled = compile(template);
-                cache[template] = compiled;
-            }
-            return compiled;
-        };
-    });
\ No newline at end of file
diff -r 8af8e840dd49 -r 27e8e9e38e07 src/implab/text/format.js
--- a/src/implab/text/format.js	Wed Jun 05 17:44:17 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,87 +0,0 @@
-define([
-    "../safe",
-    "./format-compile",
-    "dojo/number",
-    "dojo/date/locale",
-    "dojo/_base/array" ], function(safe, compile, number, date, array) {
-
-    // {short,medium,full,long}-{date,time}
-    var convert = function(value, pattern) {
-        if (!pattern)
-            return value.toString();
-
-        if (pattern.toLocaleLowerCase() == "json") {
-            var cache = [];
-            return JSON.stringify(value, function(k, v) {
-                if (!safe.isPrimitive(v)) {
-                    var id = array.indexOf(cache, v);
-                    if (id >= 0)
-                        return "@ref-" + id;
-                    else
-                        return v;
-                } else {
-                    return v;
-                }
-            },2);
-        }
-
-        if (safe.isNumber(value)) {
-            var nopt = {};
-            if (pattern.indexOf("!") === 0) {
-                nopt.round = -1;
-                pattern = pattern.substr(1);
-            }
-            nopt.pattern = pattern;
-            return number.format(value, nopt);
-        } else if (value instanceof Date) {
-            var m = pattern.match(/^(\w+)-(\w+)$/);
-            if (m)
-                return date.format(value, {
-                    selector : m[2],
-                    formatLength : m[1]
-                });
-            else if (pattern == "iso")
-                return value.toISOString();
-            else
-                return date.format(value, {
-                    selector : "date",
-                    datePattern : pattern
-                });
-        } else {
-            return value.toString(pattern);
-        }
-    };
-
-    function formatter(format) {
-        var data;
-
-        if (arguments.length <= 1)
-            return format;
-
-        data = Array.prototype.slice.call(arguments, 1);
-
-        var template = compile(format);
-
-        return template(function(name, pattern) {
-            var value = data[name];
-            return !safe.isNull(value) ? convert(value, pattern) : "";
-        });
-    }
-
-    formatter.compile = function(format) {
-        var template = compile(format);
-
-        return function() {
-            var data = arguments;
-
-            return template(function(name, pattern) {
-                var value = data[name];
-                return !safe.isNull(value) ? convert(value, pattern) : "";
-            });
-        };
-    };
-
-    formatter.convert = convert;
-
-    return formatter;
-});
\ No newline at end of file
diff -r 8af8e840dd49 -r 27e8e9e38e07 src/implab/text/template-compile.js
--- a/src/implab/text/template-compile.js	Wed Jun 05 17:44:17 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,134 +0,0 @@
-define(
-    ["dojo/request", "./format", "../log/trace!"],
-    function (request, format, trace) {
-
-        // разбивает строку шаблона на токены, возвращает контекст для
-        // дальнейшей обработки в visitTemplate
-        var parseTemplate = function (str) {
-            var tokens = str.split(/(<%=|\[%=|<%|\[%|%\]|%>)/);
-            var pos = -1;
-            var data = [],
-                code = [];
-
-            return {
-                next: function () {
-                    pos++;
-                    return pos < tokens.length;
-                },
-                token: function () {
-                    return tokens[pos];
-                },
-                pushData: function () {
-                    var i = data.length;
-                    data.push.apply(data, arguments);
-                    return i;
-                },
-                pushCode : function() {
-                    var i = code.length;
-                    code.push.apply(code, arguments);
-                    return i;
-                },
-                compile: function () {
-                    var text = "var $p = [];\n" +
-                        "var print = function(){\n" +
-                        "   $p.push(format.apply(null,arguments));\n" +
-                        "};\n" +
-                        // Introduce the data as local variables using with(){}
-                        "with(obj){\n" +
-                        code.join("\n") +
-                        "}\n" +
-                        "return $p.join('');";
-                    
-                    try {
-                        var compiled = new Function("obj, format, $data", text);
-                        /**
-                         * Функция форматирования по шаблону
-                         * 
-                         * @type{Function}
-                         * @param{Object} obj объект с параметрами для подстановки
-                         */
-                        return function (obj) {
-                            return compiled(obj || {}, format, data);
-                        };
-                    } catch (e) {
-                        trace.error([e]);
-                        trace.log([text, data]);
-                        throw e;
-                    }
-                }
-            }
-        };
-
-        function visitTemplate(context) {
-            while (context.next()) {
-                switch (context.token()) {
-                    case "<%":
-                    case "[%":
-                        visitCode(context);
-                        break;
-                    case "<%=":
-                    case "[%=":
-                        visitInline(context);
-                        break;
-                    default:
-                        visitTextFragment(context);
-                        break;
-                }
-            }
-        }
-
-        function visitInline(context) {
-            var code = ["$p.push("];
-            while (context.next()) {
-                if (context.token() == "%>" || context.token() == "%]")
-                    break;
-                code.push(context.token());
-            }
-            code.push(");");
-            context.pushCode(code.join(''));
-        }
-
-        function visitCode(context) {
-            var code = [];
-            while (context.next()) {
-                if (context.token() == "%>" || context.token() == "%]")
-                    break;
-                code.push(context.token());
-            }
-            context.pushCode(code.join(''));
-        }
-
-        function visitTextFragment(context) {
-            var i = context.pushData(context.token());
-            context.pushCode("$p.push($data["+i+"]);");
-        }
-
-        var compile = function (str) {
-            if (!str)
-                return function() { return "";};
-
-            var ctx = parseTemplate(str);
-            visitTemplate(ctx);
-            return ctx.compile();
-        };
-
-        var cache = {};
-
-        compile.load = function (id, require, callback) {
-            var url = require.toUrl(id);
-            if (url in cache) {
-                callback(cache[url]);
-            } else {
-                request(url).then(compile).then(function (tc) {
-                    callback(cache[url] = tc);
-                }, function (err) {
-                    require.signal("error", [{
-                        error: err,
-                        src: 'implab/text/template-compile'
-                    }]);
-                });
-            }
-        };
-
-        return compile;
-    });
\ No newline at end of file
diff -r 8af8e840dd49 -r 27e8e9e38e07 src/utest/store/mock.js
--- a/src/utest/store/mock.js	Wed Jun 05 17:44:17 2019 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,95 +0,0 @@
-define([
-    "dojo/_base/declare",
-    "dojo/_base/lang",
-    "dojo/request",
-    "dojo/store/Memory",
-    "dojo/Deferred",
-    "dojo/store/util/QueryResults"
-
-], function (declare, lang, request, Memory, Deferred, QueryResults) {
-    /**
-     * @amdplugin
-     * @usage
-     * 
-     * 
-     * require([
-     *     "tests/store/mock!./data/sample.json"
-     * ], function(Store) {
-     *     var store = new Store(); // will create a memory store
-     * });
-     * 
- */ - var cache = {}; - return { - load: function (id, require, callback) { - var url = require.toUrl(id); - if (url in cache) { - callback(cache[url]); - } else { - request(url).then(function (data) { - // handle result as text and parse it every time the - // store - // is created to get an independent copy - var f = cache[url] = function (opts) { - var store = new Memory(lang.mixin({ - data: JSON.parse(data), - async: true, - delay: 100 - }, opts || {})); - - declare.safeMixin(store, { - query: function () { - var results = this.inherited(arguments); - if (this.async) { - var d = new Deferred(); - setTimeout(function () { - d.resolve(results); - }, this.delay); - return new QueryResults(d.promise); - } - return results; - }, - - get: function () { - var results = this.inherited(arguments); - if (this.async) { - var d = new Deferred(); - setTimeout(function () { - d.resolve(results); - }, this.delay); - return d.promise; - } - return results; - }, - - put: function () { - var me = this; - - if (me.async) { - var inherited = me.getInherited(arguments); - var args = Array.prototype.slice.apply(arguments); - var d = new Deferred(); - - setTimeout(function () { - d.resolve(inherited.apply(me, args)); - }, me.delay); - - return d.promise; - } - return me.inherited(arguments); - } - }); - - return store; - }; - callback(f); - }, function (err) { - require.signal("error", [{ - error: err, - src: 'implab/store/mock' - }]); - }); - } - } - }; -}); \ No newline at end of file diff -r 8af8e840dd49 -r 27e8e9e38e07 utest/src/js/utest/store/mock.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/utest/src/js/utest/store/mock.js Wed Jun 05 20:44:15 2019 +0300 @@ -0,0 +1,95 @@ +define([ + "dojo/_base/declare", + "dojo/_base/lang", + "dojo/request", + "dojo/store/Memory", + "dojo/Deferred", + "dojo/store/util/QueryResults" + +], function (declare, lang, request, Memory, Deferred, QueryResults) { + /** + * @amdplugin + * @usage + * + *
+     * require([
+     *     "tests/store/mock!./data/sample.json"
+     * ], function(Store) {
+     *     var store = new Store(); // will create a memory store
+     * });
+     * 
+ */ + var cache = {}; + return { + load: function (id, require, callback) { + var url = require.toUrl(id); + if (url in cache) { + callback(cache[url]); + } else { + request(url).then(function (data) { + // handle result as text and parse it every time the + // store + // is created to get an independent copy + var f = cache[url] = function (opts) { + var store = new Memory(lang.mixin({ + data: JSON.parse(data), + async: true, + delay: 100 + }, opts || {})); + + declare.safeMixin(store, { + query: function () { + var results = this.inherited(arguments); + if (this.async) { + var d = new Deferred(); + setTimeout(function () { + d.resolve(results); + }, this.delay); + return new QueryResults(d.promise); + } + return results; + }, + + get: function () { + var results = this.inherited(arguments); + if (this.async) { + var d = new Deferred(); + setTimeout(function () { + d.resolve(results); + }, this.delay); + return d.promise; + } + return results; + }, + + put: function () { + var me = this; + + if (me.async) { + var inherited = me.getInherited(arguments); + var args = Array.prototype.slice.apply(arguments); + var d = new Deferred(); + + setTimeout(function () { + d.resolve(inherited.apply(me, args)); + }, me.delay); + + return d.promise; + } + return me.inherited(arguments); + } + }); + + return store; + }; + callback(f); + }, function (err) { + require.signal("error", [{ + error: err, + src: 'implab/store/mock' + }]); + }); + } + } + }; +}); \ No newline at end of file