You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by ak...@apache.org on 2015/07/02 10:27:01 UTC

[6/9] incubator-ignite git commit: # ignite-843 Cleanup module.

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8e792605/modules/web-control-center/nodejs/utils/generatorXml.js
----------------------------------------------------------------------
diff --git a/modules/web-control-center/nodejs/utils/generatorXml.js b/modules/web-control-center/nodejs/utils/generatorXml.js
new file mode 100644
index 0000000..ae7ffbc
--- /dev/null
+++ b/modules/web-control-center/nodejs/utils/generatorXml.js
@@ -0,0 +1,502 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+var generatorUtils = require("./generatorUtils");
+var dataStructures = require("../public/javascripts/dataStructures.js");
+
+exports.generateClusterConfiguration = function(cluster) {
+    var res = generatorUtils.builder();
+
+    res.push('' +
+        '<?xml version="1.0" encoding="UTF-8"?>\n' +
+        '\n' +
+        '<!-- ' + generatorUtils.mainComment() + ' -->\n' +    
+        '<beans xmlns="http://www.springframework.org/schema/beans"\n' +
+        '       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"\n' +
+        '       xmlns:util="http://www.springframework.org/schema/util"\n' +
+        '       xsi:schemaLocation="http://www.springframework.org/schema/beans\n' +
+        '                           http://www.springframework.org/schema/beans/spring-beans.xsd\n' +
+        '                           http://www.springframework.org/schema/util\n' +
+        '                           http://www.springframework.org/schema/util/spring-util.xsd">\n' +
+        '    <bean class="org.apache.ignite.configuration.IgniteConfiguration">\n');
+
+    res.deep = 2;
+
+    if (cluster.discovery) {
+        res.startBlock('<property name="discoverySpi">');
+        res.startBlock('<bean class="org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi">');
+        res.startBlock('<property name="ipFinder">');
+
+        var d = cluster.discovery;
+
+        switch (d.kind) {
+            case 'Multicast':
+                res.startBlock('<bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.multicast.TcpDiscoveryMulticastIpFinder">');
+
+                addProperty(res, d.Multicast, 'multicastGroup');
+                addProperty(res, d.Multicast, 'multicastPort');
+                addProperty(res, d.Multicast, 'responseWaitTime');
+                addProperty(res, d.Multicast, 'addressRequestAttempts');
+                addProperty(res, d.Multicast, 'localAddress');
+
+                res.endBlock('</bean>');
+
+                break;
+
+            case 'Vm':
+                if (d.Vm.addresses.length > 0) {
+                    res.startBlock('<bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder">');
+
+                    addListProperty(res, d.Vm, 'addresses');
+
+                    res.endBlock('</bean>');
+                }
+                else {
+                    res.line('<bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder"/>');
+                }
+
+                break;
+
+            case 'S3':
+                res.startBlock('<bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.s3.TcpDiscoveryS3IpFinder">');
+
+                if (d.S3 && d.S3.bucketName)
+                    res.line('<property name="bucketName" value="' + escapeAttr(d.S3.bucketName) + '" />');
+
+                res.endBlock('</bean>');
+
+                break;
+
+            case 'Cloud':
+                res.startBlock('<bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.cloud.TcpDiscoveryCloudIpFinder">');
+
+                addProperty(res, d.Cloud, 'credential');
+                addProperty(res, d.Cloud, 'credentialPath');
+                addProperty(res, d.Cloud, 'identity');
+                addProperty(res, d.Cloud, 'provider');
+
+                res.endBlock('</bean>');
+
+                break;
+
+            case 'GoogleStorage':
+                res.startBlock('<bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.gce.TcpDiscoveryGoogleStorageIpFinder">');
+
+                addProperty(res, d.GoogleStorage, 'projectName');
+                addProperty(res, d.GoogleStorage, 'bucketName');
+                addProperty(res, d.GoogleStorage, 'serviceAccountP12FilePath');
+
+                //if (d.GoogleStorage.addrReqAttempts) todo ????
+                //    res.line('<property name="serviceAccountP12FilePath" value="' + escapeAttr(d.GoogleStorage.addrReqAttempts) + '"/>');
+
+                res.endBlock('</bean>');
+
+                break;
+
+            case 'Jdbc':
+                res.startBlock('<bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.jdbc.TcpDiscoveryJdbcIpFinder">');
+                res.line('<property name="initSchema" value="' + (d.Jdbc.initSchema != null || d.Jdbc.initSchema) + '"/>');
+                res.endBlock('</bean>');
+
+                break;
+
+            case 'SharedFs':
+                if (d.SharedFs.path) {
+                    res.startBlock('<bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.sharedfs.TcpDiscoverySharedFsIpFinder">');
+                    addProperty(res, d.SharedFs, 'path');
+                    res.endBlock('</bean>');
+                }
+                else {
+                    res.line('<bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.sharedfs.TcpDiscoverySharedFsIpFinder"/>');
+                }
+
+                break;
+
+            default:
+                throw "Unknown discovery kind: " + d.kind;
+        }
+
+        res.endBlock('</property>');
+        res.endBlock('</bean>');
+        res.endBlock('</property>');
+
+        res.needEmptyLine = true
+    }
+
+    if (cluster.caches && cluster.caches.length > 0) {
+        res.emptyLineIfNeeded();
+
+        res.startBlock('<property name="cacheConfiguration">');
+        res.startBlock('<list>');
+
+        for (var i = 0; i < cluster.caches.length; i++) {
+            if (i > 0)
+                res.line();
+
+            generateCacheConfiguration(cluster.caches[i], res);
+        }
+
+        res.endBlock('</list>');
+        res.endBlock('</property>');
+
+        res.needEmptyLine = true;
+    }
+
+    if (cluster.includeEventTypes && cluster.includeEventTypes.length > 0) {
+        res.emptyLineIfNeeded();
+        
+        res.startBlock('<property name="includeEventTypes">');
+        
+        if (cluster.includeEventTypes.length == 1) {
+            res.line('<util:constant static-field="org.apache.ignite.events.EventType.' + cluster.includeEventTypes[0] + '"/>')
+        }
+        else {
+            res.startBlock('<array>');
+
+            for (i = 0; i < cluster.includeEventTypes.length; i++) {
+                if (i > 0)
+                    res.line();
+
+                var eventGroup = cluster.includeEventTypes[i];
+
+                res.line('<!-- EventType.' + eventGroup + ' -->');
+
+                var eventList = dataStructures.eventGroups[eventGroup];
+
+                for (var k = 0; k < eventList.length; k++) {
+                    res.line('<util:constant static-field="org.apache.ignite.events.EventType.' + eventList[k] + '"/>')
+                }
+            }
+
+            res.endBlock('</array>');
+        }
+        
+        res.endBlock('</property>');
+
+        res.needEmptyLine = true;
+    }
+    
+    addBeanWithProperties(res, cluster.atomicConfiguration, 'atomicConfiguration',
+        generatorUtils.atomicConfiguration.className, generatorUtils.atomicConfiguration.fields);
+
+    res.needEmptyLine = true;
+
+    addProperty(res, cluster, 'networkTimeout');
+    addProperty(res, cluster, 'networkSendRetryDelay');
+    addProperty(res, cluster, 'networkSendRetryCount');
+    addProperty(res, cluster, 'segmentCheckFrequency');
+    addProperty(res, cluster, 'waitForSegmentOnStart');
+    addProperty(res, cluster, 'discoveryStartupDelay');
+    
+    res.needEmptyLine = true;
+    
+    addProperty(res, cluster, 'deploymentMode');
+
+    res.needEmptyLine = true;
+
+    addProperty(res, cluster, 'marshalLocalJobs');
+    addProperty(res, cluster, 'marshCacheKeepAliveTime');
+    addProperty(res, cluster, 'marshCachePoolSize');
+
+    res.needEmptyLine = true;
+
+    addProperty(res, cluster, 'metricsExpireTime');
+    addProperty(res, cluster, 'metricsHistorySize');
+    addProperty(res, cluster, 'metricsLogFrequency');
+    addProperty(res, cluster, 'metricsUpdateFrequency');
+
+    res.needEmptyLine = true;
+
+    addProperty(res, cluster, 'peerClassLoadingEnabled');
+    addListProperty(res, cluster, 'peerClassLoadingLocalClassPathExclude');
+    addProperty(res, cluster, 'peerClassLoadingMissedResourcesCacheSize');
+    addProperty(res, cluster, 'peerClassLoadingThreadPoolSize');
+    
+    res.needEmptyLine = true;
+
+    if (cluster.swapSpaceSpi && cluster.swapSpaceSpi.kind == 'FileSwapSpaceSpi') {
+        addBeanWithProperties(res, cluster.swapSpaceSpi.FileSwapSpaceSpi, 'swapSpaceSpi',
+            generatorUtils.swapSpaceSpi.className, generatorUtils.swapSpaceSpi.fields, true);
+
+        res.needEmptyLine = true;
+    }
+    
+    addProperty(res, cluster, 'clockSyncSamples');
+    addProperty(res, cluster, 'clockSyncFrequency');
+    addProperty(res, cluster, 'timeServerPortBase');
+    addProperty(res, cluster, 'timeServerPortRange');
+
+    res.needEmptyLine = true;
+
+    addProperty(res, cluster, 'publicThreadPoolSize');
+    addProperty(res, cluster, 'systemThreadPoolSize');
+    addProperty(res, cluster, 'managementThreadPoolSize');
+    addProperty(res, cluster, 'igfsThreadPoolSize');
+
+    res.needEmptyLine = true;
+    
+    addBeanWithProperties(res, cluster.transactionConfiguration, 'transactionConfiguration',
+        generatorUtils.transactionConfiguration.className, generatorUtils.transactionConfiguration.fields);
+
+    res.needEmptyLine = true;
+
+    addProperty(res, cluster, 'cacheSanityCheckEnabled');
+    
+    res.needEmptyLine = true;
+
+    addProperty(res, cluster, 'utilityCacheKeepAliveTime');
+    addProperty(res, cluster, 'utilityCachePoolSize');
+    
+    res.push('    </bean>\n');
+    res.push('</beans>');
+
+    return res.join('');
+};
+
+function createEvictionPolicy(res, evictionPolicy, propertyName) {
+    if (evictionPolicy && evictionPolicy.kind) {
+        var e = generatorUtils.evictionPolicies[evictionPolicy.kind];
+
+        var obj = evictionPolicy[evictionPolicy.kind.toUpperCase()];
+
+        addBeanWithProperties(res, obj, propertyName, e.className, e.fields, true);
+    }
+}
+
+function generateCacheConfiguration(cacheCfg, res) {
+    if (!res)
+        res = generatorUtils.builder();
+
+    res.startBlock('<bean class="org.apache.ignite.configuration.CacheConfiguration">');
+
+    addProperty(res, cacheCfg, 'name');
+
+    res.needEmptyLine = true;
+
+    addProperty(res, cacheCfg, 'mode', 'cacheMode');
+
+    addProperty(res, cacheCfg, 'atomicityMode');
+    addProperty(res, cacheCfg, 'backups');
+
+    res.needEmptyLine = true;
+
+    addProperty(res, cacheCfg, 'memoryMode');
+    addProperty(res, cacheCfg, 'offHeapMaxMemory');
+    addProperty(res, cacheCfg, 'swapEnabled');
+
+    res.needEmptyLine = true;
+
+    createEvictionPolicy(res, cacheCfg.evictionPolicy, 'evictionPolicy');
+
+    res.needEmptyLine = true;
+
+    if (cacheCfg.nearConfiguration && (cacheCfg.nearConfiguration.nearStartSize || cacheCfg.nearConfiguration.nearEvictionPolicy.kind)) {
+        res.emptyLineIfNeeded();
+
+        res.startBlock('<property name="nearConfiguration">');
+        res.startBlock('<bean class="org.apache.ignite.configuration.NearCacheConfiguration">');
+
+        addProperty(res, cacheCfg.nearConfiguration, 'nearStartSize');
+
+        createEvictionPolicy(res, cacheCfg.nearConfiguration.nearEvictionPolicy, 'nearEvictionPolicy');
+
+        res.endBlock('</bean>');
+        res.endBlock('</property>');
+    }
+
+    res.needEmptyLine = true;
+
+    addProperty(res, cacheCfg, 'sqlEscapeAll');
+    addProperty(res, cacheCfg, 'sqlOnheapRowCacheSize');
+    addProperty(res, cacheCfg, 'longQueryWarningTimeout');
+
+    if (cacheCfg.indexedTypes && cacheCfg.indexedTypes.length > 0) {
+        res.startBlock('<property name="indexedTypes">');
+        res.startBlock('<array>');
+
+        for (var i = 0; i < cacheCfg.indexedTypes.length; i++) {
+            var pair = cacheCfg.indexedTypes[i];
+
+            res.line('<value>' + escape(pair.keyClass) + '</value>');
+            res.line('<value>' + escape(pair.valueClass) + '</value>');
+        }
+
+        res.endBlock('</array>');
+        res.endBlock('</property>');
+    }
+
+    addListProperty(res, cacheCfg, 'sqlFunctionClasses', 'array');
+
+    res.needEmptyLine = true;
+
+    addProperty(res, cacheCfg, 'rebalanceMode');
+    addProperty(res, cacheCfg, 'rebalanceThreadPoolSize');
+    addProperty(res, cacheCfg, 'rebalanceBatchSize');
+    addProperty(res, cacheCfg, 'rebalanceOrder');
+    addProperty(res, cacheCfg, 'rebalanceDelay');
+    addProperty(res, cacheCfg, 'rebalanceTimeout');
+    addProperty(res, cacheCfg, 'rebalanceThrottle');
+
+    res.needEmptyLine = true;
+
+    if (cacheCfg.cacheStoreFactory && cacheCfg.cacheStoreFactory.kind) {
+        var obj = cacheCfg.cacheStoreFactory[cacheCfg.cacheStoreFactory.kind];
+        var data = generatorUtils.storeFactories[cacheCfg.cacheStoreFactory.kind];
+
+        addBeanWithProperties(res, obj, 'cacheStoreFactory', data.className, data.fields, true);
+    }
+
+    res.needEmptyLine = true;
+
+    addProperty(res, cacheCfg, 'invalidate');
+    addProperty(res, cacheCfg, 'defaultLockTimeout');
+    addProperty(res, cacheCfg, 'transactionManagerLookupClassName');
+
+    res.needEmptyLine = true;
+
+    addProperty(res, cacheCfg, 'writeBehindEnabled');
+    addProperty(res, cacheCfg, 'writeBehindBatchSize');
+    addProperty(res, cacheCfg, 'writeBehindFlushSize');
+    addProperty(res, cacheCfg, 'writeBehindFlushFrequency');
+    addProperty(res, cacheCfg, 'writeBehindFlushThreadCount');
+
+    res.needEmptyLine = true;
+
+    addProperty(res, cacheCfg, 'statisticsEnabled');
+    addProperty(res, cacheCfg, 'managementEnabled');
+    addProperty(res, cacheCfg, 'readFromBackup');
+    addProperty(res, cacheCfg, 'copyOnRead');
+    addProperty(res, cacheCfg, 'maxConcurrentAsyncOperations');
+    
+    res.endBlock('</bean>');
+
+    return res;
+}
+
+exports.generateCacheConfiguration = generateCacheConfiguration;
+
+function addProperty(res, obj, propName, setterName) {
+    var val = obj[propName];
+
+    if (val) {
+        res.emptyLineIfNeeded();
+
+        res.line('<property name="' + (setterName ? setterName : propName) + '" value="' + escapeAttr(val) + '"/>');
+    }
+}
+
+function addBeanWithProperties(res, bean, beanPropName, beanClass, props, createBeanAlthoughNoProps) {
+    if (!bean)
+        return;
+
+    if (generatorUtils.hasProperty(bean, props)) {
+        res.emptyLineIfNeeded();
+        res.startBlock('<property name="' + beanPropName + '">');
+        res.startBlock('<bean class="' + beanClass + '">');
+
+        for (var propName in props) {
+            if (props.hasOwnProperty(propName)) {
+                var descr = props[propName];
+
+                if (descr) {
+                    if (descr.type == 'list') {
+                        addListProperty(res, bean, propName, descr.setterName);
+                    }
+                    else if (descr.type == 'className') {
+                        if (bean[propName]) {
+                            res.startBlock('<property name="' + propName + '">');
+                            res.line('<bean class="' + generatorUtils.knownClasses[bean[propName]].className + '"/>');
+                            res.endBlock('</property>');
+                        }
+                    }
+                    else if (descr.type == 'propertiesAsList') {
+                        var val = bean[propName];
+
+                        if (val && val.length > 0) {
+                            res.startBlock('<property name="' + propName + '">');
+                            res.startBlock('<props>');
+
+                            for (var i = 0; i < val.length; i++) {
+                                var nameAndValue = val[i];
+
+                                var eqIndex = nameAndValue.indexOf('=');
+                                if (eqIndex >= 0) {
+                                    res.line('<prop key="' + escapeAttr(nameAndValue.substring(0, eqIndex)) + '">' +
+                                            + escape(nameAndValue.substr(eqIndex + 1)) + '</prop>');
+                                }
+                            }
+
+                            res.endBlock('</props>');
+                            res.endBlock('</property>');
+                        }
+                    }
+                    else {
+                        addProperty(res, bean, propName, descr.setterName);
+                    }
+                }
+                else {
+                    addProperty(res, bean, propName);
+                }
+            }
+        }
+
+        res.endBlock('</bean>');
+        res.endBlock('</property>');
+    }
+    else if (createBeanAlthoughNoProps) {
+        res.emptyLineIfNeeded();
+        res.line('<property name="' + beanPropName + '">');
+        res.line('    <bean class="' + beanClass + '"/>');
+        res.line('</property>');
+    }
+}
+function addListProperty(res, obj, propName, listType, rowFactory) {
+    var val = obj[propName];
+
+    if (val && val.length > 0) {
+        res.emptyLineIfNeeded();
+
+        if (!listType)
+            listType = 'list';
+
+        if (!rowFactory)
+            rowFactory = function(val) { return '<value>' + escape(val) + '</value>' };
+
+        res.startBlock('<property name="' + propName + '">');
+        res.startBlock('<' + listType + '>');
+
+        for (var i = 0; i < val.length; i++)
+            res.line(rowFactory(val[i]));
+
+        res.endBlock('</' + listType + '>');
+        res.endBlock('</property>');
+    }
+}
+
+function escapeAttr(s) {
+    if (typeof(s) != 'string')
+        return s;
+
+    return s.replace(/&/g, '&amp;').replace(/"/g, '&quot;');
+}
+
+function escape(s) {
+    if (typeof(s) != 'string')
+        return s;
+
+    return s.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8e792605/modules/web-control-center/nodejs/views/caches.jade
----------------------------------------------------------------------
diff --git a/modules/web-control-center/nodejs/views/caches.jade b/modules/web-control-center/nodejs/views/caches.jade
new file mode 100644
index 0000000..d6bda10
--- /dev/null
+++ b/modules/web-control-center/nodejs/views/caches.jade
@@ -0,0 +1,68 @@
+//-
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+extends layout-sidebar
+
+append scripts
+    script(src='/javascripts/controllers/caches.js')
+
+include includes/controls
+
+block content
+    .docs-header
+        h1 Caches
+        p Create and configure Ignite caches.
+        hr
+    .docs-body(ng-controller='cachesController')
+        .links(ng-hide='caches.length == 0')
+            table.col-sm-12(st-table='caches')
+                tbody
+                    tr(ng-repeat='row in caches track by row._id')
+                        td.col-sm-6(ng-class='{active: row._id == selectedItem._id}')
+                            a(ng-click='selectItem(row)') {{$index + 1}}. {{row.name}}, {{row.mode | displayValue:modes:'Cache mode not set'}}, {{row.atomicityMode | displayValue:atomicities:'Cache atomicity not set'}}
+        button.btn.btn-primary(ng-click='createItem()') Add cache
+        hr
+        form.form-horizontal(name='inputForm' ng-if='backupItem' novalidate)
+            div(bs-collapse data-start-collapsed='false')
+                .panel.panel-default
+                    .panel-heading
+                        h3
+                            a(bs-collapse-toggle) General
+                    .panel-collapse(bs-collapse-target)
+                        .panel-body
+                            .settings-row(ng-repeat='field in general')
+                                +form-row
+            div(bs-collapse data-start-collapsed='true')
+                .panel-title(ng-show='expanded')
+                    h3
+                        a(bs-collapse-toggle='0' ng-click='expanded = !expanded;') {{expanded ? 'Hide advanced settings...' : 'Show advanced settings...'}}
+                .panel-collapse(bs-collapse-target)
+                    .span(bs-collapse data-start-collapsed='true' data-allow-multiple='true')
+                        .panel.panel-default(ng-repeat='group in advanced')
+                            .panel-heading
+                                h3
+                                    a(bs-collapse-toggle) {{group.label}}
+                                    i.tipLabel.fa.fa-question-circle(ng-if='group.tip' bs-tooltip='joinTip(group.tip)' type='button')
+                                    i.tipLabel.fa.fa-question-circle.blank(ng-if='!group.tip')
+                            .panel-collapse(bs-collapse-target)
+                                .panel-body
+                                    .settings-row(ng-repeat='field in group.fields')
+                                        +form-row
+                .panel-title
+                    h3
+                        a(bs-collapse-toggle='0' ng-click='expanded = !expanded;') {{expanded ? 'Hide advanced settings...' : 'Show advanced settings...'}}
+            button#save-btn.btn.btn-primary(ng-disabled='inputForm.$invalid' ng-click='saveItem()') Save
+            button.btn.btn-primary.btn-second(ng-show='backupItem._id' ng-click='removeItem()') Remove

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8e792605/modules/web-control-center/nodejs/views/clients.jade
----------------------------------------------------------------------
diff --git a/modules/web-control-center/nodejs/views/clients.jade b/modules/web-control-center/nodejs/views/clients.jade
new file mode 100644
index 0000000..6b55449
--- /dev/null
+++ b/modules/web-control-center/nodejs/views/clients.jade
@@ -0,0 +1,26 @@
+//-
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+extends layout-sidebar
+block head
+block content
+    .docs-header
+        h1 Clients
+        p Create and configure Ignite clients.
+        hr
+    .docs-body(ng-controller='clientsRouter')
+block body
+    script(src='/javascripts/controllers/clients.js')
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8e792605/modules/web-control-center/nodejs/views/clusters.jade
----------------------------------------------------------------------
diff --git a/modules/web-control-center/nodejs/views/clusters.jade b/modules/web-control-center/nodejs/views/clusters.jade
new file mode 100644
index 0000000..8bb8ef9
--- /dev/null
+++ b/modules/web-control-center/nodejs/views/clusters.jade
@@ -0,0 +1,71 @@
+//-
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+extends layout-sidebar
+
+append scripts
+    script(src='/javascripts/controllers/clusters.js')
+
+include includes/controls
+
+block content
+    .docs-header
+        h1 Clusters
+        p Create and configure Ignite clusters.
+        hr
+    .docs-body(ng-controller='clustersController')
+        .links(ng-hide='clusters.length == 0')
+            table.col-sm-12(st-table='clusters')
+                tbody
+                    tr(ng-repeat='row in clusters track by row._id')
+                        td.col-sm-6(ng-class='{active: row._id == selectedItem._id}')
+                            a(ng-click='selectItem(row)') {{$index + 1}}. {{row.name}}, {{row.discovery.kind | displayValue:discoveries:'Discovery not set'}}
+        button.btn.btn-primary(ng-click='createItem()' ng-disabled='!create.template') &nbspAdd cluster
+        label(style='margin-left: 15px; margin-right: 10px') Use template:
+        button.btn.btn-default(ng-init='create.template = templates[0].value' ng-model='create.template' data-template='/select' data-placeholder='Choose cluster template' bs-options='item.value as item.label for item in templates' bs-select)
+        i.tiplabel.fa.fa-question-circle(bs-tooltip data-title='{{joinTip(templateTip)}}' type='button')
+        hr
+        form.form-horizontal(name='inputForm' ng-if='backupItem' novalidate)
+            div(bs-collapse data-start-collapsed='false')
+                .panel.panel-default
+                    .panel-heading
+                        h3
+                            a(bs-collapse-toggle) General
+                    .panel-collapse(bs-collapse-target)
+                        .panel-body
+                            .settings-row(ng-repeat='field in general')
+                                +form-row
+            div(bs-collapse data-start-collapsed='true')
+                .panel-title(ng-show='expanded')
+                    h3
+                        a(bs-collapse-toggle='0' ng-click='expanded = !expanded;') {{expanded ? 'Hide advanced settings...' : 'Show advanced settings...'}}
+                .panel-collapse(bs-collapse-target)
+                    .span(bs-collapse data-start-collapsed='true' data-allow-multiple='true')
+                        .panel.panel-default(ng-repeat='group in advanced')
+                            .panel-heading
+                                h3
+                                    a(bs-collapse-toggle) {{group.label}}
+                                    i.tipLabel.fa.fa-question-circle(ng-if='group.tip' bs-tooltip='joinTip(group.tip)' type='button')
+                                    i.tipLabel.fa.fa-question-circle.blank(ng-if='!group.tip')
+                            .panel-collapse(bs-collapse-target)
+                                .panel-body
+                                    .settings-row(ng-repeat='field in group.fields')
+                                        +form-row
+                .panel-title
+                    h3
+                        a(bs-collapse-toggle='0' ng-click='expanded = !expanded;') {{expanded ? 'Hide advanced settings...' : 'Show advanced settings...'}}
+            button#save-btn.btn.btn-primary(ng-disabled='inputForm.$invalid' ng-click='saveItem()') Save
+            button.btn.btn-primary(ng-show='backupItem._id' ng-click='removeItem()') Remove
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8e792605/modules/web-control-center/nodejs/views/error.jade
----------------------------------------------------------------------
diff --git a/modules/web-control-center/nodejs/views/error.jade b/modules/web-control-center/nodejs/views/error.jade
new file mode 100644
index 0000000..cfa2ad1
--- /dev/null
+++ b/modules/web-control-center/nodejs/views/error.jade
@@ -0,0 +1,22 @@
+//-
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+extends layout
+
+block container
+  h1= message
+  h2= error.status
+  pre #{error.stack}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8e792605/modules/web-control-center/nodejs/views/includes/controls.jade
----------------------------------------------------------------------
diff --git a/modules/web-control-center/nodejs/views/includes/controls.jade b/modules/web-control-center/nodejs/views/includes/controls.jade
new file mode 100644
index 0000000..028b187
--- /dev/null
+++ b/modules/web-control-center/nodejs/views/includes/controls.jade
@@ -0,0 +1,193 @@
+//-
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+mixin tipField(lines)
+    i.tipField.fa.fa-question-circle(ng-if=lines bs-tooltip='joinTip(#{lines})' type='button')
+    i.tipField.fa.fa-question-circle.blank(ng-if='!#{lines}')
+
+mixin tipLabel(lines)
+    i.tipLabel.fa.fa-question-circle(ng-if=lines bs-tooltip='joinTip(#{lines})' type='button')
+    i.tipLabel.fa.fa-question-circle.blank(ng-if='!#{lines}')
+
+mixin exclamation(mdl, err, msg)
+    i.fa.fa-exclamation-triangle.form-control-feedback(ng-show='inputForm["#{mdl}"].$error.#{err}' bs-tooltip data-title='#{msg}' type='button')
+
+mixin details-row
+    - var lblDetailClasses = ['col-sm-4', 'details-label']
+
+    - var detailMdl = 'getModel(backupItem, detail.path)[detail.model]';
+    - var detailCommon = {'ng-model': detailMdl};
+
+    div(ng-switch='detail.type')
+        div.checkbox(ng-switch-when='check')
+            label
+                input(type='checkbox')&attributes(detailCommon)
+                |{{detail.label}}
+                +tipLabel('detail.tip')
+        div(ng-switch-when='text')
+            label(class=lblDetailClasses) {{detail.label}}:
+            .col-sm-8
+                +tipField('detail.tip')
+                .input-tip
+                    input.form-control(type='text' placeholder='{{detail.placeholder}}')&attributes(detailCommon)
+        div(ng-switch-when='number' )
+            label(class=lblDetailClasses) {{detail.label}}:
+            .col-sm-8
+                +tipField('detail.tip')
+                .input-tip
+                    input.form-control(name='{{detail.model}}' type='number' placeholder='{{detail.placeholder}}' min='{{detail.min ? detail.min : 0}}' max='{{detail.max ? detail.max : Number.MAX_VALUE}}')&attributes(detailCommon)
+                    +exclamation('{{detail.model}}', 'min', 'Value is less than allowable minimum.')
+                    +exclamation('{{detail.model}}', 'max', 'Value is more than allowable maximum.')
+                    +exclamation('{{detail.model}}', 'number', 'Invalid value. Only numbers allowed.')
+        div(ng-switch-when='dropdown')
+            label(class=lblDetailClasses) {{detail.label}}:
+            .col-sm-8
+                +tipField('detail.tip')
+                .input-tip
+                    button.form-control(bs-select data-placeholder='{{detail.placeholder}}' bs-options='item.value as item.label for item in {{detail.items}}')&attributes(detailCommon)
+        div(ng-switch-when='dropdown-multiple')
+            label(class=lblDetailClasses) {{detail.label}}:
+            .col-sm-8
+                button.form-control(bs-select data-multiple='1' data-placeholder='{{detail.placeholder}}' bs-options='item.value as item.label for item in {{detail.items}}')&attributes(detailCommon)
+            +tipField('detail.tip')
+        div(ng-switch-when='table-simple' style='margin-right: 5px; margin-top: -0.65em')&attributes(detailCommon)
+            table.col-sm-12.links-edit(st-table='#{detailMdl}' ng-show='#{detailMdl}.length > 0')
+                tbody
+                    tr(ng-repeat='item in #{detailMdl} track by $index')
+                        td.col-sm-11
+                            div(ng-show='detail.editIdx != {{$index}}')
+                                a(ng-click='detail.editIdx = $index; curValue = #{detailMdl}[$index]') {{$index + 1}}) {{item}}
+                                i.tipField.fa.fa-remove(ng-click='detail.editIdx = -1; #{detailMdl}.splice($index, 1)')
+                            div(ng-show='detail.editIdx == {{$index}}')
+                                label.labelField {{$index + 1}})
+                                i.tipField.fa.fa-floppy-o(ng-click='detail.editIdx = -1; #{detailMdl}[$index]=curValue')
+                                .input-tip
+                                    input.form-control(type='text' ng-model='curValue' placeholder='{{detail.placeholder}}')
+                        td.col-sm-1(ng-if='detail.reordering')
+                            i.fa.fa-arrow-up(ng-show='$index > 0' ng-click='swapSimpleItems(detailMdl, $index, $index - 1); detail.editIdx = -1;')
+                            i.fa.fa-arrow-down(ng-show='$index < #{detailMdl}.length - 1' ng-click='swapSimpleItems(#{detailMdl}, $index, $index + 1); detail.editIdx = -1;')
+            button.btn.btn-primary.fieldButton(ng-disabled='!newValue || #{detailMdl}.indexOf(newValue) >= 0' ng-click='detail.editIdx = -1; #{detailMdl} ? #{detailMdl}.push(newValue) : #{detailMdl} = [newValue];') Add
+            +tipField('detail.tip')
+            .input-tip
+                input.form-control(type='text' ng-model='newValue' ng-focus='detail.editIdx = -1' placeholder='{{detail.placeholder}}')
+
+mixin form-row
+    - var lblClasses = ['col-sm-2']
+
+    - var fieldMdl = 'getModel(backupItem, field.path)[field.model]';
+    - var fieldCommon = {'ng-model': fieldMdl};
+
+    div(ng-switch='field.type')
+        div.checkbox.col-sm-6(ng-switch-when='check')
+            label
+                input(type='checkbox')&attributes(fieldCommon)
+                | {{field.label}}
+                +tipLabel('field.tip')
+        div(ng-switch-when='text')
+            label(class=lblClasses ng-class='{required: field.required}') {{field.label}}:
+            .col-sm-4
+                +tipField('field.tip')
+                .input-tip
+                    input.form-control(type='text' placeholder='{{field.placeholder}}' ng-required='field.required')&attributes(fieldCommon)
+        div(ng-switch-when='password')
+            label(class=lblClasses ng-class='{required: field.required}') {{field.label}}:
+            .col-sm-4
+                +tipField('field.tip')
+                .input-tip
+                    input.form-control(type='password' placeholder='{{field.placeholder}}' ng-required='field.required')&attributes(fieldCommon)
+        div(ng-switch-when='number')
+            label(class=lblClasses ng-class='{required: field.required}') {{field.label}}:
+            .col-sm-4
+                +tipField('field.tip')
+                .input-tip
+                    input.form-control(name='{{field.model}}' type='number' placeholder='{{field.placeholder}}' min='{{field.min ? field.min : 0}}' max='{{field.max ? field.max : Number.MAX_VALUE}}' ng-required='field.required')&attributes(fieldCommon)
+                    +exclamation('{{field.model}}', 'min', 'Value is less than allowable minimum.')
+                    +exclamation('{{field.model}}', 'max', 'Value is more than allowable maximum.')
+                    +exclamation('{{field.model}}', 'number', 'Invalid value. Only numbers allowed.')
+        div(ng-switch-when='dropdown')
+            label(class=lblClasses ng-class='{required: field.required}') {{field.label}}:
+            .col-sm-4
+                +tipField('field.tip')
+                .input-tip
+                    button.form-control(bs-select ng-required='field.required' data-placeholder='{{field.placeholder}}' bs-options='item.value as item.label for item in {{field.items}}')&attributes(fieldCommon)
+        div(ng-switch-when='dropdown-multiple')
+            label(class=lblClasses ng-class='{required: field.required}') {{field.label}}:
+            .col-sm-4
+                +tipField('field.tip')
+                .input-tip
+                    button.form-control(bs-select ng-disabled='{{field.items}}.length == 0' data-multiple='1' data-placeholder='{{field.placeholder}}' bs-options='item.value as item.label for item in {{field.items}}')&attributes(fieldCommon)
+            a.customize(ng-show='field.addLink' ng-href='{{field.addLink.ref}}') {{field.addLink.label}}
+        div(ng-switch-when='dropdown-details')
+            - var expanded = 'field.details[' + fieldMdl + '].expanded'
+
+            label(class=lblClasses ng-class='{required: field.required}') {{field.label}}:
+            .col-sm-4
+                +tipField('field.tip')
+                .input-tip
+                    button.form-control(bs-select ng-required='field.required' data-placeholder='{{field.placeholder}}' bs-options='item.value as item.label for item in {{field.items}}')&attributes(fieldCommon)
+            a.customize(ng-show='#{fieldMdl} && field.details[#{fieldMdl}].fields' ng-click='#{expanded} = !#{expanded}') {{#{expanded} ? "Hide settings" : "Show settings"}}
+            .col-sm-6.panel-details(ng-show='#{expanded} && #{fieldMdl}')
+                .details-row(ng-repeat='detail in field.details[#{fieldMdl}].fields')
+                    +details-row
+        div(ng-switch-when='table-simple')&attributes(fieldCommon)
+            div
+                label {{field.tableLabel}}: {{#{fieldMdl}.length}}
+                +tipLabel('field.tip')
+            table.links-edit.col-sm-12(st-table='#{fieldMdl}' ng-show='#{fieldMdl}.length > 0')
+                tbody
+                    tr.col-sm-12(ng-repeat='item in #{fieldMdl} track by $index')
+                        td.col-sm-6
+                            div(ng-show='field.editIdx != {{$index}}')
+                                a(ng-click='field.editIdx = $index; curValue = #{fieldMdl}[$index]') {{$index + 1}}) {{item | compact}}
+                                i.tipField.fa.fa-remove(ng-click='field.editIdx = -1; #{fieldMdl}.splice($index, 1)')
+                            div(ng-show='field.editIdx == {{$index}}')
+                                label.labelField {{$index + 1}})
+                                i.tipField.fa.fa-floppy-o(ng-click='field.editIdx = -1; #{fieldMdl}[$index]=curValue')
+                                .input-tip
+                                    input.form-control(type='text' ng-model='curValue' placeholder='{{field.placeholder}}')
+                        td.col-sm-1(ng-if='field.reordering')
+                            i.fa.fa-arrow-up(ng-show='$index > 0' ng-click='swapSimpleItems(fieldMdl, $index, $index - 1); field.editIdx = -1;')
+                            i.fa.fa-arrow-down(ng-show='$index < #{fieldMdl}.length - 1' ng-click='swapSimpleItems(#{fieldMdl}, $index, $index + 1); field.editIdx = -1;')
+            .col-sm-6
+                button.btn.btn-primary.fieldButton(ng-disabled='!newValue || #{fieldMdl}.indexOf(newValue) >= 0' ng-click='field.editIdx = -1; #{fieldMdl} ? #{fieldMdl}.push(newValue) : #{fieldMdl} = [newValue];') Add
+                +tipField('field.tip')
+                .input-tip
+                    input.form-control(type='text' ng-model='newValue' ng-focus='field.editIdx = -1'  placeholder='{{field.placeholder}}')
+        div(ng-switch-when='indexedTypes')
+            - var tblMdl = 'backupItem.indexedTypes'
+            div
+                label Indexed types: {{#{tblMdl}.length}}
+                +tipLabel('field.tip')
+            table.links-edit.col-sm-12(st-table=tblMdl ng-show='#{tblMdl}.length > 0')
+                tbody
+                    tr.col-sm-12(ng-repeat='item in #{tblMdl}')
+                        td.col-sm-6
+                            div(ng-show='field.editIdx != {{$index}}')
+                                a(ng-click='field.editIdx = $index; curKeyClass = #{tblMdl}[$index].keyClass; curValueClass = #{tblMdl}[$index].valueClass') {{$index + 1}}) {{item.keyClass}} / {{item.valueClass}}
+                                i.tipField.fa.fa-remove(ng-click='field.editIdx = -1; #{tblMdl}.splice($index, 1)')
+                            div(ng-show='field.editIdx == {{$index}}')
+                                label.labelField {{$index + 1}})
+                                i.tipField.fa.fa-floppy-o(ng-click='field.editIdx = -1; #{tblMdl}[$index]={keyClass: curKeyClass, valueClass: curValueClass}')
+                                .input-tip
+                                    .col-sm-12
+                                        input.form-control.table-form-control(type='text' ng-model='curKeyClass' placeholder='Key class full name')
+                                        label &nbsp;/&nbsp;
+                                        input.form-control.table-form-control(type='text' ng-model='curValueClass' placeholder='Value class full name')
+            .col-sm-6
+                input.form-control(type='text' ng-model='newKeyClass' ng-focus='field.editIdx = -1' placeholder='Key class full name')
+                .settings-row
+                    input.form-control(type='text' ng-model='newValueClass' ng-focus='field.editIdx = -1' placeholder='Value class full name')
+                button.btn.btn-primary.fieldButton(ng-click='field.editIdx = -1; addIndexedTypes(newKeyClass, newValueClass)') Add

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8e792605/modules/web-control-center/nodejs/views/includes/footer.jade
----------------------------------------------------------------------
diff --git a/modules/web-control-center/nodejs/views/includes/footer.jade b/modules/web-control-center/nodejs/views/includes/footer.jade
new file mode 100644
index 0000000..3cc0f86
--- /dev/null
+++ b/modules/web-control-center/nodejs/views/includes/footer.jade
@@ -0,0 +1,23 @@
+//-
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+.container.container-footer
+    footer
+        center
+            p
+                | Powered by
+                a(href='http://ignite.incubator.apache.org')  Apache Ignite
+                | , version 1.1.0
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8e792605/modules/web-control-center/nodejs/views/includes/header.jade
----------------------------------------------------------------------
diff --git a/modules/web-control-center/nodejs/views/includes/header.jade b/modules/web-control-center/nodejs/views/includes/header.jade
new file mode 100644
index 0000000..9ffb687
--- /dev/null
+++ b/modules/web-control-center/nodejs/views/includes/header.jade
@@ -0,0 +1,36 @@
+//-
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+header.header(id='header')
+    .container
+        h1.navbar-brand
+            a(href='/') Apache Ignite Web Configurator
+        .navbar-collapse.collapse(ng-controller='auth')
+            ul.nav.navbar-nav(ng-controller='activeLink')
+                li
+                    a(ng-class="{active: isActive('/clusters')}" href='/clusters') Configuration
+                li
+                    a(ng-class="{active: isActive('/sql')}" href='/sql') SQL
+            ul.nav.navbar-nav.pull-right(ng-init='user = #{JSON.stringify(user)}')
+                li(ng-show='user')
+                    a.dropdown-toggle(data-toggle='dropdown' aria-expanded='true' bs-dropdown data-template='user-dropdown' data-placement='bottom-right') {{user.username}}
+                        span.caret
+                    script#user-dropdown(type='text/ng-template')
+                        ul.dropdown-menu
+                            li
+                                a(href='/rest/auth/logout') Log Out
+                li.nav-login(ng-show='!user')
+                    a(ng-click='login()' href='#') Log In
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8e792605/modules/web-control-center/nodejs/views/index.jade
----------------------------------------------------------------------
diff --git a/modules/web-control-center/nodejs/views/index.jade b/modules/web-control-center/nodejs/views/index.jade
new file mode 100644
index 0000000..b913fb0
--- /dev/null
+++ b/modules/web-control-center/nodejs/views/index.jade
@@ -0,0 +1,29 @@
+//-
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+extends layout
+block container
+    .row
+        .docs-content
+            div
+                p
+                    | Apache Ignite<sup>tm</sup> In-Memory Data Fabric is a high-performance,
+                    | integrated and distributed in-memory platform for computing and transacting on large-scale data
+                    | sets in real-time, orders of magnitude faster than possible with traditional disk-based or flash technologies.
+        .block-image.block-display-image
+                img(ng-src='https://www.filepicker.io/api/file/lydEeGB6Rs9hwbpcQxiw' alt='Apache Ignite stack')
+        .text-center(ng-controller='auth')
+            button.btn.btn-primary(ng-click='login()' href='#') Configure Now

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8e792605/modules/web-control-center/nodejs/views/layout-sidebar.jade
----------------------------------------------------------------------
diff --git a/modules/web-control-center/nodejs/views/layout-sidebar.jade b/modules/web-control-center/nodejs/views/layout-sidebar.jade
new file mode 100644
index 0000000..f88bb7d
--- /dev/null
+++ b/modules/web-control-center/nodejs/views/layout-sidebar.jade
@@ -0,0 +1,37 @@
+//-
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+extends layout
+
+block container
+    .row
+        .col-sm-2.border-right.section-left.greedy
+            .sidebar-nav
+                ul.menu(ng-controller='activeLink')
+                    li
+                        a(ng-class="{active: isActive('/clusters')}" href='/clusters') Clusters
+                    li
+                        a(ng-class="{active: isActive('/caches')}" href='/caches') Caches
+                    li
+                        a(ng-class="{active: isActive('/persistence')}" href='/persistence') Persistence
+                    li
+                        a(ng-class="{active: isActive('/clients')}" href='/clients') Clients
+                    li
+                        p
+                        a(ng-class="{active: isActive('/summary')}" href='/summary') Summary
+        .col-sm-10.border-left.section-right
+            .docs-content
+                block content
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8e792605/modules/web-control-center/nodejs/views/layout.jade
----------------------------------------------------------------------
diff --git a/modules/web-control-center/nodejs/views/layout.jade b/modules/web-control-center/nodejs/views/layout.jade
new file mode 100644
index 0000000..d7a48be
--- /dev/null
+++ b/modules/web-control-center/nodejs/views/layout.jade
@@ -0,0 +1,59 @@
+//-
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+doctype html
+html(ng-app='ignite-web-configurator')
+    head
+        title= title
+
+        block css
+            // Bootstrap
+            link(rel='stylesheet', href='//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.4/css/bootstrap.css')
+
+            // Font Awesome Icons
+            link(rel='stylesheet', href='//maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.css')
+
+            // Font
+            link(rel='stylesheet', href='//fonts.googleapis.com/css?family=Roboto+Slab:700:serif|Roboto+Slab:400:serif')
+
+            link(rel='stylesheet', href='/stylesheets/style.css')
+
+        block scripts
+            script(src='//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.js')
+
+            script(src='//cdnjs.cloudflare.com/ajax/libs/lodash.js/3.9.3/lodash.min.js')
+
+            script(src='//ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.js')
+            script(src='//cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.15/angular-sanitize.js')
+            script(src='//cdnjs.cloudflare.com/ajax/libs/angular-strap/2.2.2/angular-strap.js')
+            script(src='//cdnjs.cloudflare.com/ajax/libs/angular-strap/2.2.2/angular-strap.tpl.min.js')
+
+            script(src='https://cdnjs.cloudflare.com/ajax/libs/angular-smart-table/2.0.3/smart-table.js')
+
+            script(src='/javascripts/controllers/common.js')
+            script(src='/javascripts/dataStructures.js')
+
+            script(src='/javascripts/bundle.js')
+    body.theme-line.body-overlap
+        .wrapper
+            include includes/header
+
+            .container.body-container
+                .main-content
+                    .main-head
+                        block container
+
+            include includes/footer

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8e792605/modules/web-control-center/nodejs/views/login.jade
----------------------------------------------------------------------
diff --git a/modules/web-control-center/nodejs/views/login.jade b/modules/web-control-center/nodejs/views/login.jade
new file mode 100644
index 0000000..8ad1109
--- /dev/null
+++ b/modules/web-control-center/nodejs/views/login.jade
@@ -0,0 +1,47 @@
+//-
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+.modal.center(role='dialog')
+    .modal-dialog
+        .modal-content
+            .modal-header.header
+                div(id='errors-container')
+                button.close(type='button', ng-click='$hide()', aria-hidden='true') &times;
+                h1.navbar-brand.pull-left
+                    a(href='/') Apache Ignite Web Configurator
+                h4.modal-title Authentication
+                p Log in or register in order to collaborate
+            form.form-horizontal(name='loginForm')
+                .modal-body.row
+                    .col-sm-9.login.col-sm-offset-1
+                        .form-group(ng-show='action == "register"')
+                            label.col-sm-3.control-label Full Name:
+                            .controls.col-sm-9
+                                input.form-control(type='text', ng-model='user_info.username', placeholder='John Smith', focus-me='action=="register"', ng-required='action=="register"')
+                        .form-group
+                            label.col-sm-3.control-label Email:
+                            .controls.col-sm-9
+                                input.form-control(type='email', ng-model='user_info.email', placeholder='you@domain.com', focus-me='action=="login"', required)
+                        .form-group
+                            label.col-sm-3.control-label Password:
+                            .controls.col-sm-9
+                                input.form-control(type='password', ng-model='user_info.password', placeholder='Password', required)
+            .modal-footer
+                a.show-signup.ng-hide(ng-show='action != "login"', ng-click='action = "login";') log in
+                a.show-signup(ng-show="action != 'register'", ng-click='action = "register";') sign up
+                | &nbsp;or&nbsp;
+                button.btn.btn-primary(ng-click='auth(action, user_info)' ng-show='action == "login"' ng-disabled='loginForm.$invalid') Log In
+                button.btn.btn-primary(ng-click='auth(action, user_info)' ng-show='action == "register"' ng-disabled='loginForm.$invalid') Sign Up

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8e792605/modules/web-control-center/nodejs/views/persistence.jade
----------------------------------------------------------------------
diff --git a/modules/web-control-center/nodejs/views/persistence.jade b/modules/web-control-center/nodejs/views/persistence.jade
new file mode 100644
index 0000000..2d1ba6f
--- /dev/null
+++ b/modules/web-control-center/nodejs/views/persistence.jade
@@ -0,0 +1,115 @@
+//-
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+extends layout-sidebar
+
+append scripts
+    script(src='/javascripts/controllers/persistences.js')
+
+include includes/controls
+
+mixin dbcheck(chk)
+    input(type='checkbox' style='margin-left: 5px' ng-checked=chk)
+
+block content
+    .docs-header
+        h1 Persistence
+        p Create and configure Ignite persistence.
+        hr
+    .docs-body(ng-controller='persistenceController')
+        .links(ng-hide='persistences.length == 0')
+            table.col-sm-12(st-table='persistences')
+                tbody
+                    tr(ng-repeat='row in persistences track by row._id')
+                        td.col-sm-6(ng-class='{active: row._id == selectedItem._id}')
+                            a(ng-click='selectItem(row)') {{$index + 1}}. {{row.name}}, {{row.database | displayValue:databases:'Database not set'}}
+        button.btn.btn-primary(ng-click='createItem()') Add
+        hr
+        form.form-horizontal(name='inputForm' ng-if='backupItem' novalidate)
+            div(bs-collapse data-start-collapsed='false')
+                .panel.panel-default
+                    .panel-heading
+                        h3
+                            a(bs-collapse-toggle) Connection
+                    .panel-collapse(bs-collapse-target)
+                        .panel-body
+                            .settings-row(ng-repeat='field in connection')
+                                +form-row
+            div(bs-collapse data-start-collapsed='true' ng-hide='data.tables.length == 0')
+                .panel.panel-default
+                    .panel-heading
+                        h3
+                            a(bs-collapse-toggle) Metadata
+                    .panel-collapse(bs-collapse-target)
+                        .panel-body
+                            div(ng-hide='data.tables.length == 0')
+                                table.table-bordered.table-condensed.links-edit-small-padding.col-sm-12(st-table='data.tables')
+                                    thead
+                                        tr
+                                            th.col-sm-3 Schema/Table
+                                            th Key class
+                                            th Value class
+                                    tbody
+                                        tr(ng-repeat='row in data.tables')
+                                            td(colspan='{{row.tableName ? 1 : 3}}')
+                                                div.checkbox(ng-if='!row.tableName')
+                                                    label(ng-click='selectSchema($index)')
+                                                        input(type='checkbox' ng-checked='row.use')
+                                                        | {{row.schemaName}}
+                                                div.checkbox(ng-if='row.tableName')
+                                                    label(style='padding-left: 30px' ng-click='selectTable($index)')
+                                                        input(type='checkbox' ng-checked = 'row.use')
+                                                        | {{row.tableName}}
+                                            td(ng-if='row.tableName')
+                                                a(ng-show='data.curTableIdx != $index' ng-click='selectTable($index)') {{row.keyClass}}
+                                                input.form-control(type='text' ng-show='data.curTableIdx == $index' ng-model='data.curKeyClass' placeholder='Key class full name')
+                                            td(ng-if='row.tableName')
+                                                a(ng-show='data.curTableIdx != $index' ng-click='selectTable($index)') {{row.valueClass}}
+                                                input.form-control(type='text' ng-show='data.curTableIdx == $index' ng-model='data.curValueClass' placeholder='Value class full name')
+                            div(ng-hide='data.curTableIdx < 0')
+                                table.table-bordered.table-condensed.links-edit-small-padding.col-sm-12(st-table='data.tables[data.curTableIdx].fields')
+                                    thead
+                                        tr
+                                            th(style='width:45px') Use
+                                            th(style='width:45px') Key
+                                            th(style='width:45px') Ak
+                                            th DB Name
+                                            th DB Type
+                                            th Java Name
+                                            th Java Type
+                                    tbody
+                                        tr(ng-repeat='row in data.tables[data.curTableIdx].fields')
+                                            td
+                                                +dbcheck('row.use')
+                                            td
+                                                +dbcheck('row.key')
+                                            td
+                                                +dbcheck('row.ak')
+                                            td
+                                                label {{row.dbName}}
+                                            td
+                                                label {{row.dbType}}
+                                            td
+                                                a(ng-show='data.curFieldIdx != $index' ng-click='selectField($index)') {{row.javaName}}
+                                                input.form-control(type='text' ng-show='data.curFieldIdx == $index' ng-model='data.curJavaName' placeholder='Field Java name')
+                                            td
+                                                a(ng-show='data.curFieldIdx != $index' ng-click='selectField($index)') {{row.javaType}}
+                                                input.form-control(type='text' ng-show='data.curFieldIdx == $index' ng-model='data.curJavaType' placeholder='Field Java type')
+        button.btn.btn-primary(ng-disabled='inputForm.$invalid' ng-click='saveItem()') Save
+        button.btn.btn-primary.btn-second(ng-show='backupItem._id' ng-click='removeItem()') Remove
+        button.btn.btn-primary.btn-second(ng-click='reloadMetadata()') Reload
+
+

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8e792605/modules/web-control-center/nodejs/views/sql.jade
----------------------------------------------------------------------
diff --git a/modules/web-control-center/nodejs/views/sql.jade b/modules/web-control-center/nodejs/views/sql.jade
new file mode 100644
index 0000000..a816251
--- /dev/null
+++ b/modules/web-control-center/nodejs/views/sql.jade
@@ -0,0 +1,23 @@
+//-
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+extends layout
+
+block container
+    .docs-header
+        h1 SQL
+        p Connect to Zeppelin and execute SQL queries.
+        hr

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8e792605/modules/web-control-center/nodejs/views/summary.jade
----------------------------------------------------------------------
diff --git a/modules/web-control-center/nodejs/views/summary.jade b/modules/web-control-center/nodejs/views/summary.jade
new file mode 100644
index 0000000..afbdf4c
--- /dev/null
+++ b/modules/web-control-center/nodejs/views/summary.jade
@@ -0,0 +1,93 @@
+//-
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+extends layout-sidebar
+
+append scripts
+    script(src='/javascripts/controllers/summary.js')
+    script(src='//cdnjs.cloudflare.com/ajax/libs/SyntaxHighlighter/3.0.83/scripts/shCore.min.js')    
+    script(src='//cdnjs.cloudflare.com/ajax/libs/SyntaxHighlighter/3.0.83/scripts/shBrushXml.js')    
+    script(src='//cdnjs.cloudflare.com/ajax/libs/SyntaxHighlighter/3.0.83/scripts/shBrushJava.js')    
+    script(src='//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/2.3.2/js/bootstrap.min.js')
+        
+append css
+    link(rel='stylesheet', href='http://cdnjs.cloudflare.com/ajax/libs/SyntaxHighlighter/3.0.83/styles/shCore.css')
+    link(rel='stylesheet', href='http://cdnjs.cloudflare.com/ajax/libs/SyntaxHighlighter/3.0.83/styles/shThemeMidnight.css')
+        
+block content
+    .docs-header
+        h1 Summary
+        p Configurations summary.
+        hr
+    .docs-body(ng-controller='summaryController')
+        div(ng-hide='clusters.length > 0')
+            | No cluster configured. You can&nbsp;
+            a(href='clusters') configure
+            |  it.
+        div(ng-hide='clusters.length == 0')
+            p Following cluster configurations are created, you can download its as xml, java code or as docker file
+            .links
+                table.col-sm-12(st-table='clusters')
+                    tbody
+                        tr(ng-repeat='row in clusters track by row._id')
+                            td.col-sm-6(ng-class='{active: row._id == selectedItem._id}')
+                                a(ng-click='selectItem(row)') {{$index + 1}}. {{row.name}}
+            #cfgResult.configBox(ng-show='selectedItem && !generateError && !loading', style='margin-top: 20px')
+                ul.nav.nav-tabs
+                    li(ng-class='{active: cfgLang == "xml"}')
+                        a(href, ng-click='cfgLang = "xml"')
+                            img(src='images/xml.png', width='16px' height='16px')
+                            |  XML
+                    li(ng-class='{active: cfgLang=="java"}')
+                        a(href, ng-click='cfgLang = "java"')
+                            img(src='images/java.png', width='16px' height='16px')
+                            |  Java
+                    li(ng-class="{active: cfgLang=='docker'}")
+                        a(href, ng-click='cfgLang = "docker"')
+                            img(src='images/docker.png', width='16px' height='16px')
+                            |  Dockerfile
+
+                div(style='padding-top: 10px')        
+                    #xmlResult(ng-show="cfgLang == 'xml'")
+                        #xmlResultDiv
+                
+                    #javaResult(ng-show="cfgLang == 'java'")
+                        label
+                            input(type='checkbox', ng-model="generateJavaClass")
+                            | generate java class.
+
+                        #javaResultDiv
+                    
+                    #dockerResult(ng-show="cfgLang == 'docker'")
+                        p
+                            a(href='https://docs.docker.com/reference/builder') Dockerfile
+                            | is a text file with instructions to create Docker image. To build image you have to
+                            | store following Docker file with your xml ignite configurations to the same directory. 
+                        
+                        form.form-horizontal
+                            .form-group
+                                label.control-label.col-sm-3(for='os') Operation System
+                                .col-sm-6
+                                    input#os.form-control(type='text', ng-model='dockerArg.os', placeholder='debian:8')
+                                
+                            .form-group
+                                | Download as 
+                                a(href, ng-click='downloadDocker()') file
+                                
+                                textarea.form-control(rows=30, readonly=true)
+                                    | {{ dockerFile() }}
+
+                div(ng-show='generateError') {{generateError}}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8e792605/modules/web-control-center/nodejs/views/templates/select.jade
----------------------------------------------------------------------
diff --git a/modules/web-control-center/nodejs/views/templates/select.jade b/modules/web-control-center/nodejs/views/templates/select.jade
new file mode 100644
index 0000000..4a39795
--- /dev/null
+++ b/modules/web-control-center/nodejs/views/templates/select.jade
@@ -0,0 +1,26 @@
+//-
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+ul.select.dropdown-menu(tabindex='-1', ng-show='$isVisible()', role='select')
+    li(role='presentation', ng-repeat='match in $matches')
+        hr(ng-if='!match.value' style='margin: 5px 0')
+        a(style='cursor: default;', role='menuitem', tabindex='-1', ng-class='{active: $isActive($index)}' ng-click='$select($index, $event)')
+            i.pull-right(class='{{$iconCheckmark}}', ng-if='$isMultiple && $isActive($index)' ng-class='{active: $isActive($index)}' style='margin-left: 15px')
+            span(ng-bind='match.label')
+    li(ng-if='$showAllNoneButtons || ($isMultiple && $matches.length > 5)')
+        hr(style='margin: 5px 0')
+        a(ng-click='$selectAll()') {{$allText}}
+        a(ng-click='$selectNone()') {{$noneText}}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8e792605/modules/webconfig/licenses/apache-2.0.txt
----------------------------------------------------------------------
diff --git a/modules/webconfig/licenses/apache-2.0.txt b/modules/webconfig/licenses/apache-2.0.txt
deleted file mode 100644
index d645695..0000000
--- a/modules/webconfig/licenses/apache-2.0.txt
+++ /dev/null
@@ -1,202 +0,0 @@
-
-                                 Apache License
-                           Version 2.0, January 2004
-                        http://www.apache.org/licenses/
-
-   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
-   1. Definitions.
-
-      "License" shall mean the terms and conditions for use, reproduction,
-      and distribution as defined by Sections 1 through 9 of this document.
-
-      "Licensor" shall mean the copyright owner or entity authorized by
-      the copyright owner that is granting the License.
-
-      "Legal Entity" shall mean the union of the acting entity and all
-      other entities that control, are controlled by, or are under common
-      control with that entity. For the purposes of this definition,
-      "control" means (i) the power, direct or indirect, to cause the
-      direction or management of such entity, whether by contract or
-      otherwise, or (ii) ownership of fifty percent (50%) or more of the
-      outstanding shares, or (iii) beneficial ownership of such entity.
-
-      "You" (or "Your") shall mean an individual or Legal Entity
-      exercising permissions granted by this License.
-
-      "Source" form shall mean the preferred form for making modifications,
-      including but not limited to software source code, documentation
-      source, and configuration files.
-
-      "Object" form shall mean any form resulting from mechanical
-      transformation or translation of a Source form, including but
-      not limited to compiled object code, generated documentation,
-      and conversions to other media types.
-
-      "Work" shall mean the work of authorship, whether in Source or
-      Object form, made available under the License, as indicated by a
-      copyright notice that is included in or attached to the work
-      (an example is provided in the Appendix below).
-
-      "Derivative Works" shall mean any work, whether in Source or Object
-      form, that is based on (or derived from) the Work and for which the
-      editorial revisions, annotations, elaborations, or other modifications
-      represent, as a whole, an original work of authorship. For the purposes
-      of this License, Derivative Works shall not include works that remain
-      separable from, or merely link (or bind by name) to the interfaces of,
-      the Work and Derivative Works thereof.
-
-      "Contribution" shall mean any work of authorship, including
-      the original version of the Work and any modifications or additions
-      to that Work or Derivative Works thereof, that is intentionally
-      submitted to Licensor for inclusion in the Work by the copyright owner
-      or by an individual or Legal Entity authorized to submit on behalf of
-      the copyright owner. For the purposes of this definition, "submitted"
-      means any form of electronic, verbal, or written communication sent
-      to the Licensor or its representatives, including but not limited to
-      communication on electronic mailing lists, source code control systems,
-      and issue tracking systems that are managed by, or on behalf of, the
-      Licensor for the purpose of discussing and improving the Work, but
-      excluding communication that is conspicuously marked or otherwise
-      designated in writing by the copyright owner as "Not a Contribution."
-
-      "Contributor" shall mean Licensor and any individual or Legal Entity
-      on behalf of whom a Contribution has been received by Licensor and
-      subsequently incorporated within the Work.
-
-   2. Grant of Copyright License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      copyright license to reproduce, prepare Derivative Works of,
-      publicly display, publicly perform, sublicense, and distribute the
-      Work and such Derivative Works in Source or Object form.
-
-   3. Grant of Patent License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      (except as stated in this section) patent license to make, have made,
-      use, offer to sell, sell, import, and otherwise transfer the Work,
-      where such license applies only to those patent claims licensable
-      by such Contributor that are necessarily infringed by their
-      Contribution(s) alone or by combination of their Contribution(s)
-      with the Work to which such Contribution(s) was submitted. If You
-      institute patent litigation against any entity (including a
-      cross-claim or counterclaim in a lawsuit) alleging that the Work
-      or a Contribution incorporated within the Work constitutes direct
-      or contributory patent infringement, then any patent licenses
-      granted to You under this License for that Work shall terminate
-      as of the date such litigation is filed.
-
-   4. Redistribution. You may reproduce and distribute copies of the
-      Work or Derivative Works thereof in any medium, with or without
-      modifications, and in Source or Object form, provided that You
-      meet the following conditions:
-
-      (a) You must give any other recipients of the Work or
-          Derivative Works a copy of this License; and
-
-      (b) You must cause any modified files to carry prominent notices
-          stating that You changed the files; and
-
-      (c) You must retain, in the Source form of any Derivative Works
-          that You distribute, all copyright, patent, trademark, and
-          attribution notices from the Source form of the Work,
-          excluding those notices that do not pertain to any part of
-          the Derivative Works; and
-
-      (d) If the Work includes a "NOTICE" text file as part of its
-          distribution, then any Derivative Works that You distribute must
-          include a readable copy of the attribution notices contained
-          within such NOTICE file, excluding those notices that do not
-          pertain to any part of the Derivative Works, in at least one
-          of the following places: within a NOTICE text file distributed
-          as part of the Derivative Works; within the Source form or
-          documentation, if provided along with the Derivative Works; or,
-          within a display generated by the Derivative Works, if and
-          wherever such third-party notices normally appear. The contents
-          of the NOTICE file are for informational purposes only and
-          do not modify the License. You may add Your own attribution
-          notices within Derivative Works that You distribute, alongside
-          or as an addendum to the NOTICE text from the Work, provided
-          that such additional attribution notices cannot be construed
-          as modifying the License.
-
-      You may add Your own copyright statement to Your modifications and
-      may provide additional or different license terms and conditions
-      for use, reproduction, or distribution of Your modifications, or
-      for any such Derivative Works as a whole, provided Your use,
-      reproduction, and distribution of the Work otherwise complies with
-      the conditions stated in this License.
-
-   5. Submission of Contributions. Unless You explicitly state otherwise,
-      any Contribution intentionally submitted for inclusion in the Work
-      by You to the Licensor shall be under the terms and conditions of
-      this License, without any additional terms or conditions.
-      Notwithstanding the above, nothing herein shall supersede or modify
-      the terms of any separate license agreement you may have executed
-      with Licensor regarding such Contributions.
-
-   6. Trademarks. This License does not grant permission to use the trade
-      names, trademarks, service marks, or product names of the Licensor,
-      except as required for reasonable and customary use in describing the
-      origin of the Work and reproducing the content of the NOTICE file.
-
-   7. Disclaimer of Warranty. Unless required by applicable law or
-      agreed to in writing, Licensor provides the Work (and each
-      Contributor provides its Contributions) on an "AS IS" BASIS,
-      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-      implied, including, without limitation, any warranties or conditions
-      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
-      PARTICULAR PURPOSE. You are solely responsible for determining the
-      appropriateness of using or redistributing the Work and assume any
-      risks associated with Your exercise of permissions under this License.
-
-   8. Limitation of Liability. In no event and under no legal theory,
-      whether in tort (including negligence), contract, or otherwise,
-      unless required by applicable law (such as deliberate and grossly
-      negligent acts) or agreed to in writing, shall any Contributor be
-      liable to You for damages, including any direct, indirect, special,
-      incidental, or consequential damages of any character arising as a
-      result of this License or out of the use or inability to use the
-      Work (including but not limited to damages for loss of goodwill,
-      work stoppage, computer failure or malfunction, or any and all
-      other commercial damages or losses), even if such Contributor
-      has been advised of the possibility of such damages.
-
-   9. Accepting Warranty or Additional Liability. While redistributing
-      the Work or Derivative Works thereof, You may choose to offer,
-      and charge a fee for, acceptance of support, warranty, indemnity,
-      or other liability obligations and/or rights consistent with this
-      License. However, in accepting such obligations, You may act only
-      on Your own behalf and on Your sole responsibility, not on behalf
-      of any other Contributor, and only if You agree to indemnify,
-      defend, and hold each Contributor harmless for any liability
-      incurred by, or claims asserted against, such Contributor by reason
-      of your accepting any such warranty or additional liability.
-
-   END OF TERMS AND CONDITIONS
-
-   APPENDIX: How to apply the Apache License to your work.
-
-      To apply the Apache License to your work, attach the following
-      boilerplate notice, with the fields enclosed by brackets "[]"
-      replaced with your own identifying information. (Don't include
-      the brackets!)  The text should be enclosed in the appropriate
-      comment syntax for the file format. We also recommend that a
-      file or class name and description of purpose be included on the
-      same "printed page" as the copyright notice for easier
-      identification within third-party archives.
-
-   Copyright [yyyy] [name of copyright owner]
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-   you may not use this file except in compliance with the License.
-   You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8e792605/modules/webconfig/nodejs/.gitignore
----------------------------------------------------------------------
diff --git a/modules/webconfig/nodejs/.gitignore b/modules/webconfig/nodejs/.gitignore
deleted file mode 100644
index b512c09..0000000
--- a/modules/webconfig/nodejs/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-node_modules
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8e792605/modules/webconfig/nodejs/DEVNOTES.txt
----------------------------------------------------------------------
diff --git a/modules/webconfig/nodejs/DEVNOTES.txt b/modules/webconfig/nodejs/DEVNOTES.txt
deleted file mode 100644
index eb35c0a..0000000
--- a/modules/webconfig/nodejs/DEVNOTES.txt
+++ /dev/null
@@ -1,14 +0,0 @@
-Ignite Web Configurator Build Instructions
-======================================
-
-Before run need install locally:
-
-1. NodeJS using installer from site https://nodejs.org
-2. MongoDB folow instructions from site http://docs.mongodb.org/manual/installation
-
-To run:
-
-1. Run following command in terminal for upload all dependence: "npm install" in 'modules/webconfig/nodejs' folder.
-2. Run MongoDB.
-3. Start application by following command in terminal: "npm start" in 'modules/webconfig/nodejs' folder.
-4. Open in browser: localhost:3000
\ No newline at end of file