changeset 34:27e8e9e38e07 default tip

Слияние
author nickolay
date Wed, 05 Jun 2019 20:44:15 +0300
parents 8af8e840dd49 (current diff) 1dc2fd263b90 (diff)
children
files core/src/js/safe.js src/djol/BaseLayer.js src/djol/ClearTool.js src/djol/CoordPickerTool.js src/djol/DeactivationTool.js src/djol/DistanceMeasureTool.js src/djol/DynamicStyle.js src/djol/IdentificationTool.js src/djol/IdentifyGroup.js src/djol/IdentifyItem.js src/djol/ImageLayer.js src/djol/ImageWMSSource.js src/djol/LayerCheckBox.js src/djol/LayerRadioButton.js src/djol/LayerSwitcher.js src/djol/Map.js src/djol/MeasureToolBase.js src/djol/OSMSource.js src/djol/OlTool.js src/djol/PopupContainer.js src/djol/SquareMeasureTool.js src/djol/TileLayer.js src/djol/TileWMSSource.js src/djol/ToolBoxController.js src/djol/ToolType.js src/djol/VectorLayer.js src/djol/VectorStore.js src/djol/VectorStoreQuery.js src/djol/WFSSource.js src/djol/_OneshotTool.js src/djol/_ToolBase.js src/djol/declare-style.js src/djol/format/coords.js src/djol/format/nls/coords.js src/djol/format/nls/ru/coords.js src/djol/format/nls/ru/units.js src/djol/format/nls/units.js src/djol/interaction/FeatureDrag.js src/djol/listen.js src/djol/main.js src/djol/ol-stub.js src/djol/resources/LayerCheckBoxTemplate.html src/djol/resources/LayerRadioButtonTemplate.html src/djol/resources/LayerSwitcherTemplate.html src/djol/resources/PopupContainerTemplate.html src/djol/resources/mapToolCheckBox.html src/implab/Deferred.js src/implab/Uri.js src/implab/Uuid.js src/implab/components/ActivationController.js src/implab/components/StateMachine.js src/implab/components/_ActivatableMixin.js src/implab/data/DataContext.js src/implab/data/MapSchema.js src/implab/data/ObjectStore.js src/implab/data/RestStore.js src/implab/data/StatefullStoreAdapter.js src/implab/data/StoreAdapter.js src/implab/data/_ModelBase.js src/implab/data/_StatefulModelMixin.js src/implab/data/declare-model.js src/implab/declare.js src/implab/declare/_load.js src/implab/declare/override.js src/implab/di/ActivationContext.js src/implab/di/ActivationError.js src/implab/di/Container.js src/implab/di/Descriptor.js src/implab/di/ReferenceDescriptor.js src/implab/di/ServiceDescriptor.js src/implab/di/ValueDescriptor.js src/implab/dom/css.js src/implab/dom/inject.js src/implab/guard.js src/implab/log/ConsoleLogChannel.js src/implab/log/_LogMixin.js src/implab/log/listeners/console.js src/implab/log/trace.js src/implab/messaging/Client.js src/implab/messaging/Destination.js src/implab/messaging/Listener.js src/implab/messaging/Session.js src/implab/safe.js src/implab/text/format-compile.js src/implab/text/format.js src/implab/text/template-compile.js src/utest/store/mock.js
diffstat 147 files changed, 4423 insertions(+), 6406 deletions(-) [+]
line wrap: on
line diff
--- 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/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.project	Wed Jun 05 20:44:15 2019 +0300
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>implab</name>
+	<comment>Project implab created by Buildship.</comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.buildship.core.gradleprojectbuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.buildship.core.gradleprojectnature</nature>
+	</natures>
+</projectDescription>
--- /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
--- /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
--- /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
--- /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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>core</name>
+	<comment>Project core created by Buildship.</comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.buildship.core.gradleprojectbuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.buildship.core.gradleprojectnature</nature>
+	</natures>
+</projectDescription>
--- /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
--- /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
--- /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
--- /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"
+}
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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 Имя свойства, в которое будет записан
+         *                идентификатор, если не указан, то идентификатор будет
+         *                взят из родительского хранилища или использоваться
+         *                строка <code>id</code>
+         * @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;
+            });
+        },
+
+        /**
+         * Выполняет запрос в родительском хранилище, для этого используется
+         * <code>translateQuery</code> для подготовки запроса, затем,
+         * <code>mapItem</code> для преобразования результатов.
+         */
+        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
--- /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
--- /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
--- /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).
+     * 
+     * Описание схемы выглядит следующим образом
+     * <pre>
+     * {
+     *      name : null, // отображение в обе стороны без преобразования
+     *      
+     *      age : Number,   // при преобразоваении к объекту поле будет преобразовано dst.age = Number(src.age)
+     *                      // обратное преобразование отсутстсвует
+     *      
+     *      age : [Number, null] // тоже самое что и age : Number
+     *      
+     *      date : [Date, function(v) { return v.toString() }] // указывается преобразование в одну и в другую сторону
+     * }
+     * <pre>
+     */
+    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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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 <null>" : "@value";
+        }
+    });
+});
\ No newline at end of file
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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;
+        }
+
+    });
+});
--- /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
--- /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;
+    });
--- /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);
+            },
+
+            /**
+             * Выполняет метод для каждого элемента массива, останавливается, когда
+             * либо достигнут конец массива, либо функция <c>cb</c> вернула
+             * значение.
+             * 
+             * @param{Array | Object} obj массив элементов для просмотра
+             * @param{Function} cb функция, вызываемая для каждого элемента
+             * @param{Object} thisArg значение, которое будет передано в качестве
+             *                <c>this</c> в <c>cb</c>.
+             * @returns Результат вызова функции <c>cb</c>, либо <c>undefined</c>
+             *          если достигнут конец массива.
+             */
+            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
--- /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;",
+            "&" : "&amp;",
+            "\\:" : "&colon;"
+        };
+
+        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
--- /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
--- /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
--- /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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>dom</name>
+	<comment>Project dom created by Buildship.</comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.buildship.core.gradleprojectbuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.buildship.core.gradleprojectnature</nature>
+	</natures>
+</projectDescription>
--- /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
--- /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
--- /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"
+}
--- /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
--- /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
--- /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
Binary file gradle/wrapper/gradle-wrapper.jar has changed
--- /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
--- /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" "$@"
--- /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
--- /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
--- 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
--- 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
--- 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
--- 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
--- 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
--- 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
--- 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
--- 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 : "<div class='identify-item-group'><div data-dojo-attach-point='identifyItemGroupTitle' class='identify-item-group-title'></div><div class='identify-item-group-content-container' data-dojo-attach-point='containerNode'></div></div>",
-
-                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
--- 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 : "<div class='identify-item'></div>",
-
-        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
--- 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
--- 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
--- 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
--- 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
--- 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
--- 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
--- 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
--- 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
--- 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
--- 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
--- 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
--- 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
--- 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
--- 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
--- 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
--- 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
--- 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
-                 * 
-                 * <pre>
-                 * {
-                 *     extent : ol3.Extent,
-                 * }
-                 * </pre>
-                 */
-                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
--- 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
-     * 
-     * <pre>
-     * var store = new VectorStore({
-     *     source : vectorSource
-     * });
-     * 
-     * var req = new VectorStoreQuery({
-     *     city : &quot;Moscow&quot;
-     * }, [ 30, 50, 40, 60 ]);
-     * 
-     * store.query(req).then(showResults);
-     * </pre>
-     */
-    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
--- 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
--- 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
--- 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
--- 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
--- 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
--- 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
--- 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
--- 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 : "м<sup>2</sup>",
-    kilometers2 : "км<sup>2</sup>",
-    nmiles : "миль",
-    nmiles2 : "миль<sup>2</sup>"
-});
\ No newline at end of file
--- 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 : "m<sup>2</sup>",
-        kilometers2 : "m<sup>2</sup>",
-        nmiles : "nmi",
-        nmiles2 : "nmi<sup>2</sup>"
-    },
-    ru : true
-});
\ No newline at end of file
--- 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
--- 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
--- 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
--- 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
--- 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 @@
-<div class="poisk-layer-checkbox">
-	<input type="checkbox" data-dojo-type="dijit/form/CheckBox" data-dojo-attach-point="checkBox"/><span
-		class="label" data-dojo-attach-point="labelNode"></span>
-</div>
\ No newline at end of file
--- 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 @@
-<div class="poisk-layer-radiobutton">
-	<input type="radio" data-dojo-attach-point="radioButton"
-		data-dojo-type="dijit/form/RadioButton" /><span
-		data-dojo-attach-point="labelNode"></span>
-</div>
\ No newline at end of file
--- 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 @@
-<div class="poisk-layer-switcher">
-	<h4 class="group-label" data-dojo-attach-point="infoLayersLabelNode"></h4>
-    <div data-dojo-attach-point="infoLayersContainer" data-dojo-type="app/view/Container"></div>
-    <h4 class="group-label" data-dojo-attach-point="baseLayersLabelNode"></h4>
-    <div data-dojo-attach-point="baseLayersContainer" data-dojo-type="app/view/Container"></div>
-</div>
\ No newline at end of file
--- 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 @@
-<div class="ol-popup">
-    <div data-dojo-attach-point="popupOverlay" class="popup-overlay">
-        <span class="inline-ghost"></span>
-        <div class="fa fa-spinner fa-pulse"></div>
-    </div>
-    <div class="ol-popup-closer fa fa-times" data-dojo-attach-point="popupCloser"></div>
-    <div class="popup-content" data-dojo-attach-point="popupContent"></div>
-</div>
\ No newline at end of file
--- 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 @@
-<div class="mapToolCheckBox poisk-measure-control tooltipMatchNode below">
-    <div data-dojo-attach-point="iconsBlock" class="iconsBlock"></div>
-</div>
\ No newline at end of file
--- 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
--- 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
--- 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
--- 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
--- 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
--- 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
--- 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
--- 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
--- 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
--- 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
--- 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
--- 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 Имя свойства, в которое будет записан
-         *                идентификатор, если не указан, то идентификатор будет
-         *                взят из родительского хранилища или использоваться
-         *                строка <code>id</code>
-         * @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;
-            });
-        },
-
-        /**
-         * Выполняет запрос в родительском хранилище, для этого используется
-         * <code>translateQuery</code> для подготовки запроса, затем,
-         * <code>mapItem</code> для преобразования результатов.
-         */
-        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
--- 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
--- 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
--- 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).
-     * 
-     * Описание схемы выглядит следующим образом
-     * <pre>
-     * {
-     *      name : null, // отображение в обе стороны без преобразования
-     *      
-     *      age : Number,   // при преобразоваении к объекту поле будет преобразовано dst.age = Number(src.age)
-     *                      // обратное преобразование отсутстсвует
-     *      
-     *      age : [Number, null] // тоже самое что и age : Number
-     *      
-     *      date : [Date, function(v) { return v.toString() }] // указывается преобразование в одну и в другую сторону
-     * }
-     * <pre>
-     */
-    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
--- 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
--- 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
--- 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
--- 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
--- 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
--- 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
--- 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
--- 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
--- 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
--- 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 <null>" : "@value";
-        }
-    });
-});
\ No newline at end of file
--- 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
--- 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
--- 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 Объект, который будет использован в качестве
-     *                <code>this</code>, если не указан, будет
-     *                <code>null</code>
-     * @param{Function|String} m Функция или имя метода, обязательный параметр.
-     *                         Если указано имя, тогда параметр <code>o</code>
-     *                         также должен быть задан
-     * @param{Array} args Параметры для вызова метода, не обязательно.
-     * @returns{dojo/promise}
-     * @deprecated use <code>safe.async() + when()</code> 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
--- 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
--- 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
--- 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
--- 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
--- 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
--- 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;
-        }
-
-    });
-});
--- 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
--- 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;
-    });
--- 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);
-            },
-
-            /**
-             * Выполняет метод для каждого элемента массива, останавливается, когда
-             * либо достигнут конец массива, либо функция <c>cb</c> вернула
-             * значение.
-             * 
-             * @param{Array | Object} obj массив элементов для просмотра
-             * @param{Function} cb функция, вызываемая для каждого элемента
-             * @param{Object} thisArg значение, которое будет передано в качестве
-             *                <c>this</c> в <c>cb</c>.
-             * @returns Результат вызова функции <c>cb</c>, либо <c>undefined</c>
-             *          если достигнут конец массива.
-             */
-            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
--- 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;",
-            "&" : "&amp;",
-            "\\:" : "&colon;"
-        };
-
-        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
--- 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
--- 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
--- 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
-     * 
-     * <pre>
-     * require([
-     *     &quot;tests/store/mock!./data/sample.json&quot;
-     * ], function(Store) {
-     *     var store = new Store(); // will create a memory store
-     * });
-     * </pre>
-     */
-    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
--- /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
+     * 
+     * <pre>
+     * require([
+     *     &quot;tests/store/mock!./data/sample.json&quot;
+     * ], function(Store) {
+     *     var store = new Store(); // will create a memory store
+     * });
+     * </pre>
+     */
+    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