You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by an...@apache.org on 2015/07/22 13:00:29 UTC

[01/10] incubator-ignite git commit: # ignite-843 moved

Repository: incubator-ignite
Updated Branches:
  refs/heads/ignite-843 e7ebf452f -> 8a3357242


http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/src/main/js/views/templates/copy.jade
----------------------------------------------------------------------
diff --git a/modules/web-control-center/src/main/js/views/templates/copy.jade b/modules/web-control-center/src/main/js/views/templates/copy.jade
new file mode 100644
index 0000000..22cc64c
--- /dev/null
+++ b/modules/web-control-center/src/main/js/views/templates/copy.jade
@@ -0,0 +1,31 @@
+//-
+    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(tabindex='-1' role='dialog')
+    .modal-dialog
+        .modal-content
+            .modal-header
+                button.close(type="button" ng-click="$hide()") ×
+                h4.modal-title Copy
+            form.form-horizontal(name='inputForm' novalidate)
+                .modal-body.row
+                    .col-sm-9.login.col-sm-offset-1
+                        label.required.labelFormField() New name: 
+                        .col-sm-9
+                            input.form-control(type="text" ng-model='newName' required)
+            .modal-footer
+                button.btn.btn-default(type="button" ng-click="$hide()") Cancel
+                button.btn.btn-primary(type="button" ng-disabled='inputForm.$invalid' ng-click="ok(newName)") Confirm
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/src/main/js/views/templates/layout.jade
----------------------------------------------------------------------
diff --git a/modules/web-control-center/src/main/js/views/templates/layout.jade b/modules/web-control-center/src/main/js/views/templates/layout.jade
new file mode 100644
index 0000000..a4191ae
--- /dev/null
+++ b/modules/web-control-center/src/main/js/views/templates/layout.jade
@@ -0,0 +1,61 @@
+//-
+    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-control-center', ng-init='user = #{JSON.stringify(user)}; becomeUsed = #{becomeUsed}')
+    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.10.0/lodash.min.js')
+
+            script(src='//ajax.googleapis.com/ajax/libs/angularjs/1.4.2/angular.js')
+            script(src='//cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.2/angular-sanitize.js')
+            script(src='//cdnjs.cloudflare.com/ajax/libs/angular-strap/2.3.0/angular-strap.js')
+            script(src='//cdnjs.cloudflare.com/ajax/libs/angular-strap/2.3.0/angular-strap.tpl.min.js')
+
+            script(src='//cdnjs.cloudflare.com/ajax/libs/angular-smart-table/2.0.3/smart-table.js')
+
+            script(src='//cdnjs.cloudflare.com/ajax/libs/ace/1.2.0/ace.js')
+            script(src='//angular-ui.github.io/ui-ace/dist/ui-ace.min.js')
+
+            script(src='/common-module.js')
+            script(src='/data-structures.js')
+
+    body.theme-line.body-overlap
+        .wrapper
+            include ../includes/header
+
+            block main-container
+                .container.body-container
+                    .main-content
+                        block container
+
+            include ../includes/footer

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/src/main/js/views/templates/select.jade
----------------------------------------------------------------------
diff --git a/modules/web-control-center/src/main/js/views/templates/select.jade b/modules/web-control-center/src/main/js/views/templates/select.jade
new file mode 100644
index 0000000..10c1946
--- /dev/null
+++ b/modules/web-control-center/src/main/js/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 == undefined' style='margin: 5px 0')
+        a(style='cursor: default; padding: 3px 6px;', role='menuitem', tabindex='-1', ng-class='{active: $isActive($index)}' ng-click='$select($index, $event)')
+            i(class='{{$iconCheckmark}}', ng-if='$isActive($index)' ng-class='{active: $isActive($index)}' style='color: #ec1c24; margin-left: 15px; line-height: 20px; float: right;background-color: transparent;')
+            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


[10/10] incubator-ignite git commit: # ignite-843 moved

Posted by an...@apache.org.
# ignite-843 moved


Project: http://git-wip-us.apache.org/repos/asf/incubator-ignite/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-ignite/commit/8a335724
Tree: http://git-wip-us.apache.org/repos/asf/incubator-ignite/tree/8a335724
Diff: http://git-wip-us.apache.org/repos/asf/incubator-ignite/diff/8a335724

Branch: refs/heads/ignite-843
Commit: 8a33572426c877c690e788ee1f71f7ff79edae70
Parents: e7ebf45
Author: Andrey <an...@gridgain.com>
Authored: Wed Jul 22 18:01:16 2015 +0700
Committer: Andrey <an...@gridgain.com>
Committed: Wed Jul 22 18:01:16 2015 +0700

----------------------------------------------------------------------
 modules/web-control-center/nodejs/.gitignore    |    4 -
 modules/web-control-center/nodejs/DEVNOTES.txt  |   21 -
 modules/web-control-center/nodejs/app.js        |  154 ---
 modules/web-control-center/nodejs/bin/www       |   85 --
 .../nodejs/config/default.json                  |    8 -
 .../nodejs/controllers/admin-controller.js      |   68 -
 .../controllers/cache-viewer-controller.js      |   77 --
 .../nodejs/controllers/caches-controller.js     |  333 -----
 .../nodejs/controllers/clusters-controller.js   |  309 -----
 .../nodejs/controllers/common-module.js         |  422 -------
 .../nodejs/controllers/metadata-controller.js   |  678 ----------
 .../nodejs/controllers/models/caches.json       |  918 --------------
 .../nodejs/controllers/models/clusters.json     |  907 --------------
 .../nodejs/controllers/models/metadata.json     |  230 ----
 .../nodejs/controllers/models/summary.json      |  163 ---
 .../nodejs/controllers/profile-controller.js    |   51 -
 .../nodejs/controllers/summary-controller.js    |  164 ---
 modules/web-control-center/nodejs/db.js         |  358 ------
 .../nodejs/helpers/configuration-loader.js      |   22 -
 .../nodejs/helpers/data-structures.js           |   84 --
 modules/web-control-center/nodejs/package.json  |   50 -
 .../nodejs/public/favicon.ico                   |  Bin 1150 -> 0 bytes
 .../nodejs/public/images/docker.png             |  Bin 994 -> 0 bytes
 .../nodejs/public/images/java.png               |  Bin 170 -> 0 bytes
 .../nodejs/public/images/logo.png               |  Bin 8148 -> 0 bytes
 .../nodejs/public/images/xml.png                |  Bin 232 -> 0 bytes
 .../nodejs/public/stylesheets/style.less        | 1172 ------------------
 .../web-control-center/nodejs/routes/admin.js   |   79 --
 .../web-control-center/nodejs/routes/caches.js  |   95 --
 .../nodejs/routes/clusters.js                   |  104 --
 .../nodejs/routes/generator/common.js           |  299 -----
 .../nodejs/routes/generator/docker.js           |   58 -
 .../nodejs/routes/generator/java.js             |  626 ----------
 .../nodejs/routes/generator/xml.js              |  580 ---------
 .../nodejs/routes/metadata.js                   |   95 --
 .../web-control-center/nodejs/routes/profile.js |   97 --
 .../web-control-center/nodejs/routes/public.js  |  123 --
 modules/web-control-center/nodejs/routes/sql.js |   24 -
 .../web-control-center/nodejs/routes/summary.js |  108 --
 .../nodejs/views/configuration/caches.jade      |   74 --
 .../nodejs/views/configuration/clusters.jade    |   77 --
 .../nodejs/views/configuration/metadata.jade    |  121 --
 .../nodejs/views/configuration/sidebar.jade     |   39 -
 .../nodejs/views/configuration/summary.jade     |  117 --
 .../web-control-center/nodejs/views/error.jade  |   22 -
 .../nodejs/views/includes/controls.jade         |  322 -----
 .../nodejs/views/includes/footer.jade           |   22 -
 .../nodejs/views/includes/header.jade           |   39 -
 .../web-control-center/nodejs/views/index.jade  |   30 -
 .../web-control-center/nodejs/views/login.jade  |   55 -
 .../nodejs/views/settings/admin.jade            |   58 -
 .../nodejs/views/settings/profile.jade          |   58 -
 .../nodejs/views/templates/confirm.jade         |   27 -
 .../nodejs/views/templates/copy.jade            |   31 -
 .../nodejs/views/templates/layout.jade          |   61 -
 .../nodejs/views/templates/select.jade          |   26 -
 .../web-control-center/src/main/js/.gitignore   |    4 +
 .../web-control-center/src/main/js/DEVNOTES.txt |   21 +
 modules/web-control-center/src/main/js/app.js   |  154 +++
 modules/web-control-center/src/main/js/bin/www  |   85 ++
 .../src/main/js/config/default.json             |    8 +
 .../src/main/js/controllers/admin-controller.js |   68 +
 .../js/controllers/cache-viewer-controller.js   |   77 ++
 .../main/js/controllers/caches-controller.js    |  333 +++++
 .../main/js/controllers/clusters-controller.js  |  309 +++++
 .../src/main/js/controllers/common-module.js    |  422 +++++++
 .../main/js/controllers/metadata-controller.js  |  678 ++++++++++
 .../src/main/js/controllers/models/caches.json  |  918 ++++++++++++++
 .../main/js/controllers/models/clusters.json    |  907 ++++++++++++++
 .../main/js/controllers/models/metadata.json    |  230 ++++
 .../src/main/js/controllers/models/summary.json |  163 +++
 .../main/js/controllers/profile-controller.js   |   51 +
 .../main/js/controllers/summary-controller.js   |  164 +++
 modules/web-control-center/src/main/js/db.js    |  358 ++++++
 .../src/main/js/helpers/configuration-loader.js |   22 +
 .../src/main/js/helpers/data-structures.js      |   84 ++
 .../web-control-center/src/main/js/package.json |   50 +
 .../src/main/js/public/favicon.ico              |  Bin 0 -> 1150 bytes
 .../src/main/js/public/images/docker.png        |  Bin 0 -> 994 bytes
 .../src/main/js/public/images/java.png          |  Bin 0 -> 170 bytes
 .../src/main/js/public/images/logo.png          |  Bin 0 -> 8148 bytes
 .../src/main/js/public/images/xml.png           |  Bin 0 -> 232 bytes
 .../src/main/js/public/stylesheets/style.less   | 1172 ++++++++++++++++++
 .../src/main/js/routes/admin.js                 |   79 ++
 .../src/main/js/routes/caches.js                |   95 ++
 .../src/main/js/routes/clusters.js              |  104 ++
 .../src/main/js/routes/generator/common.js      |  299 +++++
 .../src/main/js/routes/generator/docker.js      |   58 +
 .../src/main/js/routes/generator/java.js        |  626 ++++++++++
 .../src/main/js/routes/generator/xml.js         |  580 +++++++++
 .../src/main/js/routes/metadata.js              |   95 ++
 .../src/main/js/routes/profile.js               |   97 ++
 .../src/main/js/routes/public.js                |  123 ++
 .../src/main/js/routes/sql.js                   |   24 +
 .../src/main/js/routes/summary.js               |  108 ++
 .../src/main/js/views/configuration/caches.jade |   74 ++
 .../main/js/views/configuration/clusters.jade   |   77 ++
 .../main/js/views/configuration/metadata.jade   |  121 ++
 .../main/js/views/configuration/sidebar.jade    |   39 +
 .../main/js/views/configuration/summary.jade    |  117 ++
 .../src/main/js/views/error.jade                |   22 +
 .../src/main/js/views/includes/controls.jade    |  322 +++++
 .../src/main/js/views/includes/footer.jade      |   22 +
 .../src/main/js/views/includes/header.jade      |   39 +
 .../src/main/js/views/index.jade                |   30 +
 .../src/main/js/views/login.jade                |   55 +
 .../src/main/js/views/settings/admin.jade       |   58 +
 .../src/main/js/views/settings/profile.jade     |   58 +
 .../src/main/js/views/templates/confirm.jade    |   27 +
 .../src/main/js/views/templates/copy.jade       |   31 +
 .../src/main/js/views/templates/layout.jade     |   61 +
 .../src/main/js/views/templates/select.jade     |   26 +
 112 files changed, 9745 insertions(+), 9745 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/nodejs/.gitignore
----------------------------------------------------------------------
diff --git a/modules/web-control-center/nodejs/.gitignore b/modules/web-control-center/nodejs/.gitignore
deleted file mode 100644
index 65f2596..0000000
--- a/modules/web-control-center/nodejs/.gitignore
+++ /dev/null
@@ -1,4 +0,0 @@
-node_modules
-*.idea
-*.log
-*.css
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/nodejs/DEVNOTES.txt
----------------------------------------------------------------------
diff --git a/modules/web-control-center/nodejs/DEVNOTES.txt b/modules/web-control-center/nodejs/DEVNOTES.txt
deleted file mode 100644
index aa56011..0000000
--- a/modules/web-control-center/nodejs/DEVNOTES.txt
+++ /dev/null
@@ -1,21 +0,0 @@
-Ignite Web Control Center Instructions
-======================================
-
-How to deploy:
-
-1. Install locally NodeJS using installer from site https://nodejs.org for your OS.
-2. Install locally MongoDB folow instructions from site http://docs.mongodb.org/manual/installation
-3. Checkout ignite-843 branch.
-4. Change directory '$IGNITE_HOME/modules/web-control-center/nodejs'.
-5. Run "npm install" in terminal for download all dependencies.
-
-Steps 1 - 5 should be executed once.
-
-How to run:
-
-1. Run MongoDB.
- 1.1 In terminal change dir to $MONGO_ISNTALL_DIR/server/3.0/bin.
- 1.2 Run "mongod".
-2. In new terminal change directory '$IGNITE_HOME/modules/web-control-center/nodejs'.
-3. Start application by executing "npm start".
-4. In browser open: http://localhost:3000
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/nodejs/app.js
----------------------------------------------------------------------
diff --git a/modules/web-control-center/nodejs/app.js b/modules/web-control-center/nodejs/app.js
deleted file mode 100644
index 8c347db..0000000
--- a/modules/web-control-center/nodejs/app.js
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * 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 flash = require('connect-flash');
-var express = require('express');
-var path = require('path');
-var favicon = require('serve-favicon');
-var logger = require('morgan');
-var cookieParser = require('cookie-parser');
-var bodyParser = require('body-parser');
-var session = require('express-session');
-var mongoStore = require('connect-mongo')(session);
-
-var publicRoutes = require('./routes/public');
-var clustersRouter = require('./routes/clusters');
-var cachesRouter = require('./routes/caches');
-var metadataRouter = require('./routes/metadata');
-var summary = require('./routes/summary');
-var adminRouter = require('./routes/admin');
-var profileRouter = require('./routes/profile');
-var sqlRouter = require('./routes/sql');
-
-var passport = require('passport');
-
-var db = require('./db');
-
-var app = express();
-
-// Views engine setup.
-app.set('views', path.join(__dirname, 'views'));
-app.set('view engine', 'jade');
-
-// Site favicon.
-app.use(favicon(__dirname + '/public/favicon.ico'));
-
-app.use(logger('dev'));
-
-app.use(bodyParser.json());
-app.use(bodyParser.urlencoded({extended: false}));
-
-app.use(require('less-middleware')(path.join(__dirname, 'public'), {
-    render: {
-        compress: false
-    }
-}));
-
-app.use(express.static(path.join(__dirname, 'public')));
-app.use(express.static(path.join(__dirname, 'controllers')));
-app.use(express.static(path.join(__dirname, 'helpers')));
-
-app.use(cookieParser('keyboard cat'));
-
-app.use(session({
-    secret: 'keyboard cat',
-    resave: false,
-    saveUninitialized: true,
-    store: new mongoStore({
-        mongooseConnection: db.mongoose.connection
-    })
-}));
-
-app.use(flash());
-
-app.use(passport.initialize());
-app.use(passport.session());
-
-passport.serializeUser(db.Account.serializeUser());
-passport.deserializeUser(db.Account.deserializeUser());
-
-passport.use(db.Account.createStrategy());
-
-var mustAuthenticated = function (req, res, next) {
-    req.isAuthenticated() ? next() : res.redirect('/');
-};
-
-var adminOnly = function(req, res, next) {
-    req.isAuthenticated() && req.user.admin ? next() : res.sendStatus(403);
-};
-
-app.all('/configuration/*', mustAuthenticated);
-
-app.all('*', function(req, res, next) {
-    var becomeUsed = req.session.viewedUser && req.user.admin;
-
-    res.locals.user = becomeUsed ? req.session.viewedUser : req.user;
-    res.locals.becomeUsed = becomeUsed;
-
-    req.currentUserId = function() {
-        if (!req.user)
-            return null;
-
-        if (req.session.viewedUser && req.user.admin)
-            return req.session.viewedUser._id;
-
-        return req.user._id;
-    };
-
-    next();
-});
-
-app.use('/', publicRoutes);
-app.use('/admin', mustAuthenticated, adminOnly, adminRouter);
-app.use('/profile', mustAuthenticated, profileRouter);
-
-app.use('/configuration/clusters', clustersRouter);
-app.use('/configuration/caches', cachesRouter);
-app.use('/configuration/metadata', metadataRouter);
-app.use('/configuration/summary', summary);
-app.use('/sql', sqlRouter);
-
-// Catch 404 and forward to error handler.
-app.use(function (req, res, next) {
-    var err = new Error('Not Found: ' + req.originalUrl);
-    err.status = 404;
-    next(err);
-});
-
-// Error handlers.
-
-// Development error handler: will print stacktrace.
-if (app.get('env') === 'development') {
-    app.use(function (err, req, res) {
-        res.status(err.status || 500);
-        res.render('error', {
-            message: err.message,
-            error: err
-        });
-    });
-}
-
-// Production error handler: no stacktraces leaked to user.
-app.use(function (err, req, res) {
-    res.status(err.status || 500);
-    res.render('error', {
-        message: err.message,
-        error: {}
-    });
-});
-
-module.exports = app;

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/nodejs/bin/www
----------------------------------------------------------------------
diff --git a/modules/web-control-center/nodejs/bin/www b/modules/web-control-center/nodejs/bin/www
deleted file mode 100644
index 4cf0583..0000000
--- a/modules/web-control-center/nodejs/bin/www
+++ /dev/null
@@ -1,85 +0,0 @@
-#!/usr/bin/env node
-
-/**
- * Module dependencies.
- */
-var app = require('../app');
-var config = require('../helpers/configuration-loader.js');
-var debug = require('debug')('ignite-web-control-center:server');
-var http = require('http');
-
-/**
- * Get port from environment and store in Express.
- */
-var port = normalizePort(process.env.PORT || config.get('express:port'));
-app.set('port', port);
-
-/**
- * Create HTTP server.
- */
-var server = http.createServer(app);
-
-/**
- * Listen on provided port, on all network interfaces.
- */
-server.listen(port);
-server.on('error', onError);
-server.on('listening', onListening);
-
-/**
- * Normalize a port into a number, string, or false.
- */
-function normalizePort(val) {
-  var port = parseInt(val, 10);
-
-  if (isNaN(port)) {
-    // named pipe
-    return val;
-  }
-
-  if (port >= 0) {
-    // port number
-    return port;
-  }
-
-  return false;
-}
-
-/**
- * Event listener for HTTP server "error" event.
- */
-function onError(error) {
-  if (error.syscall !== 'listen') {
-    throw error;
-  }
-
-  var bind = typeof port === 'string'
-    ? 'Pipe ' + port
-    : 'Port ' + port;
-
-  // handle specific listen errors with friendly messages
-  switch (error.code) {
-    case 'EACCES':
-      console.error(bind + ' requires elevated privileges');
-      process.exit(1);
-      break;
-    case 'EADDRINUSE':
-      console.error(bind + ' is already in use');
-      process.exit(1);
-      break;
-    default:
-      throw error;
-  }
-}
-
-/**
- * Event listener for HTTP server "listening" event.
- */
-function onListening() {
-  var addr = server.address();
-  var bind = typeof addr === 'string'
-    ? 'pipe ' + addr
-    : 'port ' + addr.port;
-
-  debug('Listening on ' + bind);
-}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/nodejs/config/default.json
----------------------------------------------------------------------
diff --git a/modules/web-control-center/nodejs/config/default.json b/modules/web-control-center/nodejs/config/default.json
deleted file mode 100644
index 72dbd4e..0000000
--- a/modules/web-control-center/nodejs/config/default.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-    "express": {
-        "port": 3000
-    },
-    "mongoDB": {
-        "url": "mongodb://localhost/web-control-center"
-    }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/nodejs/controllers/admin-controller.js
----------------------------------------------------------------------
diff --git a/modules/web-control-center/nodejs/controllers/admin-controller.js b/modules/web-control-center/nodejs/controllers/admin-controller.js
deleted file mode 100644
index 09490fe..0000000
--- a/modules/web-control-center/nodejs/controllers/admin-controller.js
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * 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.
- */
-
-controlCenterModule.controller('adminController', ['$scope', '$http', '$common', '$confirm', function ($scope, $http, $common, $confirm) {
-    $scope.users = null;
-
-    function reload() {
-        $http.post('admin/list')
-            .success(function (data) {
-                $scope.users = data;
-            })
-            .error(function (errMsg) {
-                $common.showError($common.errorMessage(errMsg));
-            });
-    }
-
-    reload();
-
-    $scope.removeUser = function (user) {
-        $confirm.show('Are you sure you want to remove user: "' + user.username + '"?').then(function () {
-            $http.post('admin/remove', {userId: user._id}).success(
-                function () {
-                    var i = _.findIndex($scope.users, function (u) {
-                        return u._id == user._id;
-                    });
-
-                    if (i >= 0)
-                        $scope.users.splice(i, 1);
-
-                    $common.showInfo('User has been removed: "' + user.username + '"');
-                }).error(function (errMsg) {
-                    $common.showError('Failed to remove user: "' + $common.errorMessage(errMsg) + '"');
-                });
-        });
-    };
-
-    $scope.toggleAdmin = function (user) {
-        if (user.adminChanging)
-            return;
-
-        user.adminChanging = true;
-
-        $http.post('admin/save', {userId: user._id, adminFlag: user.admin}).success(
-            function () {
-                $common.showInfo('Admin right was successfully toggled for user: "' + user.username + '"');
-
-                user.adminChanging = false;
-            }).error(function (errMsg) {
-                $common.showError('Failed to toggle admin right for user: "' + $common.errorMessage(errMsg) + '"');
-
-                user.adminChanging = false;
-            });
-    }
-}]);
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/nodejs/controllers/cache-viewer-controller.js
----------------------------------------------------------------------
diff --git a/modules/web-control-center/nodejs/controllers/cache-viewer-controller.js b/modules/web-control-center/nodejs/controllers/cache-viewer-controller.js
deleted file mode 100644
index 6e0c130..0000000
--- a/modules/web-control-center/nodejs/controllers/cache-viewer-controller.js
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * 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 demoResults = [
-    {
-        id: 256,
-        s: 'com.foo.User@3213',
-        fields: {
-            id: 256,
-            firstName: 'Ivan',
-            lastName: 'Ivanov',
-            old: 23
-        }
-    },
-
-    {
-        id: 384,
-        s: 'com.foo.User@23214',
-        fields: {
-            id: 384,
-            firstName: 'Sergey',
-            lastName: 'Petrov',
-            old: 28
-        }
-    },
-
-    {
-        id: 923,
-        s: 'com.foo.User@93494',
-        fields: {
-            id: 923,
-            firstName: 'Andrey',
-            lastName: 'Sidorov',
-            old: 28
-        }
-    }
-];
-
-var demoCaches = ['Users', 'Organizations', 'Cities'];
-
-controlCenterModule.controller('cacheViewerController', ['$scope', '$http', '$common', function ($scope, $http, $common) {
-    $scope.results = demoResults;
-
-    $scope.caches = demoCaches;
-
-    $scope.defCache = $scope.caches.length > 0 ? $scope.caches[0] : null;
-
-    var sqlEditor = ace.edit('querySql');
-
-    sqlEditor.setOptions({
-        highlightActiveLine: false,
-        showPrintMargin: false,
-        showGutter: true,
-        theme: "ace/theme/chrome",
-        mode: "ace/mode/sql",
-        fontSize: 14
-    });
-
-    sqlEditor.setValue("select u.id from User u where u.name like 'aaaa';");
-
-    sqlEditor.selection.clearSelection()
-
-}]);

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/nodejs/controllers/caches-controller.js
----------------------------------------------------------------------
diff --git a/modules/web-control-center/nodejs/controllers/caches-controller.js b/modules/web-control-center/nodejs/controllers/caches-controller.js
deleted file mode 100644
index 0c23e3b..0000000
--- a/modules/web-control-center/nodejs/controllers/caches-controller.js
+++ /dev/null
@@ -1,333 +0,0 @@
-/*
- * 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.
- */
-
-controlCenterModule.controller('cachesController', ['$scope', '$http', '$common', '$confirm', '$copy', '$table', function ($scope, $http, $common, $confirm, $copy, $table) {
-        $scope.joinTip = $common.joinTip;
-        $scope.getModel = $common.getModel;
-
-        $scope.tableNewItem = $table.tableNewItem;
-        $scope.tableNewItemActive = $table.tableNewItemActive;
-        $scope.tableEditing = $table.tableEditing;
-        $scope.tableStartEdit = $table.tableStartEdit;
-        $scope.tableRemove = $table.tableRemove;
-
-        $scope.tableSimpleSave = $table.tableSimpleSave;
-        $scope.tableSimpleSaveVisible = $table.tableSimpleSaveVisible;
-        $scope.tableSimpleUp = $table.tableSimpleUp;
-        $scope.tableSimpleDown = $table.tableSimpleDown;
-        $scope.tableSimpleDownVisible = $table.tableSimpleDownVisible;
-
-        $scope.tablePairSave = $table.tablePairSave;
-        $scope.tablePairSaveVisible = $table.tablePairSaveVisible;
-
-        $scope.atomicities = [
-            {value: 'ATOMIC', label: 'ATOMIC'},
-            {value: 'TRANSACTIONAL', label: 'TRANSACTIONAL'}
-        ];
-
-        $scope.modes = [
-            {value: 'PARTITIONED', label: 'PARTITIONED'},
-            {value: 'REPLICATED', label: 'REPLICATED'},
-            {value: 'LOCAL', label: 'LOCAL'}
-        ];
-
-        $scope.atomicWriteOrderModes = [
-            {value: 'CLOCK', label: 'CLOCK'},
-            {value: 'PRIMARY', label: 'PRIMARY'}
-        ];
-
-        $scope.memoryModes = [
-            {value: 'ONHEAP_TIERED', label: 'ONHEAP_TIERED'},
-            {value: 'OFFHEAP_TIERED', label: 'OFFHEAP_TIERED'},
-            {value: 'OFFHEAP_VALUES', label: 'OFFHEAP_VALUES'}
-        ];
-
-        $scope.evictionPolicies = [
-            {value: 'LRU', label: 'LRU'},
-            {value: 'RND', label: 'Random'},
-            {value: 'FIFO', label: 'FIFO'},
-            {value: 'SORTED', label: 'Sorted'},
-            {value: undefined, label: 'Not set'}
-        ];
-
-        $scope.rebalanceModes = [
-            {value: 'SYNC', label: 'SYNC'},
-            {value: 'ASYNC', label: 'ASYNC'},
-            {value: 'NONE', label: 'NONE'}
-        ];
-
-        $scope.cacheStoreFactories = [
-            {value: 'CacheJdbcPojoStoreFactory', label: 'JDBC POJO store factory'},
-            {value: 'CacheJdbcBlobStoreFactory', label: 'JDBC BLOB store factory'},
-            {value: 'CacheHibernateBlobStoreFactory', label: 'Hibernate BLOB store factory'},
-            {value: undefined, label: 'Not set'}
-        ];
-
-        $scope.cacheStoreJdbcDialects = [
-            {value: 'Oracle', label: 'Oracle'},
-            {value: 'DB2', label: 'IBM DB2'},
-            {value: 'SQLServer', label: 'Microsoft SQL Server'},
-            {value: 'MySQL', label: 'My SQL'},
-            {value: 'PostgreSQL', label: 'Postgre SQL'},
-            {value: 'H2', label: 'H2 database'}
-        ];
-
-        $scope.general = [];
-        $scope.advanced = [];
-
-        $http.get('/models/caches.json')
-            .success(function (data) {
-                $scope.screenTip = data.screenTip;
-                $scope.general = data.general;
-                $scope.advanced = data.advanced;
-            })
-            .error(function (errMsg) {
-                $common.showError(errMsg);
-            });
-
-        $scope.caches = [];
-
-        $scope.required = function (field) {
-            var model = $common.isDefined(field.path) ? field.path + '.' + field.model : field.model;
-
-            var backupItem = $scope.backupItem;
-
-            var memoryMode = backupItem.memoryMode;
-
-            var onHeapTired = memoryMode == 'ONHEAP_TIERED';
-            var offHeapTired = memoryMode == 'OFFHEAP_TIERED';
-
-            var offHeapMaxMemory = backupItem.offHeapMaxMemory;
-
-            if (model == 'offHeapMaxMemory' && offHeapTired)
-                return true;
-
-            if (model == 'evictionPolicy.kind' && onHeapTired)
-                return backupItem.swapEnabled || ($common.isDefined(offHeapMaxMemory) && offHeapMaxMemory >= 0);
-
-            return false;
-        };
-
-        $scope.tableSimpleValid = function (item, field, fx, index) {
-            var model = item[field.model];
-
-            if ($common.isDefined(model)) {
-                var idx = _.indexOf(model, fx);
-
-                // Found itself.
-                if (index >= 0 && index == idx)
-                    return true;
-
-                // Found duplicate.
-                if (idx >= 0) {
-                    $common.showError('SQL function such class name already exists!');
-
-                    return false;
-                }
-            }
-
-            return true;
-        };
-
-        $scope.tablePairValid = function (item, field, keyCls, valCls, index) {
-            var model = item[field.model];
-
-            if ($common.isDefined(model)) {
-                var idx = _.findIndex(model, function (pair) {
-                    return pair.keyClass == keyCls
-                });
-
-                // Found itself.
-                if (index >= 0 && index == idx)
-                    return true;
-
-                // Found duplicate.
-                if (idx >= 0) {
-                    $common.showError('Indexed type with such key class already exists!');
-
-                    return false;
-                }
-            }
-
-            return true;
-        };
-
-        // When landing on the page, get caches and show them.
-        $http.post('caches/list')
-            .success(function (data) {
-                $scope.spaces = data.spaces;
-                $scope.caches = data.caches;
-
-                var restoredItem = angular.fromJson(sessionStorage.cacheBackupItem);
-
-                if (restoredItem) {
-                    if (restoredItem._id) {
-                        var idx = _.findIndex($scope.caches, function (cache) {
-                            return cache._id == restoredItem._id;
-                        });
-
-                        if (idx >= 0) {
-                            $scope.selectedItem = $scope.caches[idx];
-                            $scope.backupItem = restoredItem;
-                        }
-                        else
-                            sessionStorage.removeItem('cacheBackupItem');
-                    }
-                    else
-                        $scope.backupItem = restoredItem;
-                }
-                else if ($scope.caches.length > 0)
-                    $scope.selectItem($scope.caches[0]);
-
-                $scope.$watch('backupItem', function (val) {
-                    if (val)
-                        sessionStorage.cacheBackupItem = angular.toJson(val);
-                }, true);
-            })
-            .error(function (errMsg) {
-                $common.showError(errMsg);
-            });
-
-        $scope.selectItem = function (item) {
-            $table.tableReset();
-
-            $scope.selectedItem = item;
-            $scope.backupItem = angular.copy(item);
-        };
-
-        // Add new cache.
-        $scope.createItem = function () {
-            $table.tableReset();
-
-            $scope.backupItem = {mode: 'PARTITIONED', atomicityMode: 'ATOMIC', readFromBackup: true, copyOnRead: true};
-            $scope.backupItem.space = $scope.spaces[0]._id;
-        };
-
-        // Check cache logical consistency.
-        function validate(item) {
-            var cacheStoreFactorySelected = item.cacheStoreFactory && item.cacheStoreFactory.kind;
-
-            if (cacheStoreFactorySelected && !(item.readThrough || item.writeThrough)) {
-                $common.showError('Store is configured but read/write through are not enabled!');
-
-                return false;
-            }
-
-            if ((item.readThrough || item.writeThrough) && !cacheStoreFactorySelected) {
-                $common.showError('Read / write through are enabled but store is not configured!');
-
-                return false;
-            }
-
-            if (item.writeBehindEnabled && !cacheStoreFactorySelected) {
-                $common.showError('Write behind enabled but store is not configured!');
-
-                return false;
-            }
-
-            return true;
-        }
-
-        // Save cache into database.
-        function save(item) {
-            $http.post('caches/save', item)
-                .success(function (_id) {
-                    var idx = _.findIndex($scope.caches, function (cache) {
-                        return cache._id == _id;
-                    });
-
-                    if (idx >= 0)
-                        angular.extend($scope.caches[idx], item);
-                    else {
-                        item._id = _id;
-
-                        $scope.caches.push(item);
-                    }
-
-                    $scope.selectItem(item);
-
-                    $common.showInfo('Cache "' + item.name + '" saved.');
-                })
-                .error(function (errMsg) {
-                    $common.showError(errMsg);
-                });
-        }
-
-        // Save cache.
-        $scope.saveItem = function () {
-            $table.tableReset();
-
-            var item = $scope.backupItem;
-
-            if (validate(item))
-                save(item);
-        };
-
-        // Save cache with new name.
-        $scope.saveItemAs = function () {
-            $table.tableReset();
-
-            if (validate($scope.backupItem))
-                $copy.show($scope.backupItem.name).then(function (newName) {
-                    var item = angular.copy($scope.backupItem);
-
-                    item._id = undefined;
-                    item.name = newName;
-
-                    save(item);
-                });
-        };
-
-        // Remove cache from db.
-        $scope.removeItem = function () {
-            $table.tableReset();
-
-            var selectedItem = $scope.selectedItem;
-
-            $confirm.show('Are you sure you want to remove cache: "' + selectedItem.name + '"?').then(
-                function () {
-                    var _id = selectedItem._id;
-
-                    $http.post('caches/remove', {_id: _id})
-                        .success(function () {
-                            $common.showInfo('Cache has been removed: ' + selectedItem.name);
-
-                            var caches = $scope.caches;
-
-                            var idx = _.findIndex(caches, function (cache) {
-                                return cache._id == _id;
-                            });
-
-                            if (idx >= 0) {
-                                caches.splice(idx, 1);
-
-                                if (caches.length > 0)
-                                    $scope.selectItem(caches[0]);
-                                else {
-                                    $scope.selectedItem = undefined;
-                                    $scope.backupItem = undefined;
-                                }
-                            }
-                        })
-                        .error(function (errMsg) {
-                            $common.showError(errMsg);
-                        });
-                }
-            );
-        };
-    }]
-);
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/nodejs/controllers/clusters-controller.js
----------------------------------------------------------------------
diff --git a/modules/web-control-center/nodejs/controllers/clusters-controller.js b/modules/web-control-center/nodejs/controllers/clusters-controller.js
deleted file mode 100644
index 1ec78a1..0000000
--- a/modules/web-control-center/nodejs/controllers/clusters-controller.js
+++ /dev/null
@@ -1,309 +0,0 @@
-/*
- * 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.
- */
-
-controlCenterModule.controller('clustersController', ['$scope', '$http', '$common', '$confirm', '$copy', '$table', function ($scope, $http, $common, $confirm, $copy, $table) {
-        $scope.joinTip = $common.joinTip;
-        $scope.getModel = $common.getModel;
-
-        $scope.tableNewItem = $table.tableNewItem;
-        $scope.tableNewItemActive = $table.tableNewItemActive;
-        $scope.tableEditing = $table.tableEditing;
-        $scope.tableStartEdit = $table.tableStartEdit;
-        $scope.tableRemove = $table.tableRemove;
-
-        $scope.tableSimpleSave = $table.tableSimpleSave;
-        $scope.tableSimpleSaveVisible = $table.tableSimpleSaveVisible;
-        $scope.tableSimpleUp = $table.tableSimpleUp;
-        $scope.tableSimpleDown = $table.tableSimpleDown;
-        $scope.tableSimpleDownVisible = $table.tableSimpleDownVisible;
-
-        $scope.templates = [
-            {
-                value: {discovery: {kind: 'Multicast', Vm: {addresses: ['127.0.0.1:47500..47510']}, Multicast: {}}},
-                label: 'multicast'
-            },
-            {value: {discovery: {kind: 'Vm', Vm: {addresses: ['127.0.0.1:47500..47510']}}}, label: 'local'}
-        ];
-
-        $scope.discoveries = [
-            {value: 'Vm', label: 'static IPs'},
-            {value: 'Multicast', label: 'multicast'},
-            {value: 'S3', label: 'AWS S3'},
-            {value: 'Cloud', label: 'apache jclouds'},
-            {value: 'GoogleStorage', label: 'google cloud storage'},
-            {value: 'Jdbc', label: 'JDBC'},
-            {value: 'SharedFs', label: 'shared filesystem'}
-        ];
-
-        $scope.swapSpaceSpis = [
-            {value: 'FileSwapSpaceSpi', label: 'File-based swap'},
-            {value: undefined, label: 'Not set'}
-        ];
-
-        $scope.events = [];
-
-        for (var eventGroupName in eventGroups) {
-            if (eventGroups.hasOwnProperty(eventGroupName)) {
-                $scope.events.push({value: eventGroupName, label: eventGroupName});
-            }
-        }
-
-        $scope.cacheModes = [
-            {value: 'LOCAL', label: 'LOCAL'},
-            {value: 'REPLICATED', label: 'REPLICATED'},
-            {value: 'PARTITIONED', label: 'PARTITIONED'}
-        ];
-
-        $scope.deploymentModes = [
-            {value: 'PRIVATE', label: 'PRIVATE'},
-            {value: 'ISOLATED', label: 'ISOLATED'},
-            {value: 'SHARED', label: 'SHARED'},
-            {value: 'CONTINUOUS', label: 'CONTINUOUS'}
-        ];
-
-        $scope.transactionConcurrency = [
-            {value: 'OPTIMISTIC', label: 'OPTIMISTIC'},
-            {value: 'PESSIMISTIC', label: 'PESSIMISTIC'}
-        ];
-
-        $scope.transactionIsolation = [
-            {value: 'READ_COMMITTED', label: 'READ_COMMITTED'},
-            {value: 'REPEATABLE_READ', label: 'REPEATABLE_READ'},
-            {value: 'SERIALIZABLE', label: 'SERIALIZABLE'}
-        ];
-
-        $scope.segmentationPolicy = [
-            {value: 'RESTART_JVM', label: 'RESTART_JVM'},
-            {value: 'STOP', label: 'STOP'},
-            {value: 'NOOP', label: 'NOOP'}
-        ];
-
-        $scope.marshallers = [
-            {value: 'OptimizedMarshaller', label: 'OptimizedMarshaller'},
-            {value: 'JdkMarshaller', label: 'JdkMarshaller'}
-        ];
-
-        $scope.tableSimpleValid = function (item, field, val, index) {
-            var model = $common.getModel(item, field)[field.model];
-
-            if ($common.isDefined(model)) {
-                var idx = _.indexOf(model, val);
-
-                // Found itself.
-                if (index >= 0 && index == idx)
-                    return true;
-
-                // Found duplicate.
-                if (idx >= 0) {
-                    var msg = 'Such IP address already exists!';
-
-                    if (field.model == 'regions')
-                        msg = 'Such region already exists!';
-                    if (field.model == 'zones')
-                        msg = 'Such zone already exists!';
-
-                    $common.showError(msg);
-
-                    return false;
-                }
-            }
-
-            return true;
-        };
-
-        $scope.clusters = [];
-
-        $http.get('/models/clusters.json')
-            .success(function (data) {
-                $scope.screenTip = data.screenTip;
-                $scope.templateTip = data.templateTip;
-
-                $scope.general = data.general;
-                $scope.advanced = data.advanced;
-            })
-            .error(function (errMsg) {
-                $common.showError(errMsg);
-            });
-
-        // When landing on the page, get clusters and show them.
-        $http.post('clusters/list')
-            .success(function (data) {
-                $scope.caches = data.caches;
-                $scope.spaces = data.spaces;
-                $scope.clusters = data.clusters;
-
-                var restoredItem = angular.fromJson(sessionStorage.clusterBackupItem);
-
-                if (restoredItem) {
-                    if (restoredItem._id) {
-                        var idx = _.findIndex($scope.clusters, function (cluster) {
-                            return cluster._id == restoredItem._id;
-                        });
-
-                        if (idx >= 0) {
-                            $scope.selectedItem = $scope.clusters[idx];
-                            $scope.backupItem = restoredItem;
-                        }
-                        else
-                            sessionStorage.removeItem('clusterBackupItem');
-                    }
-                    else
-                        $scope.backupItem = restoredItem;
-                }
-                else if ($scope.clusters.length > 0)
-                    $scope.selectItem($scope.clusters[0]);
-
-                $scope.$watch('backupItem', function (val) {
-                    if (val)
-                        sessionStorage.clusterBackupItem = angular.toJson(val);
-                }, true);
-            })
-            .error(function (errMsg) {
-                $common.showError(errMsg);
-            });
-
-        $scope.selectItem = function (item) {
-            $table.tableReset();
-
-            $scope.selectedItem = item;
-            $scope.backupItem = angular.copy(item);
-        };
-
-        // Add new cluster.
-        $scope.createItem = function () {
-            $table.tableReset();
-
-            $scope.backupItem = angular.copy($scope.create.template);
-            $scope.backupItem.space = $scope.spaces[0]._id;
-        };
-
-        $scope.indexOfCache = function (cacheId) {
-            return _.findIndex($scope.caches, function (cache) {
-                return cache.value == cacheId;
-            });
-        };
-
-        // Check cluster logical consistency.
-        function validate(item) {
-            if (!item.swapSpaceSpi || !item.swapSpaceSpi.kind && item.caches) {
-                for (var i = 0; i < item.caches.length; i++) {
-                    var idx = $scope.indexOfCache(item.caches[i]);
-
-                    if (idx >= 0) {
-                        var cache = $scope.caches[idx];
-
-                        if (cache.swapEnabled) {
-                            $common.showError('Swap space SPI is not configured, but cache "' + cache.label + '" configured to use swap!');
-
-                            return false;
-                        }
-                    }
-                }
-            }
-
-            return true;
-        }
-
-        // Save cluster in database.
-        function save(item) {
-            $http.post('clusters/save', item)
-                .success(function (_id) {
-                    var idx = _.findIndex($scope.clusters, function (cluster) {
-                        return cluster._id == _id;
-                    });
-
-                    if (idx >= 0)
-                        angular.extend($scope.clusters[idx], item);
-                    else {
-                        item._id = _id;
-
-                        $scope.clusters.push(item);
-                    }
-
-                    $scope.selectItem(item);
-
-                    $common.showInfo('Cluster "' + item.name + '" saved.');
-                })
-                .error(function (errMsg) {
-                    $common.showError(errMsg);
-                });
-        }
-
-        // Save cluster.
-        $scope.saveItem = function () {
-            $table.tableReset();
-
-            var item = $scope.backupItem;
-
-            if (validate(item))
-                save(item);
-        };
-
-        // Save cluster with new name.
-        $scope.saveItemAs = function () {
-            $table.tableReset();
-
-            if (validate($scope.backupItem))
-                $copy.show($scope.backupItem.name).then(function (newName) {
-                    var item = angular.copy($scope.backupItem);
-
-                    item._id = undefined;
-                    item.name = newName;
-
-                    save(item);
-                });
-        };
-
-        // Remove cluster from db.
-        $scope.removeItem = function () {
-            $table.tableReset();
-
-            var selectedItem = $scope.selectedItem;
-
-            $confirm.show('Are you sure you want to remove cluster: "' + selectedItem.name + '"?').then(
-                function () {
-                    var _id = selectedItem._id;
-
-                    $http.post('clusters/remove', {_id: _id})
-                        .success(function () {
-                            $common.showInfo('Cluster has been removed: ' + selectedItem.name);
-
-                            var clusters = $scope.clusters;
-
-                            var idx = _.findIndex(clusters, function (cluster) {
-                                return cluster._id == _id;
-                            });
-
-                            if (idx >= 0) {
-                                clusters.splice(idx, 1);
-
-                                if (clusters.length > 0)
-                                    $scope.selectItem(clusters[0]);
-                                else {
-                                    $scope.selectedItem = undefined;
-                                    $scope.backupItem = undefined;
-                                }
-                            }
-                        })
-                        .error(function (errMsg) {
-                            $common.showError(errMsg);
-                        });
-                }
-            );
-        };
-    }]
-);
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/nodejs/controllers/common-module.js
----------------------------------------------------------------------
diff --git a/modules/web-control-center/nodejs/controllers/common-module.js b/modules/web-control-center/nodejs/controllers/common-module.js
deleted file mode 100644
index 75af155..0000000
--- a/modules/web-control-center/nodejs/controllers/common-module.js
+++ /dev/null
@@ -1,422 +0,0 @@
-/*
- * 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 controlCenterModule = angular.module('ignite-web-control-center', ['smart-table', 'mgcrea.ngStrap', 'ui.ace', 'ngSanitize']);
-
-// Modal popup configuration.
-controlCenterModule.config(function ($modalProvider) {
-    angular.extend($modalProvider.defaults, {
-        html: true
-    });
-});
-
-// Tooltips configuration.
-controlCenterModule.config(function ($tooltipProvider) {
-    angular.extend($tooltipProvider.defaults, {
-        container: 'body',
-        placement: 'right',
-        html: 'true',
-        trigger: 'click hover'
-    });
-});
-
-// Comboboxes configuration.
-controlCenterModule.config(function ($selectProvider) {
-    angular.extend($selectProvider.defaults, {
-        maxLength: '1',
-        allText: 'Select All',
-        noneText: 'Clear All',
-        templateUrl: '/select',
-        iconCheckmark: 'fa fa-check',
-        caretHtml: '<span class="caret"></span>'
-    });
-});
-
-// Alerts configuration.
-controlCenterModule.config(function ($alertProvider) {
-    angular.extend($alertProvider.defaults, {
-        container: 'body',
-        placement: 'top-right',
-        duration: '5',
-        type: 'danger'
-    });
-});
-
-// Common functions to be used in controllers.
-controlCenterModule.service('$common', ['$alert', function ($alert) {
-    var msgModal = undefined;
-
-    function errorMessage(errMsg) {
-        return errMsg ? errMsg : 'Internal server error.';
-    }
-
-    function isDefined(v) {
-        return !(v === undefined || v === null);
-    }
-
-    return {
-        getModel: function (obj, field) {
-            var path = field.path;
-
-            if (!isDefined(path))
-                return obj;
-
-            path = path.replace(/\[(\w+)\]/g, '.$1'); // convert indexes to properties
-            path = path.replace(/^\./, '');           // strip a leading dot
-
-            var segs = path.split('.');
-            var root = obj;
-
-            while (segs.length > 0) {
-                var pathStep = segs.shift();
-
-                if (typeof root[pathStep] === 'undefined')
-                    root[pathStep] = {};
-
-                root = root[pathStep];
-            }
-
-            return root;
-        },
-        joinTip: function (arr) {
-            if (!arr) {
-                return arr;
-            }
-
-            var lines = arr.map(function (line) {
-                var rtrimmed = line.replace(/\s+$/g, '');
-
-                if (rtrimmed.indexOf('>', this.length - 1) == -1) {
-                    rtrimmed = rtrimmed + '<br/>';
-                }
-
-                return rtrimmed;
-            });
-
-            return lines.join("");
-        },
-        isDefined: isDefined,
-        isNonEmpty: function (s) {
-            return isDefined(s) && s.trim().length > 0;
-        },
-        errorMessage: errorMessage,
-        showError: function (msg) {
-            if (msgModal)
-                msgModal.hide();
-
-            msgModal = $alert({title: errorMessage(msg)});
-        },
-        showInfo: function (msg) {
-            if (msgModal)
-                msgModal.hide();
-
-            msgModal = $alert({
-                type: 'success',
-                title: msg,
-                duration: 2
-            });
-        }
-    }
-}]);
-
-// Confirm popup service.
-controlCenterModule.service('$confirm', function ($modal, $rootScope, $q) {
-    var scope = $rootScope.$new();
-
-    var deferred;
-
-    scope.ok = function () {
-        deferred.resolve();
-
-        confirmModal.hide();
-    };
-
-    var confirmModal = $modal({templateUrl: '/confirm', scope: scope, placement: 'center', show: false});
-
-    var parentShow = confirmModal.show;
-
-    confirmModal.show = function (content) {
-        scope.content = content || 'Confirm deletion?';
-
-        deferred = $q.defer();
-
-        parentShow();
-
-        return deferred.promise;
-    };
-
-    return confirmModal;
-});
-
-// "Save as" popup service.
-controlCenterModule.service('$copy', function ($modal, $rootScope, $q) {
-    var scope = $rootScope.$new();
-
-    var deferred;
-
-    scope.ok = function (newName) {
-        deferred.resolve(newName);
-
-        copyModal.hide();
-    };
-
-    var copyModal = $modal({templateUrl: '/copy', scope: scope, placement: 'center', show: false});
-
-    var parentShow = copyModal.show;
-
-    copyModal.show = function (oldName) {
-        scope.newName = oldName + '(1)';
-
-        deferred = $q.defer();
-
-        parentShow();
-
-        return deferred.promise;
-    };
-
-    return copyModal;
-});
-
-// Tables support service.
-controlCenterModule.service('$table', ['$common', function ($common) {
-    function _swapSimpleItems(a, ix1, ix2) {
-        var tmp = a[ix1];
-
-        a[ix1] = a[ix2];
-        a[ix2] = tmp;
-    }
-
-    function _model(item, field) {
-        return $common.getModel(item, field);
-    }
-
-    var table = {name: 'none', editIndex: -1};
-
-    function _tableReset() {
-        table.name = 'none';
-        table.editIndex = -1;
-    }
-
-    function _tableState(name, editIndex) {
-        table.name = name;
-        table.editIndex = editIndex;
-    }
-
-    return {
-        tableState: function (name, editIndex) {
-            _tableState(name, editIndex);
-        },
-        tableReset: function () {
-            _tableReset();
-        },
-        tableNewItem: function (field) {
-            _tableState(field.model, -1);
-        },
-        tableNewItemActive: function (field) {
-            return table.name == field.model && table.editIndex < 0;
-        },
-        tableEditing: function (field, index) {
-            return table.name == field.model && table.editIndex == index;
-        },
-        tableStartEdit: function (item, field, index) {
-            _tableState(field.model, index);
-
-            return _model(item, field)[field.model][index];
-        },
-        tableRemove: function (item, field, index) {
-            _tableReset();
-
-            _model(item, field)[field.model].splice(index, 1);
-        },
-        tableSimpleSave: function (valueValid, item, field, newValue, index) {
-            if (valueValid(item, field, newValue, index)) {
-                _tableReset();
-
-                if (index < 0) {
-                    if (_model(item, field)[field.model])
-                        _model(item, field)[field.model].push(newValue);
-                    else
-                        _model(item, field)[field.model] = [newValue];
-                }
-                else
-                    _model(item, field)[field.model][index] = newValue;
-            }
-        },
-        tableSimpleSaveVisible: function (newValue) {
-            return $common.isNonEmpty(newValue);
-        },
-        tableSimpleUp: function (item, field, index) {
-            _tableReset();
-
-            _swapSimpleItems(_model(item, field)[field.model], index, index - 1);
-        },
-        tableSimpleDown: function (item, field, index) {
-            _tableReset();
-
-            _swapSimpleItems(_model(item, field)[field.model], index, index + 1);
-        },
-        tableSimpleDownVisible: function (item, field, index) {
-            return index < _model(item, field)[field.model].length - 1;
-        },
-        tablePairSave: function (pairValid, item, field, newKey, newValue, index) {
-            if (pairValid(item, field, newKey, newValue, index)) {
-                _tableReset();
-
-                var pair = {};
-
-                if (index < 0) {
-                    pair[field.keyName] = newKey;
-                    pair[field.valueName] = newValue;
-
-                    if (item[field.model])
-                        item[field.model].push(pair);
-                    else
-                        item[field.model] = [pair];
-                }
-                else {
-                    pair = item[field.model][index];
-
-                    pair[field.keyName] = newKey;
-                    pair[field.valueName] = newValue;
-                }
-            }
-        },
-        tablePairSaveVisible: function (newKey, newValue) {
-            return $common.isNonEmpty(newKey) && $common.isNonEmpty(newValue);
-        }
-    }
-}]);
-
-
-// Filter to decode name using map(value, label).
-controlCenterModule.filter('displayValue', function () {
-    return function (v, m, dflt) {
-        var i = _.findIndex(m, function (item) {
-            return item.value == v;
-        });
-
-        if (i >= 0) {
-            return m[i].label;
-        }
-
-        if (dflt) {
-            return dflt;
-        }
-
-        return 'Unknown value';
-    }
-});
-
-/**
- * Filter for replacing all occurrences of {@code org.apache.ignite.} with {@code o.a.i.},
- * {@code org.apache.ignite.internal.} with {@code o.a.i.i.},
- * {@code org.apache.ignite.internal.visor.} with {@code o.a.i.i.v.} and
- * {@code org.apache.ignite.scalar.} with {@code o.a.i.s.}.
- *
- * @param s String to replace in.
- * @return Replaces string.
- */
-controlCenterModule.filter('compact', function () {
-    return function (s) {
-        return s.replace("org.apache.ignite.internal.visor.", "o.a.i.i.v.").
-            replace("org.apache.ignite.internal.", "o.a.i.i.").
-            replace("org.apache.ignite.scalar.", "o.a.i.s.").
-            replace("org.apache.ignite.", "o.a.i.");
-    }
-});
-
-// Directive to enable validation for IP addresses.
-controlCenterModule.directive('ipaddress', function () {
-    const ip = '(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])';
-    const port = '([0-9]{1,4}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])';
-    const portRange = '(:' + port + '(..' + port + ')?)?';
-    const host = '(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])';
-
-    return {
-        require: 'ngModel',
-        link: function (scope, elem, attrs, ctrl) {
-            ctrl.$validators.ipaddress = function (modelValue, viewValue) {
-                if (ctrl.$isEmpty(modelValue) || !attrs['ipaddress'])
-                    return true;
-
-                return viewValue.match(new RegExp('(^' + ip + portRange + '$)|(^' + host + portRange + '$)')) != null;
-            }
-        }
-    }
-});
-
-// Directive to enable validation to match specified value.
-controlCenterModule.directive('match', function ($parse) {
-    return {
-        require: 'ngModel',
-        link: function (scope, elem, attrs, ctrl) {
-            scope.$watch(function () {
-                return $parse(attrs.match)(scope) === ctrl.$modelValue;
-            }, function (currentValue) {
-                ctrl.$setValidity('mismatch', currentValue);
-            });
-        }
-    };
-});
-
-// Navigation bar controller.
-controlCenterModule.controller('activeLink', [
-    '$scope', function ($scope) {
-        $scope.isActive = function (path) {
-            return window.location.pathname.substr(0, path.length) == path;
-        };
-    }]);
-
-// Login popup controller.
-controlCenterModule.controller('auth', [
-    '$scope', '$modal', '$alert', '$http', '$window', '$common',
-    function ($scope, $modal, $alert, $http, $window, $common) {
-        $scope.errorMessage = $common.errorMessage;
-
-        $scope.action = 'login';
-
-        $scope.valid = false;
-
-        $scope.userDropdown = [{"text": "Profile", "href": "/profile"}];
-
-        if (!$scope.becomeUsed) {
-            if ($scope.user && $scope.user.admin)
-                $scope.userDropdown.push({"text": "Admin Panel", "href": "/admin"});
-
-            $scope.userDropdown.push({"text": "Log Out", "href": "/logout"});
-        }
-
-        // Pre-fetch an external template populated with a custom scope
-        var authModal = $modal({scope: $scope, templateUrl: '/login', show: false});
-
-        $scope.login = function () {
-            // Show when some event occurs (use $promise property to ensure the template has been loaded)
-            authModal.$promise.then(authModal.show);
-        };
-
-        $scope.auth = function (action, user_info) {
-            $http.post('/' + action, user_info)
-                .success(function () {
-                    authModal.hide();
-
-                    $window.location = '/configuration/clusters';
-                })
-                .error(function (data) {
-                    $alert({placement: 'top', container: '#errors-container', title: $scope.errorMessage(data)});
-                });
-        };
-    }]);
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/nodejs/controllers/metadata-controller.js
----------------------------------------------------------------------
diff --git a/modules/web-control-center/nodejs/controllers/metadata-controller.js b/modules/web-control-center/nodejs/controllers/metadata-controller.js
deleted file mode 100644
index b62cde5..0000000
--- a/modules/web-control-center/nodejs/controllers/metadata-controller.js
+++ /dev/null
@@ -1,678 +0,0 @@
-/*
- * 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.
- */
-
-controlCenterModule.controller('metadataController', ['$scope', '$http', '$common', '$confirm', '$copy', '$table', function ($scope, $http, $common, $confirm, $copy, $table) {
-        $scope.joinTip = $common.joinTip;
-        $scope.getModel = $common.getModel;
-
-        $scope.tableNewItem = $table.tableNewItem;
-        $scope.tableNewItemActive = $table.tableNewItemActive;
-        $scope.tableEditing = $table.tableEditing;
-        $scope.tableStartEdit = $table.tableStartEdit;
-        $scope.tableRemove = $table.tableRemove;
-
-        $scope.tableSimpleSave = $table.tableSimpleSave;
-        $scope.tableSimpleSaveVisible = $table.tableSimpleSaveVisible;
-        $scope.tableSimpleUp = $table.tableSimpleUp;
-        $scope.tableSimpleDown = $table.tableSimpleDown;
-        $scope.tableSimpleDownVisible = $table.tableSimpleDownVisible;
-
-        $scope.tablePairSave = $table.tablePairSave;
-        $scope.tablePairSaveVisible = $table.tablePairSaveVisible;
-
-        $scope.templates = [
-            {value: {kind: 'query'}, label: 'query'},
-            {value: {kind: 'store'}, label: 'store'},
-            {value: {kind: 'both'}, label: 'both'}
-        ];
-
-        $scope.template = $scope.templates[0].value;
-
-        $scope.kinds = [
-            {value: 'query', label: 'query'},
-            {value: 'store', label: 'store'},
-            {value: 'both', label: 'both'}
-        ];
-
-        $scope.databases = [
-            {value: 'oracle', label: 'Oracle database'},
-            {value: 'db2', label: 'IBM DB2'},
-            {value: 'mssql', label: 'MS SQL Server'},
-            {value: 'postgre', label: 'PostgreSQL'},
-            {value: 'mysql', label: 'MySQL'},
-            {value: 'h2', label: 'H2 database'}
-        ];
-
-        $scope.jdbcTypes = [
-            {value: 'BIT', label: 'BIT'},
-            {value: 'BOOLEAN', label: 'BOOLEAN'},
-            {value: 'TINYINT', label: 'TINYINT'},
-            {value: 'SMALLINT', label: 'SMALLINT'},
-            {value: 'INTEGER', label: 'INTEGER'},
-            {value: 'BIGINT', label: 'BIGINT'},
-            {value: 'REAL', label: 'REAL'},
-            {value: 'FLOAT', label: 'FLOAT'},
-            {value: 'DOUBLE', label: 'DOUBLE'},
-            {value: 'NUMERIC', label: 'NUMERIC'},
-            {value: 'DECIMAL', label: 'DECIMAL'},
-            {value: 'CHAR', label: 'CHAR'},
-            {value: 'VARCHAR', label: 'VARCHAR'},
-            {value: 'LONGVARCHAR', label: 'LONGVARCHAR'},
-            {value: 'NCHAR', label: 'NCHAR'},
-            {value: 'NVARCHAR', label: 'NVARCHAR'},
-            {value: 'LONGNVARCHAR', label: 'LONGNVARCHAR'},
-            {value: 'DATE', label: 'DATE'},
-            {value: 'TIME', label: 'TIME'},
-            {value: 'TIMESTAMP', label: 'TIMESTAMP'}
-        ];
-
-        $scope.javaTypes = [
-            {value: 'boolean', label: 'boolean'},
-            {value: 'Boolean', label: 'Boolean'},
-            {value: 'byte', label: 'byte'},
-            {value: 'Byte', label: 'Byte'},
-            {value: 'short', label: 'short'},
-            {value: 'Short', label: 'Short'},
-            {value: 'int', label: 'int'},
-            {value: 'Integer', label: 'Integer'},
-            {value: 'long', label: 'long'},
-            {value: 'Long', label: 'Long'},
-            {value: 'float', label: 'float'},
-            {value: 'Float', label: 'Float'},
-            {value: 'double', label: 'double'},
-            {value: 'Double', label: 'Double'},
-            {value: 'BigDecimal', label: 'BigDecimal'},
-            {value: 'String', label: 'String'},
-            {value: 'Date', label: 'Date'},
-            {value: 'Time', label: 'Time'},
-            {value: 'Timestamp', label: 'Timestamp'}
-        ];
-
-        $scope.sortDirections = [
-            {value: 'ASC', label: 'ASC'},
-            {value: 'DESC', label: 'DESC'}
-        ];
-
-        $scope.data = {
-            curTableIdx: 0,
-            curFieldIdx: 0,
-            curKeyClass: '',
-            curValueClass: '',
-            curJavaName: '',
-            curJavaType: '',
-            tables: [
-                {schemaName: 'Schema1', use: true},
-                {
-                    schemaName: 'Schema1',
-                    use: true,
-                    tableName: 'Table1',
-                    keyClass: 'KeyClass1',
-                    valueClass: 'ValueClass1',
-                    fields: [
-                        {
-                            use: true,
-                            key: true,
-                            ak: true,
-                            dbName: 'name1',
-                            dbType: 'dbType1',
-                            javaName: 'javaName1',
-                            javaType: 'javaType1'
-                        },
-                        {
-                            use: true,
-                            key: false,
-                            ak: false,
-                            dbName: 'name2',
-                            dbType: 'dbType2',
-                            javaName: 'javaName2',
-                            javaType: 'javaType2'
-                        },
-                        {
-                            use: false,
-                            key: false,
-                            ak: false,
-                            dbName: 'name3',
-                            dbType: 'dbType3',
-                            javaName: 'javaName3',
-                            javaType: 'javaType3'
-                        }
-                    ]
-                },
-                {schemaName: 'Schema2 with very long name', use: false},
-                {
-                    schemaName: 'Schema2',
-                    use: false,
-                    tableName: 'Table2',
-                    keyClass: 'KeyClass2',
-                    valueClass: 'ValueClass2',
-                    fields: [
-                        {
-                            use: true,
-                            key: true,
-                            ak: true,
-                            dbName: 'name4',
-                            dbType: 'dbType4',
-                            javaName: 'javaName4',
-                            javaType: 'javaType4'
-                        },
-                        {
-                            use: true,
-                            key: false,
-                            ak: false,
-                            dbName: 'name5',
-                            dbType: 'dbType5',
-                            javaName: 'javaName5',
-                            javaType: 'javaType5'
-                        },
-                        {
-                            use: false,
-                            key: false,
-                            ak: false,
-                            dbName: 'name6',
-                            dbType: 'dbType6',
-                            javaName: 'javaName6',
-                            javaType: 'javaType6'
-                        }
-                    ]
-                },
-                {
-                    schemaName: 'Schema2',
-                    use: false,
-                    tableName: 'Table3',
-                    keyClass: 'KeyClass3',
-                    valueClass: 'ValueClass3',
-                    fields: [
-                        {
-                            use: true,
-                            key: true,
-                            ak: true,
-                            dbName: 'name7',
-                            dbType: 'dbType7',
-                            javaName: 'javaName7',
-                            javaType: 'javaType7'
-                        },
-                        {
-                            use: true,
-                            key: false,
-                            ak: false,
-                            dbName: 'name8',
-                            dbType: 'dbType8',
-                            javaName: 'javaName8',
-                            javaType: 'javaType8'
-                        },
-                        {
-                            use: false,
-                            key: false,
-                            ak: false,
-                            dbName: 'name9',
-                            dbType: 'dbType9',
-                            javaName: 'javaName9',
-                            javaType: 'javaType9'
-                        },
-                        {
-                            use: false,
-                            key: false,
-                            ak: false,
-                            dbName: 'name10',
-                            dbType: 'dbType10',
-                            javaName: 'javaName10',
-                            javaType: 'javaType10'
-                        },
-                        {
-                            use: false,
-                            key: false,
-                            ak: false,
-                            dbName: 'name11',
-                            dbType: 'dbType11',
-                            javaName: 'javaName11',
-                            javaType: 'javaType11'
-                        },
-                        {
-                            use: false,
-                            key: false,
-                            ak: false,
-                            dbName: 'name12',
-                            dbType: 'dbType12',
-                            javaName: 'javaName12',
-                            javaType: 'javaType12'
-                        }
-                    ]
-                }]
-        };
-
-        $scope.metadatas = [];
-
-        $http.get('/models/metadata.json')
-            .success(function (data) {
-                $scope.screenTip = data.screenTip;
-                $scope.templateTip = data.templateTip;
-                $scope.metadataManual = data.metadataManual;
-                $scope.metadataDb = data.metadataDb;
-            })
-            .error(function (errMsg) {
-                $common.showError(errMsg);
-            });
-
-        // When landing on the page, get metadatas and show them.
-        $http.post('metadata/list')
-            .success(function (data) {
-                $scope.spaces = data.spaces;
-                $scope.metadatas = data.metadatas;
-
-                var restoredItem = angular.fromJson(sessionStorage.metadataBackupItem);
-
-                if (restoredItem && restoredItem._id) {
-                    var idx = _.findIndex($scope.metadatas, function (metadata) {
-                        return metadata._id == restoredItem._id;
-                    });
-
-                    if (idx >= 0) {
-                        $scope.selectedItem = $scope.metadatas[idx];
-
-                        $scope.backupItem = restoredItem;
-                    }
-                    else
-                        sessionStorage.removeItem('metadataBackupItem');
-                }
-                else
-                    $scope.backupItem = restoredItem;
-
-                $scope.$watch('backupItem', function (val) {
-                    if (val)
-                        sessionStorage.metadataBackupItem = angular.toJson(val);
-                }, true);
-            })
-            .error(function (errMsg) {
-                $common.showError(errMsg);
-            });
-
-        $scope.selectItem = function (item) {
-            $table.tableReset();
-
-            $scope.selectedItem = item;
-            $scope.backupItem = angular.copy(item);
-        };
-
-        // Add new metadata.
-        $scope.createItem = function () {
-            $table.tableReset();
-
-            $scope.backupItem = angular.copy($scope.template);
-            $scope.backupItem.space = $scope.spaces[0]._id;
-        };
-
-        // Check cache type metadata logical consistency.
-        function validate(item) {
-            return true;
-        }
-
-        // Save cache type metadata into database.
-        function save(item) {
-            $http.post('metadata/save', item)
-                .success(function (_id) {
-                    $common.showInfo('Metadata "' + item.name + '" saved.');
-
-                    var idx = _.findIndex($scope.metadatas, function (metadata) {
-                        return metadata._id == _id;
-                    });
-
-                    if (idx >= 0)
-                        angular.extend($scope.metadatas[idx], item);
-                    else {
-                        item._id = _id;
-
-                        $scope.metadatas.push(item);
-                    }
-
-                    $scope.selectItem(item);
-
-                    $common.showInfo('Cache type metadata"' + item.name + '" saved.');
-                })
-                .error(function (errMsg) {
-                    $common.showError(errMsg);
-                });
-        }
-
-        // Save cache type metadata.
-        $scope.saveItem = function () {
-            $table.tableReset();
-
-            var item = $scope.backupItem;
-
-            if (validate(item))
-                save(item);
-        };
-
-        // Save cache type metadata with new name.
-        $scope.saveItemAs = function () {
-            $table.tableReset();
-
-            if (validate($scope.backupItem))
-                $copy.show($scope.backupItem.name).then(function (newName) {
-                    var item = angular.copy($scope.backupItem);
-
-                    item._id = undefined;
-                    item.name = newName;
-
-                    save(item);
-                });
-        };
-
-        $scope.removeItem = function () {
-            $table.tableReset();
-
-            var selectedItem = $scope.selectedItem;
-
-            $confirm.show('Are you sure you want to remove cache type metadata: "' + selectedItem.name + '"?').then(
-                function () {
-                    var _id = selectedItem._id;
-
-                    $http.post('metadata/remove', {_id: _id})
-                        .success(function () {
-                            $common.showInfo('Cache type metadata has been removed: ' + selectedItem.name);
-
-                            var metadatas = $scope.metadatas;
-
-                            var idx = _.findIndex(metadatas, function (metadata) {
-                                return metadata._id == _id;
-                            });
-
-                            if (idx >= 0) {
-                                metadatas.splice(idx, 1);
-
-                                if (metadatas.length > 0)
-                                    $scope.selectItem(metadatas[0]);
-                                else {
-                                    $scope.selectedItem = undefined;
-                                    $scope.backupItem = undefined;
-                                }
-                            }
-                        })
-                        .error(function (errMsg) {
-                            $common.showError(errMsg);
-                        });
-                });
-        };
-
-        $scope.tableSimpleValid = function (item, field, name, index) {
-            var model = item[field.model];
-
-            if ($common.isDefined(model)) {
-                var idx = _.indexOf(model, name);
-
-                // Found itself.
-                if (index >= 0 && index == idx)
-                    return true;
-
-                // Found duplicate.
-                if (idx >= 0) {
-                    $common.showError('Field with such name already exists!');
-
-                    return false;
-                }
-            }
-
-            return true;
-        };
-
-        $scope.tablePairValid = function (item, field, name, clsName, index) {
-            var model = item[field.model];
-
-            if ($common.isDefined(model)) {
-                var idx = _.findIndex(model, function (pair) {
-                    return pair.name == name
-                });
-
-                // Found itself.
-                if (index >= 0 && index == idx)
-                    return true;
-
-                // Found duplicate.
-                if (idx >= 0) {
-                    $common.showError('Field with such name already exists!');
-
-                    return false;
-                }
-            }
-
-            return true;
-        };
-
-        $scope.tableDbFieldSaveVisible = function (dbName, dbType, javaName, javaType) {
-            return $common.isNonEmpty(dbName) && $common.isDefined(dbType) &&
-                $common.isNonEmpty(javaName) && $common.isDefined(javaType);
-        };
-
-        $scope.tableDbFieldSave = function (field, newDbName, newDbType, newJavaName, newJavaType, index) {
-            var item = $scope.backupItem;
-
-            var model = item[field.model];
-
-            var newItem = {dbName: newDbName, dbType: newDbType, javaName: newJavaName, javaType: newJavaType};
-
-            if ($common.isDefined(model)) {
-                var idx = _.findIndex(model, function (dbMeta) {
-                    return dbMeta.dbName == newDbName
-                });
-
-                // Found duplicate.
-                if (idx >= 0 && index != idx) {
-                    $common.showError('DB field with such name already exists!');
-
-                    return;
-                }
-
-                if (index < 0) {
-                    if (model)
-                        model.push(newItem);
-                    else
-                        item[field.model] = [newItem];
-                }
-                else {
-                    var dbField = model[index];
-
-                    dbField.dbName = newDbName;
-                    dbField.dbType = newDbType;
-                    dbField.javaName = newJavaName;
-                    dbField.javaType = newJavaType;
-                }
-            }
-            else
-                item[field.model] = [newItem];
-
-            $table.tableReset();
-        };
-
-        $scope.tableGroupSaveVisible = function (group) {
-            return $common.isNonEmpty(group);
-        };
-
-        function tableGroupValid(groupName, index) {
-            var groups = $scope.backupItem.groups;
-
-            if ($common.isDefined(groups)) {
-                var idx = _.findIndex(groups, function (group) {
-                    return group.name == groupName;
-                });
-
-                // Found itself.
-                if (index >= 0 && index == idx)
-                    return true;
-
-                // Found duplicate.
-                if (idx >= 0) {
-                    $common.showError('Group with such name already exists!');
-
-                    return false;
-                }
-            }
-
-            return true;
-        }
-
-        $scope.tableGroupSave = function (groupName, index) {
-            if (tableGroupValid(groupName, index)) {
-                $table.tableReset();
-
-                var item = $scope.backupItem;
-
-                if (index < 0) {
-                    var newGroup = {name: groupName};
-
-                    if (item.groups)
-                        item.groups.push(newGroup);
-                    else
-                        item.groups = [newGroup];
-                }
-                else
-                    item.groups[index].name = groupName;
-            }
-        };
-
-        $scope.tableGroupNewItem = function (groupIndex) {
-            var groupName = $scope.backupItem.groups[groupIndex].name;
-
-            return $table.tableNewItem({model: groupName});
-        };
-
-        $scope.tableGroupNewItemActive = function (groupIndex) {
-            var groupName = $scope.backupItem.groups[groupIndex].name;
-
-            return $table.tableNewItemActive({model: groupName});
-        };
-
-        $scope.tableGroupItemEditing = function (groupIndex, index) {
-            var groups = $scope.backupItem.groups;
-
-            if (groups)
-                return $table.tableEditing({model: groups[groupIndex].name}, index);
-
-            return false;
-        };
-
-        $scope.tableGroupItemStartEdit = function (groupIndex, index) {
-            var groups = $scope.backupItem.groups;
-
-            $table.tableState(groups[groupIndex].name, index);
-
-            return groups[groupIndex].fields[index];
-        };
-
-        $scope.tableGroupItemSaveVisible = function (fieldName, className) {
-            return $common.isNonEmpty(fieldName) && $common.isNonEmpty(className);
-        };
-
-        function tableGroupItemValid(fieldName, groupIndex, index) {
-            var groupItems = $scope.backupItem.groups[groupIndex].fields;
-
-            if ($common.isDefined(groupItems)) {
-                var idx = _.findIndex(groupItems, function (groupItem) {
-                    return groupItem.name == fieldName;
-                });
-
-                // Found itself.
-                if (index >= 0 && index == idx)
-                    return true;
-
-                // Found duplicate.
-                if (idx >= 0) {
-                    $common.showError('Field with such name already exists in group!');
-
-                    return false;
-                }
-            }
-
-            return true;
-        }
-
-        $scope.tableGroupItemSave = function (fieldName, className, direction, groupIndex, index) {
-            if (tableGroupItemValid(fieldName, groupIndex, index)) {
-                $table.tableReset();
-
-                var group = $scope.backupItem.groups[groupIndex];
-
-                if (index < 0) {
-                    var newGroupItem = {name: fieldName, className: className, direction: direction};
-
-                    if (group.fields)
-                        group.fields.push(newGroupItem);
-                    else
-                        group.fields = [newGroupItem];
-                }
-                else {
-                    var groupItem = group.fields[index];
-
-                    groupItem.name = fieldName;
-                    groupItem.className = className;
-                    groupItem.direction = direction;
-                }
-            }
-        };
-
-        $scope.tableRemoveGroupItem = function (group, index) {
-            $table.tableReset();
-
-            group.fields.splice(index, 1);
-        };
-
-        $scope.selectSchema = function (idx) {
-            var data = $scope.data;
-            var tables = data.tables;
-            var schemaName = tables[idx].schemaName;
-            var use = tables[idx].use;
-
-            for (var i = idx + 1; i < tables.length; i++) {
-                var item = tables[i];
-
-                if (item.schemaName == schemaName && item.tableName)
-                    item.use = use;
-                else
-                    break;
-            }
-
-            data.curTableIdx = -1;
-            data.curFieldIdx = -1;
-        };
-
-        $scope.selectTable = function (idx) {
-            var data = $scope.data;
-
-            data.curTableIdx = idx;
-            data.curFieldIdx = -1;
-
-            if (idx >= 0) {
-                var tbl = data.tables[idx];
-
-                data.curKeyClass = tbl.keyClass;
-                data.curValueClass = tbl.valueClass;
-            }
-        };
-
-        $scope.selectField = function (idx) {
-            var data = $scope.data;
-
-            data.curFieldIdx = idx;
-
-            if (idx >= 0) {
-                var fld = data.tables[data.curTableIdx].fields[idx];
-
-                data.curJavaName = fld.javaName;
-                data.curJavaType = fld.javaType;
-            }
-        };
-    }]
-);
\ No newline at end of file


[05/10] incubator-ignite git commit: # ignite-843 moved

Posted by an...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/src/main/js/controllers/common-module.js
----------------------------------------------------------------------
diff --git a/modules/web-control-center/src/main/js/controllers/common-module.js b/modules/web-control-center/src/main/js/controllers/common-module.js
new file mode 100644
index 0000000..75af155
--- /dev/null
+++ b/modules/web-control-center/src/main/js/controllers/common-module.js
@@ -0,0 +1,422 @@
+/*
+ * 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 controlCenterModule = angular.module('ignite-web-control-center', ['smart-table', 'mgcrea.ngStrap', 'ui.ace', 'ngSanitize']);
+
+// Modal popup configuration.
+controlCenterModule.config(function ($modalProvider) {
+    angular.extend($modalProvider.defaults, {
+        html: true
+    });
+});
+
+// Tooltips configuration.
+controlCenterModule.config(function ($tooltipProvider) {
+    angular.extend($tooltipProvider.defaults, {
+        container: 'body',
+        placement: 'right',
+        html: 'true',
+        trigger: 'click hover'
+    });
+});
+
+// Comboboxes configuration.
+controlCenterModule.config(function ($selectProvider) {
+    angular.extend($selectProvider.defaults, {
+        maxLength: '1',
+        allText: 'Select All',
+        noneText: 'Clear All',
+        templateUrl: '/select',
+        iconCheckmark: 'fa fa-check',
+        caretHtml: '<span class="caret"></span>'
+    });
+});
+
+// Alerts configuration.
+controlCenterModule.config(function ($alertProvider) {
+    angular.extend($alertProvider.defaults, {
+        container: 'body',
+        placement: 'top-right',
+        duration: '5',
+        type: 'danger'
+    });
+});
+
+// Common functions to be used in controllers.
+controlCenterModule.service('$common', ['$alert', function ($alert) {
+    var msgModal = undefined;
+
+    function errorMessage(errMsg) {
+        return errMsg ? errMsg : 'Internal server error.';
+    }
+
+    function isDefined(v) {
+        return !(v === undefined || v === null);
+    }
+
+    return {
+        getModel: function (obj, field) {
+            var path = field.path;
+
+            if (!isDefined(path))
+                return obj;
+
+            path = path.replace(/\[(\w+)\]/g, '.$1'); // convert indexes to properties
+            path = path.replace(/^\./, '');           // strip a leading dot
+
+            var segs = path.split('.');
+            var root = obj;
+
+            while (segs.length > 0) {
+                var pathStep = segs.shift();
+
+                if (typeof root[pathStep] === 'undefined')
+                    root[pathStep] = {};
+
+                root = root[pathStep];
+            }
+
+            return root;
+        },
+        joinTip: function (arr) {
+            if (!arr) {
+                return arr;
+            }
+
+            var lines = arr.map(function (line) {
+                var rtrimmed = line.replace(/\s+$/g, '');
+
+                if (rtrimmed.indexOf('>', this.length - 1) == -1) {
+                    rtrimmed = rtrimmed + '<br/>';
+                }
+
+                return rtrimmed;
+            });
+
+            return lines.join("");
+        },
+        isDefined: isDefined,
+        isNonEmpty: function (s) {
+            return isDefined(s) && s.trim().length > 0;
+        },
+        errorMessage: errorMessage,
+        showError: function (msg) {
+            if (msgModal)
+                msgModal.hide();
+
+            msgModal = $alert({title: errorMessage(msg)});
+        },
+        showInfo: function (msg) {
+            if (msgModal)
+                msgModal.hide();
+
+            msgModal = $alert({
+                type: 'success',
+                title: msg,
+                duration: 2
+            });
+        }
+    }
+}]);
+
+// Confirm popup service.
+controlCenterModule.service('$confirm', function ($modal, $rootScope, $q) {
+    var scope = $rootScope.$new();
+
+    var deferred;
+
+    scope.ok = function () {
+        deferred.resolve();
+
+        confirmModal.hide();
+    };
+
+    var confirmModal = $modal({templateUrl: '/confirm', scope: scope, placement: 'center', show: false});
+
+    var parentShow = confirmModal.show;
+
+    confirmModal.show = function (content) {
+        scope.content = content || 'Confirm deletion?';
+
+        deferred = $q.defer();
+
+        parentShow();
+
+        return deferred.promise;
+    };
+
+    return confirmModal;
+});
+
+// "Save as" popup service.
+controlCenterModule.service('$copy', function ($modal, $rootScope, $q) {
+    var scope = $rootScope.$new();
+
+    var deferred;
+
+    scope.ok = function (newName) {
+        deferred.resolve(newName);
+
+        copyModal.hide();
+    };
+
+    var copyModal = $modal({templateUrl: '/copy', scope: scope, placement: 'center', show: false});
+
+    var parentShow = copyModal.show;
+
+    copyModal.show = function (oldName) {
+        scope.newName = oldName + '(1)';
+
+        deferred = $q.defer();
+
+        parentShow();
+
+        return deferred.promise;
+    };
+
+    return copyModal;
+});
+
+// Tables support service.
+controlCenterModule.service('$table', ['$common', function ($common) {
+    function _swapSimpleItems(a, ix1, ix2) {
+        var tmp = a[ix1];
+
+        a[ix1] = a[ix2];
+        a[ix2] = tmp;
+    }
+
+    function _model(item, field) {
+        return $common.getModel(item, field);
+    }
+
+    var table = {name: 'none', editIndex: -1};
+
+    function _tableReset() {
+        table.name = 'none';
+        table.editIndex = -1;
+    }
+
+    function _tableState(name, editIndex) {
+        table.name = name;
+        table.editIndex = editIndex;
+    }
+
+    return {
+        tableState: function (name, editIndex) {
+            _tableState(name, editIndex);
+        },
+        tableReset: function () {
+            _tableReset();
+        },
+        tableNewItem: function (field) {
+            _tableState(field.model, -1);
+        },
+        tableNewItemActive: function (field) {
+            return table.name == field.model && table.editIndex < 0;
+        },
+        tableEditing: function (field, index) {
+            return table.name == field.model && table.editIndex == index;
+        },
+        tableStartEdit: function (item, field, index) {
+            _tableState(field.model, index);
+
+            return _model(item, field)[field.model][index];
+        },
+        tableRemove: function (item, field, index) {
+            _tableReset();
+
+            _model(item, field)[field.model].splice(index, 1);
+        },
+        tableSimpleSave: function (valueValid, item, field, newValue, index) {
+            if (valueValid(item, field, newValue, index)) {
+                _tableReset();
+
+                if (index < 0) {
+                    if (_model(item, field)[field.model])
+                        _model(item, field)[field.model].push(newValue);
+                    else
+                        _model(item, field)[field.model] = [newValue];
+                }
+                else
+                    _model(item, field)[field.model][index] = newValue;
+            }
+        },
+        tableSimpleSaveVisible: function (newValue) {
+            return $common.isNonEmpty(newValue);
+        },
+        tableSimpleUp: function (item, field, index) {
+            _tableReset();
+
+            _swapSimpleItems(_model(item, field)[field.model], index, index - 1);
+        },
+        tableSimpleDown: function (item, field, index) {
+            _tableReset();
+
+            _swapSimpleItems(_model(item, field)[field.model], index, index + 1);
+        },
+        tableSimpleDownVisible: function (item, field, index) {
+            return index < _model(item, field)[field.model].length - 1;
+        },
+        tablePairSave: function (pairValid, item, field, newKey, newValue, index) {
+            if (pairValid(item, field, newKey, newValue, index)) {
+                _tableReset();
+
+                var pair = {};
+
+                if (index < 0) {
+                    pair[field.keyName] = newKey;
+                    pair[field.valueName] = newValue;
+
+                    if (item[field.model])
+                        item[field.model].push(pair);
+                    else
+                        item[field.model] = [pair];
+                }
+                else {
+                    pair = item[field.model][index];
+
+                    pair[field.keyName] = newKey;
+                    pair[field.valueName] = newValue;
+                }
+            }
+        },
+        tablePairSaveVisible: function (newKey, newValue) {
+            return $common.isNonEmpty(newKey) && $common.isNonEmpty(newValue);
+        }
+    }
+}]);
+
+
+// Filter to decode name using map(value, label).
+controlCenterModule.filter('displayValue', function () {
+    return function (v, m, dflt) {
+        var i = _.findIndex(m, function (item) {
+            return item.value == v;
+        });
+
+        if (i >= 0) {
+            return m[i].label;
+        }
+
+        if (dflt) {
+            return dflt;
+        }
+
+        return 'Unknown value';
+    }
+});
+
+/**
+ * Filter for replacing all occurrences of {@code org.apache.ignite.} with {@code o.a.i.},
+ * {@code org.apache.ignite.internal.} with {@code o.a.i.i.},
+ * {@code org.apache.ignite.internal.visor.} with {@code o.a.i.i.v.} and
+ * {@code org.apache.ignite.scalar.} with {@code o.a.i.s.}.
+ *
+ * @param s String to replace in.
+ * @return Replaces string.
+ */
+controlCenterModule.filter('compact', function () {
+    return function (s) {
+        return s.replace("org.apache.ignite.internal.visor.", "o.a.i.i.v.").
+            replace("org.apache.ignite.internal.", "o.a.i.i.").
+            replace("org.apache.ignite.scalar.", "o.a.i.s.").
+            replace("org.apache.ignite.", "o.a.i.");
+    }
+});
+
+// Directive to enable validation for IP addresses.
+controlCenterModule.directive('ipaddress', function () {
+    const ip = '(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])';
+    const port = '([0-9]{1,4}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])';
+    const portRange = '(:' + port + '(..' + port + ')?)?';
+    const host = '(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])';
+
+    return {
+        require: 'ngModel',
+        link: function (scope, elem, attrs, ctrl) {
+            ctrl.$validators.ipaddress = function (modelValue, viewValue) {
+                if (ctrl.$isEmpty(modelValue) || !attrs['ipaddress'])
+                    return true;
+
+                return viewValue.match(new RegExp('(^' + ip + portRange + '$)|(^' + host + portRange + '$)')) != null;
+            }
+        }
+    }
+});
+
+// Directive to enable validation to match specified value.
+controlCenterModule.directive('match', function ($parse) {
+    return {
+        require: 'ngModel',
+        link: function (scope, elem, attrs, ctrl) {
+            scope.$watch(function () {
+                return $parse(attrs.match)(scope) === ctrl.$modelValue;
+            }, function (currentValue) {
+                ctrl.$setValidity('mismatch', currentValue);
+            });
+        }
+    };
+});
+
+// Navigation bar controller.
+controlCenterModule.controller('activeLink', [
+    '$scope', function ($scope) {
+        $scope.isActive = function (path) {
+            return window.location.pathname.substr(0, path.length) == path;
+        };
+    }]);
+
+// Login popup controller.
+controlCenterModule.controller('auth', [
+    '$scope', '$modal', '$alert', '$http', '$window', '$common',
+    function ($scope, $modal, $alert, $http, $window, $common) {
+        $scope.errorMessage = $common.errorMessage;
+
+        $scope.action = 'login';
+
+        $scope.valid = false;
+
+        $scope.userDropdown = [{"text": "Profile", "href": "/profile"}];
+
+        if (!$scope.becomeUsed) {
+            if ($scope.user && $scope.user.admin)
+                $scope.userDropdown.push({"text": "Admin Panel", "href": "/admin"});
+
+            $scope.userDropdown.push({"text": "Log Out", "href": "/logout"});
+        }
+
+        // Pre-fetch an external template populated with a custom scope
+        var authModal = $modal({scope: $scope, templateUrl: '/login', show: false});
+
+        $scope.login = function () {
+            // Show when some event occurs (use $promise property to ensure the template has been loaded)
+            authModal.$promise.then(authModal.show);
+        };
+
+        $scope.auth = function (action, user_info) {
+            $http.post('/' + action, user_info)
+                .success(function () {
+                    authModal.hide();
+
+                    $window.location = '/configuration/clusters';
+                })
+                .error(function (data) {
+                    $alert({placement: 'top', container: '#errors-container', title: $scope.errorMessage(data)});
+                });
+        };
+    }]);
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/src/main/js/controllers/metadata-controller.js
----------------------------------------------------------------------
diff --git a/modules/web-control-center/src/main/js/controllers/metadata-controller.js b/modules/web-control-center/src/main/js/controllers/metadata-controller.js
new file mode 100644
index 0000000..b62cde5
--- /dev/null
+++ b/modules/web-control-center/src/main/js/controllers/metadata-controller.js
@@ -0,0 +1,678 @@
+/*
+ * 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.
+ */
+
+controlCenterModule.controller('metadataController', ['$scope', '$http', '$common', '$confirm', '$copy', '$table', function ($scope, $http, $common, $confirm, $copy, $table) {
+        $scope.joinTip = $common.joinTip;
+        $scope.getModel = $common.getModel;
+
+        $scope.tableNewItem = $table.tableNewItem;
+        $scope.tableNewItemActive = $table.tableNewItemActive;
+        $scope.tableEditing = $table.tableEditing;
+        $scope.tableStartEdit = $table.tableStartEdit;
+        $scope.tableRemove = $table.tableRemove;
+
+        $scope.tableSimpleSave = $table.tableSimpleSave;
+        $scope.tableSimpleSaveVisible = $table.tableSimpleSaveVisible;
+        $scope.tableSimpleUp = $table.tableSimpleUp;
+        $scope.tableSimpleDown = $table.tableSimpleDown;
+        $scope.tableSimpleDownVisible = $table.tableSimpleDownVisible;
+
+        $scope.tablePairSave = $table.tablePairSave;
+        $scope.tablePairSaveVisible = $table.tablePairSaveVisible;
+
+        $scope.templates = [
+            {value: {kind: 'query'}, label: 'query'},
+            {value: {kind: 'store'}, label: 'store'},
+            {value: {kind: 'both'}, label: 'both'}
+        ];
+
+        $scope.template = $scope.templates[0].value;
+
+        $scope.kinds = [
+            {value: 'query', label: 'query'},
+            {value: 'store', label: 'store'},
+            {value: 'both', label: 'both'}
+        ];
+
+        $scope.databases = [
+            {value: 'oracle', label: 'Oracle database'},
+            {value: 'db2', label: 'IBM DB2'},
+            {value: 'mssql', label: 'MS SQL Server'},
+            {value: 'postgre', label: 'PostgreSQL'},
+            {value: 'mysql', label: 'MySQL'},
+            {value: 'h2', label: 'H2 database'}
+        ];
+
+        $scope.jdbcTypes = [
+            {value: 'BIT', label: 'BIT'},
+            {value: 'BOOLEAN', label: 'BOOLEAN'},
+            {value: 'TINYINT', label: 'TINYINT'},
+            {value: 'SMALLINT', label: 'SMALLINT'},
+            {value: 'INTEGER', label: 'INTEGER'},
+            {value: 'BIGINT', label: 'BIGINT'},
+            {value: 'REAL', label: 'REAL'},
+            {value: 'FLOAT', label: 'FLOAT'},
+            {value: 'DOUBLE', label: 'DOUBLE'},
+            {value: 'NUMERIC', label: 'NUMERIC'},
+            {value: 'DECIMAL', label: 'DECIMAL'},
+            {value: 'CHAR', label: 'CHAR'},
+            {value: 'VARCHAR', label: 'VARCHAR'},
+            {value: 'LONGVARCHAR', label: 'LONGVARCHAR'},
+            {value: 'NCHAR', label: 'NCHAR'},
+            {value: 'NVARCHAR', label: 'NVARCHAR'},
+            {value: 'LONGNVARCHAR', label: 'LONGNVARCHAR'},
+            {value: 'DATE', label: 'DATE'},
+            {value: 'TIME', label: 'TIME'},
+            {value: 'TIMESTAMP', label: 'TIMESTAMP'}
+        ];
+
+        $scope.javaTypes = [
+            {value: 'boolean', label: 'boolean'},
+            {value: 'Boolean', label: 'Boolean'},
+            {value: 'byte', label: 'byte'},
+            {value: 'Byte', label: 'Byte'},
+            {value: 'short', label: 'short'},
+            {value: 'Short', label: 'Short'},
+            {value: 'int', label: 'int'},
+            {value: 'Integer', label: 'Integer'},
+            {value: 'long', label: 'long'},
+            {value: 'Long', label: 'Long'},
+            {value: 'float', label: 'float'},
+            {value: 'Float', label: 'Float'},
+            {value: 'double', label: 'double'},
+            {value: 'Double', label: 'Double'},
+            {value: 'BigDecimal', label: 'BigDecimal'},
+            {value: 'String', label: 'String'},
+            {value: 'Date', label: 'Date'},
+            {value: 'Time', label: 'Time'},
+            {value: 'Timestamp', label: 'Timestamp'}
+        ];
+
+        $scope.sortDirections = [
+            {value: 'ASC', label: 'ASC'},
+            {value: 'DESC', label: 'DESC'}
+        ];
+
+        $scope.data = {
+            curTableIdx: 0,
+            curFieldIdx: 0,
+            curKeyClass: '',
+            curValueClass: '',
+            curJavaName: '',
+            curJavaType: '',
+            tables: [
+                {schemaName: 'Schema1', use: true},
+                {
+                    schemaName: 'Schema1',
+                    use: true,
+                    tableName: 'Table1',
+                    keyClass: 'KeyClass1',
+                    valueClass: 'ValueClass1',
+                    fields: [
+                        {
+                            use: true,
+                            key: true,
+                            ak: true,
+                            dbName: 'name1',
+                            dbType: 'dbType1',
+                            javaName: 'javaName1',
+                            javaType: 'javaType1'
+                        },
+                        {
+                            use: true,
+                            key: false,
+                            ak: false,
+                            dbName: 'name2',
+                            dbType: 'dbType2',
+                            javaName: 'javaName2',
+                            javaType: 'javaType2'
+                        },
+                        {
+                            use: false,
+                            key: false,
+                            ak: false,
+                            dbName: 'name3',
+                            dbType: 'dbType3',
+                            javaName: 'javaName3',
+                            javaType: 'javaType3'
+                        }
+                    ]
+                },
+                {schemaName: 'Schema2 with very long name', use: false},
+                {
+                    schemaName: 'Schema2',
+                    use: false,
+                    tableName: 'Table2',
+                    keyClass: 'KeyClass2',
+                    valueClass: 'ValueClass2',
+                    fields: [
+                        {
+                            use: true,
+                            key: true,
+                            ak: true,
+                            dbName: 'name4',
+                            dbType: 'dbType4',
+                            javaName: 'javaName4',
+                            javaType: 'javaType4'
+                        },
+                        {
+                            use: true,
+                            key: false,
+                            ak: false,
+                            dbName: 'name5',
+                            dbType: 'dbType5',
+                            javaName: 'javaName5',
+                            javaType: 'javaType5'
+                        },
+                        {
+                            use: false,
+                            key: false,
+                            ak: false,
+                            dbName: 'name6',
+                            dbType: 'dbType6',
+                            javaName: 'javaName6',
+                            javaType: 'javaType6'
+                        }
+                    ]
+                },
+                {
+                    schemaName: 'Schema2',
+                    use: false,
+                    tableName: 'Table3',
+                    keyClass: 'KeyClass3',
+                    valueClass: 'ValueClass3',
+                    fields: [
+                        {
+                            use: true,
+                            key: true,
+                            ak: true,
+                            dbName: 'name7',
+                            dbType: 'dbType7',
+                            javaName: 'javaName7',
+                            javaType: 'javaType7'
+                        },
+                        {
+                            use: true,
+                            key: false,
+                            ak: false,
+                            dbName: 'name8',
+                            dbType: 'dbType8',
+                            javaName: 'javaName8',
+                            javaType: 'javaType8'
+                        },
+                        {
+                            use: false,
+                            key: false,
+                            ak: false,
+                            dbName: 'name9',
+                            dbType: 'dbType9',
+                            javaName: 'javaName9',
+                            javaType: 'javaType9'
+                        },
+                        {
+                            use: false,
+                            key: false,
+                            ak: false,
+                            dbName: 'name10',
+                            dbType: 'dbType10',
+                            javaName: 'javaName10',
+                            javaType: 'javaType10'
+                        },
+                        {
+                            use: false,
+                            key: false,
+                            ak: false,
+                            dbName: 'name11',
+                            dbType: 'dbType11',
+                            javaName: 'javaName11',
+                            javaType: 'javaType11'
+                        },
+                        {
+                            use: false,
+                            key: false,
+                            ak: false,
+                            dbName: 'name12',
+                            dbType: 'dbType12',
+                            javaName: 'javaName12',
+                            javaType: 'javaType12'
+                        }
+                    ]
+                }]
+        };
+
+        $scope.metadatas = [];
+
+        $http.get('/models/metadata.json')
+            .success(function (data) {
+                $scope.screenTip = data.screenTip;
+                $scope.templateTip = data.templateTip;
+                $scope.metadataManual = data.metadataManual;
+                $scope.metadataDb = data.metadataDb;
+            })
+            .error(function (errMsg) {
+                $common.showError(errMsg);
+            });
+
+        // When landing on the page, get metadatas and show them.
+        $http.post('metadata/list')
+            .success(function (data) {
+                $scope.spaces = data.spaces;
+                $scope.metadatas = data.metadatas;
+
+                var restoredItem = angular.fromJson(sessionStorage.metadataBackupItem);
+
+                if (restoredItem && restoredItem._id) {
+                    var idx = _.findIndex($scope.metadatas, function (metadata) {
+                        return metadata._id == restoredItem._id;
+                    });
+
+                    if (idx >= 0) {
+                        $scope.selectedItem = $scope.metadatas[idx];
+
+                        $scope.backupItem = restoredItem;
+                    }
+                    else
+                        sessionStorage.removeItem('metadataBackupItem');
+                }
+                else
+                    $scope.backupItem = restoredItem;
+
+                $scope.$watch('backupItem', function (val) {
+                    if (val)
+                        sessionStorage.metadataBackupItem = angular.toJson(val);
+                }, true);
+            })
+            .error(function (errMsg) {
+                $common.showError(errMsg);
+            });
+
+        $scope.selectItem = function (item) {
+            $table.tableReset();
+
+            $scope.selectedItem = item;
+            $scope.backupItem = angular.copy(item);
+        };
+
+        // Add new metadata.
+        $scope.createItem = function () {
+            $table.tableReset();
+
+            $scope.backupItem = angular.copy($scope.template);
+            $scope.backupItem.space = $scope.spaces[0]._id;
+        };
+
+        // Check cache type metadata logical consistency.
+        function validate(item) {
+            return true;
+        }
+
+        // Save cache type metadata into database.
+        function save(item) {
+            $http.post('metadata/save', item)
+                .success(function (_id) {
+                    $common.showInfo('Metadata "' + item.name + '" saved.');
+
+                    var idx = _.findIndex($scope.metadatas, function (metadata) {
+                        return metadata._id == _id;
+                    });
+
+                    if (idx >= 0)
+                        angular.extend($scope.metadatas[idx], item);
+                    else {
+                        item._id = _id;
+
+                        $scope.metadatas.push(item);
+                    }
+
+                    $scope.selectItem(item);
+
+                    $common.showInfo('Cache type metadata"' + item.name + '" saved.');
+                })
+                .error(function (errMsg) {
+                    $common.showError(errMsg);
+                });
+        }
+
+        // Save cache type metadata.
+        $scope.saveItem = function () {
+            $table.tableReset();
+
+            var item = $scope.backupItem;
+
+            if (validate(item))
+                save(item);
+        };
+
+        // Save cache type metadata with new name.
+        $scope.saveItemAs = function () {
+            $table.tableReset();
+
+            if (validate($scope.backupItem))
+                $copy.show($scope.backupItem.name).then(function (newName) {
+                    var item = angular.copy($scope.backupItem);
+
+                    item._id = undefined;
+                    item.name = newName;
+
+                    save(item);
+                });
+        };
+
+        $scope.removeItem = function () {
+            $table.tableReset();
+
+            var selectedItem = $scope.selectedItem;
+
+            $confirm.show('Are you sure you want to remove cache type metadata: "' + selectedItem.name + '"?').then(
+                function () {
+                    var _id = selectedItem._id;
+
+                    $http.post('metadata/remove', {_id: _id})
+                        .success(function () {
+                            $common.showInfo('Cache type metadata has been removed: ' + selectedItem.name);
+
+                            var metadatas = $scope.metadatas;
+
+                            var idx = _.findIndex(metadatas, function (metadata) {
+                                return metadata._id == _id;
+                            });
+
+                            if (idx >= 0) {
+                                metadatas.splice(idx, 1);
+
+                                if (metadatas.length > 0)
+                                    $scope.selectItem(metadatas[0]);
+                                else {
+                                    $scope.selectedItem = undefined;
+                                    $scope.backupItem = undefined;
+                                }
+                            }
+                        })
+                        .error(function (errMsg) {
+                            $common.showError(errMsg);
+                        });
+                });
+        };
+
+        $scope.tableSimpleValid = function (item, field, name, index) {
+            var model = item[field.model];
+
+            if ($common.isDefined(model)) {
+                var idx = _.indexOf(model, name);
+
+                // Found itself.
+                if (index >= 0 && index == idx)
+                    return true;
+
+                // Found duplicate.
+                if (idx >= 0) {
+                    $common.showError('Field with such name already exists!');
+
+                    return false;
+                }
+            }
+
+            return true;
+        };
+
+        $scope.tablePairValid = function (item, field, name, clsName, index) {
+            var model = item[field.model];
+
+            if ($common.isDefined(model)) {
+                var idx = _.findIndex(model, function (pair) {
+                    return pair.name == name
+                });
+
+                // Found itself.
+                if (index >= 0 && index == idx)
+                    return true;
+
+                // Found duplicate.
+                if (idx >= 0) {
+                    $common.showError('Field with such name already exists!');
+
+                    return false;
+                }
+            }
+
+            return true;
+        };
+
+        $scope.tableDbFieldSaveVisible = function (dbName, dbType, javaName, javaType) {
+            return $common.isNonEmpty(dbName) && $common.isDefined(dbType) &&
+                $common.isNonEmpty(javaName) && $common.isDefined(javaType);
+        };
+
+        $scope.tableDbFieldSave = function (field, newDbName, newDbType, newJavaName, newJavaType, index) {
+            var item = $scope.backupItem;
+
+            var model = item[field.model];
+
+            var newItem = {dbName: newDbName, dbType: newDbType, javaName: newJavaName, javaType: newJavaType};
+
+            if ($common.isDefined(model)) {
+                var idx = _.findIndex(model, function (dbMeta) {
+                    return dbMeta.dbName == newDbName
+                });
+
+                // Found duplicate.
+                if (idx >= 0 && index != idx) {
+                    $common.showError('DB field with such name already exists!');
+
+                    return;
+                }
+
+                if (index < 0) {
+                    if (model)
+                        model.push(newItem);
+                    else
+                        item[field.model] = [newItem];
+                }
+                else {
+                    var dbField = model[index];
+
+                    dbField.dbName = newDbName;
+                    dbField.dbType = newDbType;
+                    dbField.javaName = newJavaName;
+                    dbField.javaType = newJavaType;
+                }
+            }
+            else
+                item[field.model] = [newItem];
+
+            $table.tableReset();
+        };
+
+        $scope.tableGroupSaveVisible = function (group) {
+            return $common.isNonEmpty(group);
+        };
+
+        function tableGroupValid(groupName, index) {
+            var groups = $scope.backupItem.groups;
+
+            if ($common.isDefined(groups)) {
+                var idx = _.findIndex(groups, function (group) {
+                    return group.name == groupName;
+                });
+
+                // Found itself.
+                if (index >= 0 && index == idx)
+                    return true;
+
+                // Found duplicate.
+                if (idx >= 0) {
+                    $common.showError('Group with such name already exists!');
+
+                    return false;
+                }
+            }
+
+            return true;
+        }
+
+        $scope.tableGroupSave = function (groupName, index) {
+            if (tableGroupValid(groupName, index)) {
+                $table.tableReset();
+
+                var item = $scope.backupItem;
+
+                if (index < 0) {
+                    var newGroup = {name: groupName};
+
+                    if (item.groups)
+                        item.groups.push(newGroup);
+                    else
+                        item.groups = [newGroup];
+                }
+                else
+                    item.groups[index].name = groupName;
+            }
+        };
+
+        $scope.tableGroupNewItem = function (groupIndex) {
+            var groupName = $scope.backupItem.groups[groupIndex].name;
+
+            return $table.tableNewItem({model: groupName});
+        };
+
+        $scope.tableGroupNewItemActive = function (groupIndex) {
+            var groupName = $scope.backupItem.groups[groupIndex].name;
+
+            return $table.tableNewItemActive({model: groupName});
+        };
+
+        $scope.tableGroupItemEditing = function (groupIndex, index) {
+            var groups = $scope.backupItem.groups;
+
+            if (groups)
+                return $table.tableEditing({model: groups[groupIndex].name}, index);
+
+            return false;
+        };
+
+        $scope.tableGroupItemStartEdit = function (groupIndex, index) {
+            var groups = $scope.backupItem.groups;
+
+            $table.tableState(groups[groupIndex].name, index);
+
+            return groups[groupIndex].fields[index];
+        };
+
+        $scope.tableGroupItemSaveVisible = function (fieldName, className) {
+            return $common.isNonEmpty(fieldName) && $common.isNonEmpty(className);
+        };
+
+        function tableGroupItemValid(fieldName, groupIndex, index) {
+            var groupItems = $scope.backupItem.groups[groupIndex].fields;
+
+            if ($common.isDefined(groupItems)) {
+                var idx = _.findIndex(groupItems, function (groupItem) {
+                    return groupItem.name == fieldName;
+                });
+
+                // Found itself.
+                if (index >= 0 && index == idx)
+                    return true;
+
+                // Found duplicate.
+                if (idx >= 0) {
+                    $common.showError('Field with such name already exists in group!');
+
+                    return false;
+                }
+            }
+
+            return true;
+        }
+
+        $scope.tableGroupItemSave = function (fieldName, className, direction, groupIndex, index) {
+            if (tableGroupItemValid(fieldName, groupIndex, index)) {
+                $table.tableReset();
+
+                var group = $scope.backupItem.groups[groupIndex];
+
+                if (index < 0) {
+                    var newGroupItem = {name: fieldName, className: className, direction: direction};
+
+                    if (group.fields)
+                        group.fields.push(newGroupItem);
+                    else
+                        group.fields = [newGroupItem];
+                }
+                else {
+                    var groupItem = group.fields[index];
+
+                    groupItem.name = fieldName;
+                    groupItem.className = className;
+                    groupItem.direction = direction;
+                }
+            }
+        };
+
+        $scope.tableRemoveGroupItem = function (group, index) {
+            $table.tableReset();
+
+            group.fields.splice(index, 1);
+        };
+
+        $scope.selectSchema = function (idx) {
+            var data = $scope.data;
+            var tables = data.tables;
+            var schemaName = tables[idx].schemaName;
+            var use = tables[idx].use;
+
+            for (var i = idx + 1; i < tables.length; i++) {
+                var item = tables[i];
+
+                if (item.schemaName == schemaName && item.tableName)
+                    item.use = use;
+                else
+                    break;
+            }
+
+            data.curTableIdx = -1;
+            data.curFieldIdx = -1;
+        };
+
+        $scope.selectTable = function (idx) {
+            var data = $scope.data;
+
+            data.curTableIdx = idx;
+            data.curFieldIdx = -1;
+
+            if (idx >= 0) {
+                var tbl = data.tables[idx];
+
+                data.curKeyClass = tbl.keyClass;
+                data.curValueClass = tbl.valueClass;
+            }
+        };
+
+        $scope.selectField = function (idx) {
+            var data = $scope.data;
+
+            data.curFieldIdx = idx;
+
+            if (idx >= 0) {
+                var fld = data.tables[data.curTableIdx].fields[idx];
+
+                data.curJavaName = fld.javaName;
+                data.curJavaType = fld.javaType;
+            }
+        };
+    }]
+);
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/src/main/js/controllers/models/caches.json
----------------------------------------------------------------------
diff --git a/modules/web-control-center/src/main/js/controllers/models/caches.json b/modules/web-control-center/src/main/js/controllers/models/caches.json
new file mode 100644
index 0000000..0ffc9d4
--- /dev/null
+++ b/modules/web-control-center/src/main/js/controllers/models/caches.json
@@ -0,0 +1,918 @@
+{
+  "screenTip": {
+    "workflowTitle": "Use Caches view to:",
+    "workflowContent": [
+      "<ul>",
+      "  <li>Configure caches.</li>",
+      "  <li>Associate metadata with cache queries and/or cache store.</li>",
+      "</ul>"
+    ],
+    "whatsNextTitle": "What's next:",
+    "whatsNextContent": [
+      "<ul>",
+      "  <li>Configure clusters.</li>",
+      "  <li>Configure cache type metadata.</li>",
+      "  <li>Generate XML and java code on Summary view.</li>",
+      "</ul>"
+    ]
+  },
+  "general": [
+    {
+      "label": "Name",
+      "type": "text",
+      "model": "name",
+      "required": true,
+      "placeholder": "Input name"
+    },
+    {
+      "label": "Mode",
+      "type": "dropdown",
+      "model": "mode",
+      "placeholder": "PARTITIONED",
+      "items": "modes",
+      "tip": [
+        "Cache modes:",
+        "<ul>",
+        "  <li>Partitioned - in this mode the overall key set will be divided into partitions and all partitions will be split equally between participating nodes.</li>",
+        "  <li>Replicated - in this mode all the keys are distributed to all participating nodes.</li>",
+        "  <li>Local - in this mode caches residing on different grid nodes will not know about each other.</li>",
+        "</ul>"
+      ]
+    },
+    {
+      "label": "Atomicity",
+      "type": "dropdown",
+      "model": "atomicityMode",
+      "placeholder": "ATOMIC",
+      "items": "atomicities",
+      "tip": [
+        "Atomicity:",
+        "<ul>",
+        "  <li>Transactional - in this mode specified fully ACID-compliant transactional cache behavior.</li>",
+        "  <li>Atomic - in this mode distributed transactions and distributed locking are not supported.</li>",
+        "</ul>"
+      ]
+    },
+    {
+      "label": "Backups",
+      "type": "number",
+      "model": "backups",
+      "hide": "backupItem.mode == 'LOCAL'",
+      "placeholder": 0,
+      "tip": [
+        "Number of nodes used to back up single partition for partitioned cache."
+      ]
+    },
+    {
+      "label": "Read from backup",
+      "type": "check",
+      "model": "readFromBackup",
+      "placeholder": true,
+      "hide": "!backupItem.backups || backupItem.mode == 'LOCAL'",
+      "tip": [
+        "Flag indicating whether data can be read from backup.",
+        "If not set then always get data from primary node (never from backup)."
+      ]
+    },
+    {
+      "label": "Copy on read",
+      "type": "check",
+      "model": "copyOnRead",
+      "placeholder": true,
+      "tip": [
+        "Flag indicating whether copy of of the value stored in cache should be created for cache operation implying return value.",
+        "Also if this flag is set copies are created for values passed to CacheInterceptor and to CacheEntryProcessor."
+      ]
+    },
+    {
+      "label": "Invalidate near cache",
+      "type": "check",
+      "model": "invalidate",
+      "tip": [
+        "Invalidation flag for near cache entries in transaction.",
+        "If set then values will be invalidated (nullified) upon commit in near cache."
+      ]
+    }
+  ],
+  "advanced": [
+    {
+      "label": "Concurrency control",
+      "tip": [
+        "Cache concurrent usage settings."
+      ],
+      "fields": [
+        {
+          "label": "Max async operations",
+          "type": "number",
+          "model": "maxConcurrentAsyncOperations",
+          "placeholder": 500,
+          "tip": [
+            "Maximum number of allowed concurrent asynchronous operations.",
+            "If 0 then number of concurrent asynchronous operations is unlimited."
+          ]
+        },
+        {
+          "label": "Default lock timeout",
+          "type": "number",
+          "model": "defaultLockTimeout",
+          "placeholder": 0,
+          "tip": [
+            "Default lock acquisition timeout.",
+            "If 0 then lock acquisition will never timeout."
+          ]
+        },
+        {
+          "label": "Entry versioning",
+          "type": "dropdown",
+          "model": "atomicWriteOrderMode",
+          "placeholder": "Choose versioning",
+          "items": "atomicWriteOrderModes",
+          "hide": "backupItem.atomicityMode == 'TRANSACTIONAL'",
+          "tip": [
+            "Write ordering mode determines which node assigns the write version, sender or the primary node.",
+            "<ul>",
+            "  <li>CLOCK - in this mode write versions are assigned on a sender node which generally leads to better performance.</li>",
+            "  <li>PRIMARY - in this mode version is assigned only on primary node. This means that sender will only send write request to primary node, which in turn will assign write version and forward it to backups.</li>",
+            "</ul>"
+          ]
+        }
+      ]
+    },
+    {
+      "label": "Memory",
+      "tip": [
+        "Cache memory settings."
+      ],
+      "fields": [
+        {
+          "label": "Mode",
+          "type": "dropdown",
+          "model": "memoryMode",
+          "placeholder": "ONHEAP_TIERED",
+          "items": "memoryModes",
+          "tip": [
+            "Memory modes:",
+            "<ul>",
+            "  <li>ONHEAP_TIERED - entries are cached on heap memory first.",
+            "    <ul>",
+            "      <li>If offheap memory is enabled and eviction policy evicts an entry from heap memory, entry will be moved to offheap memory. If offheap memory is disabled, then entry is simply discarded.</li>",
+            "      <li>If swap space is enabled and offheap memory fills up, then entry will be evicted into swap space. If swap space is disabled, then entry will be discarded. If swap is enabled and offheap memory is disabled, then entry will be evicted directly from heap memory into swap.</li>",
+            "    </ul>",
+            "  </li>",
+            "  <li>OFFHEAP_TIERED - works the same as ONHEAP_TIERED, except that entries never end up in heap memory and get stored in offheap memory right away. Entries get cached in offheap memory first and then get evicted to swap, if one is configured.</li>",
+            "  <li>OFFHEAP_VALUES - entry keys will be stored on heap memory, and values will be stored in offheap memory. Note that in this mode entries can be evicted only to swap.</li>",
+            "</ul>"
+          ]
+        },
+        {
+          "label": "Off-heap max memory",
+          "type": "number",
+          "model": "offHeapMaxMemory",
+          "min": -1,
+          "placeholder": -1,
+          "hide": "backupItem.memoryMode == 'OFFHEAP_VALUES'",
+          "tip": [
+            "Sets maximum amount of memory available to off-heap storage.",
+            "Possible values are:",
+            "<ul>",
+            "  <li>-1 - means that off-heap storage is disabled.</li>",
+            "  <li>0 - Ignite will not limit off-heap storage (it's up to user to properly add and remove entries from cache to ensure that off-heap storage does not grow infinitely.</li>",
+            "  <li>Any positive value specifies the limit of off-heap storage in bytes.</li>",
+            "</ul>"
+          ]
+        },
+        {
+          "label": "Eviction policy",
+          "type": "dropdown-details",
+          "path": "evictionPolicy",
+          "model": "kind",
+          "placeholder": "Choose eviction policy",
+          "items": "evictionPolicies",
+          "hide": "backupItem.memoryMode == 'OFFHEAP_TIERED'",
+          "tip": [
+            "Optional cache eviction policy. Must be set for entries to be evicted from on-heap to off-heap or swap."
+          ],
+          "details": {
+            "LRU": {
+              "expanded": false,
+              "fields": [
+                {
+                  "label": "Batch size",
+                  "type": "number",
+                  "path": "evictionPolicy.LRU",
+                  "model": "batchSize",
+                  "placeholder": 1,
+                  "tip": [
+                    "Number of entries to remove on shrink."
+                  ]
+                },
+                {
+                  "label": "Max memory size",
+                  "type": "number",
+                  "path": "evictionPolicy.LRU",
+                  "model": "maxMemorySize",
+                  "placeholder": 0,
+                  "tip": [
+                    "Maximum allowed cache size in bytes."
+                  ]
+                },
+                {
+                  "label": "Max size",
+                  "type": "number",
+                  "path": "evictionPolicy.LRU",
+                  "model": "maxSize",
+                  "placeholder": 100000,
+                  "tip": [
+                    "Maximum allowed size of cache before entry will start getting evicted."
+                  ]
+                }
+              ]
+            },
+            "RND": {
+              "expanded": false,
+              "fields": [
+                {
+                  "label": "Max size",
+                  "type": "number",
+                  "path": "evictionPolicy.RND",
+                  "model": "maxSize",
+                  "placeholder": 100000,
+                  "tip": [
+                    "Maximum allowed size of cache before entry will start getting evicted."
+                  ]
+                }
+              ]
+            },
+            "FIFO": {
+              "expanded": false,
+              "fields": [
+                {
+                  "label": "Batch size",
+                  "type": "number",
+                  "path": "evictionPolicy.FIFO",
+                  "model": "batchSize",
+                  "placeholder": 1,
+                  "tip": [
+                    "Number of entries to remove on shrink."
+                  ]
+                },
+                {
+                  "label": "Max memory size",
+                  "type": "number",
+                  "path": "evictionPolicy.FIFO",
+                  "model": "maxMemorySize",
+                  "placeholder": 0,
+                  "tip": [
+                    "Maximum allowed cache size in bytes."
+                  ]
+                },
+                {
+                  "label": "Max size",
+                  "type": "number",
+                  "path": "evictionPolicy.FIFO",
+                  "model": "maxSize",
+                  "placeholder": 100000,
+                  "tip": [
+                    "Maximum allowed size of cache before entry will start getting evicted."
+                  ]
+                }
+              ]
+            },
+            "SORTED": {
+              "expanded": false,
+              "fields": [
+                {
+                  "label": "Batch size",
+                  "type": "number",
+                  "path": "evictionPolicy.SORTED",
+                  "model": "batchSize",
+                  "placeholder": 1,
+                  "tip": [
+                    "Number of entries to remove on shrink."
+                  ]
+                },
+                {
+                  "label": "Max memory size",
+                  "type": "number",
+                  "path": "evictionPolicy.SORTED",
+                  "model": "maxMemorySize",
+                  "placeholder": 0,
+                  "tip": [
+                    "Maximum allowed cache size in bytes."
+                  ]
+                },
+                {
+                  "label": "Max size",
+                  "type": "number",
+                  "path": "evictionPolicy.SORTED",
+                  "model": "maxSize",
+                  "placeholder": 100000,
+                  "tip": [
+                    "Maximum allowed size of cache before entry will start getting evicted."
+                  ]
+                }
+              ]
+            }
+          }
+        },
+        {
+          "label": "Start size",
+          "type": "number",
+          "model": "startSize",
+          "placeholder": 1500000,
+          "tip": [
+            "Initial cache size which will be used to pre-create internal hash table after start."
+          ]
+        },
+        {
+          "label": "Swap enabled",
+          "type": "check",
+          "model": "swapEnabled",
+          "tip": [
+            "Flag indicating whether swap storage is enabled or not for this cache."
+          ]
+        }
+      ]
+    },
+    {
+      "label": "Query",
+      "tip": [
+        "Cache query settings."
+      ],
+      "fields": [
+        {
+          "label": "Escape table and filed names",
+          "type": "check",
+          "model": "sqlEscapeAll",
+          "tip": [
+            "If set then all the SQL table and field names will be escaped with double quotes.",
+            "This enforces case sensitivity for field names and also allows having special characters in table and field names."
+          ]
+        },
+        {
+          "label": "On-heap cache for off-heap indexes",
+          "type": "number",
+          "model": "sqlOnheapRowCacheSize",
+          "placeholder": 10240,
+          "tip": [
+            "Number of SQL rows which will be cached onheap to avoid deserialization on each SQL index access."
+          ]
+        },
+        {
+          "label": "Long query timeout",
+          "type": "number",
+          "model": "longQueryWarningTimeout",
+          "placeholder": 3000,
+          "tip": [
+            "Timeout in milliseconds after which long query warning will be printed."
+          ]
+        },
+        {
+          "type": "indexedTypes",
+          "model": "indexedTypes",
+          "keyName": "keyClass",
+          "valueName": "valueClass",
+          "tip": [
+            "Collection of types to index."
+          ]
+        },
+        {
+          "label": "SQL functions",
+          "type": "table-simple",
+          "model": "sqlFunctionClasses",
+          "editIdx": -1,
+          "placeholder": "SQL function full class name",
+          "tableTip": [
+            "Collections of classes with user-defined functions for SQL queries."
+          ],
+          "tip": [
+            "Class with user-defined functions for SQL queries."
+          ]
+        }
+      ]
+    },
+    {
+      "label": "Rebalance",
+      "tip": [
+        "Cache rebalance settings."
+      ],
+      "fields": [
+        {
+          "label": "Mode",
+          "type": "dropdown",
+          "model": "rebalanceMode",
+          "placeholder": "ASYNC",
+          "items": "rebalanceModes",
+          "tip": [
+            "Rebalance modes:",
+            "<ul>",
+            "  <li>Synchronous - in this mode distributed caches will not start until all necessary data is loaded from other available grid nodes.</li>",
+            "  <li>Asynchronous - in this mode distributed caches will start immediately and will load all necessary data from other available grid nodes in the background.</li>",
+            "  <li>None - in this mode no rebalancing will take place which means that caches will be either loaded on demand from persistent store whenever data is accessed, or will be populated explicitly.</li>",
+            "</ul>"
+          ]
+        },
+        {
+          "label": "Pool size",
+          "type": "number",
+          "model": "rebalanceThreadPoolSize",
+          "placeholder": 2,
+          "tip": [
+            "Size of rebalancing thread pool.<br>",
+            "Note that size serves as a hint and implementation may create more threads for rebalancing than specified here (but never less threads)."
+          ]
+        },
+        {
+          "label": "Batch size",
+          "type": "number",
+          "model": "rebalanceBatchSize",
+          "placeholder": "512 * 1024",
+          "tip": [
+            "Size (in bytes) to be loaded within a single rebalance message.",
+            "Rebalancing algorithm will split total data set on every node into multiple batches prior to sending data."
+          ]
+        },
+        {
+          "label": "Order",
+          "type": "number",
+          "model": "rebalanceOrder",
+          "placeholder": 0,
+          "tip": [
+            "If cache rebalance order is positive, rebalancing for this cache will be started only when rebalancing for all caches with smaller rebalance order (except caches with rebalance order 0) will be completed."
+          ]
+        },
+        {
+          "label": "Delay",
+          "type": "number",
+          "model": "rebalanceDelay",
+          "placeholder": 0,
+          "tip": [
+            "Delay in milliseconds upon a node joining or leaving topology (or crash) after which rebalancing should be started automatically."
+          ]
+        },
+        {
+          "label": "Timeout",
+          "type": "number",
+          "model": "rebalanceTimeout",
+          "placeholder": 10000,
+          "tip": [
+            "Rebalance timeout in milliseconds."
+          ]
+        },
+        {
+          "label": "Throttle",
+          "type": "number",
+          "model": "rebalanceThrottle",
+          "placeholder": 0,
+          "tip": [
+            "Time in milliseconds to wait between rebalance messages to avoid overloading of CPU or network."
+          ]
+        }
+      ]
+    },
+    {
+      "label": "Server near cache",
+      "tip": [
+        "Near cache settings.",
+        "Near cache is a small local cache that stores most recently or most frequently accessed data.",
+        "Should be used in case when it is impossible to send computations to remote nodes."
+      ],
+      "fields": [
+        {
+          "label": "Enabled",
+          "type": "check",
+          "model": "nearCacheEnabled",
+          "tip": [
+            "Flag indicating whether to configure near cache."
+          ]
+        },
+        {
+          "label": "Start size",
+          "type": "number",
+          "path": "nearConfiguration",
+          "model": "nearStartSize",
+          "hide": "!backupItem.nearCacheEnabled",
+          "placeholder": 375000,
+          "tip": [
+            "Initial cache size for near cache which will be used to pre-create internal hash table after start."
+          ]
+        },
+        {
+          "label": "Eviction policy",
+          "type": "dropdown-details",
+          "path": "nearConfiguration.nearEvictionPolicy",
+          "model": "kind",
+          "placeholder": "Choose eviction policy",
+          "items": "evictionPolicies",
+          "hide": "!backupItem.nearCacheEnabled",
+          "tip": [
+            "Cache expiration policy."
+          ],
+          "details": {
+            "LRU": {
+              "expanded": false,
+              "fields": [
+                {
+                  "label": "Batch size",
+                  "type": "number",
+                  "path": "nearConfiguration.nearEvictionPolicy.LRU",
+                  "model": "batchSize",
+                  "placeholder": 1,
+                  "tip": [
+                    "Number of entries to remove on shrink."
+                  ]
+                },
+                {
+                  "label": "Max memory size",
+                  "type": "number",
+                  "path": "nearConfiguration.nearEvictionPolicy.LRU",
+                  "model": "maxMemorySize",
+                  "placeholder": 0,
+                  "tip": [
+                    "Maximum allowed cache size in bytes."
+                  ]
+                },
+                {
+                  "label": "Max size",
+                  "type": "number",
+                  "path": "nearConfiguration.nearEvictionPolicy.LRU",
+                  "model": "maxSize",
+                  "placeholder": 100000,
+                  "tip": [
+                    "Maximum allowed size of cache before entry will start getting evicted."
+                  ]
+                }
+              ]
+            },
+            "RND": {
+              "expanded": false,
+              "fields": [
+                {
+                  "label": "Max size",
+                  "type": "number",
+                  "path": "nearConfiguration.nearEvictionPolicy.RND",
+                  "model": "maxSize",
+                  "placeholder": 100000,
+                  "tip": [
+                    "Maximum allowed size of cache before entry will start getting evicted."
+                  ]
+                }
+              ]
+            },
+            "FIFO": {
+              "expanded": false,
+              "fields": [
+                {
+                  "label": "Batch size",
+                  "type": "number",
+                  "path": "nearConfiguration.nearEvictionPolicy.FIFO",
+                  "model": "batchSize",
+                  "placeholder": 1,
+                  "tip": [
+                    "Number of entries to remove on shrink."
+                  ]
+                },
+                {
+                  "label": "Max memory size",
+                  "type": "number",
+                  "path": "nearConfiguration.nearEvictionPolicy.FIFO",
+                  "model": "maxMemorySize",
+                  "placeholder": 0,
+                  "tip": [
+                    "Maximum allowed cache size in bytes."
+                  ]
+                },
+                {
+                  "label": "Max size",
+                  "type": "number",
+                  "path": "nearConfiguration.nearEvictionPolicy.FIFO",
+                  "model": "maxSize",
+                  "placeholder": 100000,
+                  "tip": [
+                    "Maximum allowed size of cache before entry will start getting evicted."
+                  ]
+                }
+              ]
+            },
+            "SORTED": {
+              "expanded": false,
+              "fields": [
+                {
+                  "label": "Batch size",
+                  "type": "number",
+                  "path": "nearConfiguration.nearEvictionPolicy.SORTED",
+                  "model": "batchSize",
+                  "placeholder": 1,
+                  "tip": [
+                    "Number of entries to remove on shrink."
+                  ]
+                },
+                {
+                  "label": "Max memory size",
+                  "type": "number",
+                  "path": "nearConfiguration.nearEvictionPolicy.SORTED",
+                  "model": "maxMemorySize",
+                  "placeholder": 0,
+                  "tip": [
+                    "Maximum allowed cache size in bytes."
+                  ]
+                },
+                {
+                  "label": "Max size",
+                  "type": "number",
+                  "path": "nearConfiguration.nearEvictionPolicy.SORTED",
+                  "model": "maxSize",
+                  "placeholder": 100000,
+                  "tip": [
+                    "Maximum allowed size of cache before entry will start getting evicted."
+                  ]
+                }
+              ]
+            }
+          }
+        }
+      ]
+    },
+    {
+      "label": "Statistics",
+      "tip": [
+        "Cache statistics and management settings."
+      ],
+      "fields": [
+        {
+          "label": "Statistics enabled",
+          "type": "check",
+          "model": "statisticsEnabled",
+          "tip": [
+            "Flag indicating whether statistics gathering is enabled on a cache."
+          ]
+        },
+        {
+          "label": "Management enabled",
+          "type": "check",
+          "model": "managementEnabled",
+          "tip": [
+            "Flag indicating whether management is enabled on this cache."
+          ]
+        }
+      ]
+    },
+    {
+      "label": "Store",
+      "tip": [
+        "Cache store settings."
+      ],
+      "fields": [
+        {
+          "label": "Store factory",
+          "type": "dropdown-details",
+          "path": "cacheStoreFactory",
+          "model": "kind",
+          "placeholder": "Choose store factory",
+          "items": "cacheStoreFactories",
+          "tip": [
+            "Factory for persistent storage for cache data."
+          ],
+          "details": {
+            "CacheJdbcPojoStoreFactory": {
+              "expanded": true,
+              "fields": [
+                {
+                  "label": "Data source bean",
+                  "type": "text",
+                  "path": "cacheStoreFactory.CacheJdbcPojoStoreFactory",
+                  "model": "dataSourceBean",
+                  "required": true,
+                  "placeholder": "Bean name in Spring context",
+                  "tip": [
+                    "Name of the data source bean in Spring context."
+                  ]
+                },
+                {
+                  "label": "Dialect",
+                  "type": "dropdown",
+                  "path": "cacheStoreFactory.CacheJdbcPojoStoreFactory",
+                  "model": "dialect",
+                  "required": true,
+                  "placeholder": "Choose JDBC dialect",
+                  "items": "cacheStoreJdbcDialects",
+                  "tip": [
+                    "Dialect of SQL implemented by a particular RDBMS:",
+                    "<ul>",
+                    "  <li>Generic JDBC dialect.</li>",
+                    "  <li>Oracle database.</li>",
+                    "  <li>IBM DB2.</li>",
+                    "  <li>Microsoft SQL Server.</li>",
+                    "  <li>My SQL.</li>",
+                    "  <li>H2 database.</li>",
+                    "</ul>"
+                  ]
+                }
+              ]
+            },
+            "CacheJdbcBlobStoreFactory": {
+              "expanded": true,
+              "fields": [
+                {
+                  "label": "user",
+                  "type": "text",
+                  "path": "cacheStoreFactory.CacheJdbcBlobStoreFactory",
+                  "model": "user",
+                  "required": true,
+                  "tip": [
+                    "User name for database access."
+                  ]
+                },
+                {
+                  "label": "Data source bean",
+                  "type": "text",
+                  "path": "cacheStoreFactory.CacheJdbcBlobStoreFactory",
+                  "model": "dataSourceBean",
+                  "required": true,
+                  "placeholder": "Bean name in Spring context",
+                  "tip": [
+                    "Name of the data source bean in Spring context."
+                  ]
+                },
+                {
+                  "label": "Init schema",
+                  "type": "check",
+                  "path": "cacheStoreFactory.CacheJdbcBlobStoreFactory",
+                  "model": "initSchema",
+                  "tip": [
+                    "Flag indicating whether DB schema should be initialized by Ignite (default behaviour) or was explicitly created by user."
+                  ]
+                },
+                {
+                  "label": "Create query",
+                  "type": "text",
+                  "path": "cacheStoreFactory.CacheJdbcBlobStoreFactory",
+                  "model": "createTableQuery",
+                  "placeholder": "SQL for table creation",
+                  "tip": [
+                    "Query for table creation in underlying database.",
+                    "Default value: create table if not exists ENTRIES (key binary primary key, val binary)"
+                  ]
+                },
+                {
+                  "label": "Load query",
+                  "type": "text",
+                  "path": "cacheStoreFactory.CacheJdbcBlobStoreFactory",
+                  "model": "loadQuery",
+                  "placeholder": "SQL for load entry",
+                  "tip": [
+                    "Query for entry load from underlying database.",
+                    "Default value: select * from ENTRIES where key=?"
+                  ]
+                },
+                {
+                  "label": "Insert query",
+                  "type": "text",
+                  "path": "cacheStoreFactory.CacheJdbcBlobStoreFactory",
+                  "model": "insertQuery",
+                  "placeholder": "SQL for insert entry",
+                  "tip": [
+                    "Query for insert entry into underlying database.",
+                    "Default value: insert into ENTRIES (key, val) values (?, ?)"
+                  ]
+                },
+                {
+                  "label": "Update query",
+                  "type": "text",
+                  "path": "cacheStoreFactory.CacheJdbcBlobStoreFactory",
+                  "model": "updateQuery",
+                  "placeholder": "SQL for update entry",
+                  "tip": [
+                    "Query fpr update entry in underlying database.",
+                    "Default value: update ENTRIES set val=? where key=?"
+                  ]
+                },
+                {
+                  "label": "Delete query",
+                  "type": "text",
+                  "path": "cacheStoreFactory.CacheJdbcBlobStoreFactory",
+                  "model": "deleteQuery",
+                  "placeholder": "SQL for delete entry",
+                  "tip": [
+                    "Query for delete entry from underlying database.",
+                    "Default value: delete from ENTRIES where key=?"
+                  ]
+                }
+              ]
+            },
+            "CacheHibernateBlobStoreFactory": {
+              "expanded": true,
+              "fields": [
+                {
+                  "label": "Hibernate properties",
+                  "type": "table-simple",
+                  "path": "cacheStoreFactory.CacheHibernateBlobStoreFactory",
+                  "model": "hibernateProperties",
+                  "editIdx": -1,
+                  "placeholder": "key=value",
+                  "tip": [
+                    "List of Hibernate properties.",
+                    "For example: connection.url=jdbc:h2:mem:"
+                  ]
+                }
+              ]
+            }
+          }
+        },
+        {
+          "label": "Load previous value",
+          "type": "check",
+          "model": "loadPreviousValue",
+          "tip": [
+            "Flag indicating whether value should be loaded from store if it is not in the cache for following cache operations:",
+            "<ul>",
+            "  <li>IgniteCache.putIfAbsent()</li>",
+            "  <li>IgniteCache.replace()</li>",
+            "  <li>IgniteCache.replace()</li>",
+            "  <li>IgniteCache.remove()</li>",
+            "  <li>IgniteCache.getAndPut()</li>",
+            "  <li>IgniteCache.getAndRemove()</li>",
+            "  <li>IgniteCache.getAndReplace()</li>",
+            "  <li>IgniteCache.getAndPutIfAbsent()</li>",
+            "</ul>"
+          ]
+        },
+        {
+          "label": "Read-through",
+          "type": "check",
+          "model": "readThrough",
+          "tip": [
+            "Flag indicating whether read-through caching should be used."
+          ]
+        },
+        {
+          "label": "Write-through",
+          "type": "check",
+          "model": "writeThrough",
+          "tip": [
+            "Flag indicating whether write-through caching should be used."
+          ]
+        }
+      ]
+    },
+    {
+      "label": "Write behind",
+      "tip": [
+        "Cache write behind settings.",
+        "Write-behind is a special mode when updates to cache accumulated and then asynchronously flushed to persistent store as a bulk operation."
+      ],
+      "fields": [
+        {
+          "label": "Enabled",
+          "type": "check",
+          "model": "writeBehindEnabled",
+          "tip": [
+            "Flag indicating whether Ignite should use write-behind behaviour for the cache store."
+          ]
+        },
+        {
+          "label": "Batch size",
+          "type": "number",
+          "model": "writeBehindBatchSize",
+          "hide": "!backupItem.writeBehindEnabled",
+          "placeholder": 512,
+          "tip": [
+            "Maximum batch size for write-behind cache store operations.",
+            "Store operations (get or remove) are combined in a batch of this size to be passed to cache store."
+          ]
+        },
+        {
+          "label": "Flush size",
+          "type": "number",
+          "model": "writeBehindFlushSize",
+          "hide": "!backupItem.writeBehindEnabled",
+          "placeholder": 10240,
+          "tip": [
+            "Maximum size of the write-behind cache.<br>",
+            "If cache size exceeds this value, all cached items are flushed to the cache store and write cache is cleared."
+          ]
+        },
+        {
+          "label": "Flush frequency",
+          "type": "number",
+          "model": "writeBehindFlushFrequency",
+          "hide": "!backupItem.writeBehindEnabled",
+          "placeholder": 5000,
+          "tip": [
+            "Frequency with which write-behind cache is flushed to the cache store in milliseconds."
+          ]
+        },
+        {
+          "label": "Flush threads count",
+          "type": "number",
+          "model": "writeBehindFlushThreadCount",
+          "hide": "!backupItem.writeBehindEnabled",
+          "placeholder": 1,
+          "tip": [
+            "Number of threads that will perform cache flushing."
+          ]
+        }
+      ]
+    }
+  ]
+}


[03/10] incubator-ignite git commit: # ignite-843 moved

Posted by an...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/src/main/js/public/stylesheets/style.less
----------------------------------------------------------------------
diff --git a/modules/web-control-center/src/main/js/public/stylesheets/style.less b/modules/web-control-center/src/main/js/public/stylesheets/style.less
new file mode 100644
index 0000000..4900581
--- /dev/null
+++ b/modules/web-control-center/src/main/js/public/stylesheets/style.less
@@ -0,0 +1,1172 @@
+/*
+ * 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.
+ */
+
+@logo-path: "https://www.filepicker.io/api/file/QagunjDGRFul2JgNCAli";
+@input-height: 28px;
+@ignite-red: #ec1c24;
+@ignite-block-callout-background: #f3f8f3;
+@ignite-block-callout: #50af51;
+
+hr {
+  margin-top: 20px;
+  margin-bottom: 20px;
+}
+
+.main-header .logo {
+  height: auto;
+}
+
+.main-sidebar {
+  padding-top: 60px;
+}
+
+.navbar-default .navbar-brand, .navbar-default .navbar-brand:hover {
+  position: absolute;
+  width: 100%;
+  left: 0;
+  text-align: center;
+}
+
+.modal-backdrop.am-fade {
+  opacity: .5;
+  transition: opacity .15s linear;
+  &.ng-enter {
+    opacity: 0;
+    &.ng-enter-active {
+      opacity: .5;
+    }
+  }
+  &.ng-leave {
+    opacity: .5;
+    &.ng-leave-active {
+      opacity: 0;
+    }
+  }
+}
+
+.modal.center .modal-dialog {
+  position: fixed;
+  top: 50%;
+  left: 50%;
+  -webkit-transform: translateX(-50%) translateY(-50%);
+  transform: translateX(-50%) translateY(-50%);
+}
+
+.border-left {
+  box-shadow: 1px 0 0 0 #eee inset;
+}
+
+.border-right {
+  box-shadow: 1px 0 0 0 #eee;
+}
+
+.theme-line {
+  background-color: #f9f9f9;
+}
+
+.theme-line header {
+  background-color: #fff;
+}
+
+.theme-line header a.btn {
+  border: 0 none;
+  padding: 10px 25px;
+  background-color: rgba(0, 0, 0, 0.15);
+}
+
+.theme-line header a.btn:hover {
+  background-color: rgba(0, 0, 0, 0.25);
+}
+
+.theme-line header a.btn.btn-link {
+  background: transparent;
+  color: rgba(255, 255, 255, 0.8);
+}
+
+.theme-line header a.btn.btn-link:hover {
+  color: #fff;
+  text-decoration: none;
+}
+
+.theme-line .navbar-nav a {
+  background-color: transparent;
+}
+
+.theme-line .navbar-nav a:hover,
+.theme-line .navbar-nav a:active,
+.theme-line .navbar-nav a:focus {
+  background-color: transparent;
+}
+
+.theme-line .main-links {
+  padding-top: 50px;
+}
+
+.theme-line .main-links h3 {
+  margin-top: 0;
+  font-size: 17px;
+}
+
+.theme-line .main-links .links a {
+  color: #888;
+}
+
+.theme-line .main-links .links a:hover {
+  text-decoration: none;
+}
+
+.theme-line #category-columns,
+.theme-solid #category-columns {
+  margin: 50px 30px 0;
+}
+
+.theme-line #category-columns h4 {
+  text-transform: uppercase;
+  font-weight: 300;
+  color: #999;
+  font-size: 14px;
+}
+
+.theme-line #category-columns ul {
+  list-style: none;
+  padding: 0;
+  margin-bottom: 15px;
+}
+
+.theme-line #category-columns ul li a {
+  padding: 5px 0;
+  display: block;
+  font-size: 16px;
+}
+
+.theme-line #category-columns ul .view-all {
+  font-size: 0.85em;
+}
+
+.theme-line .docs-header {
+  color: #999;
+  overflow: hidden;
+}
+
+.theme-line .docs-header h1 {
+  color: #444;
+  margin-top: 0;
+  font-size: 22px;
+}
+
+.theme-line .btn-primary {
+  border: 0 none;
+  background-color: @ignite-red;
+}
+
+.theme-line .btn-primary:hover {
+  background-color: #950d12;
+}
+
+.theme-line .main-content .nav-horizontal a {
+  box-shadow: 0 0;
+  border: 0 none;
+  background-color: #fff;
+  border-radius: 0;
+  color: #aaa;
+  padding: 6px;
+  margin: 0 14px;
+}
+
+.theme-line .main-content .nav-horizontal a:hover {
+  color: #999;
+  border-bottom: 5px solid #ddd;
+}
+
+.theme-line .main-content .nav-horizontal a.active {
+  border-bottom: 5px solid #888;
+}
+
+.theme-line .navbar-nav, .theme-line .sidebar-nav {
+  ul li > a.active {
+    cursor: default;
+    pointer-events: none;
+  }
+}
+
+.theme-line .sidebar-nav {
+  color: #474a54;
+  padding-bottom: 30px;
+
+  ul {
+    padding: 0;
+    list-style: none;
+    font-size: 14px;
+    margin: 3px 0 0;
+    li {
+      color: #666;
+      line-height: @input-height;
+
+      span.fa-stack {
+        margin-right: 5px;
+        font-size: 12px;
+        height: 26px;
+      }
+
+      a {
+        font-size: 18px;
+        color: #666;
+        position: relative;
+        white-space: nowrap;
+        overflow: hidden;
+        -o-text-overflow: ellipsis;
+        text-overflow: ellipsis;
+      }
+    }
+  }
+}
+
+.theme-line .sidebar-nav ul li a:hover {
+  text-decoration: none;
+}
+
+.theme-line .select,
+.theme-line .typeahead {
+  li a {
+    color: #666;
+    background-color: transparent;
+  }
+
+  li a:hover {
+    color: @ignite-red;
+  }
+
+  .active {
+    background-color: #eee;
+  }
+}
+
+.theme-line .sidebar-nav ul li .subcategory {
+  padding-left: 15px;
+}
+
+.theme-line .sidebar-nav h4 {
+  margin-top: 2em;
+  font-weight: normal;
+  text-transform: uppercase;
+  font-size: 11px;
+  margin-bottom: 10px;
+  color: #bbb;
+}
+
+.theme-line .sidebar-nav h4:first-child {
+  margin-top: 0;
+}
+
+.theme-line .sidebar-nav .ask {
+  width: 100%;
+  text-align: center;
+  padding: 10px;
+}
+
+.theme-line .border-left .sidebar-nav {
+  padding-left: 15px;
+}
+
+.theme-line .suggest {
+  padding: 5px;
+  display: inline-block;
+  font-size: 12px;
+}
+
+.header {
+  padding: 15px;
+}
+
+.header .has-github {
+  padding-right: 136px;
+}
+
+.header h1.navbar-brand {
+  height: 40px;
+  width: 200px;
+  padding: 0;
+  margin: 5px 15px 0 0;
+}
+
+.header h1.navbar-brand a {
+  text-indent: -99999px;
+  background: no-repeat center center;
+  display: block;
+  width: 100%;
+  height: 100%;
+  background-size: contain;
+}
+
+.header .nav.navbar-nav.pull-right {
+  position: relative;
+  right: -30px;
+}
+
+.header .nav.navbar-nav .not-link {
+  padding: 15px;
+  display: inline-block;
+}
+
+.header .nav.navbar-nav .stable,
+.header .nav.navbar-nav .beta,
+.header .nav.navbar-nav .private {
+  font-size: 9px;
+  padding: 3px 5px;
+  display: inline-block;
+  line-height: 8px;
+  border-radius: 3px;
+  margin-left: 6px;
+  color: #fff;
+  top: -2px;
+  position: relative;
+  opacity: 0.6;
+  -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=60)";
+  filter: alpha(opacity=60);
+}
+
+.header .nav.navbar-nav a:hover > .stable,
+.header .nav.navbar-nav a:hover > .beta,
+.header .nav.navbar-nav a:hover > .private {
+  opacity: 1;
+  -ms-filter: none;
+  filter: none;
+}
+
+.header .nav.navbar-nav .beta {
+  background-color: #59c3d1;
+}
+
+.header .nav.navbar-nav .stable {
+  background-color: #41b841;
+}
+
+.header .nav.navbar-nav .private {
+  background-color: #333;
+}
+
+.theme-line header {
+  border-bottom: 8px solid;
+}
+
+.theme-line header h2 {
+  color: #aaa;
+}
+
+.theme-line header p {
+  color: #666;
+}
+
+.theme-line header {
+  border-bottom-color: @ignite-red;
+}
+
+.theme-line .navbar-nav {
+  color: #888;
+}
+
+.theme-line .navbar-nav a {
+  color: #bbb;
+}
+
+.theme-line header a.btn {
+  background-color: @ignite-red;
+}
+
+.theme-line header a.btn:hover {
+  background-color: #950d12;
+}
+
+.theme-line header .navbar-nav .tt-cursor {
+  background-color: @ignite-red;
+}
+
+.theme-line header .navbar-nav a:hover, .theme-line header .navbar-nav .open > a {
+  color: @ignite-red;
+}
+
+.theme-line .navbar-nav .active a {
+  //font-weight: bold;
+  color: @ignite-red;
+}
+
+.theme-line .navbar-nav .active a:hover {
+  color: #950d12;
+}
+
+.theme-line .main-links .links a:hover {
+  color: @ignite-red;
+}
+
+.theme-line .main-content a {
+  color: #666;
+}
+
+.theme-line .main-content a:hover {
+  color: #950d12;
+}
+
+.theme-line .sidebar-nav ul li a.active:before {
+  background-color: @ignite-red;
+}
+
+.theme-line .sidebar-nav ul li a.active {
+  color: @ignite-red;
+}
+
+.theme-line .sidebar-nav ul li a:hover, .theme-line .sidebar-nav ul li a.active:hover {
+  color: #950d12;
+}
+
+.theme-line .main-content .nav-horizontal a.active {
+  border-color: @ignite-red;
+  color: @ignite-red;
+}
+
+.theme-line .main-content .nav-horizontal a:hover {
+  color: #950d12;
+}
+
+.theme-line .main-content .nav-horizontal a.active:hover {
+  border-color: #950d12;
+}
+
+.theme-line header .navbar-nav a.active, .theme-line #versions-list li a:hover strong, .theme-line #versions-list li a.active .current, .theme-line #versions-list li a:active .current {
+  color: @ignite-red;
+}
+
+.theme-line header .navbar-nav a {
+  font-size: 18px;
+}
+
+.theme-line.body-threes .section-right .threes-nav .btn-default:hover, .theme-line.page-docs.body-threes .section-right .threes-nav .pull-right a:hover {
+  color: @ignite-red;
+  border-color: @ignite-red;
+}
+
+.theme-line .section-right {
+  padding-left: 30px;
+}
+
+.body-overlap .main-content {
+  margin-top: 30px;
+}
+
+.body-box .main-content,
+.body-overlap .main-content {
+  padding: 30px;
+  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1);
+  background-color: #fff;
+}
+
+body {
+  font-weight: 400;
+  font-family: Roboto Slab, serif;;
+}
+
+h1, h2, h3, h4, h5, h6 {
+  font-weight: 700;
+  font-family: Roboto Slab, serif;
+  margin-bottom: 10px;
+}
+
+.submit-vote.submit-vote-parent.voted a.submit-vote-button, .submit-vote.submit-vote-parent a.submit-vote-button:hover {
+  background-color: @ignite-red;
+}
+
+div.submit-vote.submit-vote-parent.voted a.submit-vote-button:hover {
+  background-color: #950d12;
+}
+
+a, .link .title {
+  color: @ignite-red;
+}
+
+a:hover, .link:hover .title {
+  color: #950d12;
+}
+
+.header h1.navbar-brand a {
+  background-image: url("@{logo-path}");
+}
+
+.header h1.navbar-brand {
+  width: 96px;
+}
+
+.block-edit-parameters {
+  text-align: right;
+  padding-bottom: 5px;
+}
+
+.container-footer {
+  margin-top: 20px;
+}
+
+/* Modal */
+.modal {
+  display: block;
+  overflow: hidden;
+}
+
+.modal .close {
+  position: absolute;
+  top: 10px;
+  right: 10px;
+  float: none;
+}
+
+// Close icon
+.modal-header .close {
+  margin-right: -2px;
+}
+
+.modal .modal-dialog {
+  width: 610px;
+}
+
+.modal .modal-content {
+  border-radius: 0;
+  background-color: #f7f7f7;
+}
+
+.modal .modal-content .modal-header {
+  background-color: #fff;
+  text-align: center;
+  color: #555;
+  padding: 15px;
+  font-family: "myriad-pro", sans-serif;
+}
+
+.modal .modal-content .modal-header h4 {
+  font-family: "myriad-pro", sans-serif;
+  font-size: 22px;
+}
+
+.modal .modal-content .modal-header h4 .fa {
+  display: block;
+  font-size: 41px;
+  color: #ddd;
+  margin-bottom: 5px;
+}
+
+.modal .modal-content .modal-header p {
+  color: #aaa;
+  font-size: 1em;
+  margin: 3px 0 0;
+}
+
+.modal .modal-content .modal-spacer {
+  padding: 10px 10px 0 10px;
+}
+
+.modal .modal-content .modal-footer {
+  margin-top: 0;
+}
+
+.modal-body {
+  padding-top: 15px;
+}
+
+h1.ignite-logo {
+  background-image: url("@{logo-path}");
+}
+
+.block-display-image img {
+  max-width: 100%;
+  max-height: 450px;
+  margin: auto;
+  display: block;
+}
+
+.greedy {
+  min-height: 200px;
+  height: ~"calc(100vh - 290px)";
+}
+
+@media (min-width: 768px) {
+  .navbar-nav > li > a {
+    padding-top: 18px;
+    padding-bottom: 10px;
+  }
+}
+
+.details-row {
+  padding: 0 10px;
+}
+
+.details-row, .settings-row {
+  display: block;
+  margin: 10px 0;
+
+  label.table-header {
+    line-height: @input-height;
+  }
+
+  [class*="col-"] {
+    display: inline-block;
+    vertical-align: middle;
+    float: none;
+
+    padding-left: 0 !important;
+    padding-right: 0 !important;
+  }
+
+  input[type="checkbox"] {
+    line-height: 20px;
+    margin-right: 5px;
+  }
+
+  .checkbox label {
+    line-height: 20px;
+    vertical-align: middle;
+  }
+}
+
+button {
+  margin-right: 5px;
+}
+
+h1,
+h2,
+h3 {
+  user-select: none;
+  font-weight: normal;
+  /* Makes the vertical size of the text the same for all fonts. */
+  line-height: 1;
+}
+
+h3 {
+  color: black;
+  font-size: 1.2em;
+  margin-top: 0;
+  margin-bottom: 1.5em;
+}
+
+table tr:hover {
+  cursor: pointer;
+}
+
+.btn {
+  padding: 3px 6px;
+}
+
+button .caret, .btn .caret {
+  float: right;
+  margin-left: 5px;
+  margin-top: 7px;
+}
+
+.base-control {
+  text-align: left;
+  padding: 3px 3px;
+  height: @input-height;
+}
+
+.form-control:extend(.base-control all) {
+  display: inline-block;
+
+  button {
+    text-align: left;
+  }
+}
+
+.theme-line .panel-heading {
+  padding: 10px 10px;
+  margin: 0;
+
+  h3 {
+    margin-bottom: 0;
+  }
+
+  h3 > a {
+    color: black;
+  }
+}
+
+.theme-line .panel-title {
+  a {
+    color: @ignite-red;
+  }
+
+  h3 {
+    margin-bottom: 20px;
+  }
+}
+
+.theme-line .panel-body {
+  padding: 10px 20px;
+}
+
+.theme-line .main-content a.customize {
+  margin-left: 5px;
+  color: @ignite-red;
+}
+
+.theme-line .panel-collapse {
+  margin: 0;
+}
+
+.theme-line .links table {
+  display: table;
+  table-layout: fixed;
+
+  td {
+    padding-left: 18px;
+  }
+
+  .active a {
+    color: @ignite-red;
+    font-weight: bold;
+  }
+
+  a:hover {
+    color: #950d12;
+  }
+
+  a {
+    color: #666;
+  }
+}
+
+.theme-line table.links-edit:extend(.theme-line .links table all) {
+  margin-top: 5px;
+  margin-bottom: 5px;
+
+  label {
+    line-height: @input-height;
+    color: #666;
+  }
+}
+
+.theme-line table.links-edit-details:extend(.theme-line .links table all) {
+  margin-bottom: 10px;
+
+  label {
+    line-height: @input-height;
+    color: #666;
+  }
+
+  td {
+    padding: 0;
+
+    .input-tip {
+      padding: 0;
+    }
+  }
+}
+
+.theme-line table.admin {
+  tr:hover {
+    cursor: default;
+  }
+
+  thead > tr th.header {
+    padding: 0 0 10px;
+
+    div {
+      padding: 0
+    }
+  }
+
+  margin-bottom: 10px;
+
+  label {
+    line-height: @input-height;
+    color: #666;
+  }
+
+  thead > tr th, td {
+    padding: 10px 10px;
+
+    .input-tip {
+      padding: 0;
+    }
+  }
+
+  tfoot > tr > td {
+    padding: 0;
+
+    .pagination {
+      margin: 10px 0;
+
+      > .active > a {
+        color: @ignite-red;
+        font-weight: bold;
+        border-color: #ddd;
+        background-color: #eee;
+      }
+    }
+  }
+}
+
+.panel-title a {
+  font-size: 14px;
+}
+
+.panel-details {
+  margin-top: 10px;
+
+  padding: 0;
+
+  border-radius: 5px;
+  border: thin dotted lightgrey;
+}
+
+.tooltip.right .tooltip-arrow {
+  border-right-color: @ignite-red;
+}
+
+.tooltip > .tooltip-inner {
+  max-width: 400px;
+  text-align: left;
+  background-color: @ignite-red;
+}
+
+label {
+  font-weight: normal;
+  margin-bottom: 0;
+}
+
+.form-horizontal .checkbox {
+  padding-top: 0;
+}
+
+.input-tip {
+  display: block;
+  overflow: hidden;
+}
+
+.labelField {
+  float: left;
+  margin-right: 5px;
+}
+
+.labelFormField {
+  float: left;
+  line-height: @input-height;
+}
+
+.form-horizontal .form-group {
+  margin: 0;
+}
+
+.form-horizontal .has-feedback .form-control-feedback {
+  right: 0;
+}
+
+.tipField {
+  float: right;
+  line-height: @input-height;
+  margin-left: 5px;
+}
+
+.tipLabel {
+  font-size: 14px;
+  margin-left: 5px;
+}
+
+.fieldSep {
+  float: right;
+  line-height: @input-height;
+  margin: 0 5px;
+}
+
+.fieldButton {
+  float: right;
+  margin-left: 5px;
+  margin-right: 0;
+}
+
+.fa-plus {
+  cursor: pointer;
+}
+
+.fa-remove {
+  color: @ignite-red;
+  cursor: pointer;
+}
+
+.fa-floppy-o {
+  cursor: pointer;
+}
+
+.fa-arrow-up {
+  cursor: pointer;
+}
+
+.fa-arrow-down {
+  cursor: pointer;
+}
+
+label.required:after {
+  color: @ignite-red;
+  content: ' *';
+  display: inline;
+}
+
+.blank {
+  visibility: hidden;
+}
+
+.alert {
+  outline: 0
+}
+
+.alert.bottom, .alert.bottom-left, .alert.bottom-right, .alert.top,
+.alert.top-left, .alert.top-right {
+  position: fixed;
+  z-index: 1050;
+  margin: 20px
+}
+
+.alert.top, .alert.top-left, .alert.top-right {
+  top: 50px
+}
+
+.alert.top {
+  right: 0;
+  left: 0
+}
+
+.alert.top-right {
+  right: 0
+}
+
+.alert.top-right .close {
+  padding-left: 10px
+}
+
+.alert.top-left {
+  left: 0
+}
+
+.alert.top-left .close {
+  padding-right: 10px
+}
+
+.alert.bottom, .alert.bottom-left, .alert.bottom-right {
+  bottom: 0
+}
+
+.alert.bottom {
+  right: 0;
+  left: 0
+}
+
+.alert.bottom-right {
+  right: 0
+}
+
+.alert.bottom-right .close {
+  padding-left: 10px
+}
+
+.alert.bottom-left {
+  left: 0
+}
+
+.alert.bottom-left .close {
+  padding-right: 10px
+}
+
+//  Summary page
+#cfgResult textarea {
+  font-family: monospace;
+  font-size: 12px;
+}
+
+input[type="number"]::-webkit-outer-spin-button,
+input[type="number"]::-webkit-inner-spin-button {
+  -webkit-appearance: none;
+  margin: 0;
+}
+
+input[type="number"] {
+  -moz-appearance: textfield;
+}
+
+input.ng-dirty.ng-invalid, button.ng-dirty.ng-invalid {
+  border-color: @ignite-red;
+
+  :focus {
+    border-color: @ignite-red;
+  }
+}
+
+.form-control-feedback {
+  display: inline-block;
+  color: @ignite-red;
+  right: 18px;
+  line-height: @input-height;
+  pointer-events: initial;
+}
+
+.syntaxhighlighter {
+  padding: 10px 5px;
+  border-radius: 6px;
+}
+
+.theme-line table.links-edit-small-padding:extend(.theme-line .links table all) {
+  label {
+    line-height: @input-height;
+    color: #666;
+  }
+
+  a {
+    line-height: @input-height;
+  }
+
+  input[type="checkbox"] {
+    line-height: 20px;
+    margin-right: 5px;
+  }
+
+  .checkbox label {
+    line-height: 20px;
+    vertical-align: middle;
+  }
+
+  th {
+    text-align: center;
+  }
+
+  td {
+    padding-left: 10px;
+  }
+
+  margin-top: 10px;
+}
+
+.configBox .nav > li > a {
+  padding: 5px 5px;
+}
+
+.viewedUser {
+  position: absolute;
+  width: 100%;
+  left: 0;
+
+  text-align: center;
+
+  margin-top: -15px;
+
+  background-color: #f8d5d8;
+}
+
+a {
+  cursor: pointer;
+}
+
+.st-sort-ascent:after {
+  content: '\25B2';
+}
+
+.st-sort-descent:after {
+  content: '\25BC';
+}
+
+.panel {
+  margin-bottom: 0;
+}
+
+.panel-group {
+  margin-bottom: 0;
+}
+
+.panel-group .panel + .panel {
+  margin-top: 20px;
+}
+
+.margin-top-dflt {
+  margin-top: 10px;
+}
+
+.margin-bottom-dflt {
+  margin-bottom: 10px;
+}
+
+.margin-dflt {
+  margin-top: 10px;
+  margin-bottom: 10px;
+}
+
+.padding-top-dflt {
+  padding-top: 10px;
+}
+
+.padding-bottom-dflt {
+  padding-bottom: 10px;
+}
+
+.padding-dflt {
+  padding-top: 10px;
+  padding-bottom: 10px;
+}
+
+.theme-line .panel-title h3 {
+  margin-top: 20px;
+  margin-bottom: 20px;
+}
+
+.block-callout-parent {
+  background-color: @ignite-block-callout-background;
+  overflow: hidden;
+}
+
+.block-callout {
+  background-color: @ignite-block-callout-background;
+  display: inline-block;
+  vertical-align: top;
+  width: 50%;
+
+  i {
+    padding: 10px 5px 0 10px;
+    color: @ignite-block-callout;
+  }
+
+  ul {
+    padding-left: 20px;
+    margin-bottom: 0;
+  }
+
+  p {
+    padding: 5px 0 10px 20px;
+    margin: 0;
+  }
+
+  label {
+    font-weight: bold;
+    color: @ignite-block-callout;
+  }
+}
+
+.block-callout-border {
+  border-left: 5px solid;
+  border-color: @ignite-block-callout;
+}
+
+.labelHeader {
+  font-weight: bold;
+}
+
+.ace_editor, #ace_document {
+  width: 100%;
+  height: 400px;
+}
+
+

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/src/main/js/routes/admin.js
----------------------------------------------------------------------
diff --git a/modules/web-control-center/src/main/js/routes/admin.js b/modules/web-control-center/src/main/js/routes/admin.js
new file mode 100644
index 0000000..5af72f7
--- /dev/null
+++ b/modules/web-control-center/src/main/js/routes/admin.js
@@ -0,0 +1,79 @@
+/*
+ * 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 router = require('express').Router();
+var db = require('../db');
+
+router.get('/', function (req, res) {
+    res.render('settings/admin');
+});
+
+/**
+ * Get list of user accounts.
+ */
+router.post('/list', function (req, res) {
+    db.Account.find({}).sort('username').exec(function (err, users) {
+        if (err)
+            return res.status(500).send(err.message);
+
+        res.json(users);
+    });
+});
+
+router.post('/remove', function (req, res) {
+    var userId = req.body.userId;
+
+    db.Account.findByIdAndRemove(userId, function (err) {
+        if (err)
+            return res.status(500).send(err);
+
+        res.sendStatus(200);
+    });
+});
+
+router.post('/save', function (req, res) {
+    var userId = req.body.userId;
+    var adminFlag = req.body.adminFlag;
+
+    db.Account.findByIdAndUpdate(userId, {admin: adminFlag}, function (err) {
+        if (err)
+            return res.status(500).send(err.message);
+
+        res.sendStatus(200);
+    });
+});
+
+router.get('/become', function (req, res) {
+    var viewedUserId = req.query.viewedUserId;
+
+    if (!viewedUserId) {
+        req.session.viewedUser = null;
+
+        return res.redirect('/admin');
+    }
+
+    db.Account.findById(viewedUserId).exec(function (err, viewedUser) {
+        if (err)
+            return res.sendStatus(404);
+
+        req.session.viewedUser = viewedUser;
+
+        res.redirect('/');
+    })
+});
+
+module.exports = router;
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/src/main/js/routes/caches.js
----------------------------------------------------------------------
diff --git a/modules/web-control-center/src/main/js/routes/caches.js b/modules/web-control-center/src/main/js/routes/caches.js
new file mode 100644
index 0000000..3fefd37
--- /dev/null
+++ b/modules/web-control-center/src/main/js/routes/caches.js
@@ -0,0 +1,95 @@
+/*
+ * 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 router = require('express').Router();
+var db = require('../db');
+
+/* GET caches page. */
+router.get('/', function (req, res) {
+    res.render('configuration/caches');
+});
+
+/**
+ * Get spaces and caches accessed for user account.
+ *
+ * @param req Request.
+ * @param res Response.
+ */
+router.post('/list', function (req, res) {
+    var user_id = req.currentUserId();
+
+    // Get owned space and all accessed space.
+    db.Space.find({$or: [{owner: user_id}, {usedBy: {$elemMatch: {account: user_id}}}]}, function (err, spaces) {
+        if (err)
+            return res.status(500).send(err.message);
+
+        var space_ids = spaces.map(function (value) {
+            return value._id;
+        });
+
+        // Get all caches for spaces.
+        db.Cache.find({space: {$in: space_ids}}).sort('name').exec(function (err, caches) {
+            if (err)
+                return res.status(500).send(err.message);
+
+            res.json({spaces: spaces, caches: caches});
+        });
+    });
+});
+
+/**
+ * Save cache.
+ */
+router.post('/save', function (req, res) {
+    if (req.body._id)
+        db.Cache.update({_id: req.body._id}, req.body, {upsert: true}, function (err) {
+            if (err)
+                return res.status(500).send(err.message);
+
+            res.send(req.body._id);
+        });
+    else {
+        db.Cache.findOne({name: req.body.name}, function (err, cache) {
+            if (err)
+                return res.status(500).send(err.message);
+
+            if (cache)
+                return res.status(500).send('Cache with name: "' + cache.name + '" already exist.');
+
+            (new db.Cache(req.body)).save(function (err, cache) {
+                if (err)
+                    return res.status(500).send(err.message);
+
+                res.send(cache._id);
+            });
+        });
+    }
+});
+
+/**
+ * Remove cache by ._id.
+ */
+router.post('/remove', function (req, res) {
+    db.Cache.remove(req.body, function (err) {
+        if (err)
+            return res.status(500).send(err.message);
+
+        res.sendStatus(200);
+    })
+});
+
+module.exports = router;
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/src/main/js/routes/clusters.js
----------------------------------------------------------------------
diff --git a/modules/web-control-center/src/main/js/routes/clusters.js b/modules/web-control-center/src/main/js/routes/clusters.js
new file mode 100644
index 0000000..182130d
--- /dev/null
+++ b/modules/web-control-center/src/main/js/routes/clusters.js
@@ -0,0 +1,104 @@
+/*
+ * 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 router = require('express').Router();
+var db = require('../db');
+
+/* GET clusters page. */
+router.get('/', function (req, res) {
+    res.render('configuration/clusters');
+});
+
+/**
+ * Get spaces and clusters accessed for user account.
+ *
+ * @param req Request.
+ * @param res Response.
+ */
+router.post('/list', function (req, res) {
+    var user_id = req.currentUserId();
+
+    // Get owned space and all accessed space.
+    db.Space.find({$or: [{owner: user_id}, {usedBy: {$elemMatch: {account: user_id}}}]}, function (err, spaces) {
+        if (err)
+            return res.status(500).send(err.message);
+
+        var space_ids = spaces.map(function (value) {
+            return value._id;
+        });
+
+        db.Cache.find({space: {$in: space_ids}}, '_id name swapEnabled', function (err, caches) {
+            if (err)
+                return res.status(500).send(err);
+
+            // Get all clusters for spaces.
+            db.Cluster.find({space: {$in: space_ids}}).sort('name').exec(function (err, clusters) {
+                if (err)
+                    return res.status(500).send(err.message);
+
+                var cachesJson = caches.map(function (cache) {
+                    return {value: cache._id, label: cache.name, swapEnabled: cache.swapEnabled};
+                });
+
+                res.json({spaces: spaces, caches: cachesJson, clusters: clusters});
+            });
+        });
+    });
+});
+
+/**
+ * Save cluster.
+ */
+router.post('/save', function (req, res) {
+    if (req.body._id)
+        db.Cluster.update({_id: req.body._id}, req.body, {upsert: true}, function (err) {
+            if (err)
+                return res.status(500).send(err.message);
+
+            res.send(req.body._id);
+        });
+    else {
+        db.Cluster.findOne({name: req.body.name}, function (err, cluster) {
+            if (err)
+                return res.status(500).send(err.message);
+
+            if (cluster)
+                return res.status(500).send('Cluster with name: "' + cluster.name + '" already exist.');
+
+            (new db.Cluster(req.body)).save(function (err, cluster) {
+                if (err)
+                    return res.status(500).send(err.message);
+
+                res.send(cluster._id);
+            });
+        });
+    }
+});
+
+/**
+ * Remove cluster by ._id.
+ */
+router.post('/remove', function (req, res) {
+    db.Cluster.remove(req.body, function (err) {
+        if (err)
+            return res.status(500).send(err.message);
+
+        res.sendStatus(200);
+    })
+});
+
+module.exports = router;
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/src/main/js/routes/generator/common.js
----------------------------------------------------------------------
diff --git a/modules/web-control-center/src/main/js/routes/generator/common.js b/modules/web-control-center/src/main/js/routes/generator/common.js
new file mode 100644
index 0000000..dcbf156
--- /dev/null
+++ b/modules/web-control-center/src/main/js/routes/generator/common.js
@@ -0,0 +1,299 @@
+/*
+ * 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 _ = require('lodash');
+
+exports.isDefined = function (v) {
+    return !(v === undefined || v === null);
+};
+
+exports.mainComment = mainComment;
+
+function mainComment() {
+    return 'This configuration was generated by Ignite Control Center ('
+        + formatDate(new Date()) + ')';
+}
+
+function addLeadingZero(numberStr, minSize) {
+    if (typeof (numberStr) != 'string')
+        numberStr = '' + numberStr;
+
+    while (numberStr.length < minSize) {
+        numberStr = '0' + numberStr;
+    }
+
+    return numberStr;
+}
+
+exports.formatDate = formatDate;
+
+function formatDate(date) {
+    var dd = addLeadingZero(date.getDate(), 2);
+    var mm = addLeadingZero(date.getMonth() + 1, 2);
+
+    var yyyy = date.getFullYear();
+
+    return mm + '/' + dd + '/' + yyyy + ' ' + addLeadingZero(date.getHours(), 2) + ':' + addLeadingZero(date.getMinutes(), 2);
+}
+
+exports.builder = function () {
+    var res = [];
+
+    res.deep = 0;
+    res.lineStart = true;
+
+    res.append = function (s) {
+        if (this.lineStart) {
+            for (var i = 0; i < this.deep; i++)
+                this.push('    ');
+
+            this.lineStart = false;
+        }
+
+        this.push(s);
+
+        return this;
+    };
+
+    res.line = function (s) {
+        if (s)
+            this.append(s);
+
+        this.push('\n');
+        this.lineStart = true;
+
+        return this;
+    };
+
+    res.startBlock = function (s) {
+        if (s)
+            this.append(s);
+
+        this.push('\n');
+        this.lineStart = true;
+        this.deep++;
+
+        return this;
+    };
+
+    res.endBlock = function (s) {
+        this.deep--;
+
+        if (s)
+            this.append(s);
+
+        this.push('\n');
+        this.lineStart = true;
+
+        return this;
+    };
+
+    res.emptyLineIfNeeded = function () {
+        if (this.needEmptyLine) {
+            this.line();
+
+            this.needEmptyLine = false;
+
+            return true;
+        }
+
+        return false;
+    };
+
+    res.imports = {};
+
+    res.importClass = function (fullClassName) {
+        var dotIdx = fullClassName.lastIndexOf('.');
+
+        var shortName;
+
+        if (dotIdx > 0)
+            shortName = fullClassName.substr(dotIdx + 1);
+        else
+            shortName = fullClassName;
+
+        if (this.imports[shortName]) {
+            if (this.imports[shortName] != fullClassName)
+                throw "Class name conflict: " + this.imports[shortName] + ' and ' + fullClassName;
+        }
+        else {
+            this.imports[shortName] = fullClassName;
+        }
+
+        return shortName;
+    };
+
+    res.generateImports = function () {
+        var res = [];
+
+        for (var clsName in this.imports) {
+            if (this.imports.hasOwnProperty(clsName))
+                res.push('import ' + this.imports[clsName] + ';');
+        }
+
+        return res.join('\n')
+    };
+
+    return res;
+};
+
+function ClassDescriptor(className, fields) {
+    this.className = className;
+    this.fields = fields;
+}
+
+exports.evictionPolicies = {
+    'LRU': new ClassDescriptor('org.apache.ignite.cache.eviction.lru.LruEvictionPolicy',
+        {batchSize: null, maxMemorySize: null, maxSize: null}),
+    'RND': new ClassDescriptor('org.apache.ignite.cache.eviction.random.RandomEvictionPolicy', {maxSize: null}),
+    'FIFO': new ClassDescriptor('org.apache.ignite.cache.eviction.fifo.FifoEvictionPolicy',
+        {batchSize: null, maxMemorySize: null, maxSize: null}),
+    'SORTED': new ClassDescriptor('org.apache.ignite.cache.eviction.sorted.SortedEvictionPolicy',
+        {batchSize: null, maxMemorySize: null, maxSize: null})
+};
+
+exports.marshallers = {
+    OptimizedMarshaller: new ClassDescriptor('org.apache.ignite.marshaller.optimized.OptimizedMarshaller', {
+        poolSize: null,
+        requireSerializable: null
+    }),
+    JdkMarshaller: new ClassDescriptor('org.apache.ignite.marshaller.jdk.JdkMarshaller', {})
+};
+
+exports.knownClasses = {
+    Oracle: new ClassDescriptor('org.apache.ignite.cache.store.jdbc.dialect.OracleDialect', {}),
+    DB2: new ClassDescriptor('org.apache.ignite.cache.store.jdbc.dialect.DB2Dialect', {}),
+    SQLServer: new ClassDescriptor('org.apache.ignite.cache.store.jdbc.dialect.SQLServerDialect', {}),
+    MySQL: new ClassDescriptor('org.apache.ignite.cache.store.jdbc.dialect.MySQLDialect', {}),
+    PostgreSQL: new ClassDescriptor('org.apache.ignite.cache.store.jdbc.dialect.BasicJdbcDialect', {}),
+    H2: new ClassDescriptor('org.apache.ignite.cache.store.jdbc.dialect.H2Dialect', {})
+};
+
+exports.dataSources = {
+    Oracle: 'oracle.jdbc.pool.OracleDataSource',
+    DB2: 'com.ibm.db2.jcc.DB2ConnectionPoolDataSource',
+    SQLServer: 'com.microsoft.sqlserver.jdbc.SQLServerDataSource',
+    MySQL: 'com.mysql.jdbc.jdbc2.optional.MysqlDataSource',
+    PostgreSQL: 'org.postgresql.ds.PGPoolingDataSource',
+    H2: 'org.h2.jdbcx.JdbcDataSource'
+};
+
+exports.storeFactories = {
+    CacheJdbcPojoStoreFactory: new ClassDescriptor('org.apache.ignite.cache.store.jdbc.CacheJdbcPojoStoreFactory', {
+        dataSourceBean: null,
+        dialect: {type: 'className'}
+    }),
+
+    CacheJdbcBlobStoreFactory: new ClassDescriptor('org.apache.ignite.cache.store.jdbc.CacheJdbcBlobStoreFactory', {
+        user: null,
+        dataSourceBean: null,
+        initSchema: null,
+        createTableQuery: null,
+        loadQuery: null,
+        insertQuery: null,
+        updateQuery: null,
+        deleteQuery: null
+    }),
+
+    CacheHibernateBlobStoreFactory: new ClassDescriptor('org.apache.ignite.cache.store.hibernate.CacheHibernateBlobStoreFactory', {
+        hibernateProperties: {type: 'propertiesAsList', propVarName: 'props'}
+    })
+};
+
+exports.atomicConfiguration = new ClassDescriptor('org.apache.ignite.configuration.AtomicConfiguration', {
+    backups: null,
+    cacheMode: {type: 'enum', enumClass: 'CacheMode'},
+    atomicSequenceReserveSize: null
+});
+
+exports.swapSpaceSpi = new ClassDescriptor('org.apache.ignite.spi.swapspace.file.FileSwapSpaceSpi', {
+    baseDirectory: null,
+    readStripesNumber: null,
+    maximumSparsity: {type: 'float'},
+    maxWriteQueueSize: null,
+    writeBufferSize: null
+});
+
+exports.transactionConfiguration = new ClassDescriptor('org.apache.ignite.configuration.TransactionConfiguration', {
+    defaultTxConcurrency: {type: 'enum', enumClass: 'TransactionConcurrency'},
+    transactionIsolation: {type: 'TransactionIsolation', setterName: 'defaultTxIsolation'},
+    defaultTxTimeout: null,
+    pessimisticTxLogLinger: null,
+    pessimisticTxLogSize: null,
+    txSerializableEnabled: null
+});
+
+exports.hasProperty = function (obj, props) {
+    for (var propName in props) {
+        if (props.hasOwnProperty(propName)) {
+            if (obj[propName])
+                return true;
+        }
+    }
+
+    return false;
+};
+
+/**
+ * Convert some name to valid java name.
+ *
+ * @param name to convert.
+ * @returns {string} Valid java name.
+ */
+exports.toJavaName = function (name) {
+    var javaName = name.replace(/[^A-Za-z_0-9]+/, '_');
+
+    return javaName.charAt(0).toLocaleUpperCase() + javaName.slice(1);
+};
+
+/**
+ * Generate properties file with properties stubs for stores data sources.
+ *
+ * @param cluster Configuration to process.
+ * @returns {string} Generated content.
+ */
+exports.generateProperties = function (cluster) {
+    var res = exports.builder();
+
+    var datasources = [];
+
+    if (cluster.caches && cluster.caches.length > 0) {
+        _.forEach(cluster.caches, function (cache) {
+            if (cache.cacheStoreFactory && cache.cacheStoreFactory.kind) {
+                var storeFactory = cache.cacheStoreFactory[cache.cacheStoreFactory.kind];
+
+                if (storeFactory.dialect) {
+                    var beanId = storeFactory.dataSourceBean;
+
+                    if (!_.contains(datasources, beanId)) {
+                        datasources.push(beanId);
+
+                        res.line(beanId + '.jdbc.url=YOUR_JDBC_URL');
+                        res.line(beanId + '.jdbc.username=YOUR_USER_NAME');
+                        res.line(beanId + '.jdbc.password=YOUR_PASSWORD');
+                        res.line();
+                    }
+                }
+            }
+        });
+    }
+
+    if (datasources.length > 0)
+        return '# ' + mainComment() + '\n\n' + res.join();
+
+    return undefined;
+};

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/src/main/js/routes/generator/docker.js
----------------------------------------------------------------------
diff --git a/modules/web-control-center/src/main/js/routes/generator/docker.js b/modules/web-control-center/src/main/js/routes/generator/docker.js
new file mode 100644
index 0000000..93faf8e
--- /dev/null
+++ b/modules/web-control-center/src/main/js/routes/generator/docker.js
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+exports.generateClusterConfiguration = function(cluster, os) {
+    if (!os)
+        os = 'debian:8';
+
+    return "" +
+        "# Start from a OS image.\n"+
+        "FROM " + os + "\n"+
+        "\n"+
+        "# Install tools.\n"+
+        "RUN apt-get update && apt-get install -y --fix-missing \\\n"+
+        "  wget \\\n"+
+        "  dstat \\\n"+
+        "  maven \\\n"+
+        "  git\n"+
+        "\n"+
+        "# Install Oracle JDK.\n"+
+        "RUN mkdir /opt/jdk\n"+
+        "\n"+
+        "RUN wget --header \"Cookie: oraclelicense=accept-securebackup-cookie\" \\\n"+
+        "  http://download.oracle.com/otn-pub/java/jdk/7u79-b15/jdk-7u79-linux-x64.tar.gz\n"+
+        "\n"+
+        "RUN tar -zxf jdk-7u79-linux-x64.tar.gz -C /opt/jdk\n"+
+        "\n"+
+        "RUN rm jdk-7u79-linux-x64.tar.gz\n"+
+        "\n"+
+        "RUN update-alternatives --install /usr/bin/java java /opt/jdk/jdk1.7.0_79/bin/java 100\n"+
+        "\n"+
+        "RUN update-alternatives --install /usr/bin/javac javac /opt/jdk/jdk1.7.0_79/bin/javac 100\n"+
+        "\n"+
+        "# Sets java variables.\n"+
+        "ENV JAVA_HOME /opt/jdk/jdk1.7.0_79/\n"+
+        "\n"+
+        "# Create working directory\n"+
+        "WORKDIR /home\n"+
+        "\n"+
+        "RUN wget -O ignite.zip http://tiny.cc/updater/download_ignite.php && unzip ignite.zip && rm ignite.zip\n"+
+        "\n"+
+        "COPY *.xml /tmp/\n"+
+        "\n"+
+        "RUN mv /tmp/*.xml /home/$(ls)/config";
+};

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/src/main/js/routes/generator/java.js
----------------------------------------------------------------------
diff --git a/modules/web-control-center/src/main/js/routes/generator/java.js b/modules/web-control-center/src/main/js/routes/generator/java.js
new file mode 100644
index 0000000..31cd2ac
--- /dev/null
+++ b/modules/web-control-center/src/main/js/routes/generator/java.js
@@ -0,0 +1,626 @@
+/*
+ * 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 _ = require('lodash');
+
+var generatorUtils = require("./common");
+
+exports.generateClusterConfiguration = function(cluster, javaClass, clientNearConfiguration) {
+    var res = generatorUtils.builder();
+
+    res.datasourceBeans = [];
+
+    if (javaClass) {
+        res.line('/**');
+        res.line(' * ' + generatorUtils.mainComment());
+        res.line(' */');
+        res.startBlock('public class ConfigurationFactory {');
+        res.line('/**');
+        res.line(' * Configure grid.');
+        res.line(' */');
+        res.startBlock('public IgniteConfiguration createConfiguration() {');
+    }
+    
+    res.importClass('org.apache.ignite.configuration.IgniteConfiguration');
+    
+    res.line('IgniteConfiguration cfg = new IgniteConfiguration();');
+    res.line();
+
+    if (clientNearConfiguration) {
+        res.line('cfg.setClientMode(true);');
+
+        res.line();
+    }
+
+    if (cluster.discovery) {
+        var d = cluster.discovery;
+
+        res.importClass('org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi');
+        res.line('TcpDiscoverySpi discovery = new TcpDiscoverySpi();');
+
+        switch (d.kind) {
+            case 'Multicast':
+                res.importClass('org.apache.ignite.spi.discovery.tcp.ipfinder.multicast.TcpDiscoveryMulticastIpFinder');
+
+                addBeanWithProperties(res, d.Multicast, 'discovery', 'ipFinder', 'ipFinder',
+                    'TcpDiscoveryMulticastIpFinder', {
+                        multicastGroup: null,
+                        multicastPort: null,
+                        responseWaitTime: null,
+                        addressRequestAttempts: null,
+                        localAddress: null
+                    }, true);
+
+                break;
+
+            case 'Vm':
+                res.importClass('org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder');
+
+                addBeanWithProperties(res, d.Vm, 'discovery', 'ipFinder', 'ipFinder', 'TcpDiscoveryVmIpFinder', {
+                        addresses: {type: 'list'}
+                    }, true);
+
+                break;
+
+            case 'S3':
+                res.importClass('org.apache.ignite.spi.discovery.tcp.ipfinder.s3.TcpDiscoveryS3IpFinder');
+
+                if (d.S3)
+                    addBeanWithProperties(res, d.S3, 'discovery', 'ipFinder', 'ipFinder', 'TcpDiscoveryS3IpFinder',
+                        {bucketName: null}, true);
+                else
+                    res.line('discovery.setIpFinder(new TcpDiscoveryS3IpFinder());');
+
+                break;
+
+            case 'Cloud':
+                res.importClass('org.apache.ignite.spi.discovery.tcp.ipfinder.cloud.TcpDiscoveryCloudIpFinder');
+
+                addBeanWithProperties(res, d.Cloud, 'discovery', 'ipFinder', 'ipFinder', 'TcpDiscoveryCloudIpFinder', {
+                        credential: null,
+                        credentialPath: null,
+                        identity: null,
+                        provider: null,
+                        regions: {type: 'list'},
+                        zones: {type: 'list'}
+                    }, true);
+
+                break;
+
+            case 'GoogleStorage':
+                res.importClass('org.apache.ignite.spi.discovery.tcp.ipfinder.gce.TcpDiscoveryGoogleStorageIpFinder');
+
+                addBeanWithProperties(res, d.GoogleStorage, 'discovery', 'ipFinder', 'ipFinder',
+                    'TcpDiscoveryGoogleStorageIpFinder', {
+                        projectName: null,
+                        bucketName: null,
+                        serviceAccountP12FilePath: null
+                    }, true);
+
+                //if (d.GoogleStorage.addrReqAttempts) todo ????
+                //    res.line('<property name="serviceAccountP12FilePath" value="' + escapeAttr(d.GoogleStorage.addrReqAttempts) + '"/>');
+
+                break;
+
+            case 'Jdbc':
+                res.importClass('org.apache.ignite.spi.discovery.tcp.ipfinder.jdbc.TcpDiscoveryJdbcIpFinder');
+                
+                res.line();
+                res.line('TcpDiscoveryJdbcIpFinder ipFinder = new TcpDiscoveryJdbcIpFinder();');
+                res.line('ipFinder.setInitSchema(' + (d.Jdbc.initSchema != null || d.Jdbc.initSchema) + ');');
+                res.line('discovery.setIpFinder(ipFinder);');
+                res.needEmptyLine = true;
+
+                break;
+
+            case 'SharedFs':
+                res.importClass('org.apache.ignite.spi.discovery.tcp.ipfinder.sharedfs.TcpDiscoverySharedFsIpFinder');
+
+                addBeanWithProperties(res, d.SharedFs, 'discovery', 'ipFinder', 'ipFinder',
+                    'TcpDiscoverySharedFsIpFinder', {path: null}, true);
+
+                break;
+
+            default:
+                throw "Unknown discovery kind: " + d.kind;
+        }
+
+        res.emptyLineIfNeeded();
+
+        res.line('cfg.setDiscoverySpi(discovery);');
+
+        res.needEmptyLine = true;
+    }
+
+    if (cluster.caches && cluster.caches.length > 0) {
+        res.emptyLineIfNeeded();
+
+        var names = [];
+
+        for (var i = 0; i < cluster.caches.length; i++) {
+            res.emptyLineIfNeeded();
+
+            var cache = cluster.caches[i];
+
+            var cacheName = 'cache' + generatorUtils.toJavaName(cache.name);
+
+            names.push(cacheName);
+
+            generateCacheConfiguration(cache, cacheName, res);
+
+            res.needEmptyLine = true;
+        }
+
+        res.emptyLineIfNeeded();
+
+        res.append('cfg.setCacheConfiguration(');
+
+        for (i = 0; i < names.length; i++) {
+            if (i > 0)
+                res.append(', ');
+
+            res.append(names[i]);
+        }
+
+        res.line(');');
+
+        res.needEmptyLine = true;
+    }
+
+    addBeanWithProperties(res, cluster.atomicConfiguration, 'cfg', 'atomicConfiguration', 'atomicCfg',
+        generatorUtils.atomicConfiguration.className, generatorUtils.atomicConfiguration.fields);
+
+    res.needEmptyLine = true;
+
+    addProperty(res, cluster, 'cfg', 'networkTimeout');
+    addProperty(res, cluster, 'cfg', 'networkSendRetryDelay');
+    addProperty(res, cluster, 'cfg', 'networkSendRetryCount');
+    addProperty(res, cluster, 'cfg', 'segmentCheckFrequency');
+    addProperty(res, cluster, 'cfg', 'waitForSegmentOnStart');
+    addProperty(res, cluster, 'cfg', 'discoveryStartupDelay');
+
+    res.needEmptyLine = true;
+
+    addProperty(res, cluster, 'cfg', 'deploymentMode', 'DeploymentMode');
+
+    res.needEmptyLine = true;
+
+    if (cluster.includeEventTypes && cluster.includeEventTypes.length > 0) {
+        res.emptyLineIfNeeded();
+        
+        if (cluster.includeEventTypes.length == 1) {
+            res.importClass('org.apache.ignite.events.EventType');
+            
+            res.line('cfg.setIncludeEventTypes(EventType.' + cluster.includeEventTypes[0] + ');');
+        }
+        else {
+            res.append('int[] events = new int[EventType.' + cluster.includeEventTypes[0] + '.length');
+            
+            for (i = 1; i < cluster.includeEventTypes.length; i++) {
+                res.line();
+                
+                res.append('    + EventType.' + cluster.includeEventTypes[i] + '.length');
+            }
+            
+            res.line('];');
+            res.line();
+            res.line('int k = 0;');
+
+            for (i = 0; i < cluster.includeEventTypes.length; i++) {
+                res.line();
+
+                var e = cluster.includeEventTypes[i];
+                
+                res.line('System.arraycopy(EventType.' + e + ', 0, events, k, EventType.' + e + '.length);');
+                res.line('k += EventType.' + e + '.length;');
+            }
+            
+            res.line();
+            res.line('cfg.setIncludeEventTypes(events);');
+        }
+
+        res.needEmptyLine = true;
+    }
+
+    res.needEmptyLine = true;
+
+    var marshaller = cluster.marshaller;
+
+    if (marshaller && marshaller.kind) {
+        var marshallerDesc = generatorUtils.marshallers[marshaller.kind];
+
+        addBeanWithProperties(res, marshaller[marshaller.kind], 'cfg', 'marshaller', 'marshaller',
+            marshallerDesc.className, marshallerDesc.fields, true);
+
+        addBeanWithProperties(res, marshaller[marshaller.kind], 'marshaller', marshallerDesc.className, marshallerDesc.fields, true);
+    }
+
+    addProperty(res, cluster, 'cfg', 'marshalLocalJobs');
+    addProperty(res, cluster, 'cfg', 'marshallerCacheKeepAliveTime');
+    addProperty(res, cluster, 'cfg', 'marshallerCacheThreadPoolSize');
+
+    res.needEmptyLine = true;
+
+    addProperty(res, cluster, 'cfg', 'metricsExpireTime');
+    addProperty(res, cluster, 'cfg', 'metricsHistorySize');
+    addProperty(res, cluster, 'cfg', 'metricsLogFrequency');
+    addProperty(res, cluster, 'cfg', 'metricsUpdateFrequency');
+    res.needEmptyLine = true;
+
+    addProperty(res, cluster, 'cfg', 'peerClassLoadingEnabled');
+    addMultiparamProperty(res, cluster, 'cfg', 'peerClassLoadingLocalClassPathExclude');
+    addProperty(res, cluster, 'cfg', 'peerClassLoadingMissedResourcesCacheSize');
+    addProperty(res, cluster, 'cfg', 'peerClassLoadingThreadPoolSize');
+    res.needEmptyLine = true;
+
+    if (cluster.swapSpaceSpi && cluster.swapSpaceSpi.kind == 'FileSwapSpaceSpi') {
+        addBeanWithProperties(res, cluster.swapSpaceSpi.FileSwapSpaceSpi, 'cfg', 'swapSpaceSpi', 'swapSpi',
+            generatorUtils.swapSpaceSpi.className, generatorUtils.swapSpaceSpi.fields, true);
+
+        res.needEmptyLine = true;
+    }
+
+    addProperty(res, cluster, 'cfg', 'clockSyncSamples');
+    addProperty(res, cluster, 'cfg', 'clockSyncFrequency');
+    addProperty(res, cluster, 'cfg', 'timeServerPortBase');
+    addProperty(res, cluster, 'cfg', 'timeServerPortRange');
+
+    res.needEmptyLine = true;
+
+    addProperty(res, cluster, 'cfg', 'publicThreadPoolSize');
+    addProperty(res, cluster, 'cfg', 'systemThreadPoolSize');
+    addProperty(res, cluster, 'cfg', 'managementThreadPoolSize');
+    addProperty(res, cluster, 'cfg', 'igfsThreadPoolSize');
+
+    res.needEmptyLine = true;
+
+    addBeanWithProperties(res, cluster.transactionConfiguration, 'cfg', 'transactionConfiguration',
+        'transactionConfiguration', generatorUtils.transactionConfiguration.className,
+        generatorUtils.transactionConfiguration.fields);
+
+    res.needEmptyLine = true;
+
+    addProperty(res, cluster, 'cfg', 'cacheSanityCheckEnabled');
+
+    res.needEmptyLine = true;
+
+    if (javaClass) {
+        res.line();
+        res.line('return cfg;');
+        res.endBlock('}');
+        res.endBlock('}');
+        
+        return res.generateImports() + '\n\n' + res.join('')
+    }
+    
+    return res.join('');
+};
+
+function createEvictionPolicy(res, evictionPolicy, varName, propertyName) {
+    if (evictionPolicy && evictionPolicy.kind) {
+        var e = generatorUtils.evictionPolicies[evictionPolicy.kind];
+
+        var obj = evictionPolicy[evictionPolicy.kind.toUpperCase()];
+
+        addBeanWithProperties(res, obj, varName, propertyName, propertyName, e.className, e.fields, true);
+    }
+}
+
+exports.generateCacheConfiguration = generateCacheConfiguration;
+
+/**
+ * Generate java code for cache configuration.
+ *
+ * @param cacheCfg Cache config.
+ * @param varName Variable name.
+ * @param res Result builder.
+ * @returns {*} Append generated java code to builder and return it.
+ */
+function generateCacheConfiguration(cacheCfg, varName, res) {
+    if (!res)
+        res = generatorUtils.builder();
+
+    res.emptyLineIfNeeded();
+
+    res.importClass('org.apache.ignite.cache.CacheAtomicityMode');
+    res.importClass('org.apache.ignite.cache.CacheMode');
+    res.importClass('org.apache.ignite.configuration.CacheConfiguration');
+
+    res.line('CacheConfiguration ' + varName + ' = new CacheConfiguration();');
+
+    res.needEmptyLine = true;
+
+    addProperty(res, cacheCfg, varName, 'name');
+    
+    addProperty(res, cacheCfg, varName, 'mode', 'CacheMode', 'cacheMode');
+
+    addProperty(res, cacheCfg, varName, 'atomicityMode', 'CacheAtomicityMode');
+    addProperty(res, cacheCfg, varName, 'backups');
+    addProperty(res, cacheCfg, varName, 'startSize');
+    addProperty(res, cacheCfg, varName, 'readFromBackup');
+
+    res.needEmptyLine = true;
+    
+    addProperty(res, cacheCfg, varName, 'memoryMode', 'CacheMemoryMode');
+    addProperty(res, cacheCfg, varName, 'offHeapMaxMemory');
+    addProperty(res, cacheCfg, varName, 'swapEnabled');
+    addProperty(res, cacheCfg, varName, 'copyOnRead');
+
+    res.needEmptyLine = true;
+
+    createEvictionPolicy(res, cacheCfg.evictionPolicy, varName, 'evictionPolicy');
+
+    if (cacheCfg.nearCacheEnabled) {
+        res.needEmptyLine = true;
+
+        res.importClass('org.apache.ignite.configuration.NearCacheConfiguration');
+
+        addBeanWithProperties(res, cacheCfg.nearConfiguration, varName, 'nearConfiguration', 'nearConfiguration',
+            'NearCacheConfiguration', {nearStartSize: null}, true);
+
+        if (cacheCfg.nearConfiguration && cacheCfg.nearConfiguration.nearEvictionPolicy && cacheCfg.nearConfiguration.nearEvictionPolicy.kind) {
+            createEvictionPolicy(res, cacheCfg.nearConfiguration.nearEvictionPolicy, 'nearConfiguration', 'nearEvictionPolicy');
+        }
+    }
+
+    res.needEmptyLine = true;
+    
+    addProperty(res, cacheCfg, varName, 'sqlEscapeAll');
+    addProperty(res, cacheCfg, varName, 'sqlOnheapRowCacheSize');
+    addProperty(res, cacheCfg, varName, 'longQueryWarningTimeout');
+    
+    if (cacheCfg.indexedTypes && cacheCfg.indexedTypes.length > 0) {
+        res.emptyLineIfNeeded();
+        
+        res.append(varName + '.setIndexedTypes(');
+        
+        for (var i = 0; i < cacheCfg.indexedTypes.length; i++) {
+            if (i > 0)
+                res.append(', ');
+
+            var pair = cacheCfg.indexedTypes[i];
+            
+            res.append(toJavaCode(pair.keyClass, 'class')).append(', ').append(toJavaCode(pair.valueClass, 'class'))
+        }
+        
+        res.line(');');
+    }
+
+    addMultiparamProperty(res, cacheCfg, varName, 'sqlFunctionClasses', 'class');
+    
+    res.needEmptyLine = true;
+
+    addProperty(res, cacheCfg, varName, 'rebalanceMode', 'CacheRebalanceMode');
+    addProperty(res, cacheCfg, varName, 'rebalanceThreadPoolSize');
+    addProperty(res, cacheCfg, varName, 'rebalanceBatchSize');
+    addProperty(res, cacheCfg, varName, 'rebalanceOrder');
+    addProperty(res, cacheCfg, varName, 'rebalanceDelay');
+    addProperty(res, cacheCfg, varName, 'rebalanceTimeout');
+    addProperty(res, cacheCfg, varName, 'rebalanceThrottle');
+
+    res.needEmptyLine = true;
+    
+    if (cacheCfg.cacheStoreFactory && cacheCfg.cacheStoreFactory.kind) {
+        var storeFactory = cacheCfg.cacheStoreFactory[cacheCfg.cacheStoreFactory.kind];
+        var data = generatorUtils.storeFactories[cacheCfg.cacheStoreFactory.kind];
+
+        var sfVarName = 'storeFactory' + generatorUtils.toJavaName(cacheCfg.name);
+        var dsVarName = 'none';
+
+        if (storeFactory.dialect) {
+            var dataSourceBean = storeFactory.dataSourceBean;
+
+            dsVarName = 'dataSource' + generatorUtils.toJavaName(dataSourceBean);
+
+            if (!_.contains(res.datasourceBeans, dataSourceBean)) {
+                res.datasourceBeans.push(dataSourceBean);
+
+                var dataSource = generatorUtils.dataSources[storeFactory.dialect];
+
+                res.line();
+                res.line(dataSource.className + ' ' + dsVarName + ' = new ' + dataSource.className + '();');
+                res.line(dsVarName + '.setURL(_URL_);');
+                res.line(dsVarName + '.setUsername(_User_Name_);');
+                res.line(dsVarName + '.setPassword(_Password_);');
+            }
+        }
+
+        addBeanWithProperties(res, storeFactory, varName, 'cacheStoreFactory', sfVarName, data.className,
+            data.fields, true);
+
+        if (dsVarName != 'none')
+            res.line(sfVarName + '.setDataSource(' + dsVarName + ');');
+    }
+
+    res.needEmptyLine = true;
+
+    addProperty(res, cacheCfg, varName, 'loadPreviousValue');
+    addProperty(res, cacheCfg, varName, 'readThrough');
+    addProperty(res, cacheCfg, varName, 'writeThrough');
+
+    res.needEmptyLine = true;
+    
+    addProperty(res, cacheCfg, varName, 'invalidate');
+    addProperty(res, cacheCfg, varName, 'defaultLockTimeout');
+    addProperty(res, cacheCfg, varName, 'transactionManagerLookupClassName');
+    
+    res.needEmptyLine = true;
+    
+    addProperty(res, cacheCfg, varName, 'writeBehindEnabled');
+    addProperty(res, cacheCfg, varName, 'writeBehindBatchSize');
+    addProperty(res, cacheCfg, varName, 'writeBehindFlushSize');
+    addProperty(res, cacheCfg, varName, 'writeBehindFlushFrequency');
+    addProperty(res, cacheCfg, varName, 'writeBehindFlushThreadCount');
+    
+    res.needEmptyLine = true;
+
+    addProperty(res, cacheCfg, varName, 'statisticsEnabled');
+    addProperty(res, cacheCfg, varName, 'managementEnabled');
+
+    res.needEmptyLine = true;
+
+    addProperty(res, cacheCfg, varName, 'maxConcurrentAsyncOperations');
+    
+    return res;
+}
+
+function toJavaCode(val, type) {
+    if (val == null)
+       return 'null';
+
+    if (type == 'float')
+        return val + 'f';
+    
+    if (type == 'class')
+        return val + '.class';
+    
+    if (type)
+        return type + '.' + val;
+    
+    if (typeof(val) == 'string')
+        return '"' + val.replace('"', '\\"') + '"';
+
+    if (typeof(val) == 'number' || typeof(val) == 'boolean')
+        return '' + val;
+
+    throw "Unknown type: " + typeof(val) + ' (' + val + ')';
+}
+
+function addProperty(res, obj, objVariableName, propName, enumType, setterName) {
+    var val = obj[propName];
+    
+    if (generatorUtils.isDefined(val)) {
+        res.emptyLineIfNeeded();
+
+        res.line(objVariableName + '.' + getSetterName(setterName ? setterName : propName)
+            + '(' + toJavaCode(val, enumType)  + ');');
+    }
+}
+
+function getSetterName(propName) {
+    return 'set' + propName.charAt(0).toLocaleUpperCase() + propName.slice(1);
+}
+
+function addListProperty(res, obj, objVariableName, propName, enumType, setterName) {
+    var val = obj[propName];
+    
+    if (val && val.length > 0) {
+        res.append(objVariableName + '.' + getSetterName(setterName ? setterName : propName) + '(Arrays.asList(');
+
+        for (var i = 0; i < val.length; i++) {
+            if (i > 0)
+                res.append(', ');
+            
+            res.append(toJavaCode(val[i], enumType));
+        }
+        
+        res.line('));');
+    }
+}
+
+function addMultiparamProperty(res, obj, objVariableName, propName, type, setterName) {
+    var val = obj[propName];
+    
+    if (val && val.length > 0) {
+        res.append(objVariableName + '.' + getSetterName(setterName ? setterName : propName) + '(');
+
+        for (var i = 0; i < val.length; i++) {
+            if (i > 0)
+                res.append(', ');
+            
+            res.append(toJavaCode(val[i], type));
+        }
+        
+        res.line(');');
+    }
+}
+
+function addBeanWithProperties(res, bean, objVarName, beanPropName, beanVarName, beanClass, props, createBeanAlthoughNoProps) {
+    if (bean && generatorUtils.hasProperty(bean, props)) {
+        if (!res.emptyLineIfNeeded()) {
+            res.line();
+        }
+        
+        res.line(beanClass + ' ' + beanVarName + ' = new ' + beanClass + '();');
+
+        for (var propName in props) {
+            if (props.hasOwnProperty(propName)) {
+                var descr = props[propName];
+
+                if (descr) {
+                    switch (descr.type) {
+                        case 'list':
+                            addListProperty(res, bean, beanVarName, propName, descr.elementsType, descr.setterName);
+                            break;
+                        
+                        case 'enum':
+                            addProperty(res, bean, beanVarName, propName, descr.enumClass, descr.setterName);
+                            break;
+                        
+                        case 'float':
+                            addProperty(res, bean, beanVarName, propName, 'float', descr.setterName);
+                            break;
+                        
+                        case 'propertiesAsList':
+                            var val = bean[propName];
+                            
+                            if (val && val.length > 0) {
+                                res.line('Properties ' + descr.propVarName + ' = new Properties();');
+                                
+                                for (var i = 0; i < val.length; i++) {
+                                    var nameAndValue = val[i];
+                                    
+                                    var eqIndex = nameAndValue.indexOf('=');
+                                    if (eqIndex >= 0) {
+                                        res.line(descr.propVarName + '.setProperty(' 
+                                            + nameAndValue.substring(0, eqIndex) + ', ' 
+                                            + nameAndValue.substr(eqIndex + 1) + ');');
+                                    }
+
+                                }
+                                
+                                res.line(beanVarName + '.' + getSetterName(propName) + '(' + descr.propVarName + ');');
+                            }
+                            break;
+                        
+                        case 'className':
+                            if (bean[propName]) {
+                                res.line(beanVarName + '.' + getSetterName(propName) + '(new ' + generatorUtils.knownClasses[bean[propName]].className + '());');
+                            }
+
+                            break;
+                        
+                        default:
+                            addProperty(res, bean, beanVarName, propName, null, descr.setterName);
+                    }
+                }
+                else {
+                    addProperty(res, bean, beanVarName, propName);
+                }
+            }
+        }
+        
+        res.line(objVarName + '.' + getSetterName(beanPropName) + '(' + beanVarName + ');');
+        
+        res.needEmptyLine = true;
+    }
+    else if (createBeanAlthoughNoProps) {
+        res.emptyLineIfNeeded();
+        
+        res.line(objVarName + '.' + getSetterName(beanPropName) + '(new ' + beanClass + '());');
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/src/main/js/routes/generator/xml.js
----------------------------------------------------------------------
diff --git a/modules/web-control-center/src/main/js/routes/generator/xml.js b/modules/web-control-center/src/main/js/routes/generator/xml.js
new file mode 100644
index 0000000..16ef23b
--- /dev/null
+++ b/modules/web-control-center/src/main/js/routes/generator/xml.js
@@ -0,0 +1,580 @@
+/*
+ * 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 _ = require('lodash');
+
+var generatorUtils = require("./common");
+var dataStructures = require("../../helpers/data-structures.js");
+
+exports.generateClusterConfiguration = function(cluster, clientNearConfiguration) {
+    var res = generatorUtils.builder();
+
+    res.datasources = [];
+    res.deep = 1;
+
+    if (clientNearConfiguration) {
+        res.startBlock('<bean id="nearCacheBean" class="org.apache.ignite.configuration.NearCacheConfiguration">');
+
+        if (clientNearConfiguration.nearStartSize)
+            addProperty(res, clientNearConfiguration, 'nearStartSize');
+
+        if (clientNearConfiguration.nearEvictionPolicy && clientNearConfiguration.nearEvictionPolicy.kind)
+            createEvictionPolicy(res, clientNearConfiguration.nearEvictionPolicy, 'nearEvictionPolicy');
+
+        res.endBlock('</bean>');
+
+        res.line();
+    }
+
+    // Generate Ignite Configuration.
+    res.startBlock('<bean class="org.apache.ignite.configuration.IgniteConfiguration">');
+
+    if (clientNearConfiguration) {
+        res.line('<property name="clientMode" value="true" />');
+
+        res.line();
+    }
+
+    // Generate discovery.
+    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');
+                addListProperty(res, d.Cloud, 'regions');
+                addListProperty(res, d.Cloud, 'zones');
+
+                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
+    }
+
+    // Generate atomics group.
+    addBeanWithProperties(res, cluster.atomicConfiguration, 'atomicConfiguration',
+        generatorUtils.atomicConfiguration.className, generatorUtils.atomicConfiguration.fields);
+    res.needEmptyLine = true;
+
+    // Generate communication group.
+    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;
+
+    // Generate deployment group.
+    addProperty(res, cluster, 'deploymentMode');
+    res.needEmptyLine = true;
+
+    // Generate events group.
+    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;
+    }
+
+    // Generate marshaller group.
+    var marshaller = cluster.marshaller;
+
+    if (marshaller && marshaller.kind) {
+        var marshallerDesc = generatorUtils.marshallers[marshaller.kind];
+
+        addBeanWithProperties(res, marshaller[marshaller.kind], 'marshaller', marshallerDesc.className, marshallerDesc.fields, true);
+        res.needEmptyLine = true;
+    }
+
+    addProperty(res, cluster, 'marshalLocalJobs');
+    addProperty(res, cluster, 'marshallerCacheKeepAliveTime');
+    addProperty(res, cluster, 'marshallerCacheThreadPoolSize');
+    res.needEmptyLine = true;
+
+    // Generate metrics group.
+    addProperty(res, cluster, 'metricsExpireTime');
+    addProperty(res, cluster, 'metricsHistorySize');
+    addProperty(res, cluster, 'metricsLogFrequency');
+    addProperty(res, cluster, 'metricsUpdateFrequency');
+    res.needEmptyLine = true;
+
+    // Generate PeerClassLoading group.
+    addProperty(res, cluster, 'peerClassLoadingEnabled');
+    addListProperty(res, cluster, 'peerClassLoadingLocalClassPathExclude');
+    addProperty(res, cluster, 'peerClassLoadingMissedResourcesCacheSize');
+    addProperty(res, cluster, 'peerClassLoadingThreadPoolSize');
+    res.needEmptyLine = true;
+
+    // Generate swap group.
+    if (cluster.swapSpaceSpi && cluster.swapSpaceSpi.kind == 'FileSwapSpaceSpi') {
+        addBeanWithProperties(res, cluster.swapSpaceSpi.FileSwapSpaceSpi, 'swapSpaceSpi',
+            generatorUtils.swapSpaceSpi.className, generatorUtils.swapSpaceSpi.fields, true);
+
+        res.needEmptyLine = true;
+    }
+
+    // Generate time group.
+    addProperty(res, cluster, 'clockSyncSamples');
+    addProperty(res, cluster, 'clockSyncFrequency');
+    addProperty(res, cluster, 'timeServerPortBase');
+    addProperty(res, cluster, 'timeServerPortRange');
+    res.needEmptyLine = true;
+
+    // Generate thread pools group.
+    addProperty(res, cluster, 'publicThreadPoolSize');
+    addProperty(res, cluster, 'systemThreadPoolSize');
+    addProperty(res, cluster, 'managementThreadPoolSize');
+    addProperty(res, cluster, 'igfsThreadPoolSize');
+    res.needEmptyLine = true;
+
+    // Generate transactions group.
+    addBeanWithProperties(res, cluster.transactionConfiguration, 'transactionConfiguration',
+        generatorUtils.transactionConfiguration.className, generatorUtils.transactionConfiguration.fields);
+    res.needEmptyLine = true;
+
+    // Generate caches configs.
+    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();
+
+            var cache = cluster.caches[i];
+
+            generateCacheConfiguration(cache, res);
+        }
+
+        res.endBlock('</list>');
+        res.endBlock('</property>');
+
+        res.needEmptyLine = true;
+    }
+
+    res.endBlock('</bean>');
+
+    // Build final XML:
+    // 1. Add header.
+    var xml = '<?xml version="1.0" encoding="UTF-8"?>\n\n';
+
+    xml += '<!-- ' + generatorUtils.mainComment() + ' -->\n';
+    xml += '<beans xmlns="http://www.springframework.org/schema/beans"\n';
+    xml += '       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"\n';
+    xml += '       xmlns:util="http://www.springframework.org/schema/util"\n';
+    xml += '       xsi:schemaLocation="http://www.springframework.org/schema/beans\n';
+    xml += '                           http://www.springframework.org/schema/beans/spring-beans.xsd\n';
+    xml += '                           http://www.springframework.org/schema/util\n';
+    xml += '                           http://www.springframework.org/schema/util/spring-util.xsd">\n';
+
+    // 2. Add external property file and all data sources.
+    if (res.datasources.length > 0) {
+        xml += '    <!-- Load external properties file. -->\n';
+        xml += '    <bean id="placeholderConfig" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">\n';
+        xml += '        <property name="location" value="classpath:secret.properties"/>\n';
+        xml += '    </bean>\n\n';
+
+        xml += '    <!-- Data source beans will be initialized from external properties file. -->\n';
+
+        _.forEach(res.datasources, function(item) {
+            var beanId = item.dataSourceBean;
+
+            xml += '    <bean id= "' + beanId + '" class="' + item.className + '">\n';
+            xml += '        <property name="URL" value="${' + beanId + '.jdbc.url}" />\n';
+            xml += '        <property name="user" value="${' + beanId + '.jdbc.username}" />\n';
+            xml += '        <property name="password" value="${' + beanId + '.jdbc.password}" />\n';
+            xml += '    </bean>\n\n';
+        });
+    }
+
+    // 3. Add main content.
+    xml += res.join('');
+
+    // 4. Add footer.
+    xml += '</beans>\n';
+
+    return xml;
+};
+
+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');
+    addProperty(res, cacheCfg, 'startSize');
+    addProperty(res, cacheCfg, 'readFromBackup');
+
+    res.needEmptyLine = true;
+
+    addProperty(res, cacheCfg, 'memoryMode');
+    addProperty(res, cacheCfg, 'offHeapMaxMemory');
+    addProperty(res, cacheCfg, 'swapEnabled');
+    addProperty(res, cacheCfg, 'copyOnRead');
+
+    res.needEmptyLine = true;
+
+    createEvictionPolicy(res, cacheCfg.evictionPolicy, 'evictionPolicy');
+
+    res.needEmptyLine = true;
+
+    if (cacheCfg.nearCacheEnabled) {
+        res.emptyLineIfNeeded();
+
+        res.startBlock('<property name="nearConfiguration">');
+        res.startBlock('<bean class="org.apache.ignite.configuration.NearCacheConfiguration">');
+
+        if (cacheCfg.nearConfiguration && cacheCfg.nearConfiguration.nearStartSize)
+            addProperty(res, cacheCfg.nearConfiguration, 'nearStartSize');
+
+        if (cacheCfg.nearConfiguration && cacheCfg.nearConfiguration.nearEvictionPolicy.kind)
+            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('<list>');
+
+        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('</list>');
+        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 storeFactory = cacheCfg.cacheStoreFactory[cacheCfg.cacheStoreFactory.kind];
+        var data = generatorUtils.storeFactories[cacheCfg.cacheStoreFactory.kind];
+
+        addBeanWithProperties(res, storeFactory, 'cacheStoreFactory', data.className, data.fields, true);
+
+        if (storeFactory.dialect) {
+            if (_.findIndex(res.datasources, function (ds) {
+                    return ds.dataSourceBean == storeFactory.dataSourceBean;
+                }) < 0) {
+                res.datasources.push({
+                    dataSourceBean: storeFactory.dataSourceBean,
+                    className: generatorUtils.dataSources[storeFactory.dialect]
+                });
+            }
+        }
+    }
+
+    res.needEmptyLine = true;
+
+    addProperty(res, cacheCfg, 'loadPreviousValue');
+    addProperty(res, cacheCfg, 'readThrough');
+    addProperty(res, cacheCfg, 'writeThrough');
+
+    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');
+
+    res.needEmptyLine = true;
+
+    addProperty(res, cacheCfg, 'maxConcurrentAsyncOperations');
+    
+    res.endBlock('</bean>');
+
+    return res;
+}
+
+exports.generateCacheConfiguration = generateCacheConfiguration;
+
+function addProperty(res, obj, propName, setterName) {
+    var val = obj[propName];
+
+    if (generatorUtils.isDefined(val)) {
+        res.emptyLineIfNeeded();
+
+        res.line('<property name="' + (setterName ? setterName : propName) + '" value="' + escapeAttr(val) + '"/>');
+    }
+}
+
+function addBeanWithProperties(res, bean, beanPropName, beanClass, props, createBeanAlthoughNoProps) {
+    if (bean && 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;');
+}



[07/10] incubator-ignite git commit: # ignite-843 moved

Posted by an...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/nodejs/routes/generator/xml.js
----------------------------------------------------------------------
diff --git a/modules/web-control-center/nodejs/routes/generator/xml.js b/modules/web-control-center/nodejs/routes/generator/xml.js
deleted file mode 100644
index 16ef23b..0000000
--- a/modules/web-control-center/nodejs/routes/generator/xml.js
+++ /dev/null
@@ -1,580 +0,0 @@
-/*
- * 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 _ = require('lodash');
-
-var generatorUtils = require("./common");
-var dataStructures = require("../../helpers/data-structures.js");
-
-exports.generateClusterConfiguration = function(cluster, clientNearConfiguration) {
-    var res = generatorUtils.builder();
-
-    res.datasources = [];
-    res.deep = 1;
-
-    if (clientNearConfiguration) {
-        res.startBlock('<bean id="nearCacheBean" class="org.apache.ignite.configuration.NearCacheConfiguration">');
-
-        if (clientNearConfiguration.nearStartSize)
-            addProperty(res, clientNearConfiguration, 'nearStartSize');
-
-        if (clientNearConfiguration.nearEvictionPolicy && clientNearConfiguration.nearEvictionPolicy.kind)
-            createEvictionPolicy(res, clientNearConfiguration.nearEvictionPolicy, 'nearEvictionPolicy');
-
-        res.endBlock('</bean>');
-
-        res.line();
-    }
-
-    // Generate Ignite Configuration.
-    res.startBlock('<bean class="org.apache.ignite.configuration.IgniteConfiguration">');
-
-    if (clientNearConfiguration) {
-        res.line('<property name="clientMode" value="true" />');
-
-        res.line();
-    }
-
-    // Generate discovery.
-    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');
-                addListProperty(res, d.Cloud, 'regions');
-                addListProperty(res, d.Cloud, 'zones');
-
-                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
-    }
-
-    // Generate atomics group.
-    addBeanWithProperties(res, cluster.atomicConfiguration, 'atomicConfiguration',
-        generatorUtils.atomicConfiguration.className, generatorUtils.atomicConfiguration.fields);
-    res.needEmptyLine = true;
-
-    // Generate communication group.
-    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;
-
-    // Generate deployment group.
-    addProperty(res, cluster, 'deploymentMode');
-    res.needEmptyLine = true;
-
-    // Generate events group.
-    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;
-    }
-
-    // Generate marshaller group.
-    var marshaller = cluster.marshaller;
-
-    if (marshaller && marshaller.kind) {
-        var marshallerDesc = generatorUtils.marshallers[marshaller.kind];
-
-        addBeanWithProperties(res, marshaller[marshaller.kind], 'marshaller', marshallerDesc.className, marshallerDesc.fields, true);
-        res.needEmptyLine = true;
-    }
-
-    addProperty(res, cluster, 'marshalLocalJobs');
-    addProperty(res, cluster, 'marshallerCacheKeepAliveTime');
-    addProperty(res, cluster, 'marshallerCacheThreadPoolSize');
-    res.needEmptyLine = true;
-
-    // Generate metrics group.
-    addProperty(res, cluster, 'metricsExpireTime');
-    addProperty(res, cluster, 'metricsHistorySize');
-    addProperty(res, cluster, 'metricsLogFrequency');
-    addProperty(res, cluster, 'metricsUpdateFrequency');
-    res.needEmptyLine = true;
-
-    // Generate PeerClassLoading group.
-    addProperty(res, cluster, 'peerClassLoadingEnabled');
-    addListProperty(res, cluster, 'peerClassLoadingLocalClassPathExclude');
-    addProperty(res, cluster, 'peerClassLoadingMissedResourcesCacheSize');
-    addProperty(res, cluster, 'peerClassLoadingThreadPoolSize');
-    res.needEmptyLine = true;
-
-    // Generate swap group.
-    if (cluster.swapSpaceSpi && cluster.swapSpaceSpi.kind == 'FileSwapSpaceSpi') {
-        addBeanWithProperties(res, cluster.swapSpaceSpi.FileSwapSpaceSpi, 'swapSpaceSpi',
-            generatorUtils.swapSpaceSpi.className, generatorUtils.swapSpaceSpi.fields, true);
-
-        res.needEmptyLine = true;
-    }
-
-    // Generate time group.
-    addProperty(res, cluster, 'clockSyncSamples');
-    addProperty(res, cluster, 'clockSyncFrequency');
-    addProperty(res, cluster, 'timeServerPortBase');
-    addProperty(res, cluster, 'timeServerPortRange');
-    res.needEmptyLine = true;
-
-    // Generate thread pools group.
-    addProperty(res, cluster, 'publicThreadPoolSize');
-    addProperty(res, cluster, 'systemThreadPoolSize');
-    addProperty(res, cluster, 'managementThreadPoolSize');
-    addProperty(res, cluster, 'igfsThreadPoolSize');
-    res.needEmptyLine = true;
-
-    // Generate transactions group.
-    addBeanWithProperties(res, cluster.transactionConfiguration, 'transactionConfiguration',
-        generatorUtils.transactionConfiguration.className, generatorUtils.transactionConfiguration.fields);
-    res.needEmptyLine = true;
-
-    // Generate caches configs.
-    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();
-
-            var cache = cluster.caches[i];
-
-            generateCacheConfiguration(cache, res);
-        }
-
-        res.endBlock('</list>');
-        res.endBlock('</property>');
-
-        res.needEmptyLine = true;
-    }
-
-    res.endBlock('</bean>');
-
-    // Build final XML:
-    // 1. Add header.
-    var xml = '<?xml version="1.0" encoding="UTF-8"?>\n\n';
-
-    xml += '<!-- ' + generatorUtils.mainComment() + ' -->\n';
-    xml += '<beans xmlns="http://www.springframework.org/schema/beans"\n';
-    xml += '       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"\n';
-    xml += '       xmlns:util="http://www.springframework.org/schema/util"\n';
-    xml += '       xsi:schemaLocation="http://www.springframework.org/schema/beans\n';
-    xml += '                           http://www.springframework.org/schema/beans/spring-beans.xsd\n';
-    xml += '                           http://www.springframework.org/schema/util\n';
-    xml += '                           http://www.springframework.org/schema/util/spring-util.xsd">\n';
-
-    // 2. Add external property file and all data sources.
-    if (res.datasources.length > 0) {
-        xml += '    <!-- Load external properties file. -->\n';
-        xml += '    <bean id="placeholderConfig" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">\n';
-        xml += '        <property name="location" value="classpath:secret.properties"/>\n';
-        xml += '    </bean>\n\n';
-
-        xml += '    <!-- Data source beans will be initialized from external properties file. -->\n';
-
-        _.forEach(res.datasources, function(item) {
-            var beanId = item.dataSourceBean;
-
-            xml += '    <bean id= "' + beanId + '" class="' + item.className + '">\n';
-            xml += '        <property name="URL" value="${' + beanId + '.jdbc.url}" />\n';
-            xml += '        <property name="user" value="${' + beanId + '.jdbc.username}" />\n';
-            xml += '        <property name="password" value="${' + beanId + '.jdbc.password}" />\n';
-            xml += '    </bean>\n\n';
-        });
-    }
-
-    // 3. Add main content.
-    xml += res.join('');
-
-    // 4. Add footer.
-    xml += '</beans>\n';
-
-    return xml;
-};
-
-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');
-    addProperty(res, cacheCfg, 'startSize');
-    addProperty(res, cacheCfg, 'readFromBackup');
-
-    res.needEmptyLine = true;
-
-    addProperty(res, cacheCfg, 'memoryMode');
-    addProperty(res, cacheCfg, 'offHeapMaxMemory');
-    addProperty(res, cacheCfg, 'swapEnabled');
-    addProperty(res, cacheCfg, 'copyOnRead');
-
-    res.needEmptyLine = true;
-
-    createEvictionPolicy(res, cacheCfg.evictionPolicy, 'evictionPolicy');
-
-    res.needEmptyLine = true;
-
-    if (cacheCfg.nearCacheEnabled) {
-        res.emptyLineIfNeeded();
-
-        res.startBlock('<property name="nearConfiguration">');
-        res.startBlock('<bean class="org.apache.ignite.configuration.NearCacheConfiguration">');
-
-        if (cacheCfg.nearConfiguration && cacheCfg.nearConfiguration.nearStartSize)
-            addProperty(res, cacheCfg.nearConfiguration, 'nearStartSize');
-
-        if (cacheCfg.nearConfiguration && cacheCfg.nearConfiguration.nearEvictionPolicy.kind)
-            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('<list>');
-
-        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('</list>');
-        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 storeFactory = cacheCfg.cacheStoreFactory[cacheCfg.cacheStoreFactory.kind];
-        var data = generatorUtils.storeFactories[cacheCfg.cacheStoreFactory.kind];
-
-        addBeanWithProperties(res, storeFactory, 'cacheStoreFactory', data.className, data.fields, true);
-
-        if (storeFactory.dialect) {
-            if (_.findIndex(res.datasources, function (ds) {
-                    return ds.dataSourceBean == storeFactory.dataSourceBean;
-                }) < 0) {
-                res.datasources.push({
-                    dataSourceBean: storeFactory.dataSourceBean,
-                    className: generatorUtils.dataSources[storeFactory.dialect]
-                });
-            }
-        }
-    }
-
-    res.needEmptyLine = true;
-
-    addProperty(res, cacheCfg, 'loadPreviousValue');
-    addProperty(res, cacheCfg, 'readThrough');
-    addProperty(res, cacheCfg, 'writeThrough');
-
-    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');
-
-    res.needEmptyLine = true;
-
-    addProperty(res, cacheCfg, 'maxConcurrentAsyncOperations');
-    
-    res.endBlock('</bean>');
-
-    return res;
-}
-
-exports.generateCacheConfiguration = generateCacheConfiguration;
-
-function addProperty(res, obj, propName, setterName) {
-    var val = obj[propName];
-
-    if (generatorUtils.isDefined(val)) {
-        res.emptyLineIfNeeded();
-
-        res.line('<property name="' + (setterName ? setterName : propName) + '" value="' + escapeAttr(val) + '"/>');
-    }
-}
-
-function addBeanWithProperties(res, bean, beanPropName, beanClass, props, createBeanAlthoughNoProps) {
-    if (bean && 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/8a335724/modules/web-control-center/nodejs/routes/metadata.js
----------------------------------------------------------------------
diff --git a/modules/web-control-center/nodejs/routes/metadata.js b/modules/web-control-center/nodejs/routes/metadata.js
deleted file mode 100644
index 64b8763..0000000
--- a/modules/web-control-center/nodejs/routes/metadata.js
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * 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 router = require('express').Router();
-var db = require('../db');
-
-/* GET metadata page. */
-router.get('/', function (req, res) {
-    res.render('configuration/metadata');
-});
-
-/**
- * Get spaces and metadata accessed for user account.
- *
- * @param req Request.
- * @param res Response.
- */
-router.post('/list', function (req, res) {
-    var user_id = req.currentUserId();
-
-    // Get owned space and all accessed space.
-    db.Space.find({$or: [{owner: user_id}, {usedBy: {$elemMatch: {account: user_id}}}]}, function (err, spaces) {
-        if (err)
-            return res.status(500).send(err.message);
-
-        var space_ids = spaces.map(function (value) {
-            return value._id;
-        });
-
-        // Get all metadata for spaces.
-        db.CacheTypeMetadata.find({space: {$in: space_ids}}).sort('name').exec(function (err, metadatas) {
-            if (err)
-                return res.status(500).send(err.message);
-
-            res.json({spaces: spaces, metadatas: metadatas});
-        });
-    });
-});
-
-/**
- * Save metadata.
- */
-router.post('/save', function (req, res) {
-    if (req.body._id)
-        db.CacheTypeMetadata.update({_id: req.body._id}, req.body, {upsert: true}, function (err) {
-            if (err)
-                return res.status(500).send(err.message);
-
-            res.send(req.body._id);
-        });
-    else {
-        db.CacheTypeMetadata.findOne({name: req.body.name}, function (err, metadata) {
-            if (err)
-                return res.status(500).send(err.message);
-
-            if (metadata)
-                return res.status(500).send('Cache type metadata with name: "' + metadata.name + '" already exist.');
-
-            (new db.CacheTypeMetadata(req.body)).save(function (err, metadata) {
-                if (err)
-                    return res.status(500).send(err.message);
-
-                res.send(metadata._id);
-            });
-        });
-    }
-});
-
-/**
- * Remove metadata by ._id.
- */
-router.post('/remove', function (req, res) {
-    db.CacheTypeMetadata.remove(req.body, function (err) {
-        if (err)
-            return res.status(500).send(err.message);
-
-        res.sendStatus(200);
-    })
-});
-
-module.exports = router;
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/nodejs/routes/profile.js
----------------------------------------------------------------------
diff --git a/modules/web-control-center/nodejs/routes/profile.js b/modules/web-control-center/nodejs/routes/profile.js
deleted file mode 100644
index 0269e7d..0000000
--- a/modules/web-control-center/nodejs/routes/profile.js
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * 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 router = require('express').Router();
-var db = require('../db');
-
-router.all('/profile/*', function (req, res, next) {
-    var userId = req.body._id;
-
-    if (userId != req.currentUserId() && userId != req.user._id)
-        return res.sendStatus(403);
-    else
-        next();
-});
-
-/**
- * Get user profile page.
- */
-router.get('/', function (req, res) {
-    var user_id = req.currentUserId();
-
-    db.Account.findById(user_id, function (err) {
-        if (err)
-            return res.status(500).send(err.message);
-
-        res.render('settings/profile');
-    });
-});
-
-/**
- * Save user profile.
- */
-router.post('/saveUser', function (req, res) {
-    var params = req.body;
-
-    if (params.newPassword) {
-        var newPassword = params.newPassword;
-
-        if (!newPassword || newPassword.length == 0)
-            return res.status(500).send('Wrong value for new password');
-
-        db.Account.findById(params._id, function (err, user) {
-            if (err)
-                return res.status(500).send(err);
-
-            user.setPassword(newPassword, function (err, updatedUser) {
-                if (err)
-                    return res.status(500).send(err.message);
-
-                if (params.userName)
-                    updatedUser.username = params.userName;
-
-                if (params.email)
-                    updatedUser.email = params.email;
-
-                updatedUser.save(function (err) {
-                    if (err)
-                        return res.status(500).send(err.message);
-
-                    res.json(user);
-                });
-            });
-        });
-    }
-    else if (params.userName || params.email) {
-        var upd = {};
-
-        if (params.userName)
-            upd.username = params.userName;
-
-        if (params.email)
-            upd.email = params.email;
-
-        db.Account.findByIdAndUpdate(params._id, upd, {new: true}, function (err, val) {
-            if (err)
-                return res.status(500).send(err.message);
-
-            res.json(val);
-        })
-    }
-});
-
-module.exports = router;
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/nodejs/routes/public.js
----------------------------------------------------------------------
diff --git a/modules/web-control-center/nodejs/routes/public.js b/modules/web-control-center/nodejs/routes/public.js
deleted file mode 100644
index 290ba90..0000000
--- a/modules/web-control-center/nodejs/routes/public.js
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * 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 router = require('express').Router();
-var passport = require('passport');
-var db = require('../db');
-
-// GET dropdown-menu template.
-router.get('/select', function (req, res) {
-    res.render('templates/select', {});
-});
-
-// GET tabs template.
-router.get('/tab', function (req, res) {
-    res.render('templates/tab', {});
-});
-
-// GET confirmation dialog.
-router.get('/confirm', function (req, res) {
-    res.render('templates/confirm', {});
-});
-
-// GET save as dialog.
-router.get('/copy', function (req, res) {
-    res.render('templates/copy', {});
-});
-
-/* GET login page. */
-router.get('/login', function (req, res) {
-    res.render('login');
-});
-
-/**
- * Register new account.
- */
-router.post('/register', function (req, res) {
-    db.Account.count(function (err, cnt) {
-        if (err)
-            return res.status(401).send(err.message);
-
-        req.body.admin = cnt == 0;
-
-        db.Account.register(new db.Account(req.body), req.body.password, function (err, account) {
-            if (err)
-                return res.status(401).send(err.message);
-
-            if (!account)
-                return res.status(500).send('Failed to create account.');
-
-            new db.Space({name: 'Personal space', owner: account._id}).save();
-
-            req.logIn(account, {}, function (err) {
-                if (err)
-                    return res.status(401).send(err.message);
-
-                return res.redirect('/configuration/clusters');
-            });
-        });
-    });
-});
-
-/**
- * Login in exist account.
- */
-router.post('/login', function (req, res, next) {
-    passport.authenticate('local', function (err, user) {
-        if (err)
-            return res.status(401).send(err.message);
-
-        if (!user)
-            return res.status(401).send('Invalid email or password');
-
-        req.logIn(user, {}, function (err) {
-            if (err)
-                return res.status(401).send(err.message);
-
-            res.redirect('/configuration/clusters');
-        });
-    })(req, res, next);
-});
-
-/**
- * Logout.
- */
-router.get('/logout', function (req, res) {
-    req.logout();
-
-    res.redirect('/');
-});
-
-/* GET home page. */
-router.get('/', function (req, res) {
-    if (req.isAuthenticated())
-        res.redirect('/configuration/clusters');
-    else
-        res.render('index');
-});
-
-///* GET sql page. */
-//router.get('/sql', function(req, res) {
-//    res.render('sql', { user: req.user });
-//});
-//
-///* GET clients page. */
-//router.get('/clients', function(req, res) {
-//    res.render('clients', { user: req.user });
-//});
-
-module.exports = router;

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/nodejs/routes/sql.js
----------------------------------------------------------------------
diff --git a/modules/web-control-center/nodejs/routes/sql.js b/modules/web-control-center/nodejs/routes/sql.js
deleted file mode 100644
index ce4565d..0000000
--- a/modules/web-control-center/nodejs/routes/sql.js
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * 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 router = require('express').Router();
-var db = require('../db');
-router.get('/', function(req, res) {
-    res.render('sql/sql');
-});
-
-module.exports = router;

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/nodejs/routes/summary.js
----------------------------------------------------------------------
diff --git a/modules/web-control-center/nodejs/routes/summary.js b/modules/web-control-center/nodejs/routes/summary.js
deleted file mode 100644
index f766945..0000000
--- a/modules/web-control-center/nodejs/routes/summary.js
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * 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 db = require('../db');
-
-var router = require('express').Router();
-
-var generatorXml = require('./generator/xml');
-var generatorJava = require('./generator/java');
-var generatorDocker = require('./generator/docker');
-
-/* GET summary page. */
-router.get('/', function (req, res) {
-    res.render('configuration/summary');
-});
-
-router.post('/generator', function (req, res) {
-    // Get cluster.
-    db.Cluster.findById(req.body._id).populate('caches').exec(function (err, cluster) {
-        if (err)
-            return res.status(500).send(err.message);
-
-        if (!cluster)
-            return res.sendStatus(404);
-
-        var clientCache = req.body.clientNearConfiguration;
-
-        if (clientCache)
-            return res.send({
-                xmlClient: generatorXml.generateClusterConfiguration(cluster, clientCache),
-                javaClient: generatorJava.generateClusterConfiguration(cluster, req.body.javaClass, clientCache)
-            });
-
-        return res.send({
-            xmlServer: generatorXml.generateClusterConfiguration(cluster),
-            javaSnippetServer: generatorJava.generateClusterConfiguration(cluster, false),
-            javaClassServer: generatorJava.generateClusterConfiguration(cluster, true),
-            docker: generatorDocker.generateClusterConfiguration(cluster, '%OS%')
-        });
-    });
-});
-
-router.post('/download', function (req, res) {
-    // Get cluster.
-    db.Cluster.findById(req.body._id).populate('caches').exec(function (err, cluster) {
-        if (err)
-            return res.status(500).send(err.message);
-
-        if (!cluster)
-            return res.sendStatus(404);
-
-        var clientNearConfiguration = req.body.clientNearConfiguration;
-
-        var archiver = require('archiver');
-
-        // Creating archive.
-        var zip = archiver('zip');
-
-        zip.on('error', function (err) {
-            res.status(500).send({error: err.message});
-        });
-
-        // On stream closed we can end the request.
-        res.on('close', function () {
-            return res.status(200).send('OK').end();
-        });
-
-        // Set the archive name.
-        res.attachment(cluster.name + (clientNearConfiguration ? '-client' : '') + '-configuration.zip');
-
-        var generatorCommon = require('./generator/common');
-
-        // Send the file to the page output.
-        zip.pipe(res);
-
-        var javaClass = req.body.javaClass;
-
-        if (!clientNearConfiguration) {
-            zip.append(generatorDocker.generateClusterConfiguration(cluster, req.body.os), {name: "Dockerfile"});
-
-            var props = generatorCommon.generateProperties(cluster);
-
-            if (props)
-                zip.append(props, {name: "secret.properties"});
-        }
-
-        zip.append(generatorXml.generateClusterConfiguration(cluster, clientNearConfiguration), {name: cluster.name + ".xml"})
-            .append(generatorJava.generateClusterConfiguration(cluster, javaClass, clientNearConfiguration),
-                {name: javaClass ? 'ConfigurationFactory.java' : cluster.name + '.snipplet.java'})
-            .finalize();
-    });
-});
-
-module.exports = router;
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/nodejs/views/configuration/caches.jade
----------------------------------------------------------------------
diff --git a/modules/web-control-center/nodejs/views/configuration/caches.jade b/modules/web-control-center/nodejs/views/configuration/caches.jade
deleted file mode 100644
index 3a011fc..0000000
--- a/modules/web-control-center/nodejs/views/configuration/caches.jade
+++ /dev/null
@@ -1,74 +0,0 @@
-//-
-    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 sidebar
-
-append scripts
-    script(src='/caches-controller.js')
-
-include ../includes/controls
-
-block content
-    .docs-header
-        h1 Create and Configure Ignite Caches
-        hr
-    .docs-body(ng-controller='cachesController')
-        +block-callout('{{screenTip.workflowTitle}}', 'joinTip(screenTip.workflowContent)', '{{screenTip.whatsNextTitle}}', 'joinTip(screenTip.whatsNextContent)')
-        .links(ng-hide='caches.length == 0')
-            .padding-dflt
-                lable.labelHeader Caches:
-                table(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'}}
-        .padding-top-dflt
-            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(['col-sm-3'], ['col-sm-3'])
-            .panel-group(bs-collapse data-allow-multiple="true")
-                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...'}}
-            div
-                button.btn.btn-primary(ng-disabled='inputForm.$invalid' ng-click='saveItem()') Save
-                button.btn.btn-primary(ng-show='backupItem._id' ng-disabled='inputForm.$invalid' ng-click='saveItemAs()') Copy
-                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/8a335724/modules/web-control-center/nodejs/views/configuration/clusters.jade
----------------------------------------------------------------------
diff --git a/modules/web-control-center/nodejs/views/configuration/clusters.jade b/modules/web-control-center/nodejs/views/configuration/clusters.jade
deleted file mode 100644
index 81acfed..0000000
--- a/modules/web-control-center/nodejs/views/configuration/clusters.jade
+++ /dev/null
@@ -1,77 +0,0 @@
-//-
-    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 sidebar
-
-append scripts
-    script(src='/clusters-controller.js')
-
-include ../includes/controls
-
-block content
-    .docs-header
-        h1 Create and Configure Ignite Clusters
-        hr
-    .docs-body(ng-controller='clustersController')
-        +block-callout('{{screenTip.workflowTitle}}', 'joinTip(screenTip.workflowContent)', '{{screenTip.whatsNextTitle}}', 'joinTip(screenTip.whatsNextContent)')
-        .links(ng-hide='clusters.length == 0')
-            .padding-dflt
-                lable.labelHeader Clusters:
-                table(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'}}
-        .padding-top-dflt
-            button.btn.btn-primary(ng-click='createItem()') &nbspAdd cluster
-            label(style='margin-left: 10px; margin-right: 10px') Use template:
-            button.btn.btn-default.base-control(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
-            .panel-group(bs-collapse data-allow-multiple="true")
-                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...'}}
-            div
-                button.btn.btn-primary(ng-disabled='inputForm.$invalid' ng-click='saveItem()') Save
-                button.btn.btn-primary(ng-show='backupItem._id' ng-disabled='inputForm.$invalid' ng-click='saveItemAs()') Copy
-                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/8a335724/modules/web-control-center/nodejs/views/configuration/metadata.jade
----------------------------------------------------------------------
diff --git a/modules/web-control-center/nodejs/views/configuration/metadata.jade b/modules/web-control-center/nodejs/views/configuration/metadata.jade
deleted file mode 100644
index d5bac06..0000000
--- a/modules/web-control-center/nodejs/views/configuration/metadata.jade
+++ /dev/null
@@ -1,121 +0,0 @@
-//-
-    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 sidebar
-
-append scripts
-    script(src='/metadata-controller.js')
-
-include ../includes/controls
-
-block content
-    .docs-header
-        h1 Create and Configure Cache Type Metadata
-        hr
-    .docs-body(ng-controller='metadataController')
-        +block-callout('{{screenTip.workflowTitle}}', 'joinTip(screenTip.workflowContent)', '{{screenTip.whatsNextTitle}}', 'joinTip(screenTip.whatsNextContent)')
-        .links(ng-hide='metadatas.length == 0')
-            .padding-dflt
-                lable.labelHeader Types metadata:
-                table(st-table='metadatas')
-                    tbody
-                        tr(ng-repeat='row in metadatas track by row._id')
-                            td.col-sm-6(ng-class='{active: row._id == selectedItem._id}')
-                                a(ng-click='selectItem(row)') {{$index + 1}}) {{row.name}}
-        .padding-top-dflt
-            button.btn.btn-primary(ng-click='panels.activePanel = [0]; createItem()') &nbspAdd metadata
-            label(style='margin-left: 6px; margin-right: 10px') For:
-            button.btn.btn-default(ng-model='template' data-template='/select' data-placeholder='Choose metadata type' 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
-        .panel-group(bs-collapse ng-model='panels.activePanel' data-allow-multiple="false")
-            .panel.panel-default
-                .panel-heading
-                    h3
-                        a(bs-collapse-toggle) Manual
-                .panel-collapse(role="tabpanel" bs-collapse-target)
-                    .panel-body
-                        form.form-horizontal(name='manualForm' ng-if='backupItem' novalidate)
-                            .settings-row(ng-repeat='field in metadataManual')
-                                +form-row
-                            button.btn.btn-primary(ng-disabled='manualForm.$invalid' ng-click='saveItem()') Save
-                            button.btn.btn-primary(ng-show='backupItem._id' ng-disabled='inputForm.$invalid' ng-click='saveItemAs()') Copy
-                            button.btn.btn-primary.btn-second(ng-show='backupItem._id' ng-click='removeItem()') Remove
-            .panel.panel-default
-                .panel-heading
-                    h3
-                        a(bs-collapse-toggle) Load from database
-                .panel-collapse(bs-collapse-target)
-                    .panel-body
-                        form.form-horizontal(name='dbForm' novalidate)
-                            .settings-row(ng-repeat='field in metadataDb')
-                                +form-row
-                        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='dbForm.$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
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/nodejs/views/configuration/sidebar.jade
----------------------------------------------------------------------
diff --git a/modules/web-control-center/nodejs/views/configuration/sidebar.jade b/modules/web-control-center/nodejs/views/configuration/sidebar.jade
deleted file mode 100644
index 7289f3e..0000000
--- a/modules/web-control-center/nodejs/views/configuration/sidebar.jade
+++ /dev/null
@@ -1,39 +0,0 @@
-//-
-    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 ../templates/layout
-
-mixin sidebar-item(ref, num, txt)
-    li
-        a(ng-class='{active: isActive("#{ref}")}' href='#{ref}')
-            span.fa-stack
-                i.fa.fa-circle-thin.fa-stack-2x
-                i.fa.fa-stack-1x #{num}
-            | #{txt}
-
-block container
-    .row
-        .col-sm-2.border-right.section-left.greedy
-            .sidebar-nav(bs-affix)
-                ul.menu(ng-controller='activeLink')
-                    +sidebar-item('/configuration/clusters', 1, 'Clusters')
-                    +sidebar-item('/configuration/metadata', 2, 'Metadata')
-                    +sidebar-item('/configuration/caches', 3, 'Caches')
-                    +sidebar-item('/configuration/summary', 4, '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/8a335724/modules/web-control-center/nodejs/views/configuration/summary.jade
----------------------------------------------------------------------
diff --git a/modules/web-control-center/nodejs/views/configuration/summary.jade b/modules/web-control-center/nodejs/views/configuration/summary.jade
deleted file mode 100644
index 6f2f6d8..0000000
--- a/modules/web-control-center/nodejs/views/configuration/summary.jade
+++ /dev/null
@@ -1,117 +0,0 @@
-//-
-    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 sidebar
-
-append scripts
-    script(src='/summary-controller.js')
-
-    script(src="//cdn.jsdelivr.net/angularjs/1.3.15/angular-animate.min.js")
-    script(src="//cdn.jsdelivr.net/angularjs/1.3.15/angular-sanitize.min.js")
-
-    script(src='//cdnjs.cloudflare.com/ajax/libs/ace/1.2.0/theme-chrome.js')
-    script(src='//cdnjs.cloudflare.com/ajax/libs/ace/1.2.0/mode-xml.js')
-    script(src='//cdnjs.cloudflare.com/ajax/libs/ace/1.2.0/mode-java.js')
-    script(src='//cdnjs.cloudflare.com/ajax/libs/ace/1.2.0/mode-dockerfile.js')
-
-append css
-
-include ../includes/controls
-
-mixin hard-link(ref, txt)
-    a(style='color:#ec1c24' href=ref target="_blank") #{txt}
-
-block content
-    .docs-header
-        h1 Configurations Summary
-        hr
-    .docs-body(ng-controller='summaryController')
-        +block-callout('{{screenTip.workflowTitle}}', 'joinTip(screenTip.workflowContent)', '{{screenTip.whatsNextTitle}}', 'joinTip(screenTip.whatsNextContent)')
-        .padding-dflt(ng-if='clusters.length == 0')
-            | No cluster configured. You can&nbsp;
-            a(href='clusters') configure
-            | &nbsp;it.
-        .padding-dflt(ng-if='clusters.length > 0')
-            lable.labelHeader Clusters:
-            .links
-                table(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}}
-        div(ng-show='selectedItem' role="tab" method='post' action='summary/download')
-            .padding-dflt(bs-collapse data-start-collapsed='false')
-                .panel.panel-default
-                    form.panel-heading(role='tab' method='post' action='summary/download')
-                        input(type="hidden" name="_id" value="{{selectedItem._id}}")
-                        input(type="hidden" name="os" value="{{os}}")
-                        input(type="hidden" name="javaClass" value="{{javaClassServer}}")
-                        h3
-                            a(bs-collapse-toggle) Server
-                            button.btn.btn-primary.pull-right(type='submit' style='margin-top: -5px') Download
-                    .panel-collapse(role="tabpanel" bs-collapse-target)
-                        .panel-body
-                            .configBox(ng-show='selectedItem' bs-tabs)
-                                div(title='<img src="/images/xml.png" width="16px" height="16px"/> XML' bs-pane)
-                                    .configBox(ui-ace='{ onLoad: aceInit, mode: "xml" }' ng-model='xmlServer' style='margin: 0.65em 0;')
-                                div(title='<img src="/images/java.png" width="16px" height="16px"/> Java' bs-pane)
-                                    .settings-row
-                                        .col-sm-1
-                                            label Generate:
-                                        .col-sm-3
-                                            button.form-control(type='button' ng-model='configServer.javaClassServer'  bs-select data-placeholder='{{detail.placeholder}}' bs-options='item.value as item.label for item in javaClassItems' data-sort='false')
-                                    .configBox(ui-ace='{ onLoad: aceInit, mode: "java" }' ng-model='javaServer')
-                                div(title='<img src="/images/docker.png" width="16px" height="16px"/> Dockerfile' bs-pane)
-                                    .settings-row
-                                        p
-                                            +hard-link('https://docs.docker.com/reference/builder', 'Docker')
-                                            | &nbsp;file is a text file with instructions to create Docker image.<br/>
-                                            | To build image you have to store following Docker file with your Ignite XML configuration to the same directory.<br>
-                                            | Also you could use predefined&nbsp;
-                                            +hard-link('https://ignite.incubator.apache.org/download.html#docker', 'Apache Ignite docker image')
-                                            | . For more information about using Ignite with Docker please read&nbsp;
-                                            +hard-link('http://apacheignite.readme.io/docs/docker-deployment', 'documentation')
-                                            |.
-                                        .col-sm-2
-                                            label(for='os') Operation System:
-                                        .col-sm-4
-                                            input#os.form-control(type='text', ng-model='configServer.os' placeholder='debian:8' data-min-length="0" data-html="1" data-auto-select="true" data-animation="am-flip-x" bs-typeahead bs-options='os for os in oss')
-                                    div(ui-ace='{ onLoad: aceInit, mode: "dockerfile" }' ng-model='dockerServer')
-            .padding-dflt(bs-collapse data-start-collapsed='false')
-                .panel.panel-default
-                    form.panel-heading(role='tab' method='post' action='summary/download')
-                        input(type="hidden" name="_id" value="{{selectedItem._id}}")
-                        input(type="hidden" name="javaClass" value="{{javaClassClient}}")
-                        input(type="hidden" name="clientNearConfiguration" value="{{backupItem}}")
-
-                        h3
-                            a(bs-collapse-toggle) Client
-                            button.btn.btn-primary.pull-right(type='submit' style='margin-top: -5px') Download
-                    .panel-collapse(role="tabpanel" bs-collapse-target)
-                        .panel-body
-                            div(ng-show='selectedItem')
-                                .settings-row(ng-repeat='field in clientFields')
-                                    +form-row-custom(['col-sm-3'], ['col-sm-3'])
-                                .configBox(bs-tabs)
-                                    div(title='<img src="/images/xml.png" width="16px" height="16px"/> XML' bs-pane)
-                                        .configBox(ui-ace='{ onLoad: aceInit, mode: "xml" }' ng-model='xmlClient' style='margin: 0.65em 0;')
-                                    div(title='<img src="/images/java.png" width="16px" height="16px"/> Java' bs-pane)
-                                        .settings-row
-                                            .col-sm-1
-                                                label Generate:
-                                            .col-sm-4
-                                                button.form-control(type='button' ng-model='backupItem.javaClassClient' bs-select data-placeholder='{{detail.placeholder}}' bs-options='item.value as item.label for item in javaClassItems' data-sort='false')
-                                        div(ui-ace='{ onLoad: aceInit, mode: "java" }' ng-model='javaClient')

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/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
deleted file mode 100644
index b458fb7..0000000
--- a/modules/web-control-center/nodejs/views/error.jade
+++ /dev/null
@@ -1,22 +0,0 @@
-//-
-    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 templates/layout
-
-block container
-  h1= message
-  h2= error.status
-  pre #{error.stack}


[04/10] incubator-ignite git commit: # ignite-843 moved

Posted by an...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/src/main/js/controllers/models/clusters.json
----------------------------------------------------------------------
diff --git a/modules/web-control-center/src/main/js/controllers/models/clusters.json b/modules/web-control-center/src/main/js/controllers/models/clusters.json
new file mode 100644
index 0000000..d6d7d23
--- /dev/null
+++ b/modules/web-control-center/src/main/js/controllers/models/clusters.json
@@ -0,0 +1,907 @@
+{
+  "screenTip": {
+    "workflowTitle": "Use Clusters view to:",
+    "workflowContent": [
+      "<ul>",
+      "  <li>Configure clusters.</li>",
+      "  <li>Associate clusters with caches.</li>",
+      "</ul>"
+    ],
+    "whatsNextTitle": "What's next:",
+    "whatsNextContent": [
+      "<ul>",
+      "  <li>Configure cache type metadata.</li>",
+      "  <li>Configure caches.</li>",
+      "  <li>Generate XML and java code on Summary view.</li>",
+      "</ul>"
+    ]
+  },
+  "templateTip": [
+    "Use following template to add a new cluster:",
+    "<ul>",
+    "  <li>multicast - cluster with multicast discovery.</li>",
+    "  <li>local - cluster with static ips discovery and pre-configured list of IP addresses.</li>",
+    "</ul>"
+  ],
+  "general": [
+    {
+      "label": "Name",
+      "type": "text",
+      "model": "name",
+      "required": true,
+      "placeholder": "Input name"
+    },
+    {
+      "label": "Caches",
+      "type": "dropdown-multiple",
+      "model": "caches",
+      "placeholder": "Choose caches",
+      "items": "caches",
+      "tip": [
+        "Select caches to start in cluster or add a new cache."
+      ],
+      "addLink": {
+        "label": "Add cache(s)",
+        "ref": "/configuration/caches"
+      }
+    },
+    {
+      "label": "Discovery",
+      "type": "dropdown-details",
+      "path": "discovery",
+      "model": "kind",
+      "required": true,
+      "placeholder": "Choose discovery",
+      "items": "discoveries",
+      "tip": [
+        "Discovery allows to discover remote nodes in grid."
+      ],
+      "details": {
+        "Vm": {
+          "expanded": true,
+          "fields": [
+            {
+              "type": "table-simple",
+              "path": "discovery.Vm",
+              "model": "addresses",
+              "editIdx": -1,
+              "reordering": true,
+              "ipaddress": true,
+              "placeholder": "IP address:port",
+              "tip": [
+                "Addresses may be represented as follows:",
+                "<ul>",
+                "  <li>IP address (e.g. 127.0.0.1, 9.9.9.9, etc);</li>",
+                "  <li>IP address and port (e.g. 127.0.0.1:47500, 9.9.9.9:47501, etc);</li>",
+                "  <li>IP address and port range (e.g. 127.0.0.1:47500..47510, 9.9.9.9:47501..47504, etc);</li>",
+                "  <li>Hostname (e.g. host1.com, host2, etc);</li>",
+                "  <li>Hostname and port (e.g. host1.com:47500, host2:47502, etc).</li>",
+                "  <li>Hostname and port range (e.g. host1.com:47500..47510, host2:47502..47508, etc).</li>",
+                "</ul>",
+                "If port is 0 or not provided then default port will be used (depends on discovery SPI configuration).",
+                "If port range is provided (e.g. host:port1..port2) the following should be considered:",
+                "<ul>",
+                "  <li>port1 < port2 should be true;</li>",
+                "  <li>Both port1 and port2 should be greater than 0.</li>",
+                "</ul>"
+              ]
+            }
+          ]
+        },
+        "Multicast": {
+          "expanded": false,
+          "fields": [
+            {
+              "label": "IP address",
+              "type": "text",
+              "path": "discovery.Multicast",
+              "model": "multicastGroup",
+              "placeholder": "228.1.2.4",
+              "tip": [
+                "IP address of multicast group."
+              ]
+            },
+            {
+              "label": "Port number",
+              "type": "number",
+              "path": "discovery.Multicast",
+              "model": "multicastPort",
+              "max": 65535,
+              "placeholder": 47400,
+              "tip": [
+                "Port number which multicast messages are sent to."
+              ]
+            },
+            {
+              "label": "Waits for reply",
+              "type": "number",
+              "path": "discovery.Multicast",
+              "model": "responseWaitTime",
+              "placeholder": 500,
+              "tip": [
+                "Time in milliseconds IP finder waits for reply to multicast address request."
+              ]
+            },
+            {
+              "label": "Attempts count",
+              "type": "number",
+              "path": "discovery.Multicast",
+              "model": "addressRequestAttempts",
+              "placeholder": 2,
+              "tip": [
+                "Number of attempts to send multicast address request.",
+                "IP finder re-sends request only in case if no reply for previous request is received."
+              ]
+            },
+            {
+              "label": "Local address",
+              "type": "text",
+              "path": "discovery.Multicast",
+              "model": "localAddress",
+              "tip": [
+                "Local host address used by this IP finder.",
+                "If provided address is non-loopback then multicast socket is bound to this interface.",
+                "If local address is not set or is any local address then IP finder creates multicast sockets for all found non-loopback addresses."
+              ]
+            }
+          ]
+        },
+        "S3": {
+          "expanded": true,
+          "fields": [
+            {
+              "label": "Bucket name",
+              "type": "text",
+              "required": true,
+              "path": "discovery.S3",
+              "model": "bucketName",
+              "placeholder": "",
+              "tip": [
+                "Bucket name for IP finder."
+              ]
+            },
+            {
+              "label": "Note, AWS credentials will be generated as stubs.",
+              "type": "label"
+            }
+          ]
+        },
+        "Cloud": {
+          "expanded": true,
+          "fields": [
+            {
+              "label": "Credential",
+              "type": "text",
+              "path": "discovery.Cloud",
+              "model": "credential",
+              "placeholder": "",
+              "tip": [
+                "Credential that is used during authentication on the cloud.",
+                "Depending on a cloud platform it can be a password or access key."
+              ]
+            },
+            {
+              "label": "Path to credential",
+              "type": "text",
+              "path": "discovery.Cloud",
+              "model": "credentialPath",
+              "placeholder": "",
+              "tip": [
+                "Path to a credential that is used during authentication on the cloud.",
+                "Access key or private key should be stored in a plain or PEM file without a passphrase."
+              ]
+            },
+            {
+              "label": "Identity",
+              "type": "text",
+              "required": true,
+              "path": "discovery.Cloud",
+              "model": "identity",
+              "placeholder": "",
+              "tip": [
+                "Identity that is used as a user name during a connection to the cloud.",
+                "Depending on a cloud platform it can be an email address, user name, etc."
+              ]
+            },
+            {
+              "label": "Provider",
+              "type": "text",
+              "required": true,
+              "path": "discovery.Cloud",
+              "model": "provider",
+              "placeholder": "",
+              "tip": [
+                "Cloud provider to use."
+              ]
+            },
+            {
+              "label": "Regions",
+              "type": "table-simple",
+              "path": "discovery.Cloud",
+              "model": "regions",
+              "editIdx": -1,
+              "placeholder": "",
+              "tableTip": [
+                "List of regions where VMs are located.",
+                "If the regions are not set then every region, that a cloud provider has, will be investigated. This could lead to significant performance degradation.",
+                "Note, that some cloud providers, like Google Compute Engine, doesn't have a notion of a region. For such providers a call to this method is redundant."
+              ],
+              "tip": [
+                "Region where VMs are located."
+              ]
+            },
+            {
+              "label": "Zones",
+              "type": "table-simple",
+              "path": "discovery.Cloud",
+              "model": "zones",
+              "editIdx": -1,
+              "placeholder": "",
+              "tableTip": [
+                "List of zones where VMs are located.",
+                "If the zones are not set then every zone from regions, set by {@link #setRegions(Collection)}}, will be taken into account.",
+                "Note, that some cloud providers, like Rackspace, doesn't have a notion of a zone. For such providers a call to this method is redundant."
+              ],
+              "tip": [
+                "Zone where VMs are located."
+              ]
+            }
+          ]
+        },
+        "GoogleStorage": {
+          "expanded": true,
+          "fields": [
+            {
+              "label": "Project name",
+              "type": "text",
+              "required": true,
+              "path": "discovery.GoogleStorage",
+              "model": "projectName",
+              "placeholder": "",
+              "tip": [
+                "Google Cloud Platforms project name.",
+                "Usually this is an auto generated project number (ex. 208709979073) that can be found in 'Overview' section of Google Developer Console."
+              ]
+            },
+            {
+              "label": "Bucket name",
+              "type": "text",
+              "required": true,
+              "path": "discovery.GoogleStorage",
+              "model": "bucketName",
+              "placeholder": "",
+              "tip": [
+                "Google Cloud Storage bucket name.",
+                "If the bucket doesn't exist Ignite will automatically create it.",
+                "However the name must be unique across whole Google Cloud Storage and Service Account Id must be authorized to perform this operation."
+              ]
+            },
+            {
+              "label": "Private key path",
+              "type": "text",
+              "required": true,
+              "path": "discovery.GoogleStorage",
+              "model": "serviceAccountP12FilePath",
+              "placeholder": "",
+              "tip": [
+                "Full path to the private key in PKCS12 format of the Service Account."
+              ]
+            },
+            {
+              "label": "Account id",
+              "type": "text",
+              "required": true,
+              "path": "discovery.GoogleStorage",
+              "model": "accountId",
+              "placeholder": "",
+              "tip": [
+                "Service account ID (typically an e-mail address)."
+              ]
+            }
+          ]
+        },
+        "Jdbc": {
+          "expanded": true,
+          "fields": [
+            {
+              "label": "DB schema should be initialized by Ignite",
+              "type": "check",
+              "path": "discovery.Jdbc",
+              "model": "initSchema",
+              "tip": [
+                "Flag indicating whether DB schema should be initialized by Ignite or was explicitly created by user."
+              ]
+            }
+          ]
+        },
+        "SharedFs": {
+          "expanded": false,
+          "fields": [
+            {
+              "label": "File path",
+              "type": "text",
+              "path": "discovery.SharedFs",
+              "model": "path",
+              "placeholder": "disco/tcp"
+            }
+          ]
+        }
+      }
+    }
+  ],
+  "advanced": [
+    {
+      "label": "Atomics configuration",
+      "tip": [
+        "Configuration for atomic data structures.",
+        "Atomics are distributed across the cluster, essentially enabling performing atomic operations (such as increment-and-get or compare-and-set) with the same globally-visible value."
+      ],
+      "fields": [
+        {
+          "label": "Backups",
+          "type": "number",
+          "path": "atomicConfiguration",
+          "model": "backups",
+          "placeholder": 0,
+          "tip": [
+            "Number of backup nodes."
+          ]
+        },
+        {
+          "label": "Cache mode",
+          "type": "dropdown",
+          "path": "atomicConfiguration",
+          "model": "cacheMode",
+          "placeholder": "PARTITIONED",
+          "items": "cacheModes",
+          "tip": [
+            "Cache modes:",
+            "<ul>",
+            "  <li>Partitioned - in this mode the overall key set will be divided into partitions and all partitions will be split equally between participating nodes.</li>",
+            "  <li>Replicated - in this mode all the keys are distributed to all participating nodes.</li>",
+            "  <li>Local - in this mode caches residing on different grid nodes will not know about each other.</li>",
+            "</ul>"
+          ]
+        },
+        {
+          "label": "Sequence reserve",
+          "type": "number",
+          "path": "atomicConfiguration",
+          "model": "atomicSequenceReserveSize",
+          "placeholder": 1000,
+          "tip": [
+            "Default number of sequence values reserved for IgniteAtomicSequence instances.",
+            "After a certain number has been reserved, consequent increments of sequence will happen locally, without communication with other nodes, until the next reservation has to be made."
+          ]
+        }
+      ]
+    },
+    {
+      "label": "Communication",
+      "tip": [
+        "Cluster communication network properties."
+      ],
+      "fields": [
+        {
+          "label": "Timeout",
+          "type": "number",
+          "model": "networkTimeout",
+          "placeholder": 5000,
+          "tip": [
+            "Maximum timeout in milliseconds for network requests."
+          ]
+        },
+        {
+          "label": "Send retry delay",
+          "type": "number",
+          "model": "networkSendRetryDelay",
+          "placeholder": 1000,
+          "tip": [
+            "Interval in milliseconds between message send retries."
+          ]
+        },
+        {
+          "label": "Send retry count",
+          "type": "number",
+          "model": "networkSendRetryCount",
+          "placeholder": 3,
+          "tip": [
+            "Message send retries count."
+          ]
+        },
+        {
+          "label": "Segment check frequency",
+          "type": "number",
+          "model": "segmentCheckFrequency",
+          "placeholder": 10000,
+          "tip": [
+            "Network segment check frequency in milliseconds.",
+            "If 0, periodic segment check is disabled and segment is checked only on topology changes (if segmentation resolvers are configured)."
+          ]
+        },
+        {
+          "label": "Wait for segment on start",
+          "type": "check",
+          "model": "waitForSegmentOnStart",
+          "tip": [
+            "Wait for segment on start flag.",
+            "<ul>",
+            "  <li>If enabled, node should wait for correct segment on start.</li>",
+            "  <li>If node detects that segment is incorrect on startup and enabled, node waits until segment becomes correct.</li>",
+            "  <li>If segment is incorrect on startup and disabled, exception is thrown.</li>",
+            "</ul>"
+          ]
+        },
+        {
+          "label": "Discovery startup delay",
+          "type": "number",
+          "model": "discoveryStartupDelay",
+          "placeholder": 600000,
+          "tip": [
+            "This value is used to expire messages from waiting list whenever node discovery discrepancies happen."
+          ]
+        }
+      ]
+    },
+    {
+      "label": "Deployment",
+      "tip": [
+        "Task and resources deployment in cluster."
+      ],
+      "fields": [
+        {
+          "label": "Mode",
+          "type": "dropdown",
+          "model": "deploymentMode",
+          "placeholder": "SHARED",
+          "items": "deploymentModes",
+          "tip": [
+            "Task classes and resources sharing mode."
+          ]
+        }
+      ]
+    },
+    {
+      "label": "Events",
+      "tip": [
+        " Grid events are used for notification about what happens within the grid."
+      ],
+      "fields": [
+        {
+          "label": "Include type",
+          "type": "dropdown-multiple",
+          "model": "includeEventTypes",
+          "placeholder": "Choose recorded event types",
+          "items": "events",
+          "tip": [
+            "Array of event types, which will be recorded by GridEventStorageManager#record(Event).",
+            "Note, that either the include event types or the exclude event types can be established."
+          ]
+        }
+      ]
+    },
+    {
+      "label": "Marshaller",
+      "tip": [
+        "Marshaller allows to marshal or unmarshal objects in grid.",
+        "It provides serialization/deserialization mechanism for all instances that are sent across networks or are otherwise serialized."
+      ],
+      "fields": [
+        {
+          "label": "Marshaller",
+          "type": "dropdown-details",
+          "path": "marshaller",
+          "model": "kind",
+          "placeholder": "Choose marshaller",
+          "items": "marshallers",
+          "tip": [
+            "Instance of marshaller to use in grid. If not provided, OptimizedMarshaller will be used on Java HotSpot VM, and JdkMarshaller will be used on other VMs."
+          ],
+          "details": {
+            "OptimizedMarshaller": {
+              "expanded": false,
+              "fields": [
+                {
+                  "label": "Streams pool size",
+                  "type": "number",
+                  "path": "marshaller.OptimizedMarshaller",
+                  "model": "poolSize",
+                  "placeholder": 0,
+                  "tip": [
+                    "Specifies size of cached object streams used by marshaller.",
+                    "Object streams are cached for performance reason to avoid costly recreation for every serialization routine.",
+                    "If 0 (default), pool is not used and each thread has its own cached object stream which it keeps reusing.",
+                    "Since each stream has an internal buffer, creating a stream for each thread can lead to high memory consumption if many large messages are marshalled or unmarshalled concurrently.",
+                    "Consider using pool in this case. This will limit number of streams that can be created and, therefore, decrease memory consumption.",
+                    "NOTE: Using streams pool can decrease performance since streams will be shared between different threads which will lead to more frequent context switching."
+                  ]
+                },
+                {
+                  "label": "Require serializable",
+                  "type": "check",
+                  "path": "marshaller.OptimizedMarshaller",
+                  "model": "requireSerializable",
+                  "tip": [
+                    "Whether marshaller should require Serializable interface or not."
+                  ]
+                }
+              ]
+            }
+          }
+        },
+        {
+          "label": "Marshal local jobs",
+          "type": "check",
+          "model": "marshalLocalJobs",
+          "placeholder": "false",
+          "tip": [
+            "If this flag is enabled, jobs mapped to local node will be marshalled as if it was remote node."
+          ]
+        },
+        {
+          "label": "Keep alive time",
+          "type": "number",
+          "model": "marshallerCacheKeepAliveTime",
+          "placeholder": 10000,
+          "tip": [
+            "Keep alive time of thread pool that is in charge of processing marshaller messages."
+          ]
+        },
+        {
+          "label": "Pool size",
+          "type": "number",
+          "model": "marshallerCacheThreadPoolSize",
+          "placeholder": "max(8, availableProcessors) * 2",
+          "tip": [
+            "Default size of thread pool that is in charge of processing marshaller messages."
+          ]
+        }
+      ]
+    },
+    {
+      "label": "Metrics",
+      "tip": [
+        "Cluster runtime metrics settings."
+      ],
+      "fields": [
+        {
+          "label": "Elapsed time",
+          "type": "number",
+          "model": "metricsExpireTime",
+          "placeholder": "Long.MAX_VALUE",
+          "min": 1,
+          "tip": [
+            "Time in milliseconds after which a certain metric value is considered expired."
+          ]
+        },
+        {
+          "label": "History size",
+          "type": "number",
+          "model": "metricsHistorySize",
+          "placeholder": 10000,
+          "min": 1,
+          "tip": [
+            "Number of metrics kept in history to compute totals and averages."
+          ]
+        },
+        {
+          "label": "Log frequency",
+          "type": "number",
+          "model": "metricsLogFrequency",
+          "placeholder": 60000,
+          "tip": [
+            "Frequency of metrics log print out. To disable set to 0"
+          ]
+        },
+        {
+          "label": "Update frequency",
+          "type": "number",
+          "model": "metricsUpdateFrequency",
+          "placeholder": 60000,
+          "tip": [
+            "Job metrics update frequency in milliseconds.",
+            "<ul>",
+            "  <li>If set to -1 job metrics are never updated.</li>",
+            "  <li>If set to 0 job metrics are updated on each job start and finish.</li>",
+            "  <li>Positive value defines the actual update frequency.</li>",
+            "</ul>"
+          ]
+        }
+      ]
+    },
+    {
+      "label": "Peer Class Loading",
+      "tip": [
+        "Cluster peer class loading settings."
+      ],
+      "fields": [
+        {
+          "label": "Enable peer class loading",
+          "type": "check",
+          "model": "peerClassLoadingEnabled",
+          "tip": [
+            "Enables/disables peer class loading."
+          ]
+        },
+        {
+          "label": "Local class path exclude",
+          "type": "text",
+          "model": "peerClassLoadingLocalClassPathExclude",
+          "placeholder": "[]",
+          "tip": [
+            "List of packages separated by comma from the system classpath that need to be peer-to-peer loaded from task originating node.",
+            "'*' is supported at the end of the package name which means that all sub-packages and their classes are included like in Java package import clause."
+          ]
+        },
+        {
+          "label": "Missed resources cache size",
+          "type": "number",
+          "model": "peerClassLoadingMissedResourcesCacheSize",
+          "placeholder": 100,
+          "tip": [
+            "If size greater than 0, missed resources will be cached and next resource request ignored.",
+            "If size is 0, then request for the resource will be sent to the remote node every time this resource is requested."
+          ]
+        },
+        {
+          "label": "Pool size",
+          "type": "number",
+          "model": "peerClassLoadingThreadPoolSize",
+          "placeholder": "availableProcessors",
+          "tip": [
+            "Thread pool size to use for peer class loading."
+          ]
+        }
+      ]
+    },
+    {
+      "label": "Swap",
+      "tip": [
+        "Settings for overflow data to disk if it cannot fit in memory."
+      ],
+      "fields": [
+        {
+          "label": "Swap space SPI",
+          "type": "dropdown-details",
+          "path": "swapSpaceSpi",
+          "model": "kind",
+          "items": "swapSpaceSpis",
+          "placeholder": "Choose swap SPI",
+          "tip": [
+            "Provides a mechanism in grid for storing data on disk.",
+            "Ignite cache uses swap space to overflow data to disk if it cannot fit in memory."
+          ],
+          "details": {
+            "FileSwapSpaceSpi": {
+              "fields": [
+                {
+                  "label": "Base directory",
+                  "type": "text",
+                  "path": "swapSpaceSpi.FileSwapSpaceSpi",
+                  "model": "baseDirectory",
+                  "placeholder": "swapspace",
+                  "tip": [
+                    "Base directory where to write files."
+                  ]
+                },
+                {
+                  "label": "Read stripe size",
+                  "type": "number",
+                  "path": "swapSpaceSpi.FileSwapSpaceSpi",
+                  "model": "readStripesNumber",
+                  "placeholder": "available CPU cores",
+                  "tip": [
+                    "Read stripe size defines number of file channels to be used concurrently."
+                  ]
+                },
+                {
+                  "label": "Maximum sparsity",
+                  "type": "number",
+                  "path": "swapSpaceSpi.FileSwapSpaceSpi",
+                  "model": "maximumSparsity",
+                  "placeholder": 0.5,
+                  "tip": [
+                    "This property defines maximum acceptable wasted file space to whole file size ratio.",
+                    "When this ratio becomes higher than specified number compacting thread starts working."
+                  ]
+                },
+                {
+                  "label": "Max write queue size",
+                  "type": "number",
+                  "path": "swapSpaceSpi.FileSwapSpaceSpi",
+                  "model": "maxWriteQueueSize",
+                  "placeholder": "1024 * 1024",
+                  "tip": [
+                    "Max write queue size in bytes.",
+                    "If there are more values are waiting for being written to disk then specified size, SPI will block on store operation."
+                  ]
+                },
+                {
+                  "label": "Write buffer size",
+                  "type": "number",
+                  "path": "swapSpaceSpi.FileSwapSpaceSpi",
+                  "model": "writeBufferSize",
+                  "placeholder": "Available CPU cores",
+                  "tip": [
+                    "Write buffer size in bytes.",
+                    "Write to disk occurs only when this buffer is full."
+                  ]
+                }
+              ]
+            }
+          }
+        }
+      ]
+    },
+    {
+      "label": "Time configuration",
+      "tip": [
+        "Time settings for CLOCK write ordering mode."
+      ],
+      "fields": [
+        {
+          "label": "Samples size",
+          "type": "number",
+          "model": "clockSyncSamples",
+          "placeholder": 8,
+          "tip": [
+            "Number of samples used to synchronize clocks between different nodes.",
+            "Clock synchronization is used for cache version assignment in CLOCK order mode."
+          ]
+        },
+        {
+          "label": "Frequency",
+          "type": "number",
+          "model": "clockSyncFrequency",
+          "placeholder": 120000,
+          "tip": [
+            "Frequency at which clock is synchronized between nodes, in milliseconds.",
+            "Clock synchronization is used for cache version assignment in CLOCK order mode."
+          ]
+        },
+        {
+          "label": "Port base",
+          "type": "number",
+          "model": "timeServerPortBase",
+          "max": 65535,
+          "placeholder": 31100,
+          "tip": [
+            "Time server provides clock synchronization between nodes.",
+            "Base UPD port number for grid time server. Time server will be started on one of free ports in range."
+          ]
+        },
+        {
+          "label": "Port range",
+          "type": "number",
+          "model": "timeServerPortRange",
+          "placeholder": 100,
+          "tip": [
+            "Time server port range."
+          ]
+        }
+      ]
+    },
+    {
+      "label": "Thread pools size",
+      "tip": [
+        "Settings for node thread pools."
+      ],
+      "fields": [
+        {
+          "label": "Public",
+          "type": "number",
+          "model": "publicThreadPoolSize",
+          "placeholder": "max(8, availableProcessors) * 2",
+          "tip": [
+            "Thread pool that is in charge of processing ComputeJob, GridJobs and user messages sent to node."
+          ]
+        },
+        {
+          "label": "System",
+          "type": "number",
+          "model": "systemThreadPoolSize",
+          "placeholder": "max(8, availableProcessors) * 2",
+          "tip": [
+            "Thread pool that is in charge of processing internal system messages."
+          ]
+        },
+        {
+          "label": "Management",
+          "type": "number",
+          "model": "managementThreadPoolSize",
+          "placeholder": 4,
+          "tip": [
+            "Thread pool that is in charge of processing internal and Visor ComputeJob, GridJobs."
+          ]
+        },
+        {
+          "label": "IGFS",
+          "type": "number",
+          "model": "igfsThreadPoolSize",
+          "placeholder": "availableProcessors",
+          "tip": [
+            "Thread pool that is in charge of processing outgoing IGFS messages."
+          ]
+        }
+      ]
+    },
+    {
+      "label": "Transactions",
+      "tip": [
+        "Settings for transactions."
+      ],
+      "fields": [
+        {
+          "label": "Concurrency",
+          "type": "dropdown",
+          "path": "transactionConfiguration",
+          "model": "defaultTxConcurrency",
+          "placeholder": "PESSIMISTIC",
+          "items": "transactionConcurrency",
+          "tip": [
+            "Cache transaction concurrency to use when one is not explicitly specified."
+          ]
+        },
+        {
+          "label": "Isolation",
+          "type": "dropdown",
+          "path": "transactionConfiguration",
+          "model": "transactionIsolation",
+          "placeholder": "REPEATABLE_READ",
+          "items": "transactionIsolation",
+          "tip": [
+            "Default transaction isolation."
+          ]
+        },
+        {
+          "label": "Default timeout",
+          "type": "number",
+          "path": "transactionConfiguration",
+          "model": "defaultTxTimeout",
+          "placeholder": 0,
+          "tip": [
+            "Default transaction timeout."
+          ]
+        },
+        {
+          "label": "Pessimistic log cleanup delay",
+          "type": "number",
+          "path": "transactionConfiguration",
+          "model": "pessimisticTxLogLinger",
+          "placeholder": 10000,
+          "tip": [
+            "Delay, in milliseconds, after which pessimistic recovery entries will be cleaned up for failed node."
+          ]
+        },
+        {
+          "label": "Pessimistic log size",
+          "type": "number",
+          "path": "transactionConfiguration",
+          "model": "pessimisticTxLogSize",
+          "placeholder": 0,
+          "tip": [
+            "Size of pessimistic transactions log stored on node in order to recover transaction commit if originating node has left grid before it has sent all messages to transaction nodes."
+          ]
+        },
+        {
+          "label": "Manager lookup",
+          "type": "text",
+          "model": "txManagerLookupClassName",
+          "tip": [
+            "Class name of transaction manager finder for integration for JEE app servers."
+          ]
+        },
+        {
+          "label": "Enable serializable cache transactions",
+          "type": "check",
+          "path": "transactionConfiguration",
+          "model": "txSerializableEnabled",
+          "tip": [
+            "Flag to enable/disable isolation level for cache transactions.",
+            "Serializable level does carry certain overhead and if not used, should be disabled."
+          ]
+        }
+      ]
+    }
+  ]
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/src/main/js/controllers/models/metadata.json
----------------------------------------------------------------------
diff --git a/modules/web-control-center/src/main/js/controllers/models/metadata.json b/modules/web-control-center/src/main/js/controllers/models/metadata.json
new file mode 100644
index 0000000..3248f7a
--- /dev/null
+++ b/modules/web-control-center/src/main/js/controllers/models/metadata.json
@@ -0,0 +1,230 @@
+{
+  "screenTip": {
+    "workflowTitle": "Use Cache Type Metadata view to:",
+    "workflowContent": [
+      "<ul>",
+      "  <li>Manually configure metadata for queries and/or store.</li>",
+      "  <li>Configure metadata from database tables metadata.</li>",
+      "</ul>"
+    ],
+    "whatsNextTitle": "What's next:",
+    "whatsNextContent": [
+      "<ul>",
+      "  <li>Configure clusters.</li>",
+      "  <li>Associate caches with metadata.</li>",
+      "  <li>Generate XML and java code on Summary view.</li>",
+      "</ul>"
+    ]
+  },
+  "templateTip": [
+    "Use following template for metadata:",
+    "<ul>",
+    "  <li>query - Create cache type metadata to use with queries only.</li>",
+    "  <li>store - Create cache type metadata to use with JDBC POJO store only.</li>",
+    "  <li>both - Create cache type metadata to use with query and store.</li>",
+    "</ul>"
+  ],
+  "metadataManual": [
+    {
+      "label": "Name",
+      "type": "text",
+      "model": "name",
+      "required": true,
+      "placeholder": "Input name"
+    },
+    {
+      "label": "Metadata for",
+      "type": "dropdown",
+      "model": "kind",
+      "items": "kinds",
+      "tip": [
+        "Use following template for metadata:",
+        "<ul>",
+        "  <li>query - Create cache type metadata to use with queries only.</li>",
+        "  <li>store - Create cache type metadata to use with JDBC POJO store only.</li>",
+        "  <li>both - Create cache type metadata to use with query and store.</li>",
+        "</ul>"
+      ]
+    },
+    {
+      "label": "Database schema",
+      "type": "text",
+      "model": "databaseSchema",
+      "hide": "backupItem.kind == 'query'",
+      "placeholder": "Input DB schema name",
+      "tip": [
+        "Schema name in database."
+      ]
+    },
+    {
+      "label": "Database table",
+      "type": "text",
+      "model": "databaseTable",
+      "hide": "backupItem.kind == 'query'",
+      "placeholder": "Input DB table name",
+      "tip": [
+        "Table name in database."
+      ]
+    },
+    {
+      "label": "Key type",
+      "type": "text",
+      "model": "keyType",
+      "required": true,
+      "placeholder": "Full class name for Key",
+      "tip": [
+        "Key class used to store key in cache."
+      ]
+    },
+    {
+      "label": "Value type",
+      "type": "text",
+      "model": "valueType",
+      "required": true,
+      "placeholder": "Full class name for Value",
+      "tip": [
+        "Value class used to store value in cache."
+      ]
+    },
+    {
+      "label": "Key fields",
+      "type": "dbFields",
+      "model": "keyFields",
+      "keyName": "name",
+      "valueName": "className",
+      "hide": "backupItem.kind == 'query'",
+      "tip": [
+        "Collection of key fields descriptions for CacheJdbcPojoStore."
+      ]
+    },
+    {
+      "label": "Value fields",
+      "type": "dbFields",
+      "model": "valueFields",
+      "keyName": "name",
+      "valueName": "className",
+      "hide": "backupItem.kind == 'query'",
+      "tip": [
+        "Collection of value fields descriptions for CacheJdbcPojoStore.."
+      ]
+    },
+    {
+      "label": "Query fields",
+      "type": "queryFields",
+      "model": "queryFields",
+      "keyName": "name",
+      "valueName": "className",
+      "hide": "backupItem.kind != 'query'",
+      "tip": [
+        "Collection of name-to-type mappings to be queried, in addition to indexed fields."
+      ]
+    },
+    {
+      "label": "Ascending fields",
+      "type": "queryFields",
+      "model": "ascendingFields",
+      "keyName": "name",
+      "valueName": "className",
+      "hide": "backupItem.kind != 'query'",
+      "tip": [
+        "Collection of name-to-type mappings to index in ascending order."
+      ]
+    },
+    {
+      "label": "Descending fields",
+      "type": "queryFields",
+      "model": "descendingFields",
+      "keyName": "name",
+      "valueName": "className",
+      "hide": "backupItem.kind != 'query'",
+      "tip": [
+        "Collection of name-to-type mappings to index in descending order."
+      ]
+    },
+    {
+      "label": "Text fields",
+      "type": "table-simple",
+      "model": "textFields",
+      "hide": "backupItem.kind != 'query'",
+      "placeholder": "Field name",
+      "tableTip": [
+        "Fields to index as text."
+      ],
+      "tip": [
+        "Field to index as text."
+      ]
+    },
+    {
+      "label": "Groups",
+      "type": "queryGroups",
+      "model": "groups",
+      "hide": "backupItem.kind != 'query'",
+      "tip": [
+        "Collection of group indexes."
+      ]
+    }
+  ],
+  "metadataDb": [
+    {
+      "label": "Name",
+      "type": "text",
+      "model": "name"
+    },
+    {
+      "label": "Database type",
+      "type": "dropdown",
+      "model": "dbType",
+      "placeholder": "Choose database",
+      "items": "databases",
+      "tip": [
+        "Select database type to connect for loading tables metadata."
+      ]
+    },
+    {
+      "label": "Database name",
+      "type": "text",
+      "model": "dbName",
+      "tip": [
+        "Database name to connect for loading tables metadata."
+      ]
+    },
+    {
+      "label": "Host",
+      "type": "text",
+      "model": "host",
+      "placeholder": "IP address or host",
+      "tip": [
+        "IP address or host name where database server deployed."
+      ]
+    },
+    {
+      "label": "Port",
+      "type": "number",
+      "model": "port",
+      "max": 65535,
+      "placeholder": "",
+      "tip": [
+        "Port number for connecting to database."
+      ]
+    },
+    {
+      "label": "User",
+      "type": "text",
+      "model": "user",
+      "placeholder": "",
+      "tip": [
+        "User name for connecting to database."
+      ]
+    },
+    {
+      "label": "Password",
+      "type": "password",
+      "model": "password",
+      "placeholder": "",
+      "tip": [
+        "Password for connecting to database.",
+        "Note, password would not be saved."
+      ]
+    }
+  ]
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/src/main/js/controllers/models/summary.json
----------------------------------------------------------------------
diff --git a/modules/web-control-center/src/main/js/controllers/models/summary.json b/modules/web-control-center/src/main/js/controllers/models/summary.json
new file mode 100644
index 0000000..056291c
--- /dev/null
+++ b/modules/web-control-center/src/main/js/controllers/models/summary.json
@@ -0,0 +1,163 @@
+{
+  "screenTip": {
+    "workflowTitle": "Use Summary view to:",
+    "workflowContent": [
+      "<ul>",
+      "  <li>See XML and java code for server nodes configurations.</li>",
+      "  <li>See XML and java code for client nodes configurations.</li>",
+      "</ul>"
+    ],
+    "whatsNextTitle": "What's next:",
+    "whatsNextContent": [
+      "<ul>",
+      "  <li>Download XML or java code configuration.</li>",
+      "  <li>Start Ignite cluster with downloaded configuration.</li>",
+      "</ul>"
+    ]
+  },
+  "clientFields": [
+    {
+      "label": "Near cache start size",
+      "type": "number",
+      "path": "nearConfiguration",
+      "model": "nearStartSize",
+      "placeholder": 375000,
+      "tip": [
+        "Initial cache size for near cache which will be used to pre-create internal hash table after start."
+      ]
+    },
+    {
+      "label": "Near cache eviction policy",
+      "type": "dropdown-details",
+      "path": "nearConfiguration.nearEvictionPolicy",
+      "model": "kind",
+      "placeholder": "Choose eviction policy",
+      "items": "evictionPolicies",
+      "tip": [
+        "Cache expiration policy."
+      ],
+      "details": {
+        "LRU": {
+          "expanded": false,
+          "fields": [
+            {
+              "label": "Batch size",
+              "type": "number",
+              "path": "nearConfiguration.nearEvictionPolicy.LRU",
+              "model": "batchSize",
+              "placeholder": 1,
+              "tip": [
+                "Number of entries to remove on shrink."
+              ]
+            },
+            {
+              "label": "Max memory size",
+              "type": "number",
+              "path": "nearConfiguration.nearEvictionPolicy.LRU",
+              "model": "maxMemorySize",
+              "placeholder": 0,
+              "tip": [
+                "Maximum allowed cache size in bytes."
+              ]
+            },
+            {
+              "label": "Max size",
+              "type": "number",
+              "path": "nearConfiguration.nearEvictionPolicy.LRU",
+              "model": "maxSize",
+              "placeholder": 100000,
+              "tip": [
+                "Maximum allowed size of cache before entry will start getting evicted."
+              ]
+            }
+          ]
+        },
+        "RND": {
+          "expanded": false,
+          "fields": [
+            {
+              "label": "Max size",
+              "type": "number",
+              "path": "nearConfiguration.nearEvictionPolicy.RND",
+              "model": "maxSize",
+              "placeholder": 100000,
+              "tip": [
+                "Maximum allowed size of cache before entry will start getting evicted."
+              ]
+            }
+          ]
+        },
+        "FIFO": {
+          "expanded": false,
+          "fields": [
+            {
+              "label": "Batch size",
+              "type": "number",
+              "path": "nearConfiguration.nearEvictionPolicy.FIFO",
+              "model": "batchSize",
+              "placeholder": 1,
+              "tip": [
+                "Number of entries to remove on shrink."
+              ]
+            },
+            {
+              "label": "Max memory size",
+              "type": "number",
+              "path": "nearConfiguration.nearEvictionPolicy.FIFO",
+              "model": "maxMemorySize",
+              "placeholder": 0,
+              "tip": [
+                "Maximum allowed cache size in bytes."
+              ]
+            },
+            {
+              "label": "Max size",
+              "type": "number",
+              "path": "nearConfiguration.nearEvictionPolicy.FIFO",
+              "model": "maxSize",
+              "placeholder": 100000,
+              "tip": [
+                "Maximum allowed size of cache before entry will start getting evicted."
+              ]
+            }
+          ]
+        },
+        "SORTED": {
+          "expanded": false,
+          "fields": [
+            {
+              "label": "Batch size",
+              "type": "number",
+              "path": "nearConfiguration.nearEvictionPolicy.SORTED",
+              "model": "batchSize",
+              "placeholder": 1,
+              "tip": [
+                "Number of entries to remove on shrink."
+              ]
+            },
+            {
+              "label": "Max memory size",
+              "type": "number",
+              "path": "nearConfiguration.nearEvictionPolicy.SORTED",
+              "model": "maxMemorySize",
+              "placeholder": 0,
+              "tip": [
+                "Maximum allowed cache size in bytes."
+              ]
+            },
+            {
+              "label": "Max size",
+              "type": "number",
+              "path": "nearConfiguration.nearEvictionPolicy.SORTED",
+              "model": "maxSize",
+              "placeholder": 100000,
+              "tip": [
+                "Maximum allowed size of cache before entry will start getting evicted."
+              ]
+            }
+          ]
+        }
+      }
+    }
+  ]
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/src/main/js/controllers/profile-controller.js
----------------------------------------------------------------------
diff --git a/modules/web-control-center/src/main/js/controllers/profile-controller.js b/modules/web-control-center/src/main/js/controllers/profile-controller.js
new file mode 100644
index 0000000..a67df63
--- /dev/null
+++ b/modules/web-control-center/src/main/js/controllers/profile-controller.js
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+
+controlCenterModule.controller('profileController', ['$scope', '$http', '$common', function ($scope, $http, $common) {
+    $scope.profileUser = angular.copy($scope.user);
+
+    $scope.saveUser = function () {
+        var profile = $scope.profileUser;
+
+        if (profile) {
+            var userName = profile.username;
+            var changeUsername = userName != $scope.user.username;
+
+            var email = profile.email;
+            var changeEmail = email != $scope.user.email;
+
+            if (changeUsername || changeEmail || profile.changePassword) {
+                $http.post('/profile/saveUser', {
+                    _id: profile._id,
+                    userName: changeUsername ? userName : undefined,
+                    email: changeEmail ? email : undefined,
+                    newPassword: profile.changePassword ? profile.newPassword : undefined
+                }).success(function (user) {
+                    $common.showInfo('Profile saved.');
+
+                    if (changeUsername)
+                        $scope.user.username = userName;
+
+                    if (changeEmail)
+                        $scope.user.email = email;
+                }).error(function (err) {
+                    $common.showError('Failed to save profile: ' + $common.errorMessage(err));
+                });
+            }
+        }
+    };
+}]);
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/src/main/js/controllers/summary-controller.js
----------------------------------------------------------------------
diff --git a/modules/web-control-center/src/main/js/controllers/summary-controller.js b/modules/web-control-center/src/main/js/controllers/summary-controller.js
new file mode 100644
index 0000000..1291683
--- /dev/null
+++ b/modules/web-control-center/src/main/js/controllers/summary-controller.js
@@ -0,0 +1,164 @@
+/*
+ * 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.
+ */
+
+controlCenterModule.controller('summaryController', ['$scope', '$http', '$common', function ($scope, $http, $common) {
+    $scope.joinTip = $common.joinTip;
+    $scope.getModel = $common.getModel;
+
+    $scope.javaClassItems = [
+        {label: 'snippet', value: false},
+        {label: 'factory class', value: true}
+    ];
+
+    $scope.evictionPolicies = [
+        {value: 'LRU', label: 'LRU'},
+        {value: 'RND', label: 'Random'},
+        {value: 'FIFO', label: 'FIFO'},
+        {value: 'SORTED', label: 'Sorted'},
+        {value: undefined, label: 'Not set'}
+    ];
+
+    $scope.oss = ['debian:8', 'ubuntu:14.10'];
+
+    $scope.configServer = {javaClassServer: false, os: undefined};
+    $scope.backupItem = {javaClassClient: false};
+
+    $http.get('/models/summary.json')
+        .success(function (data) {
+            $scope.screenTip = data.screenTip;
+            $scope.clientFields = data.clientFields;
+        })
+        .error(function (errMsg) {
+            $common.showError(errMsg);
+        });
+
+    $scope.clusters = [];
+
+    $scope.aceInit = function (editor) {
+        editor.setReadOnly(true);
+        editor.setOption("highlightActiveLine", false);
+
+        editor.setTheme('ace/theme/chrome');
+    };
+
+    $scope.reloadServer = function () {
+        $scope.javaServer = $scope.configServer.javaClassServer ? $scope.configServer.javaClass : $scope.configServer.javaSnippet;
+
+        if ($scope.configServer.docker) {
+            var os = $scope.configServer.os ? $scope.configServer.os : $scope.oss[0];
+
+            $scope.dockerServer = $scope.configServer.docker.replace(new RegExp('\%OS\%', 'g'), os);
+        }
+    };
+
+    $scope.selectItem = function (cluster) {
+        if (!cluster)
+            return;
+
+        $scope.selectedItem = cluster;
+
+        $scope.$watch('javaClassServer', $scope.reloadServer);
+        $scope.$watch('os', $scope.reloadServer);
+
+        $scope.generateServer(cluster);
+
+        $scope.reloadServer();
+
+        $scope.$watch('configServer', function () {
+            $scope.reloadServer();
+        }, true);
+
+        $scope.$watch('backupItem', function () {
+            $scope.generateClient();
+        }, true);
+    };
+
+    $scope.generateServer = function (cluster) {
+        $http.post('summary/generator', {_id: cluster._id})
+            .success(function (data) {
+                $scope.xmlServer = data.xmlServer;
+
+                $scope.configServer.javaClass = data.javaClassServer;
+                $scope.configServer.javaSnippet = data.javaSnippetServer;
+                $scope.configServer.docker = data.docker;
+            }).error(function (errMsg) {
+                $common.showError('Failed to generate config: ' + errMsg);
+            });
+    };
+
+    $scope.generateClient = function () {
+        $http.post('summary/generator', {
+            _id: $scope.selectedItem._id, javaClass: $scope.backupItem.javaClassClient,
+            clientNearConfiguration: $scope.backupItem.nearConfiguration
+        })
+            .success(function (data) {
+                $scope.xmlClient = data.xmlClient;
+                $scope.javaClient = data.javaClient;
+            }).error(function (errMsg) {
+                $common.showError('Failed to generate config: ' + errMsg);
+            });
+    };
+
+    $scope.download = function () {
+        $http.post('summary/download', {_id: $scope.selectedItem._id, javaClass: $scope.javaClass, os: $scope.os})
+            .success(function (data) {
+                var file = document.createElement('a');
+
+                file.setAttribute('href', 'data:application/octet-stream;charset=utf-8,' + data);
+                file.setAttribute('download', $scope.selectedItem.name + '-configuration.zip');
+
+                file.style.display = 'none';
+
+                document.body.appendChild(file);
+
+                file.click();
+
+                document.body.removeChild(file);
+            })
+            .error(function (errMsg) {
+                $common.showError('Failed to generate zip: ' + errMsg);
+            });
+    };
+
+    $http.post('clusters/list').success(function (data) {
+        $scope.clusters = data.clusters;
+
+        if ($scope.clusters.length > 0) {
+            var restoredId = sessionStorage.summarySelectedId;
+
+            var selectIdx = 0;
+
+            if (restoredId) {
+                var idx = _.findIndex($scope.clusters, function (cluster) {
+                    return cluster._id == restoredId;
+                });
+
+                if (idx >= 0)
+                    selectIdx = idx;
+                else
+                    delete sessionStorage.summarySelectedId;
+            }
+
+            $scope.selectItem($scope.clusters[selectIdx]);
+
+            $scope.$watch('selectedItem', function (val) {
+                if (val)
+                    sessionStorage.summarySelectedId = val._id;
+            }, true);
+        }
+    });
+}]);

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/src/main/js/db.js
----------------------------------------------------------------------
diff --git a/modules/web-control-center/src/main/js/db.js b/modules/web-control-center/src/main/js/db.js
new file mode 100644
index 0000000..e34272c
--- /dev/null
+++ b/modules/web-control-center/src/main/js/db.js
@@ -0,0 +1,358 @@
+/*
+ * 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 config = require('./helpers/configuration-loader.js');
+
+// Mongoose for mongodb.
+var mongoose = require('mongoose'),
+    Schema = mongoose.Schema,
+    ObjectId = mongoose.Schema.Types.ObjectId,
+    passportLocalMongoose = require('passport-local-mongoose');
+
+// Connect to mongoDB database.
+mongoose.connect(config.get('mongoDB:url'), {server: {poolSize: 4}});
+
+// Define account model.
+var AccountSchema = new Schema({
+    username: String,
+    email: String,
+    lastLogin: Date,
+    admin: Boolean
+});
+
+AccountSchema.plugin(passportLocalMongoose, {usernameField: 'email', limitAttempts: true, lastLoginField: 'lastLogin',
+    usernameLowerCase: true});
+
+AccountSchema.set('toJSON', {
+    transform: function(doc, ret) {
+        return {
+            _id: ret._id,
+            email: ret.email,
+            username: ret.username,
+            admin: ret.admin,
+            lastLogin: ret.lastLogin
+        };
+    }
+});
+
+exports.Account = mongoose.model('Account', AccountSchema);
+
+// Define space model.
+exports.Space = mongoose.model('Space', new Schema({
+    name: String,
+    owner: {type: ObjectId, ref: 'Account'},
+    usedBy: [{
+        permission: {type: String, enum: ['VIEW', 'FULL']},
+        account: {type: ObjectId, ref: 'Account'}
+    }]
+}));
+
+// Define cache type metadata model.
+var CacheTypeMetadataSchema = new Schema({
+    space: {type: ObjectId, ref: 'Space'},
+    name: String,
+    kind: {type: String, enum: ['query', 'store', 'both']},
+    databaseSchema: String,
+    databaseTable: String,
+    keyType: String,
+    valueType: String,
+    keyFields: [{dbName: String, dbType: String, javaName: String, javaType: String}],
+    valueFields: [{dbName: String, dbType: String, javaName: String, javaType: String}],
+    queryFields: [{name: String, className: String}],
+    ascendingFields: [{name: String, className: String}],
+    descendingFields:  [{name: String, className: String}],
+    textFields: [String],
+    groups: [{name: String, fields: [{name: String, className: String, direction: String}]}]
+});
+
+exports.CacheTypeMetadata = mongoose.model('CacheTypeMetadata', CacheTypeMetadataSchema);
+
+// Define cache model.
+var CacheSchema = new Schema({
+    space: {type: ObjectId, ref: 'Space'},
+    name: String,
+    mode: {type: String, enum: ['PARTITIONED', 'REPLICATED', 'LOCAL']},
+    atomicityMode: {type: String, enum: ['ATOMIC', 'TRANSACTIONAL']},
+
+    backups: Number,
+    memoryMode: {type: String, enum: ['ONHEAP_TIERED', 'OFFHEAP_TIERED', 'OFFHEAP_VALUES']},
+    offHeapMaxMemory: Number,
+    startSize: Number,
+    swapEnabled: Boolean,
+
+    evictionPolicy: {
+        kind: {type: String, enum: ['LRU', 'RND', 'FIFO', 'Sorted']},
+        LRU: {
+            batchSize: Number,
+            maxMemorySize: Number,
+            maxSize: Number
+        },
+        RND: {
+            maxSize: Number
+        },
+        FIFO: {
+            batchSize: Number,
+            maxMemorySize: Number,
+            maxSize: Number
+        },
+        SORTED: {
+            batchSize: Number,
+            maxMemorySize: Number,
+            maxSize: Number
+        }
+    },
+
+    rebalanceMode: {type: String, enum: ['SYNC', 'ASYNC', 'NONE']},
+    rebalanceThreadPoolSize: Number,
+    rebalanceBatchSize: Number,
+    rebalanceOrder: Number,
+    rebalanceDelay: Number,
+    rebalanceTimeout: Number,
+    rebalanceThrottle: Number,
+
+    cacheStoreFactory: {
+        kind: {
+            type: String,
+            enum: ['CacheJdbcPojoStoreFactory', 'CacheJdbcBlobStoreFactory', 'CacheHibernateBlobStoreFactory']
+        },
+        CacheJdbcPojoStoreFactory: {
+            dataSourceBean: String,
+            dialect: {
+                type: String,
+                enum: ['Oracle', 'DB2', 'SQLServer', 'MySQL', 'PosgreSQL', 'H2']
+            }
+        },
+        CacheJdbcBlobStoreFactory: {
+            user: String,
+            dataSourceBean: String,
+            initSchema: Boolean,
+            createTableQuery: String,
+            loadQuery: String,
+            insertQuery: String,
+            updateQuery: String,
+            deleteQuery: String
+        },
+        CacheHibernateBlobStoreFactory: {
+            hibernateProperties: [String]
+        }
+    },
+    loadPreviousValue: Boolean,
+    readThrough: Boolean,
+    writeThrough: Boolean,
+
+    writeBehindEnabled: Boolean,
+    writeBehindBatchSize: Number,
+    writeBehindFlushSize: Number,
+    writeBehindFlushFrequency: Number,
+    writeBehindFlushThreadCount: Number,
+
+    invalidate: Boolean,
+    defaultLockTimeout: Number,
+    transactionManagerLookupClassName: String,
+
+    sqlEscapeAll: Boolean,
+    sqlOnheapRowCacheSize: Number,
+    longQueryWarningTimeout: Number,
+    indexedTypes: [{keyClass: String, valueClass: String}],
+    sqlFunctionClasses: [String],
+    statisticsEnabled: Boolean,
+    managementEnabled: Boolean,
+    readFromBackup: Boolean,
+    copyOnRead: Boolean,
+    maxConcurrentAsyncOperations: Number,
+    nearConfiguration: {
+        nearStartSize: Number,
+        nearEvictionPolicy: {
+            kind: {type: String, enum: ['LRU', 'RND', 'FIFO', 'Sorted']},
+            LRU: {
+                batchSize: Number,
+                maxMemorySize: Number,
+                maxSize: Number
+            },
+            RND: {
+                maxSize: Number
+            },
+            FIFO: {
+                batchSize: Number,
+                maxMemorySize: Number,
+                maxSize: Number
+            },
+            SORTED: {
+                batchSize: Number,
+                maxMemorySize: Number,
+                maxSize: Number
+            }
+        }
+    }
+});
+
+exports.Cache = mongoose.model('Cache', CacheSchema);
+
+// Define cluster schema.
+var ClusterSchema = new Schema({
+    space: {type: ObjectId, ref: 'Space'},
+    name: String,
+    discovery: {
+        kind: {type: String, enum: ['Vm', 'Multicast', 'S3', 'Cloud', 'GoogleStorage', 'Jdbc', 'SharedFs']},
+        Vm: {
+            addresses: [String]
+        },
+        Multicast: {
+            multicastGroup: String,
+            multicastPort: Number,
+            responseWaitTime: Number,
+            addressRequestAttempts: Number,
+            localAddress: String
+        },
+        S3: {
+            bucketName: String
+        },
+        Cloud: {
+            credential: String,
+            credentialPath: String,
+            identity: String,
+            provider: String,
+            regions: [String],
+            zones:  [String]
+        },
+        GoogleStorage: {
+            projectName: String,
+            bucketName: String,
+            serviceAccountP12FilePath: String,
+            addrReqAttempts: String
+        },
+        Jdbc: {
+            initSchema: Boolean
+        },
+        SharedFs: {
+            path: String
+        }
+    },
+    atomicConfiguration: {
+        backups: Number,
+        cacheMode: {type: String, enum: ['LOCAL', 'REPLICATED', 'PARTITIONED']},
+        atomicSequenceReserveSize: Number
+    },
+    caches: [{type: ObjectId, ref: 'Cache'}],
+    cacheSanityCheckEnabled: Boolean,
+    clockSyncSamples: Number,
+    clockSyncFrequency: Number,
+    deploymentMode: {type: String, enum: ['PRIVATE', 'ISOLATED', 'SHARED', 'CONTINUOUS']},
+    discoveryStartupDelay: Number,
+    igfsThreadPoolSize: Number,
+    includeEventTypes: [{
+        type: String, enum: ['EVTS_CHECKPOINT', 'EVTS_DEPLOYMENT', 'EVTS_ERROR', 'EVTS_DISCOVERY',
+            'EVTS_JOB_EXECUTION', 'EVTS_TASK_EXECUTION', 'EVTS_CACHE', 'EVTS_CACHE_REBALANCE', 'EVTS_CACHE_LIFECYCLE',
+            'EVTS_CACHE_QUERY', 'EVTS_SWAPSPACE', 'EVTS_IGFS']
+    }],
+    managementThreadPoolSize: Number,
+    marshaller: {
+        kind: {type: String, enum: ['OptimizedMarshaller', 'JdkMarshaller']},
+        OptimizedMarshaller: {
+            poolSize: Number,
+            requireSerializable: Boolean
+        }
+    },
+    marshalLocalJobs: Boolean,
+    marshallerCacheKeepAliveTime: Number,
+    marshallerCacheThreadPoolSize: Number,
+    metricsExpireTime: Number,
+    metricsHistorySize: Number,
+    metricsLogFrequency: Number,
+    metricsUpdateFrequency: Number,
+    networkTimeout: Number,
+    networkSendRetryDelay: Number,
+    networkSendRetryCount: Number,
+    peerClassLoadingEnabled: Boolean,
+    peerClassLoadingLocalClassPathExclude: [String],
+    peerClassLoadingMissedResourcesCacheSize: Number,
+    peerClassLoadingThreadPoolSize: Number,
+    publicThreadPoolSize: Number,
+    segmentCheckFrequency: Number,
+    segmentationPolicy: {type: String, enum: ['RESTART_JVM', 'STOP', 'NOOP']},
+    allSegmentationResolversPassRequired: Boolean,
+    segmentationResolveAttempts: Number,
+    swapSpaceSpi: {
+        kind: {type: String, enum: ['FileSwapSpaceSpi']},
+        FileSwapSpaceSpi: {
+            baseDirectory: String,
+            readStripesNumber: Number,
+            maximumSparsity: Number,
+            maxWriteQueueSize: Number,
+            writeBufferSize: Number
+        }
+    },
+    systemThreadPoolSize: Number,
+    timeServerPortBase: Number,
+    timeServerPortRange: Number,
+    transactionConfiguration: {
+        defaultTxConcurrency: {type: String, enum: ['OPTIMISTIC', 'PESSIMISTIC']},
+        transactionIsolation: {type: String, enum: ['READ_COMMITTED', 'REPEATABLE_READ', 'SERIALIZABLE']},
+        defaultTxTimeout: Number,
+        pessimisticTxLogLinger: Number,
+        pessimisticTxLogSize: Number,
+        txSerializableEnabled: Boolean
+    },
+    waitForSegmentOnStart: Boolean
+});
+
+// Define cluster model.
+exports.Cluster = mongoose.model('Cluster', ClusterSchema);
+
+// Define persistence schema.
+var PersistenceSchema = new Schema({
+    space: {type: ObjectId, ref: 'Space'},
+    name: String,
+    dbType: {type: String, enum: ['oracle', 'db2', 'mssql', 'postgre', 'mysql', 'h2']},
+    dbName: String,
+    host: String,
+    user: String,
+    tables: [{
+        use: Boolean,
+        schemaName: String,
+        tableName: String,
+        keyClass: String,
+        valueClass: String,
+        columns: [{
+            use: Boolean,
+            pk: Boolean,
+            ak: Boolean,
+            notNull: Boolean,
+            dbName: String,
+            dbType: Number,
+            javaName: String,
+            javaType: String
+        }]
+    }]
+});
+
+// Define persistence model.
+exports.Persistence = mongoose.model('Persistence', PersistenceSchema);
+
+exports.upsert = function (model, data, cb) {
+    if (data._id) {
+        var id = data._id;
+
+        delete data._id;
+
+        model.findOneAndUpdate({_id: id}, data, cb);
+    }
+    else
+        new model(data).save(cb);
+};
+
+exports.mongoose = mongoose;
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/src/main/js/helpers/configuration-loader.js
----------------------------------------------------------------------
diff --git a/modules/web-control-center/src/main/js/helpers/configuration-loader.js b/modules/web-control-center/src/main/js/helpers/configuration-loader.js
new file mode 100644
index 0000000..6dbb577
--- /dev/null
+++ b/modules/web-control-center/src/main/js/helpers/configuration-loader.js
@@ -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.
+ */
+
+var config = require('nconf');
+
+config.file({'file': 'config/default.json'});
+
+module.exports = config;
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/src/main/js/helpers/data-structures.js
----------------------------------------------------------------------
diff --git a/modules/web-control-center/src/main/js/helpers/data-structures.js b/modules/web-control-center/src/main/js/helpers/data-structures.js
new file mode 100644
index 0000000..2462708
--- /dev/null
+++ b/modules/web-control-center/src/main/js/helpers/data-structures.js
@@ -0,0 +1,84 @@
+/*
+ * 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.
+ */
+
+eventGroups = {
+    EVTS_CHECKPOINT: ['EVT_CHECKPOINT_SAVED', 'EVT_CHECKPOINT_LOADED', 'EVT_CHECKPOINT_REMOVED'],
+    EVTS_DEPLOYMENT: ['EVT_CLASS_DEPLOYED', 'EVT_CLASS_UNDEPLOYED', 'EVT_CLASS_DEPLOY_FAILED', 'EVT_TASK_DEPLOYED',
+        'EVT_TASK_UNDEPLOYED', 'EVT_TASK_DEPLOY_FAILED'],
+    EVTS_ERROR: ['EVT_JOB_TIMEDOUT', 'EVT_JOB_FAILED', 'EVT_JOB_FAILED_OVER', 'EVT_JOB_REJECTED', 'EVT_JOB_CANCELLED',
+        'EVT_TASK_TIMEDOUT', 'EVT_TASK_FAILED', 'EVT_CLASS_DEPLOY_FAILED', 'EVT_TASK_DEPLOY_FAILED',
+        'EVT_TASK_DEPLOYED', 'EVT_TASK_UNDEPLOYED', 'EVT_CACHE_REBALANCE_STARTED', 'EVT_CACHE_REBALANCE_STOPPED'],
+    EVTS_DISCOVERY: ['EVT_NODE_JOINED', 'EVT_NODE_LEFT', 'EVT_NODE_FAILED', 'EVT_NODE_SEGMENTED',
+        'EVT_CLIENT_NODE_DISCONNECTED', 'EVT_CLIENT_NODE_RECONNECTED'],
+    EVTS_JOB_EXECUTION: ['EVT_JOB_MAPPED', 'EVT_JOB_RESULTED', 'EVT_JOB_FAILED_OVER', 'EVT_JOB_STARTED',
+        'EVT_JOB_FINISHED', 'EVT_JOB_TIMEDOUT', 'EVT_JOB_REJECTED', 'EVT_JOB_FAILED', 'EVT_JOB_QUEUED',
+        'EVT_JOB_CANCELLED'],
+    EVTS_TASK_EXECUTION: ['EVT_TASK_STARTED', 'EVT_TASK_FINISHED', 'EVT_TASK_FAILED', 'EVT_TASK_TIMEDOUT',
+        'EVT_TASK_SESSION_ATTR_SET', 'EVT_TASK_REDUCED'],
+    EVTS_CACHE: ['EVT_CACHE_ENTRY_CREATED', 'EVT_CACHE_ENTRY_DESTROYED', 'EVT_CACHE_OBJECT_PUT',
+        'EVT_CACHE_OBJECT_READ', 'EVT_CACHE_OBJECT_REMOVED', 'EVT_CACHE_OBJECT_LOCKED', 'EVT_CACHE_OBJECT_UNLOCKED',
+        'EVT_CACHE_OBJECT_SWAPPED', 'EVT_CACHE_OBJECT_UNSWAPPED', 'EVT_CACHE_OBJECT_EXPIRED'],
+    EVTS_CACHE_REBALANCE: ['EVT_CACHE_REBALANCE_STARTED', 'EVT_CACHE_REBALANCE_STOPPED',
+        'EVT_CACHE_REBALANCE_PART_LOADED', 'EVT_CACHE_REBALANCE_PART_UNLOADED', 'EVT_CACHE_REBALANCE_OBJECT_LOADED',
+        'EVT_CACHE_REBALANCE_OBJECT_UNLOADED', 'EVT_CACHE_REBALANCE_PART_DATA_LOST'],
+    EVTS_CACHE_LIFECYCLE: ['EVT_CACHE_STARTED', 'EVT_CACHE_STOPPED', 'EVT_CACHE_NODES_LEFT'],
+    EVTS_CACHE_QUERY: ['EVT_CACHE_QUERY_EXECUTED', 'EVT_CACHE_QUERY_OBJECT_READ'],
+    EVTS_SWAPSPACE: ['EVT_SWAP_SPACE_CLEARED', 'EVT_SWAP_SPACE_DATA_REMOVED', 'EVT_SWAP_SPACE_DATA_READ',
+        'EVT_SWAP_SPACE_DATA_STORED', 'EVT_SWAP_SPACE_DATA_EVICTED'],
+    EVTS_IGFS: ['EVT_IGFS_FILE_CREATED', 'EVT_IGFS_FILE_RENAMED', 'EVT_IGFS_FILE_DELETED', 'EVT_IGFS_FILE_OPENED_READ',
+        'EVT_IGFS_FILE_OPENED_WRITE', 'EVT_IGFS_FILE_CLOSED_WRITE', 'EVT_IGFS_FILE_CLOSED_READ', 'EVT_IGFS_FILE_PURGED',
+        'EVT_IGFS_META_UPDATED', 'EVT_IGFS_DIR_CREATED', 'EVT_IGFS_DIR_RENAMED', 'EVT_IGFS_DIR_DELETED']
+};
+
+jdbcTypes = {
+    BIT: {value: "BIT", code: -7, label: "BIT"},
+    TINYINT: {value: "TINYINT", code: -6, label: "TINYINT"},
+    SMALLINT: {value: "SMALLINT", code: 5, label: "SMALLINT"},
+    INTEGER: {value: "INTEGER", code: 4, label: "INTEGER"},
+    BIGINT: {value: "BIGINT", code: -5, label: "BIGINT"},
+    FLOAT: {value: "FLOAT", code: 6, label: "FLOAT"},
+    REAL: {value: "REAL", code: 7, label: "REAL"},
+    DOUBLE: {value: "DOUBLE", code: 8, label: "DOUBLE"},
+    NUMERIC: {value: "NUMERIC", code: 2, label: "NUMERIC"},
+    DECIMAL: {value: "DECIMAL", code: 3, label: "DECIMAL"},
+    CHAR: {value: "CHAR", code: 1, label: "CHAR"},
+    VARCHAR: {value: "VARCHAR", code: 12, label: "VARCHAR"},
+    DATE: {value: "DATE", code: 91, label: "DATE"},
+    TIME: {value: "TIME", code: 92, label: "TIME"},
+    TIMESTAMP: {value: "TIMESTAMP", code: 93, label: "TIMESTAMP"},
+    BINARY: {value: "BINARY", code: -2, label: "BINARY"}
+};
+
+javaTypes = {
+    INTEGER: {value: "java.lang.Integer", label: "Integer"},
+    LONG: {value: "java.lang.Long", label: "Long"},
+    BIGDECIMAL: {value: "java.math.BigDecimal", label: "BigDecimal"},
+    FLOAT: {value: "java.lang.Float", label: "Float"},
+    DOUBLE: {value: "java.lang.Double", label: "Double"},
+    STRING: {value: "java.lang.String", label: "String"},
+    BOOLEAN: {value: "java.lang.Boolean", label: "Boolean"},
+    BYTE_ARRAY: {value: "byte[]", label: "byte[]"},
+    DATE: {value: "java.sql.Date", label: "Date"},
+    TIME: {value: "java.sql.Time", label: "Time"},
+    TIMESTAMP: {value: "java.sql.Timestamp", label: "Timestamp"}
+};
+
+if (typeof window === 'undefined') {
+    exports.eventGroups = eventGroups;
+    exports.jdbcTypes = jdbcTypes;
+    exports.javaTypes = javaTypes;
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/src/main/js/package.json
----------------------------------------------------------------------
diff --git a/modules/web-control-center/src/main/js/package.json b/modules/web-control-center/src/main/js/package.json
new file mode 100644
index 0000000..5e5463c
--- /dev/null
+++ b/modules/web-control-center/src/main/js/package.json
@@ -0,0 +1,50 @@
+{
+  "name": "ignite-web-control-center",
+  "version": "1.0.0",
+  "description": "Web application for configuration, monitoring Ignite Cluster",
+  "private": true,
+  "scripts": {
+    "start": "node ./bin/www"
+  },
+  "author": "",
+  "contributors": [
+    {
+      "name": "",
+      "email": ""
+    }
+  ],
+  "license": "Apache-2.0",
+  "keywords": "grid",
+  "homepage": "https://ignite.incubator.apache.org/",
+  "engines": {
+    "node": ">=0.12.4"
+  },
+  "dependencies": {
+    "angular-ui-ace": "^0.2.3",
+    "archiver": "^0.14.4",
+    "body-parser": "~1.12.0",
+    "connect-flash": "^0.1.1",
+    "connect-mongo": "^0.8.1",
+    "cookie-parser": "~1.3.4",
+    "debug": "~2.1.1",
+    "express": "~4.12.2",
+    "express-session": "^1.11.1",
+    "jade": "~1.9.2",
+    "less-middleware": "1.0.x",
+    "lodash": "3.10.0",
+    "mongoose": "^4.0.2",
+    "nconf": "^0.7.1",
+    "passport": "^0.2.1",
+    "passport-local": "^1.0.0",
+    "passport-local-mongoose": "^1.0.0",
+    "pg": "^4.4.0",
+    "serve-favicon": "~2.2.0",
+    "util": "^0.10.3"
+  },
+  "devDependencies": {
+    "morgan": "~1.5.1",
+    "supertest": "^1.0.1",
+    "mocha": "~2.0.1",
+    "should": "~3.1.3"
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/src/main/js/public/favicon.ico
----------------------------------------------------------------------
diff --git a/modules/web-control-center/src/main/js/public/favicon.ico b/modules/web-control-center/src/main/js/public/favicon.ico
new file mode 100644
index 0000000..74ec626
Binary files /dev/null and b/modules/web-control-center/src/main/js/public/favicon.ico differ

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/src/main/js/public/images/docker.png
----------------------------------------------------------------------
diff --git a/modules/web-control-center/src/main/js/public/images/docker.png b/modules/web-control-center/src/main/js/public/images/docker.png
new file mode 100644
index 0000000..7ec3aef
Binary files /dev/null and b/modules/web-control-center/src/main/js/public/images/docker.png differ

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/src/main/js/public/images/java.png
----------------------------------------------------------------------
diff --git a/modules/web-control-center/src/main/js/public/images/java.png b/modules/web-control-center/src/main/js/public/images/java.png
new file mode 100644
index 0000000..ddb3b8e
Binary files /dev/null and b/modules/web-control-center/src/main/js/public/images/java.png differ

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/src/main/js/public/images/logo.png
----------------------------------------------------------------------
diff --git a/modules/web-control-center/src/main/js/public/images/logo.png b/modules/web-control-center/src/main/js/public/images/logo.png
new file mode 100644
index 0000000..c3577c5
Binary files /dev/null and b/modules/web-control-center/src/main/js/public/images/logo.png differ

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/src/main/js/public/images/xml.png
----------------------------------------------------------------------
diff --git a/modules/web-control-center/src/main/js/public/images/xml.png b/modules/web-control-center/src/main/js/public/images/xml.png
new file mode 100644
index 0000000..029065e
Binary files /dev/null and b/modules/web-control-center/src/main/js/public/images/xml.png differ


[02/10] incubator-ignite git commit: # ignite-843 moved

Posted by an...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/src/main/js/routes/metadata.js
----------------------------------------------------------------------
diff --git a/modules/web-control-center/src/main/js/routes/metadata.js b/modules/web-control-center/src/main/js/routes/metadata.js
new file mode 100644
index 0000000..64b8763
--- /dev/null
+++ b/modules/web-control-center/src/main/js/routes/metadata.js
@@ -0,0 +1,95 @@
+/*
+ * 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 router = require('express').Router();
+var db = require('../db');
+
+/* GET metadata page. */
+router.get('/', function (req, res) {
+    res.render('configuration/metadata');
+});
+
+/**
+ * Get spaces and metadata accessed for user account.
+ *
+ * @param req Request.
+ * @param res Response.
+ */
+router.post('/list', function (req, res) {
+    var user_id = req.currentUserId();
+
+    // Get owned space and all accessed space.
+    db.Space.find({$or: [{owner: user_id}, {usedBy: {$elemMatch: {account: user_id}}}]}, function (err, spaces) {
+        if (err)
+            return res.status(500).send(err.message);
+
+        var space_ids = spaces.map(function (value) {
+            return value._id;
+        });
+
+        // Get all metadata for spaces.
+        db.CacheTypeMetadata.find({space: {$in: space_ids}}).sort('name').exec(function (err, metadatas) {
+            if (err)
+                return res.status(500).send(err.message);
+
+            res.json({spaces: spaces, metadatas: metadatas});
+        });
+    });
+});
+
+/**
+ * Save metadata.
+ */
+router.post('/save', function (req, res) {
+    if (req.body._id)
+        db.CacheTypeMetadata.update({_id: req.body._id}, req.body, {upsert: true}, function (err) {
+            if (err)
+                return res.status(500).send(err.message);
+
+            res.send(req.body._id);
+        });
+    else {
+        db.CacheTypeMetadata.findOne({name: req.body.name}, function (err, metadata) {
+            if (err)
+                return res.status(500).send(err.message);
+
+            if (metadata)
+                return res.status(500).send('Cache type metadata with name: "' + metadata.name + '" already exist.');
+
+            (new db.CacheTypeMetadata(req.body)).save(function (err, metadata) {
+                if (err)
+                    return res.status(500).send(err.message);
+
+                res.send(metadata._id);
+            });
+        });
+    }
+});
+
+/**
+ * Remove metadata by ._id.
+ */
+router.post('/remove', function (req, res) {
+    db.CacheTypeMetadata.remove(req.body, function (err) {
+        if (err)
+            return res.status(500).send(err.message);
+
+        res.sendStatus(200);
+    })
+});
+
+module.exports = router;
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/src/main/js/routes/profile.js
----------------------------------------------------------------------
diff --git a/modules/web-control-center/src/main/js/routes/profile.js b/modules/web-control-center/src/main/js/routes/profile.js
new file mode 100644
index 0000000..0269e7d
--- /dev/null
+++ b/modules/web-control-center/src/main/js/routes/profile.js
@@ -0,0 +1,97 @@
+/*
+ * 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 router = require('express').Router();
+var db = require('../db');
+
+router.all('/profile/*', function (req, res, next) {
+    var userId = req.body._id;
+
+    if (userId != req.currentUserId() && userId != req.user._id)
+        return res.sendStatus(403);
+    else
+        next();
+});
+
+/**
+ * Get user profile page.
+ */
+router.get('/', function (req, res) {
+    var user_id = req.currentUserId();
+
+    db.Account.findById(user_id, function (err) {
+        if (err)
+            return res.status(500).send(err.message);
+
+        res.render('settings/profile');
+    });
+});
+
+/**
+ * Save user profile.
+ */
+router.post('/saveUser', function (req, res) {
+    var params = req.body;
+
+    if (params.newPassword) {
+        var newPassword = params.newPassword;
+
+        if (!newPassword || newPassword.length == 0)
+            return res.status(500).send('Wrong value for new password');
+
+        db.Account.findById(params._id, function (err, user) {
+            if (err)
+                return res.status(500).send(err);
+
+            user.setPassword(newPassword, function (err, updatedUser) {
+                if (err)
+                    return res.status(500).send(err.message);
+
+                if (params.userName)
+                    updatedUser.username = params.userName;
+
+                if (params.email)
+                    updatedUser.email = params.email;
+
+                updatedUser.save(function (err) {
+                    if (err)
+                        return res.status(500).send(err.message);
+
+                    res.json(user);
+                });
+            });
+        });
+    }
+    else if (params.userName || params.email) {
+        var upd = {};
+
+        if (params.userName)
+            upd.username = params.userName;
+
+        if (params.email)
+            upd.email = params.email;
+
+        db.Account.findByIdAndUpdate(params._id, upd, {new: true}, function (err, val) {
+            if (err)
+                return res.status(500).send(err.message);
+
+            res.json(val);
+        })
+    }
+});
+
+module.exports = router;
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/src/main/js/routes/public.js
----------------------------------------------------------------------
diff --git a/modules/web-control-center/src/main/js/routes/public.js b/modules/web-control-center/src/main/js/routes/public.js
new file mode 100644
index 0000000..290ba90
--- /dev/null
+++ b/modules/web-control-center/src/main/js/routes/public.js
@@ -0,0 +1,123 @@
+/*
+ * 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 router = require('express').Router();
+var passport = require('passport');
+var db = require('../db');
+
+// GET dropdown-menu template.
+router.get('/select', function (req, res) {
+    res.render('templates/select', {});
+});
+
+// GET tabs template.
+router.get('/tab', function (req, res) {
+    res.render('templates/tab', {});
+});
+
+// GET confirmation dialog.
+router.get('/confirm', function (req, res) {
+    res.render('templates/confirm', {});
+});
+
+// GET save as dialog.
+router.get('/copy', function (req, res) {
+    res.render('templates/copy', {});
+});
+
+/* GET login page. */
+router.get('/login', function (req, res) {
+    res.render('login');
+});
+
+/**
+ * Register new account.
+ */
+router.post('/register', function (req, res) {
+    db.Account.count(function (err, cnt) {
+        if (err)
+            return res.status(401).send(err.message);
+
+        req.body.admin = cnt == 0;
+
+        db.Account.register(new db.Account(req.body), req.body.password, function (err, account) {
+            if (err)
+                return res.status(401).send(err.message);
+
+            if (!account)
+                return res.status(500).send('Failed to create account.');
+
+            new db.Space({name: 'Personal space', owner: account._id}).save();
+
+            req.logIn(account, {}, function (err) {
+                if (err)
+                    return res.status(401).send(err.message);
+
+                return res.redirect('/configuration/clusters');
+            });
+        });
+    });
+});
+
+/**
+ * Login in exist account.
+ */
+router.post('/login', function (req, res, next) {
+    passport.authenticate('local', function (err, user) {
+        if (err)
+            return res.status(401).send(err.message);
+
+        if (!user)
+            return res.status(401).send('Invalid email or password');
+
+        req.logIn(user, {}, function (err) {
+            if (err)
+                return res.status(401).send(err.message);
+
+            res.redirect('/configuration/clusters');
+        });
+    })(req, res, next);
+});
+
+/**
+ * Logout.
+ */
+router.get('/logout', function (req, res) {
+    req.logout();
+
+    res.redirect('/');
+});
+
+/* GET home page. */
+router.get('/', function (req, res) {
+    if (req.isAuthenticated())
+        res.redirect('/configuration/clusters');
+    else
+        res.render('index');
+});
+
+///* GET sql page. */
+//router.get('/sql', function(req, res) {
+//    res.render('sql', { user: req.user });
+//});
+//
+///* GET clients page. */
+//router.get('/clients', function(req, res) {
+//    res.render('clients', { user: req.user });
+//});
+
+module.exports = router;

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/src/main/js/routes/sql.js
----------------------------------------------------------------------
diff --git a/modules/web-control-center/src/main/js/routes/sql.js b/modules/web-control-center/src/main/js/routes/sql.js
new file mode 100644
index 0000000..ce4565d
--- /dev/null
+++ b/modules/web-control-center/src/main/js/routes/sql.js
@@ -0,0 +1,24 @@
+/*
+ * 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 router = require('express').Router();
+var db = require('../db');
+router.get('/', function(req, res) {
+    res.render('sql/sql');
+});
+
+module.exports = router;

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/src/main/js/routes/summary.js
----------------------------------------------------------------------
diff --git a/modules/web-control-center/src/main/js/routes/summary.js b/modules/web-control-center/src/main/js/routes/summary.js
new file mode 100644
index 0000000..f766945
--- /dev/null
+++ b/modules/web-control-center/src/main/js/routes/summary.js
@@ -0,0 +1,108 @@
+/*
+ * 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 db = require('../db');
+
+var router = require('express').Router();
+
+var generatorXml = require('./generator/xml');
+var generatorJava = require('./generator/java');
+var generatorDocker = require('./generator/docker');
+
+/* GET summary page. */
+router.get('/', function (req, res) {
+    res.render('configuration/summary');
+});
+
+router.post('/generator', function (req, res) {
+    // Get cluster.
+    db.Cluster.findById(req.body._id).populate('caches').exec(function (err, cluster) {
+        if (err)
+            return res.status(500).send(err.message);
+
+        if (!cluster)
+            return res.sendStatus(404);
+
+        var clientCache = req.body.clientNearConfiguration;
+
+        if (clientCache)
+            return res.send({
+                xmlClient: generatorXml.generateClusterConfiguration(cluster, clientCache),
+                javaClient: generatorJava.generateClusterConfiguration(cluster, req.body.javaClass, clientCache)
+            });
+
+        return res.send({
+            xmlServer: generatorXml.generateClusterConfiguration(cluster),
+            javaSnippetServer: generatorJava.generateClusterConfiguration(cluster, false),
+            javaClassServer: generatorJava.generateClusterConfiguration(cluster, true),
+            docker: generatorDocker.generateClusterConfiguration(cluster, '%OS%')
+        });
+    });
+});
+
+router.post('/download', function (req, res) {
+    // Get cluster.
+    db.Cluster.findById(req.body._id).populate('caches').exec(function (err, cluster) {
+        if (err)
+            return res.status(500).send(err.message);
+
+        if (!cluster)
+            return res.sendStatus(404);
+
+        var clientNearConfiguration = req.body.clientNearConfiguration;
+
+        var archiver = require('archiver');
+
+        // Creating archive.
+        var zip = archiver('zip');
+
+        zip.on('error', function (err) {
+            res.status(500).send({error: err.message});
+        });
+
+        // On stream closed we can end the request.
+        res.on('close', function () {
+            return res.status(200).send('OK').end();
+        });
+
+        // Set the archive name.
+        res.attachment(cluster.name + (clientNearConfiguration ? '-client' : '') + '-configuration.zip');
+
+        var generatorCommon = require('./generator/common');
+
+        // Send the file to the page output.
+        zip.pipe(res);
+
+        var javaClass = req.body.javaClass;
+
+        if (!clientNearConfiguration) {
+            zip.append(generatorDocker.generateClusterConfiguration(cluster, req.body.os), {name: "Dockerfile"});
+
+            var props = generatorCommon.generateProperties(cluster);
+
+            if (props)
+                zip.append(props, {name: "secret.properties"});
+        }
+
+        zip.append(generatorXml.generateClusterConfiguration(cluster, clientNearConfiguration), {name: cluster.name + ".xml"})
+            .append(generatorJava.generateClusterConfiguration(cluster, javaClass, clientNearConfiguration),
+                {name: javaClass ? 'ConfigurationFactory.java' : cluster.name + '.snipplet.java'})
+            .finalize();
+    });
+});
+
+module.exports = router;
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/src/main/js/views/configuration/caches.jade
----------------------------------------------------------------------
diff --git a/modules/web-control-center/src/main/js/views/configuration/caches.jade b/modules/web-control-center/src/main/js/views/configuration/caches.jade
new file mode 100644
index 0000000..3a011fc
--- /dev/null
+++ b/modules/web-control-center/src/main/js/views/configuration/caches.jade
@@ -0,0 +1,74 @@
+//-
+    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 sidebar
+
+append scripts
+    script(src='/caches-controller.js')
+
+include ../includes/controls
+
+block content
+    .docs-header
+        h1 Create and Configure Ignite Caches
+        hr
+    .docs-body(ng-controller='cachesController')
+        +block-callout('{{screenTip.workflowTitle}}', 'joinTip(screenTip.workflowContent)', '{{screenTip.whatsNextTitle}}', 'joinTip(screenTip.whatsNextContent)')
+        .links(ng-hide='caches.length == 0')
+            .padding-dflt
+                lable.labelHeader Caches:
+                table(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'}}
+        .padding-top-dflt
+            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(['col-sm-3'], ['col-sm-3'])
+            .panel-group(bs-collapse data-allow-multiple="true")
+                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...'}}
+            div
+                button.btn.btn-primary(ng-disabled='inputForm.$invalid' ng-click='saveItem()') Save
+                button.btn.btn-primary(ng-show='backupItem._id' ng-disabled='inputForm.$invalid' ng-click='saveItemAs()') Copy
+                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/8a335724/modules/web-control-center/src/main/js/views/configuration/clusters.jade
----------------------------------------------------------------------
diff --git a/modules/web-control-center/src/main/js/views/configuration/clusters.jade b/modules/web-control-center/src/main/js/views/configuration/clusters.jade
new file mode 100644
index 0000000..81acfed
--- /dev/null
+++ b/modules/web-control-center/src/main/js/views/configuration/clusters.jade
@@ -0,0 +1,77 @@
+//-
+    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 sidebar
+
+append scripts
+    script(src='/clusters-controller.js')
+
+include ../includes/controls
+
+block content
+    .docs-header
+        h1 Create and Configure Ignite Clusters
+        hr
+    .docs-body(ng-controller='clustersController')
+        +block-callout('{{screenTip.workflowTitle}}', 'joinTip(screenTip.workflowContent)', '{{screenTip.whatsNextTitle}}', 'joinTip(screenTip.whatsNextContent)')
+        .links(ng-hide='clusters.length == 0')
+            .padding-dflt
+                lable.labelHeader Clusters:
+                table(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'}}
+        .padding-top-dflt
+            button.btn.btn-primary(ng-click='createItem()') &nbspAdd cluster
+            label(style='margin-left: 10px; margin-right: 10px') Use template:
+            button.btn.btn-default.base-control(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
+            .panel-group(bs-collapse data-allow-multiple="true")
+                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...'}}
+            div
+                button.btn.btn-primary(ng-disabled='inputForm.$invalid' ng-click='saveItem()') Save
+                button.btn.btn-primary(ng-show='backupItem._id' ng-disabled='inputForm.$invalid' ng-click='saveItemAs()') Copy
+                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/8a335724/modules/web-control-center/src/main/js/views/configuration/metadata.jade
----------------------------------------------------------------------
diff --git a/modules/web-control-center/src/main/js/views/configuration/metadata.jade b/modules/web-control-center/src/main/js/views/configuration/metadata.jade
new file mode 100644
index 0000000..d5bac06
--- /dev/null
+++ b/modules/web-control-center/src/main/js/views/configuration/metadata.jade
@@ -0,0 +1,121 @@
+//-
+    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 sidebar
+
+append scripts
+    script(src='/metadata-controller.js')
+
+include ../includes/controls
+
+block content
+    .docs-header
+        h1 Create and Configure Cache Type Metadata
+        hr
+    .docs-body(ng-controller='metadataController')
+        +block-callout('{{screenTip.workflowTitle}}', 'joinTip(screenTip.workflowContent)', '{{screenTip.whatsNextTitle}}', 'joinTip(screenTip.whatsNextContent)')
+        .links(ng-hide='metadatas.length == 0')
+            .padding-dflt
+                lable.labelHeader Types metadata:
+                table(st-table='metadatas')
+                    tbody
+                        tr(ng-repeat='row in metadatas track by row._id')
+                            td.col-sm-6(ng-class='{active: row._id == selectedItem._id}')
+                                a(ng-click='selectItem(row)') {{$index + 1}}) {{row.name}}
+        .padding-top-dflt
+            button.btn.btn-primary(ng-click='panels.activePanel = [0]; createItem()') &nbspAdd metadata
+            label(style='margin-left: 6px; margin-right: 10px') For:
+            button.btn.btn-default(ng-model='template' data-template='/select' data-placeholder='Choose metadata type' 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
+        .panel-group(bs-collapse ng-model='panels.activePanel' data-allow-multiple="false")
+            .panel.panel-default
+                .panel-heading
+                    h3
+                        a(bs-collapse-toggle) Manual
+                .panel-collapse(role="tabpanel" bs-collapse-target)
+                    .panel-body
+                        form.form-horizontal(name='manualForm' ng-if='backupItem' novalidate)
+                            .settings-row(ng-repeat='field in metadataManual')
+                                +form-row
+                            button.btn.btn-primary(ng-disabled='manualForm.$invalid' ng-click='saveItem()') Save
+                            button.btn.btn-primary(ng-show='backupItem._id' ng-disabled='inputForm.$invalid' ng-click='saveItemAs()') Copy
+                            button.btn.btn-primary.btn-second(ng-show='backupItem._id' ng-click='removeItem()') Remove
+            .panel.panel-default
+                .panel-heading
+                    h3
+                        a(bs-collapse-toggle) Load from database
+                .panel-collapse(bs-collapse-target)
+                    .panel-body
+                        form.form-horizontal(name='dbForm' novalidate)
+                            .settings-row(ng-repeat='field in metadataDb')
+                                +form-row
+                        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='dbForm.$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
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/src/main/js/views/configuration/sidebar.jade
----------------------------------------------------------------------
diff --git a/modules/web-control-center/src/main/js/views/configuration/sidebar.jade b/modules/web-control-center/src/main/js/views/configuration/sidebar.jade
new file mode 100644
index 0000000..7289f3e
--- /dev/null
+++ b/modules/web-control-center/src/main/js/views/configuration/sidebar.jade
@@ -0,0 +1,39 @@
+//-
+    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 ../templates/layout
+
+mixin sidebar-item(ref, num, txt)
+    li
+        a(ng-class='{active: isActive("#{ref}")}' href='#{ref}')
+            span.fa-stack
+                i.fa.fa-circle-thin.fa-stack-2x
+                i.fa.fa-stack-1x #{num}
+            | #{txt}
+
+block container
+    .row
+        .col-sm-2.border-right.section-left.greedy
+            .sidebar-nav(bs-affix)
+                ul.menu(ng-controller='activeLink')
+                    +sidebar-item('/configuration/clusters', 1, 'Clusters')
+                    +sidebar-item('/configuration/metadata', 2, 'Metadata')
+                    +sidebar-item('/configuration/caches', 3, 'Caches')
+                    +sidebar-item('/configuration/summary', 4, '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/8a335724/modules/web-control-center/src/main/js/views/configuration/summary.jade
----------------------------------------------------------------------
diff --git a/modules/web-control-center/src/main/js/views/configuration/summary.jade b/modules/web-control-center/src/main/js/views/configuration/summary.jade
new file mode 100644
index 0000000..6f2f6d8
--- /dev/null
+++ b/modules/web-control-center/src/main/js/views/configuration/summary.jade
@@ -0,0 +1,117 @@
+//-
+    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 sidebar
+
+append scripts
+    script(src='/summary-controller.js')
+
+    script(src="//cdn.jsdelivr.net/angularjs/1.3.15/angular-animate.min.js")
+    script(src="//cdn.jsdelivr.net/angularjs/1.3.15/angular-sanitize.min.js")
+
+    script(src='//cdnjs.cloudflare.com/ajax/libs/ace/1.2.0/theme-chrome.js')
+    script(src='//cdnjs.cloudflare.com/ajax/libs/ace/1.2.0/mode-xml.js')
+    script(src='//cdnjs.cloudflare.com/ajax/libs/ace/1.2.0/mode-java.js')
+    script(src='//cdnjs.cloudflare.com/ajax/libs/ace/1.2.0/mode-dockerfile.js')
+
+append css
+
+include ../includes/controls
+
+mixin hard-link(ref, txt)
+    a(style='color:#ec1c24' href=ref target="_blank") #{txt}
+
+block content
+    .docs-header
+        h1 Configurations Summary
+        hr
+    .docs-body(ng-controller='summaryController')
+        +block-callout('{{screenTip.workflowTitle}}', 'joinTip(screenTip.workflowContent)', '{{screenTip.whatsNextTitle}}', 'joinTip(screenTip.whatsNextContent)')
+        .padding-dflt(ng-if='clusters.length == 0')
+            | No cluster configured. You can&nbsp;
+            a(href='clusters') configure
+            | &nbsp;it.
+        .padding-dflt(ng-if='clusters.length > 0')
+            lable.labelHeader Clusters:
+            .links
+                table(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}}
+        div(ng-show='selectedItem' role="tab" method='post' action='summary/download')
+            .padding-dflt(bs-collapse data-start-collapsed='false')
+                .panel.panel-default
+                    form.panel-heading(role='tab' method='post' action='summary/download')
+                        input(type="hidden" name="_id" value="{{selectedItem._id}}")
+                        input(type="hidden" name="os" value="{{os}}")
+                        input(type="hidden" name="javaClass" value="{{javaClassServer}}")
+                        h3
+                            a(bs-collapse-toggle) Server
+                            button.btn.btn-primary.pull-right(type='submit' style='margin-top: -5px') Download
+                    .panel-collapse(role="tabpanel" bs-collapse-target)
+                        .panel-body
+                            .configBox(ng-show='selectedItem' bs-tabs)
+                                div(title='<img src="/images/xml.png" width="16px" height="16px"/> XML' bs-pane)
+                                    .configBox(ui-ace='{ onLoad: aceInit, mode: "xml" }' ng-model='xmlServer' style='margin: 0.65em 0;')
+                                div(title='<img src="/images/java.png" width="16px" height="16px"/> Java' bs-pane)
+                                    .settings-row
+                                        .col-sm-1
+                                            label Generate:
+                                        .col-sm-3
+                                            button.form-control(type='button' ng-model='configServer.javaClassServer'  bs-select data-placeholder='{{detail.placeholder}}' bs-options='item.value as item.label for item in javaClassItems' data-sort='false')
+                                    .configBox(ui-ace='{ onLoad: aceInit, mode: "java" }' ng-model='javaServer')
+                                div(title='<img src="/images/docker.png" width="16px" height="16px"/> Dockerfile' bs-pane)
+                                    .settings-row
+                                        p
+                                            +hard-link('https://docs.docker.com/reference/builder', 'Docker')
+                                            | &nbsp;file is a text file with instructions to create Docker image.<br/>
+                                            | To build image you have to store following Docker file with your Ignite XML configuration to the same directory.<br>
+                                            | Also you could use predefined&nbsp;
+                                            +hard-link('https://ignite.incubator.apache.org/download.html#docker', 'Apache Ignite docker image')
+                                            | . For more information about using Ignite with Docker please read&nbsp;
+                                            +hard-link('http://apacheignite.readme.io/docs/docker-deployment', 'documentation')
+                                            |.
+                                        .col-sm-2
+                                            label(for='os') Operation System:
+                                        .col-sm-4
+                                            input#os.form-control(type='text', ng-model='configServer.os' placeholder='debian:8' data-min-length="0" data-html="1" data-auto-select="true" data-animation="am-flip-x" bs-typeahead bs-options='os for os in oss')
+                                    div(ui-ace='{ onLoad: aceInit, mode: "dockerfile" }' ng-model='dockerServer')
+            .padding-dflt(bs-collapse data-start-collapsed='false')
+                .panel.panel-default
+                    form.panel-heading(role='tab' method='post' action='summary/download')
+                        input(type="hidden" name="_id" value="{{selectedItem._id}}")
+                        input(type="hidden" name="javaClass" value="{{javaClassClient}}")
+                        input(type="hidden" name="clientNearConfiguration" value="{{backupItem}}")
+
+                        h3
+                            a(bs-collapse-toggle) Client
+                            button.btn.btn-primary.pull-right(type='submit' style='margin-top: -5px') Download
+                    .panel-collapse(role="tabpanel" bs-collapse-target)
+                        .panel-body
+                            div(ng-show='selectedItem')
+                                .settings-row(ng-repeat='field in clientFields')
+                                    +form-row-custom(['col-sm-3'], ['col-sm-3'])
+                                .configBox(bs-tabs)
+                                    div(title='<img src="/images/xml.png" width="16px" height="16px"/> XML' bs-pane)
+                                        .configBox(ui-ace='{ onLoad: aceInit, mode: "xml" }' ng-model='xmlClient' style='margin: 0.65em 0;')
+                                    div(title='<img src="/images/java.png" width="16px" height="16px"/> Java' bs-pane)
+                                        .settings-row
+                                            .col-sm-1
+                                                label Generate:
+                                            .col-sm-4
+                                                button.form-control(type='button' ng-model='backupItem.javaClassClient' bs-select data-placeholder='{{detail.placeholder}}' bs-options='item.value as item.label for item in javaClassItems' data-sort='false')
+                                        div(ui-ace='{ onLoad: aceInit, mode: "java" }' ng-model='javaClient')

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/src/main/js/views/error.jade
----------------------------------------------------------------------
diff --git a/modules/web-control-center/src/main/js/views/error.jade b/modules/web-control-center/src/main/js/views/error.jade
new file mode 100644
index 0000000..b458fb7
--- /dev/null
+++ b/modules/web-control-center/src/main/js/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 templates/layout
+
+block container
+  h1= message
+  h2= error.status
+  pre #{error.stack}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/src/main/js/views/includes/controls.jade
----------------------------------------------------------------------
diff --git a/modules/web-control-center/src/main/js/views/includes/controls.jade b/modules/web-control-center/src/main/js/views/includes/controls.jade
new file mode 100644
index 0000000..4a618fa
--- /dev/null
+++ b/modules/web-control-center/src/main/js/views/includes/controls.jade
@@ -0,0 +1,322 @@
+//-
+    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 block-callout(titleWorkflow, contentWorkflow, whatsNextWorkflow, whatsNextContent)
+    .block-callout-parent.block-callout-border.margin-bottom-dflt
+        .block-callout
+            i.fa.fa-check-square
+            label #{titleWorkflow}
+            p(ng-bind-html=contentWorkflow)
+        .block-callout
+            i.fa.fa-check-square
+            label #{whatsNextWorkflow}
+            p(ng-bind-html=whatsNextContent)
+
+
+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 ico-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 btn-save(show, click)
+    i.tipField.fa.fa-floppy-o(ng-show=show ng-click=click)
+
+mixin btn-add(click)
+    i.tipField.fa.fa-plus(ng-click=click)
+
+mixin btn-remove(click)
+    i.tipField.fa.fa-remove(ng-click=click)
+
+mixin btn-up(show, click)
+    i.tipField.fa.fa-arrow-up(ng-show=show ng-click=click)
+
+mixin btn-down(show, click)
+    i.tipField.fa.fa-arrow-down(ng-show=show ng-click=click)
+
+mixin table-pair-edit(keyModel, valModel, keyPlaceholder, valPlaceholder)
+    .col-sm-6(style='float: right')
+        input.form-control(type='text' ng-model=valModel placeholder=valPlaceholder)
+    label.fieldSep /
+    .input-tip
+        input.form-control(type='text' ng-model=keyModel placeholder=keyPlaceholder)
+
+mixin table-pair(header, tblMdl, keyFld, valFld, keyPlaceholder, valPlaceholder)
+    .col-sm-6
+        label.table-header #{header}:
+        +tipLabel('field.tip')
+        button.btn.btn-primary.fieldButton(ng-click='tableNewItem(field)') Add
+    table.links-edit.col-sm-12(st-table=tblMdl)
+        tbody
+            tr.col-sm-12(ng-repeat='item in #{tblMdl}')
+                td.col-sm-6
+                    div(ng-show='!tableEditing(field, $index)')
+                        a.labelFormField(ng-click='curPair = tableStartEdit(backupItem, field, $index); curKey = curPair.#{keyFld}; curValue = curPair.#{valFld}') {{$index + 1}}) {{item.#{keyFld}}} / {{item.#{valFld}}}
+                        +btn-remove('tableRemove(backupItem, field, $index)')
+                    div(ng-show='tableEditing(field, $index)')
+                        label.labelField {{$index + 1}})
+                        +btn-save('tablePairSaveVisible(curKey, curValue)', 'tablePairSave(tablePairValid, backupItem, field, curKey, curValue, $index)')
+                        +table-pair-edit('curKey', 'curValue', keyPlaceholder, valPlaceholder)
+            tr.col-sm-12(ng-show='tableNewItemActive(field)')
+                td.col-sm-6
+                    +btn-save('tablePairSaveVisible(newKey, newValue)', 'tablePairSave(tablePairValid, backupItem, field, newKey, newValue, -1)')
+                    +table-pair-edit('newKey', 'newValue', keyPlaceholder, valPlaceholder)
+
+mixin details-row
+    - var lblDetailClasses = ['col-sm-4', 'details-label']
+
+    - var detailMdl = 'getModel(backupItem, detail)[detail.model]';
+    - var detailCommon = {'ng-model': detailMdl, 'ng-required': 'detail.required'};
+
+    - var customValidators = {'ng-attr-ipaddress': '{{detail.ipaddress}}'}
+
+    div(ng-switch='detail.type')
+        div(ng-switch-when='label')
+            label {{detail.label}}
+        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 ng-class='{required: detail.required}') {{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 ng-class='{required: detail.required}') {{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)
+                    +ico-exclamation('{{detail.model}}', 'min', 'Value is less than allowable minimum.')
+                    +ico-exclamation('{{detail.model}}', 'max', 'Value is more than allowable maximum.')
+                    +ico-exclamation('{{detail.model}}', 'number', 'Invalid value. Only numbers allowed.')
+        div(ng-switch-when='dropdown')
+            label(class=lblDetailClasses ng-class='{required: detail.required}') {{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 ng-class='{required: detail.required}') {{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')&attributes(detailCommon)
+            div(ng-if='detail.label')
+                label.table-header {{detail.label}}:
+                +tipLabel('detail.tableTip')
+            table.col-sm-12.links-edit-details(st-table='#{detailMdl}')
+                tbody
+                    tr(ng-repeat='item in #{detailMdl} track by $index')
+                        td
+                            div(ng-show='!tableEditing(detail, $index)')
+                                a.labelFormField(ng-click='curValue = tableStartEdit(backupItem, detail, $index)') {{$index + 1}}) {{item}}
+                                +btn-remove('tableRemove(backupItem, detail, $index)')
+                                +btn-down('detail.reordering && tableSimpleDownVisible(backupItem, detail, $index)', 'tableSimpleDown(backupItem, detail, $index)')
+                                +btn-up('detail.reordering && $index > 0', 'tableSimpleUp(backupItem, detail, $index)')
+                            div(ng-show='tableEditing(detail, $index)')
+                                label.labelField {{$index + 1}})
+                                +btn-save('tableSimpleSaveVisible(curValue)', 'tableSimpleSave(tableSimpleValid, backupItem, detail, curValue, $index)')
+                                .input-tip.form-group.has-feedback
+                                    input.form-control(name='{{detail.model}}.edit' type='text' ng-model='curValue' placeholder='{{detail.placeholder}}')&attributes(customValidators)
+                                    +ico-exclamation('{{detail.model}}.edit', 'ipaddress', 'Invalid address, see help for format description.')
+            button.btn.btn-primary.fieldButton(ng-disabled='!newValue' ng-click='tableSimpleSave(tableSimpleValid, backupItem, detail, newValue, -1)') Add
+            +tipField('detail.tip')
+            .input-tip.form-group.has-feedback
+                input.form-control(name='{{detail.model}}' type='text' ng-model='newValue' ng-focus='tableNewItem(detail)' placeholder='{{detail.placeholder}}')&attributes(customValidators)
+                +ico-exclamation('{{detail.model}}', 'ipaddress', 'Invalid address, see help for format description.')
+
+mixin table-db-field-edit(dbName, dbType, javaName, javaType)
+    div(style='width: 22%; float: right')
+        button.form-control(ng-model=javaType bs-select data-placeholder='Java type' bs-options='item.value as item.label for item in {{javaTypes}}')
+    label.fieldSep /
+    div(style='width: 20%; float: right')
+        input.form-control(type='text' ng-model=javaName placeholder='Java name')
+    label.fieldSep /
+    div(style='width: 22%; float: right')
+        button.form-control(ng-model=dbType bs-select data-placeholder='JDBC type' bs-options='item.value as item.label for item in {{jdbcTypes}}')
+    label.fieldSep /
+    .input-tip
+        input.form-control(type='text' ng-model=dbName placeholder='DB name')
+
+mixin table-group-item-edit(fieldName, className, direction)
+    div(style='width: 15%; float: right')
+        button.form-control(ng-model=direction bs-select data-placeholder='Sort' bs-options='item.value as item.label for item in {{sortDirections}}')
+    label.fieldSep /
+    div(style='width: 38%; float: right')
+        input.form-control(type='text' ng-model=className placeholder='Class name')
+    label.fieldSep /
+    .input-tip
+        input.form-control(type='text' ng-model=fieldName placeholder='Field name')
+
+mixin form-row
+    +form-row-custom(['col-sm-2'], ['col-sm-4'])
+
+mixin form-row-custom(lblClasses, fieldClasses)
+    - var fieldMdl = 'getModel(backupItem, field)[field.model]';
+    - var fieldCommon = {'ng-model': fieldMdl, 'ng-required': 'field.required || required(field)'};
+    - var fieldRequiredClass = '{true: "required"}[field.required || required(field)]'
+    - var fieldHide = '{{field.hide}}'
+
+    div(ng-switch='field.type')
+        div.col-sm-6(ng-switch-when='label')
+            label {{field.label}}
+        div.checkbox.col-sm-6(ng-switch-when='check' ng-hide=fieldHide)
+            label
+                input(type='checkbox')&attributes(fieldCommon)
+                | {{field.label}}
+                +tipLabel('field.tip')
+        div(ng-switch-when='text' ng-hide=fieldHide)
+            label(class=lblClasses ng-class=fieldRequiredClass) {{field.label}}:
+            div(class=fieldClasses)
+                +tipField('field.tip')
+                .input-tip
+                    input.form-control(type='text' placeholder='{{field.placeholder}}')&attributes(fieldCommon)
+        div(ng-switch-when='password' ng-hide=fieldHide)
+            label(class=lblClasses ng-class=fieldRequiredClass) {{field.label}}:
+            div(class=fieldClasses)
+                +tipField('field.tip')
+                .input-tip
+                    input.form-control(type='password' placeholder='{{field.placeholder}}')&attributes(fieldCommon)
+        div(ng-switch-when='number' ng-hide=fieldHide)
+            label(class=lblClasses ng-class=fieldRequiredClass) {{field.label}}:
+            div(class=fieldClasses)
+                +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}}')&attributes(fieldCommon)
+                    +ico-exclamation('{{field.model}}', 'min', 'Value is less than allowable minimum.')
+                    +ico-exclamation('{{field.model}}', 'max', 'Value is more than allowable maximum.')
+                    +ico-exclamation('{{field.model}}', 'number', 'Invalid value. Only numbers allowed.')
+        div(ng-switch-when='dropdown' ng-hide=fieldHide)
+            label(class=lblClasses ng-class=fieldRequiredClass) {{field.label}}:
+            div(class=fieldClasses)
+                +tipField('field.tip')
+                .input-tip
+                    button.form-control(bs-select data-placeholder='{{field.placeholder}}' bs-options='item.value as item.label for item in {{field.items}}')&attributes(fieldCommon)
+        div(ng-switch-when='dropdown-multiple' ng-hide=fieldHide)
+            label(class=lblClasses ng-class=fieldRequiredClass) {{field.label}}:
+            div(class=fieldClasses)
+                +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' ng-hide=fieldHide)
+            - var expanded = 'field.details[' + fieldMdl + '].expanded'
+
+            label(class=lblClasses ng-class=fieldRequiredClass) {{field.label}}:
+            div(class=fieldClasses)
+                +tipField('field.tip')
+                .input-tip
+                    button.form-control(bs-select 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' ng-hide=fieldHide)&attributes(fieldCommon)
+            .col-sm-6
+                label.table-header {{field.label}}:
+                +tipLabel('field.tableTip')
+                button.btn.btn-primary.fieldButton(ng-click='tableNewItem(field)') Add
+            table.links-edit.col-sm-12(st-table='#{fieldMdl}')
+                tbody
+                    tr.col-sm-12(ng-repeat='item in #{fieldMdl} track by $index')
+                        td.col-sm-6
+                            div(ng-show='!tableEditing(field, $index)')
+                                a.labelFormField(ng-click='curValue = tableStartEdit(backupItem, field, $index)') {{$index + 1}}) {{item | compact}}
+                                +btn-remove('tableRemove(backupItem, field, $index)')
+                                +btn-down('field.reordering && tableSimpleDownVisible(backupItem, field, $index)', 'tableSimpleDown(backupItem, field, $index)')
+                                +btn-up('field.reordering && $index > 0', 'tableSimpleUp(backupItem, field, $index)')
+                            div(ng-show='tableEditing(field, $index)')
+                                label.labelField {{$index + 1}})
+                                +btn-save('tableSimpleSaveVisible(curValue)', 'tableSimpleSave(tableSimpleValid, backupItem, field, curValue, $index)')
+                                .input-tip
+                                    input.form-control(type='text' ng-model='curValue' placeholder='{{field.placeholder}}')
+                    tr.col-sm-12(ng-show='tableNewItemActive(field)')
+                        td.col-sm-6
+                            +btn-save('tableSimpleSaveVisible(newValue)', 'tableSimpleSave(tableSimpleValid, backupItem, field, newValue, -1)')
+                            .input-tip
+                                input.form-control(type='text' ng-model='newValue' placeholder='{{field.placeholder}}')
+        div(ng-switch-when='indexedTypes')
+            +table-pair('Index key-value type pairs', fieldMdl, 'keyClass', 'valueClass', 'Key class full name', 'Value class full name')
+        div(ng-switch-when='queryFields' ng-hide=fieldHide)
+            +table-pair('{{field.label}}', fieldMdl, 'name', 'className', 'Field name', 'Field class full name')
+        div(ng-switch-when='dbFields' ng-hide=fieldHide)
+            .col-sm-6
+                label.table-header {{field.label}}:
+                +tipLabel('field.tip')
+                button.btn.btn-primary.fieldButton(ng-click='tableNewItem(field)') Add
+            table.links-edit.col-sm-12(st-table=fieldMdl)
+                tbody
+                    tr.col-sm-12(ng-repeat='item in #{fieldMdl}')
+                        td.col-sm-6
+                            div(ng-show='!tableEditing(field, $index)')
+                                a.labelFormField(ng-click='curField = tableStartEdit(backupItem, field, $index); curDbName = curField.dbName; curDbType = curField.dbType; curJavaName = curField.javaName; curJavaType = curField.javaType') {{$index + 1}}) {{item.dbName}} / {{item.dbType}} / {{item.javaName}} / {{item.javaType}}
+                                +btn-remove('tableRemove(backupItem, field, $index)')
+                            div(ng-if='tableEditing(field, $index)')
+                                label.labelField {{$index + 1}})
+                                +btn-save('tableDbFieldSaveVisible(curDbName, curDbType, curJavaName, curJavaType)', 'tableDbFieldSave(field, curDbName, curDbType, curJavaName, curJavaType, $index)')
+                                +table-db-field-edit('curDbName', 'curDbType', 'curJavaName', 'curJavaType')
+                    tr(ng-show='tableNewItemActive(field)')
+                        td.col-sm-6
+                            +btn-save('tableDbFieldSaveVisible(newDbName, newDbType, newJavaName, newJavaType)', 'tableDbFieldSave(field, newDbName, newDbType, newJavaName, newJavaType, -1)')
+                            +table-db-field-edit('newDbName', 'newDbType', 'newJavaName', 'newJavaType')
+        div(ng-switch-when='queryGroups' ng-hide=fieldHide)
+            .col-sm-6
+                label.table-header {{field.label}}:
+                +tipLabel('field.tip')
+                button.btn.btn-primary.fieldButton(ng-click='tableNewItem(field)') Add
+            table.links-edit.col-sm-12(st-table=fieldMdl)
+                tbody
+                    tr.col-sm-12(ng-repeat='group in #{fieldMdl}')
+                        td.col-sm-6
+                            div
+                                .col-sm-12(ng-show='!tableEditing(field, $index)')
+                                    a.labelFormField(ng-click='curGroup = tableStartEdit(backupItem, field, $index); curGroupName = curGroup.name; curFields = curGroup.fields') {{$index + 1}}) {{group.name}}
+                                    +btn-remove('tableRemove(backupItem, field, $index)')
+                                    +btn-add('tableGroupNewItem($index); newDirection = "ASC"')
+                                div(ng-show='tableEditing(field, $index)')
+                                    label.labelField {{$index + 1}})
+                                    +btn-save('tableGroupSaveVisible(curGroupName)', 'tableGroupSave(curGroupName, $index)')
+                                    .input-tip
+                                        input.form-control(type='text' ng-model='curGroupName' placeholder='Index name')
+                                div
+                                    table.links-edit.col-sm-12(st-table='group.fields' ng-init='groupIndex = $index')
+                                        tr(ng-repeat='groupItem in group.fields')
+                                            td
+                                                div(ng-show='!tableGroupItemEditing(groupIndex, $index)')
+                                                    a.labelFormField(ng-click='curGroupItem = tableGroupItemStartEdit(groupIndex, $index); curFieldName = curGroupItem.name; curClassName = curGroupItem.className; curDirection = curGroupItem.direction') {{$index + 1}}) {{groupItem.name}} / {{groupItem.className}} / {{groupItem.direction}}
+                                                    +btn-remove('tableRemoveGroupItem(group, $index)')
+                                                div(ng-show='tableGroupItemEditing(groupIndex, $index)')
+                                                    label.labelField {{$index + 1}})
+                                                    +btn-save('tableGroupItemSaveVisible(curFieldName, curClassName)', 'tableGroupItemSave(curFieldName, curClassName, curDirection, groupIndex, $index)')
+                                                    +table-group-item-edit('curFieldName', 'curClassName', 'curDirection')
+                                        tr.col-sm-12(style='padding-left: 18px' ng-show='tableGroupNewItemActive(groupIndex)')
+                                            td
+                                                +btn-save('tableGroupItemSaveVisible(newFieldName, newClassName)', 'tableGroupItemSave(newFieldName, newClassName, newDirection, groupIndex, -1)')
+                                                +table-group-item-edit('newFieldName', 'newClassName', 'newDirection')
+                    tr.col-sm-12(ng-show='tableNewItemActive(field)')
+                        td.col-sm-6
+                            +btn-save('tableGroupSaveVisible(newGroupName)', 'tableGroupSave(newGroupName, -1)')
+                            .input-tip
+                                input.form-control(type='text' ng-model='newGroupName' placeholder='Group name')
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/src/main/js/views/includes/footer.jade
----------------------------------------------------------------------
diff --git a/modules/web-control-center/src/main/js/views/includes/footer.jade b/modules/web-control-center/src/main/js/views/includes/footer.jade
new file mode 100644
index 0000000..d8ff5d7
--- /dev/null
+++ b/modules/web-control-center/src/main/js/views/includes/footer.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.
+
+.container.container-footer
+    footer
+        center
+            p Apache Ignite Control Center, version 1.0.0
+            p © 2015 The Apache Software Foundation.
+            p Apache, Apache Ignite, the Apache feather and the Apache Ignite logo are trademarks of The Apache Software Foundation.
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/src/main/js/views/includes/header.jade
----------------------------------------------------------------------
diff --git a/modules/web-control-center/src/main/js/views/includes/header.jade b/modules/web-control-center/src/main/js/views/includes/header.jade
new file mode 100644
index 0000000..ab2d31e
--- /dev/null
+++ b/modules/web-control-center/src/main/js/views/includes/header.jade
@@ -0,0 +1,39 @@
+//-
+    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 header-item(active, ref, txt)
+    li
+        a(ng-class='{active: isActive("#{active}")}' href='#{ref}') #{txt}
+
+header.header(id='header')
+    .viewedUser(ng-show='becomeUsed') Currently assuming "
+        strong {{user.username}}
+        | ",&nbsp;&nbsp;
+        a(href='/admin/become') revert to your identity.
+    .container
+        h1.navbar-brand
+            a(href='/') Apache Ignite Web Configurator
+        .navbar-collapse.collapse(ng-controller='auth')
+            ul.nav.navbar-nav(ng-controller='activeLink' ng-show='user')
+                +header-item('/configuration', '/configuration/clusters', 'Configuration')
+                //+header-item('/monitoring', '/monitoring', 'Monitoring')
+                //+header-item('/sql', '/sql', 'SQL')
+                //+header-item('/deploy', '/deploy', 'Deploy')
+            ul.nav.navbar-nav.pull-right
+                li(ng-if='user')
+                    a.dropdown-toggle(data-toggle='dropdown' bs-dropdown='userDropdown' data-placement='bottom-right') {{user.username}}
+                        span.caret
+                li.nav-login(ng-if='!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/8a335724/modules/web-control-center/src/main/js/views/index.jade
----------------------------------------------------------------------
diff --git a/modules/web-control-center/src/main/js/views/index.jade b/modules/web-control-center/src/main/js/views/index.jade
new file mode 100644
index 0000000..999c4f8
--- /dev/null
+++ b/modules/web-control-center/src/main/js/views/index.jade
@@ -0,0 +1,30 @@
+//-
+    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 templates/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/8a335724/modules/web-control-center/src/main/js/views/login.jade
----------------------------------------------------------------------
diff --git a/modules/web-control-center/src/main/js/views/login.jade b/modules/web-control-center/src/main/js/views/login.jade
new file mode 100644
index 0000000..5bb39dd
--- /dev/null
+++ b/modules/web-control-center/src/main/js/views/login.jade
@@ -0,0 +1,55 @@
+//-
+    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 lbl(txt)
+    label.col-sm-3.required #{txt}
+
+.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
+                    a(href='/') Apache Ignite Web Configurator
+                h4.modal-title(style='padding-right: 55px') Authentication
+                p(style='padding-right: 55px') Log in or register in order to collaborate
+            form.form-horizontal(name='loginForm')
+                .modal-body.row
+                    .col-sm-9.login.col-sm-offset-1
+                        .details-row(ng-show='action == "register"')
+                            +lbl('Full Name:')
+                            .col-sm-9
+                                input.form-control(type='text', ng-model='user_info.username', placeholder='John Smith', focus-me='action=="register"', ng-required='action=="register"')
+                        .details-row
+                            +lbl('Email:')
+                            .col-sm-9
+                                input.form-control(type='email', ng-model='user_info.email', placeholder='you@domain.com', focus-me='action=="login"', required)
+                        .details-row
+                            +lbl('Password:')
+                            .col-sm-9
+                                input.form-control(type='password', ng-model='user_info.password', placeholder='Password', required, ng-keyup='action == "login" && $event.keyCode == 13 ? auth(action, user_info) : null')
+                        .details-row(ng-show='action == "register"')
+                            +lbl('Confirm:')
+                            .col-sm-9.input-tip.has-feedback
+                                input.form-control(type='password', ng-model='user_info.confirm', match="user_info.password" placeholder='Confirm password', required, ng-keyup='$event.keyCode == 13 ? auth(action, user_info) : null')
+
+            .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-show='action == "login"' ng-click='auth(action, user_info)') Log In
+                button.btn.btn-primary(ng-show='action == "register"' ng-disabled='loginForm.$invalid || user_info.password != user_info.confirm' ng-click='auth(action, user_info)') Sign Up

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/src/main/js/views/settings/admin.jade
----------------------------------------------------------------------
diff --git a/modules/web-control-center/src/main/js/views/settings/admin.jade b/modules/web-control-center/src/main/js/views/settings/admin.jade
new file mode 100644
index 0000000..4d50631
--- /dev/null
+++ b/modules/web-control-center/src/main/js/views/settings/admin.jade
@@ -0,0 +1,58 @@
+//-
+    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 ../templates/layout
+
+append scripts
+    script(src='/admin-controller.js')
+
+block container
+    .row(ng-controller='adminController')
+        .docs-content
+            .docs-header
+                h1 List of registered users
+                hr
+            .docs-body
+                table.table.table-striped.admin(st-table='displayedUsers' st-safe-src='users')
+                    thead
+                        tr
+                            th.header(colspan='5')
+                                .col-sm-2.pull-right
+                                    input.form-control(type='text' st-search='' placeholder='Filter users...')
+                        tr
+                            th(st-sort='username') User name
+                            th(st-sort='email') Email
+                            th.col-sm-2(st-sort='lastLogin') Last login
+                            th(width='1%'  st-sort='admin') Admin
+                            th(width='1%') Actions
+                    tbody
+                        tr(ng-repeat='row in displayedUsers')
+                            td {{row.username}}
+                            td
+                                a(ng-href='mailto:{{row.email}}') {{row.email}}
+                            td
+                                span {{row.lastLogin | date:'medium'}}
+                            td(style='text-align: center;')
+                                input(type='checkbox' ng-disabled='row.adminChanging || row._id == user._id'
+                                    ng-model='row.admin' ng-change='toggleAdmin(row)')
+                            td(style='text-align: center;')
+                                a(ng-click='removeUser(row)' ng-show='row._id != user._id' bs-tooltip data-title='Remove user')
+                                    i.fa.fa-remove
+                                a(style='margin-left: 5px' ng-href='admin/become?viewedUserId={{row._id}}' ng-show='row._id != user._id' bs-tooltip data-title='Become this user')
+                                    i.fa.fa-eye
+                    tfoot
+                        tr
+                            td(colspan='5' class="text-right")
+                                div(st-pagination st-items-by-page='15' st-displayed-pages='5')
+

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/src/main/js/views/settings/profile.jade
----------------------------------------------------------------------
diff --git a/modules/web-control-center/src/main/js/views/settings/profile.jade b/modules/web-control-center/src/main/js/views/settings/profile.jade
new file mode 100644
index 0000000..dbc6dea
--- /dev/null
+++ b/modules/web-control-center/src/main/js/views/settings/profile.jade
@@ -0,0 +1,58 @@
+//-
+    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 ../templates/layout
+
+mixin lbl(txt)
+    label.col-sm-2.required.labelFormField #{txt}
+
+append scripts
+    script(src='/profile-controller.js')
+
+block container
+    .row(ng-controller='profileController')
+        .docs-content
+            .docs-header
+                h1 User profile
+                hr
+            .docs-body
+                form.form-horizontal(name='profileForm' novalidate)
+                    .col-sm-10(style='padding: 0')
+                        .details-row
+                            +lbl('User name:')
+                            .col-sm-4
+                                input.form-control(type='text' ng-model='profileUser.username' placeholder='Input name' required)
+                        .details-row
+                            +lbl('Email:')
+                            .col-sm-4
+                                input.form-control(type='email' ng-model='profileUser.email' placeholder='you@domain.com' required)
+                        .details-row
+                            .checkbox
+                                label
+                                    input(type="checkbox" ng-model='profileUser.changePassword')
+                                    | Change password
+                        div(ng-show='profileUser.changePassword')
+                            .details-row
+                                +lbl('New password:')
+                                .col-sm-4
+                                    input.form-control(type='password', ng-model='profileUser.newPassword' placeholder='New password' ng-required='profileUser.changePassword')
+                            .details-row
+                                +lbl('Confirm:')
+                                .col-sm-4
+                                    input.form-control(type='password', ng-model='profileUser.confirmPassword' match='profileUser.newPassword' placeholder='Confirm new password' ng-required='profileUser.changePassword')
+                    .col-sm-12.details-row
+                        button.btn.btn-primary(ng-disabled='profileForm.$invalid' ng-click='saveUser()') Save
+

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/src/main/js/views/templates/confirm.jade
----------------------------------------------------------------------
diff --git a/modules/web-control-center/src/main/js/views/templates/confirm.jade b/modules/web-control-center/src/main/js/views/templates/confirm.jade
new file mode 100644
index 0000000..bdaf9bf
--- /dev/null
+++ b/modules/web-control-center/src/main/js/views/templates/confirm.jade
@@ -0,0 +1,27 @@
+//-
+    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(tabindex='-1' role='dialog')
+    .modal-dialog
+        .modal-content
+            .modal-header
+                button.close(type="button" ng-click="$hide()") &times;
+                h4.modal-title Confirmation
+            .modal-body(ng-show='content')
+                p(ng-bind-html='content' style='text-align: center;')
+            .modal-footer
+                button.btn.btn-default(type="button" ng-click="$hide()") Cancel
+                button.btn.btn-primary(type="button" ng-click="ok()") Confirm
\ No newline at end of file



[09/10] incubator-ignite git commit: # ignite-843 moved

Posted by an...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/nodejs/controllers/models/caches.json
----------------------------------------------------------------------
diff --git a/modules/web-control-center/nodejs/controllers/models/caches.json b/modules/web-control-center/nodejs/controllers/models/caches.json
deleted file mode 100644
index 0ffc9d4..0000000
--- a/modules/web-control-center/nodejs/controllers/models/caches.json
+++ /dev/null
@@ -1,918 +0,0 @@
-{
-  "screenTip": {
-    "workflowTitle": "Use Caches view to:",
-    "workflowContent": [
-      "<ul>",
-      "  <li>Configure caches.</li>",
-      "  <li>Associate metadata with cache queries and/or cache store.</li>",
-      "</ul>"
-    ],
-    "whatsNextTitle": "What's next:",
-    "whatsNextContent": [
-      "<ul>",
-      "  <li>Configure clusters.</li>",
-      "  <li>Configure cache type metadata.</li>",
-      "  <li>Generate XML and java code on Summary view.</li>",
-      "</ul>"
-    ]
-  },
-  "general": [
-    {
-      "label": "Name",
-      "type": "text",
-      "model": "name",
-      "required": true,
-      "placeholder": "Input name"
-    },
-    {
-      "label": "Mode",
-      "type": "dropdown",
-      "model": "mode",
-      "placeholder": "PARTITIONED",
-      "items": "modes",
-      "tip": [
-        "Cache modes:",
-        "<ul>",
-        "  <li>Partitioned - in this mode the overall key set will be divided into partitions and all partitions will be split equally between participating nodes.</li>",
-        "  <li>Replicated - in this mode all the keys are distributed to all participating nodes.</li>",
-        "  <li>Local - in this mode caches residing on different grid nodes will not know about each other.</li>",
-        "</ul>"
-      ]
-    },
-    {
-      "label": "Atomicity",
-      "type": "dropdown",
-      "model": "atomicityMode",
-      "placeholder": "ATOMIC",
-      "items": "atomicities",
-      "tip": [
-        "Atomicity:",
-        "<ul>",
-        "  <li>Transactional - in this mode specified fully ACID-compliant transactional cache behavior.</li>",
-        "  <li>Atomic - in this mode distributed transactions and distributed locking are not supported.</li>",
-        "</ul>"
-      ]
-    },
-    {
-      "label": "Backups",
-      "type": "number",
-      "model": "backups",
-      "hide": "backupItem.mode == 'LOCAL'",
-      "placeholder": 0,
-      "tip": [
-        "Number of nodes used to back up single partition for partitioned cache."
-      ]
-    },
-    {
-      "label": "Read from backup",
-      "type": "check",
-      "model": "readFromBackup",
-      "placeholder": true,
-      "hide": "!backupItem.backups || backupItem.mode == 'LOCAL'",
-      "tip": [
-        "Flag indicating whether data can be read from backup.",
-        "If not set then always get data from primary node (never from backup)."
-      ]
-    },
-    {
-      "label": "Copy on read",
-      "type": "check",
-      "model": "copyOnRead",
-      "placeholder": true,
-      "tip": [
-        "Flag indicating whether copy of of the value stored in cache should be created for cache operation implying return value.",
-        "Also if this flag is set copies are created for values passed to CacheInterceptor and to CacheEntryProcessor."
-      ]
-    },
-    {
-      "label": "Invalidate near cache",
-      "type": "check",
-      "model": "invalidate",
-      "tip": [
-        "Invalidation flag for near cache entries in transaction.",
-        "If set then values will be invalidated (nullified) upon commit in near cache."
-      ]
-    }
-  ],
-  "advanced": [
-    {
-      "label": "Concurrency control",
-      "tip": [
-        "Cache concurrent usage settings."
-      ],
-      "fields": [
-        {
-          "label": "Max async operations",
-          "type": "number",
-          "model": "maxConcurrentAsyncOperations",
-          "placeholder": 500,
-          "tip": [
-            "Maximum number of allowed concurrent asynchronous operations.",
-            "If 0 then number of concurrent asynchronous operations is unlimited."
-          ]
-        },
-        {
-          "label": "Default lock timeout",
-          "type": "number",
-          "model": "defaultLockTimeout",
-          "placeholder": 0,
-          "tip": [
-            "Default lock acquisition timeout.",
-            "If 0 then lock acquisition will never timeout."
-          ]
-        },
-        {
-          "label": "Entry versioning",
-          "type": "dropdown",
-          "model": "atomicWriteOrderMode",
-          "placeholder": "Choose versioning",
-          "items": "atomicWriteOrderModes",
-          "hide": "backupItem.atomicityMode == 'TRANSACTIONAL'",
-          "tip": [
-            "Write ordering mode determines which node assigns the write version, sender or the primary node.",
-            "<ul>",
-            "  <li>CLOCK - in this mode write versions are assigned on a sender node which generally leads to better performance.</li>",
-            "  <li>PRIMARY - in this mode version is assigned only on primary node. This means that sender will only send write request to primary node, which in turn will assign write version and forward it to backups.</li>",
-            "</ul>"
-          ]
-        }
-      ]
-    },
-    {
-      "label": "Memory",
-      "tip": [
-        "Cache memory settings."
-      ],
-      "fields": [
-        {
-          "label": "Mode",
-          "type": "dropdown",
-          "model": "memoryMode",
-          "placeholder": "ONHEAP_TIERED",
-          "items": "memoryModes",
-          "tip": [
-            "Memory modes:",
-            "<ul>",
-            "  <li>ONHEAP_TIERED - entries are cached on heap memory first.",
-            "    <ul>",
-            "      <li>If offheap memory is enabled and eviction policy evicts an entry from heap memory, entry will be moved to offheap memory. If offheap memory is disabled, then entry is simply discarded.</li>",
-            "      <li>If swap space is enabled and offheap memory fills up, then entry will be evicted into swap space. If swap space is disabled, then entry will be discarded. If swap is enabled and offheap memory is disabled, then entry will be evicted directly from heap memory into swap.</li>",
-            "    </ul>",
-            "  </li>",
-            "  <li>OFFHEAP_TIERED - works the same as ONHEAP_TIERED, except that entries never end up in heap memory and get stored in offheap memory right away. Entries get cached in offheap memory first and then get evicted to swap, if one is configured.</li>",
-            "  <li>OFFHEAP_VALUES - entry keys will be stored on heap memory, and values will be stored in offheap memory. Note that in this mode entries can be evicted only to swap.</li>",
-            "</ul>"
-          ]
-        },
-        {
-          "label": "Off-heap max memory",
-          "type": "number",
-          "model": "offHeapMaxMemory",
-          "min": -1,
-          "placeholder": -1,
-          "hide": "backupItem.memoryMode == 'OFFHEAP_VALUES'",
-          "tip": [
-            "Sets maximum amount of memory available to off-heap storage.",
-            "Possible values are:",
-            "<ul>",
-            "  <li>-1 - means that off-heap storage is disabled.</li>",
-            "  <li>0 - Ignite will not limit off-heap storage (it's up to user to properly add and remove entries from cache to ensure that off-heap storage does not grow infinitely.</li>",
-            "  <li>Any positive value specifies the limit of off-heap storage in bytes.</li>",
-            "</ul>"
-          ]
-        },
-        {
-          "label": "Eviction policy",
-          "type": "dropdown-details",
-          "path": "evictionPolicy",
-          "model": "kind",
-          "placeholder": "Choose eviction policy",
-          "items": "evictionPolicies",
-          "hide": "backupItem.memoryMode == 'OFFHEAP_TIERED'",
-          "tip": [
-            "Optional cache eviction policy. Must be set for entries to be evicted from on-heap to off-heap or swap."
-          ],
-          "details": {
-            "LRU": {
-              "expanded": false,
-              "fields": [
-                {
-                  "label": "Batch size",
-                  "type": "number",
-                  "path": "evictionPolicy.LRU",
-                  "model": "batchSize",
-                  "placeholder": 1,
-                  "tip": [
-                    "Number of entries to remove on shrink."
-                  ]
-                },
-                {
-                  "label": "Max memory size",
-                  "type": "number",
-                  "path": "evictionPolicy.LRU",
-                  "model": "maxMemorySize",
-                  "placeholder": 0,
-                  "tip": [
-                    "Maximum allowed cache size in bytes."
-                  ]
-                },
-                {
-                  "label": "Max size",
-                  "type": "number",
-                  "path": "evictionPolicy.LRU",
-                  "model": "maxSize",
-                  "placeholder": 100000,
-                  "tip": [
-                    "Maximum allowed size of cache before entry will start getting evicted."
-                  ]
-                }
-              ]
-            },
-            "RND": {
-              "expanded": false,
-              "fields": [
-                {
-                  "label": "Max size",
-                  "type": "number",
-                  "path": "evictionPolicy.RND",
-                  "model": "maxSize",
-                  "placeholder": 100000,
-                  "tip": [
-                    "Maximum allowed size of cache before entry will start getting evicted."
-                  ]
-                }
-              ]
-            },
-            "FIFO": {
-              "expanded": false,
-              "fields": [
-                {
-                  "label": "Batch size",
-                  "type": "number",
-                  "path": "evictionPolicy.FIFO",
-                  "model": "batchSize",
-                  "placeholder": 1,
-                  "tip": [
-                    "Number of entries to remove on shrink."
-                  ]
-                },
-                {
-                  "label": "Max memory size",
-                  "type": "number",
-                  "path": "evictionPolicy.FIFO",
-                  "model": "maxMemorySize",
-                  "placeholder": 0,
-                  "tip": [
-                    "Maximum allowed cache size in bytes."
-                  ]
-                },
-                {
-                  "label": "Max size",
-                  "type": "number",
-                  "path": "evictionPolicy.FIFO",
-                  "model": "maxSize",
-                  "placeholder": 100000,
-                  "tip": [
-                    "Maximum allowed size of cache before entry will start getting evicted."
-                  ]
-                }
-              ]
-            },
-            "SORTED": {
-              "expanded": false,
-              "fields": [
-                {
-                  "label": "Batch size",
-                  "type": "number",
-                  "path": "evictionPolicy.SORTED",
-                  "model": "batchSize",
-                  "placeholder": 1,
-                  "tip": [
-                    "Number of entries to remove on shrink."
-                  ]
-                },
-                {
-                  "label": "Max memory size",
-                  "type": "number",
-                  "path": "evictionPolicy.SORTED",
-                  "model": "maxMemorySize",
-                  "placeholder": 0,
-                  "tip": [
-                    "Maximum allowed cache size in bytes."
-                  ]
-                },
-                {
-                  "label": "Max size",
-                  "type": "number",
-                  "path": "evictionPolicy.SORTED",
-                  "model": "maxSize",
-                  "placeholder": 100000,
-                  "tip": [
-                    "Maximum allowed size of cache before entry will start getting evicted."
-                  ]
-                }
-              ]
-            }
-          }
-        },
-        {
-          "label": "Start size",
-          "type": "number",
-          "model": "startSize",
-          "placeholder": 1500000,
-          "tip": [
-            "Initial cache size which will be used to pre-create internal hash table after start."
-          ]
-        },
-        {
-          "label": "Swap enabled",
-          "type": "check",
-          "model": "swapEnabled",
-          "tip": [
-            "Flag indicating whether swap storage is enabled or not for this cache."
-          ]
-        }
-      ]
-    },
-    {
-      "label": "Query",
-      "tip": [
-        "Cache query settings."
-      ],
-      "fields": [
-        {
-          "label": "Escape table and filed names",
-          "type": "check",
-          "model": "sqlEscapeAll",
-          "tip": [
-            "If set then all the SQL table and field names will be escaped with double quotes.",
-            "This enforces case sensitivity for field names and also allows having special characters in table and field names."
-          ]
-        },
-        {
-          "label": "On-heap cache for off-heap indexes",
-          "type": "number",
-          "model": "sqlOnheapRowCacheSize",
-          "placeholder": 10240,
-          "tip": [
-            "Number of SQL rows which will be cached onheap to avoid deserialization on each SQL index access."
-          ]
-        },
-        {
-          "label": "Long query timeout",
-          "type": "number",
-          "model": "longQueryWarningTimeout",
-          "placeholder": 3000,
-          "tip": [
-            "Timeout in milliseconds after which long query warning will be printed."
-          ]
-        },
-        {
-          "type": "indexedTypes",
-          "model": "indexedTypes",
-          "keyName": "keyClass",
-          "valueName": "valueClass",
-          "tip": [
-            "Collection of types to index."
-          ]
-        },
-        {
-          "label": "SQL functions",
-          "type": "table-simple",
-          "model": "sqlFunctionClasses",
-          "editIdx": -1,
-          "placeholder": "SQL function full class name",
-          "tableTip": [
-            "Collections of classes with user-defined functions for SQL queries."
-          ],
-          "tip": [
-            "Class with user-defined functions for SQL queries."
-          ]
-        }
-      ]
-    },
-    {
-      "label": "Rebalance",
-      "tip": [
-        "Cache rebalance settings."
-      ],
-      "fields": [
-        {
-          "label": "Mode",
-          "type": "dropdown",
-          "model": "rebalanceMode",
-          "placeholder": "ASYNC",
-          "items": "rebalanceModes",
-          "tip": [
-            "Rebalance modes:",
-            "<ul>",
-            "  <li>Synchronous - in this mode distributed caches will not start until all necessary data is loaded from other available grid nodes.</li>",
-            "  <li>Asynchronous - in this mode distributed caches will start immediately and will load all necessary data from other available grid nodes in the background.</li>",
-            "  <li>None - in this mode no rebalancing will take place which means that caches will be either loaded on demand from persistent store whenever data is accessed, or will be populated explicitly.</li>",
-            "</ul>"
-          ]
-        },
-        {
-          "label": "Pool size",
-          "type": "number",
-          "model": "rebalanceThreadPoolSize",
-          "placeholder": 2,
-          "tip": [
-            "Size of rebalancing thread pool.<br>",
-            "Note that size serves as a hint and implementation may create more threads for rebalancing than specified here (but never less threads)."
-          ]
-        },
-        {
-          "label": "Batch size",
-          "type": "number",
-          "model": "rebalanceBatchSize",
-          "placeholder": "512 * 1024",
-          "tip": [
-            "Size (in bytes) to be loaded within a single rebalance message.",
-            "Rebalancing algorithm will split total data set on every node into multiple batches prior to sending data."
-          ]
-        },
-        {
-          "label": "Order",
-          "type": "number",
-          "model": "rebalanceOrder",
-          "placeholder": 0,
-          "tip": [
-            "If cache rebalance order is positive, rebalancing for this cache will be started only when rebalancing for all caches with smaller rebalance order (except caches with rebalance order 0) will be completed."
-          ]
-        },
-        {
-          "label": "Delay",
-          "type": "number",
-          "model": "rebalanceDelay",
-          "placeholder": 0,
-          "tip": [
-            "Delay in milliseconds upon a node joining or leaving topology (or crash) after which rebalancing should be started automatically."
-          ]
-        },
-        {
-          "label": "Timeout",
-          "type": "number",
-          "model": "rebalanceTimeout",
-          "placeholder": 10000,
-          "tip": [
-            "Rebalance timeout in milliseconds."
-          ]
-        },
-        {
-          "label": "Throttle",
-          "type": "number",
-          "model": "rebalanceThrottle",
-          "placeholder": 0,
-          "tip": [
-            "Time in milliseconds to wait between rebalance messages to avoid overloading of CPU or network."
-          ]
-        }
-      ]
-    },
-    {
-      "label": "Server near cache",
-      "tip": [
-        "Near cache settings.",
-        "Near cache is a small local cache that stores most recently or most frequently accessed data.",
-        "Should be used in case when it is impossible to send computations to remote nodes."
-      ],
-      "fields": [
-        {
-          "label": "Enabled",
-          "type": "check",
-          "model": "nearCacheEnabled",
-          "tip": [
-            "Flag indicating whether to configure near cache."
-          ]
-        },
-        {
-          "label": "Start size",
-          "type": "number",
-          "path": "nearConfiguration",
-          "model": "nearStartSize",
-          "hide": "!backupItem.nearCacheEnabled",
-          "placeholder": 375000,
-          "tip": [
-            "Initial cache size for near cache which will be used to pre-create internal hash table after start."
-          ]
-        },
-        {
-          "label": "Eviction policy",
-          "type": "dropdown-details",
-          "path": "nearConfiguration.nearEvictionPolicy",
-          "model": "kind",
-          "placeholder": "Choose eviction policy",
-          "items": "evictionPolicies",
-          "hide": "!backupItem.nearCacheEnabled",
-          "tip": [
-            "Cache expiration policy."
-          ],
-          "details": {
-            "LRU": {
-              "expanded": false,
-              "fields": [
-                {
-                  "label": "Batch size",
-                  "type": "number",
-                  "path": "nearConfiguration.nearEvictionPolicy.LRU",
-                  "model": "batchSize",
-                  "placeholder": 1,
-                  "tip": [
-                    "Number of entries to remove on shrink."
-                  ]
-                },
-                {
-                  "label": "Max memory size",
-                  "type": "number",
-                  "path": "nearConfiguration.nearEvictionPolicy.LRU",
-                  "model": "maxMemorySize",
-                  "placeholder": 0,
-                  "tip": [
-                    "Maximum allowed cache size in bytes."
-                  ]
-                },
-                {
-                  "label": "Max size",
-                  "type": "number",
-                  "path": "nearConfiguration.nearEvictionPolicy.LRU",
-                  "model": "maxSize",
-                  "placeholder": 100000,
-                  "tip": [
-                    "Maximum allowed size of cache before entry will start getting evicted."
-                  ]
-                }
-              ]
-            },
-            "RND": {
-              "expanded": false,
-              "fields": [
-                {
-                  "label": "Max size",
-                  "type": "number",
-                  "path": "nearConfiguration.nearEvictionPolicy.RND",
-                  "model": "maxSize",
-                  "placeholder": 100000,
-                  "tip": [
-                    "Maximum allowed size of cache before entry will start getting evicted."
-                  ]
-                }
-              ]
-            },
-            "FIFO": {
-              "expanded": false,
-              "fields": [
-                {
-                  "label": "Batch size",
-                  "type": "number",
-                  "path": "nearConfiguration.nearEvictionPolicy.FIFO",
-                  "model": "batchSize",
-                  "placeholder": 1,
-                  "tip": [
-                    "Number of entries to remove on shrink."
-                  ]
-                },
-                {
-                  "label": "Max memory size",
-                  "type": "number",
-                  "path": "nearConfiguration.nearEvictionPolicy.FIFO",
-                  "model": "maxMemorySize",
-                  "placeholder": 0,
-                  "tip": [
-                    "Maximum allowed cache size in bytes."
-                  ]
-                },
-                {
-                  "label": "Max size",
-                  "type": "number",
-                  "path": "nearConfiguration.nearEvictionPolicy.FIFO",
-                  "model": "maxSize",
-                  "placeholder": 100000,
-                  "tip": [
-                    "Maximum allowed size of cache before entry will start getting evicted."
-                  ]
-                }
-              ]
-            },
-            "SORTED": {
-              "expanded": false,
-              "fields": [
-                {
-                  "label": "Batch size",
-                  "type": "number",
-                  "path": "nearConfiguration.nearEvictionPolicy.SORTED",
-                  "model": "batchSize",
-                  "placeholder": 1,
-                  "tip": [
-                    "Number of entries to remove on shrink."
-                  ]
-                },
-                {
-                  "label": "Max memory size",
-                  "type": "number",
-                  "path": "nearConfiguration.nearEvictionPolicy.SORTED",
-                  "model": "maxMemorySize",
-                  "placeholder": 0,
-                  "tip": [
-                    "Maximum allowed cache size in bytes."
-                  ]
-                },
-                {
-                  "label": "Max size",
-                  "type": "number",
-                  "path": "nearConfiguration.nearEvictionPolicy.SORTED",
-                  "model": "maxSize",
-                  "placeholder": 100000,
-                  "tip": [
-                    "Maximum allowed size of cache before entry will start getting evicted."
-                  ]
-                }
-              ]
-            }
-          }
-        }
-      ]
-    },
-    {
-      "label": "Statistics",
-      "tip": [
-        "Cache statistics and management settings."
-      ],
-      "fields": [
-        {
-          "label": "Statistics enabled",
-          "type": "check",
-          "model": "statisticsEnabled",
-          "tip": [
-            "Flag indicating whether statistics gathering is enabled on a cache."
-          ]
-        },
-        {
-          "label": "Management enabled",
-          "type": "check",
-          "model": "managementEnabled",
-          "tip": [
-            "Flag indicating whether management is enabled on this cache."
-          ]
-        }
-      ]
-    },
-    {
-      "label": "Store",
-      "tip": [
-        "Cache store settings."
-      ],
-      "fields": [
-        {
-          "label": "Store factory",
-          "type": "dropdown-details",
-          "path": "cacheStoreFactory",
-          "model": "kind",
-          "placeholder": "Choose store factory",
-          "items": "cacheStoreFactories",
-          "tip": [
-            "Factory for persistent storage for cache data."
-          ],
-          "details": {
-            "CacheJdbcPojoStoreFactory": {
-              "expanded": true,
-              "fields": [
-                {
-                  "label": "Data source bean",
-                  "type": "text",
-                  "path": "cacheStoreFactory.CacheJdbcPojoStoreFactory",
-                  "model": "dataSourceBean",
-                  "required": true,
-                  "placeholder": "Bean name in Spring context",
-                  "tip": [
-                    "Name of the data source bean in Spring context."
-                  ]
-                },
-                {
-                  "label": "Dialect",
-                  "type": "dropdown",
-                  "path": "cacheStoreFactory.CacheJdbcPojoStoreFactory",
-                  "model": "dialect",
-                  "required": true,
-                  "placeholder": "Choose JDBC dialect",
-                  "items": "cacheStoreJdbcDialects",
-                  "tip": [
-                    "Dialect of SQL implemented by a particular RDBMS:",
-                    "<ul>",
-                    "  <li>Generic JDBC dialect.</li>",
-                    "  <li>Oracle database.</li>",
-                    "  <li>IBM DB2.</li>",
-                    "  <li>Microsoft SQL Server.</li>",
-                    "  <li>My SQL.</li>",
-                    "  <li>H2 database.</li>",
-                    "</ul>"
-                  ]
-                }
-              ]
-            },
-            "CacheJdbcBlobStoreFactory": {
-              "expanded": true,
-              "fields": [
-                {
-                  "label": "user",
-                  "type": "text",
-                  "path": "cacheStoreFactory.CacheJdbcBlobStoreFactory",
-                  "model": "user",
-                  "required": true,
-                  "tip": [
-                    "User name for database access."
-                  ]
-                },
-                {
-                  "label": "Data source bean",
-                  "type": "text",
-                  "path": "cacheStoreFactory.CacheJdbcBlobStoreFactory",
-                  "model": "dataSourceBean",
-                  "required": true,
-                  "placeholder": "Bean name in Spring context",
-                  "tip": [
-                    "Name of the data source bean in Spring context."
-                  ]
-                },
-                {
-                  "label": "Init schema",
-                  "type": "check",
-                  "path": "cacheStoreFactory.CacheJdbcBlobStoreFactory",
-                  "model": "initSchema",
-                  "tip": [
-                    "Flag indicating whether DB schema should be initialized by Ignite (default behaviour) or was explicitly created by user."
-                  ]
-                },
-                {
-                  "label": "Create query",
-                  "type": "text",
-                  "path": "cacheStoreFactory.CacheJdbcBlobStoreFactory",
-                  "model": "createTableQuery",
-                  "placeholder": "SQL for table creation",
-                  "tip": [
-                    "Query for table creation in underlying database.",
-                    "Default value: create table if not exists ENTRIES (key binary primary key, val binary)"
-                  ]
-                },
-                {
-                  "label": "Load query",
-                  "type": "text",
-                  "path": "cacheStoreFactory.CacheJdbcBlobStoreFactory",
-                  "model": "loadQuery",
-                  "placeholder": "SQL for load entry",
-                  "tip": [
-                    "Query for entry load from underlying database.",
-                    "Default value: select * from ENTRIES where key=?"
-                  ]
-                },
-                {
-                  "label": "Insert query",
-                  "type": "text",
-                  "path": "cacheStoreFactory.CacheJdbcBlobStoreFactory",
-                  "model": "insertQuery",
-                  "placeholder": "SQL for insert entry",
-                  "tip": [
-                    "Query for insert entry into underlying database.",
-                    "Default value: insert into ENTRIES (key, val) values (?, ?)"
-                  ]
-                },
-                {
-                  "label": "Update query",
-                  "type": "text",
-                  "path": "cacheStoreFactory.CacheJdbcBlobStoreFactory",
-                  "model": "updateQuery",
-                  "placeholder": "SQL for update entry",
-                  "tip": [
-                    "Query fpr update entry in underlying database.",
-                    "Default value: update ENTRIES set val=? where key=?"
-                  ]
-                },
-                {
-                  "label": "Delete query",
-                  "type": "text",
-                  "path": "cacheStoreFactory.CacheJdbcBlobStoreFactory",
-                  "model": "deleteQuery",
-                  "placeholder": "SQL for delete entry",
-                  "tip": [
-                    "Query for delete entry from underlying database.",
-                    "Default value: delete from ENTRIES where key=?"
-                  ]
-                }
-              ]
-            },
-            "CacheHibernateBlobStoreFactory": {
-              "expanded": true,
-              "fields": [
-                {
-                  "label": "Hibernate properties",
-                  "type": "table-simple",
-                  "path": "cacheStoreFactory.CacheHibernateBlobStoreFactory",
-                  "model": "hibernateProperties",
-                  "editIdx": -1,
-                  "placeholder": "key=value",
-                  "tip": [
-                    "List of Hibernate properties.",
-                    "For example: connection.url=jdbc:h2:mem:"
-                  ]
-                }
-              ]
-            }
-          }
-        },
-        {
-          "label": "Load previous value",
-          "type": "check",
-          "model": "loadPreviousValue",
-          "tip": [
-            "Flag indicating whether value should be loaded from store if it is not in the cache for following cache operations:",
-            "<ul>",
-            "  <li>IgniteCache.putIfAbsent()</li>",
-            "  <li>IgniteCache.replace()</li>",
-            "  <li>IgniteCache.replace()</li>",
-            "  <li>IgniteCache.remove()</li>",
-            "  <li>IgniteCache.getAndPut()</li>",
-            "  <li>IgniteCache.getAndRemove()</li>",
-            "  <li>IgniteCache.getAndReplace()</li>",
-            "  <li>IgniteCache.getAndPutIfAbsent()</li>",
-            "</ul>"
-          ]
-        },
-        {
-          "label": "Read-through",
-          "type": "check",
-          "model": "readThrough",
-          "tip": [
-            "Flag indicating whether read-through caching should be used."
-          ]
-        },
-        {
-          "label": "Write-through",
-          "type": "check",
-          "model": "writeThrough",
-          "tip": [
-            "Flag indicating whether write-through caching should be used."
-          ]
-        }
-      ]
-    },
-    {
-      "label": "Write behind",
-      "tip": [
-        "Cache write behind settings.",
-        "Write-behind is a special mode when updates to cache accumulated and then asynchronously flushed to persistent store as a bulk operation."
-      ],
-      "fields": [
-        {
-          "label": "Enabled",
-          "type": "check",
-          "model": "writeBehindEnabled",
-          "tip": [
-            "Flag indicating whether Ignite should use write-behind behaviour for the cache store."
-          ]
-        },
-        {
-          "label": "Batch size",
-          "type": "number",
-          "model": "writeBehindBatchSize",
-          "hide": "!backupItem.writeBehindEnabled",
-          "placeholder": 512,
-          "tip": [
-            "Maximum batch size for write-behind cache store operations.",
-            "Store operations (get or remove) are combined in a batch of this size to be passed to cache store."
-          ]
-        },
-        {
-          "label": "Flush size",
-          "type": "number",
-          "model": "writeBehindFlushSize",
-          "hide": "!backupItem.writeBehindEnabled",
-          "placeholder": 10240,
-          "tip": [
-            "Maximum size of the write-behind cache.<br>",
-            "If cache size exceeds this value, all cached items are flushed to the cache store and write cache is cleared."
-          ]
-        },
-        {
-          "label": "Flush frequency",
-          "type": "number",
-          "model": "writeBehindFlushFrequency",
-          "hide": "!backupItem.writeBehindEnabled",
-          "placeholder": 5000,
-          "tip": [
-            "Frequency with which write-behind cache is flushed to the cache store in milliseconds."
-          ]
-        },
-        {
-          "label": "Flush threads count",
-          "type": "number",
-          "model": "writeBehindFlushThreadCount",
-          "hide": "!backupItem.writeBehindEnabled",
-          "placeholder": 1,
-          "tip": [
-            "Number of threads that will perform cache flushing."
-          ]
-        }
-      ]
-    }
-  ]
-}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/nodejs/controllers/models/clusters.json
----------------------------------------------------------------------
diff --git a/modules/web-control-center/nodejs/controllers/models/clusters.json b/modules/web-control-center/nodejs/controllers/models/clusters.json
deleted file mode 100644
index d6d7d23..0000000
--- a/modules/web-control-center/nodejs/controllers/models/clusters.json
+++ /dev/null
@@ -1,907 +0,0 @@
-{
-  "screenTip": {
-    "workflowTitle": "Use Clusters view to:",
-    "workflowContent": [
-      "<ul>",
-      "  <li>Configure clusters.</li>",
-      "  <li>Associate clusters with caches.</li>",
-      "</ul>"
-    ],
-    "whatsNextTitle": "What's next:",
-    "whatsNextContent": [
-      "<ul>",
-      "  <li>Configure cache type metadata.</li>",
-      "  <li>Configure caches.</li>",
-      "  <li>Generate XML and java code on Summary view.</li>",
-      "</ul>"
-    ]
-  },
-  "templateTip": [
-    "Use following template to add a new cluster:",
-    "<ul>",
-    "  <li>multicast - cluster with multicast discovery.</li>",
-    "  <li>local - cluster with static ips discovery and pre-configured list of IP addresses.</li>",
-    "</ul>"
-  ],
-  "general": [
-    {
-      "label": "Name",
-      "type": "text",
-      "model": "name",
-      "required": true,
-      "placeholder": "Input name"
-    },
-    {
-      "label": "Caches",
-      "type": "dropdown-multiple",
-      "model": "caches",
-      "placeholder": "Choose caches",
-      "items": "caches",
-      "tip": [
-        "Select caches to start in cluster or add a new cache."
-      ],
-      "addLink": {
-        "label": "Add cache(s)",
-        "ref": "/configuration/caches"
-      }
-    },
-    {
-      "label": "Discovery",
-      "type": "dropdown-details",
-      "path": "discovery",
-      "model": "kind",
-      "required": true,
-      "placeholder": "Choose discovery",
-      "items": "discoveries",
-      "tip": [
-        "Discovery allows to discover remote nodes in grid."
-      ],
-      "details": {
-        "Vm": {
-          "expanded": true,
-          "fields": [
-            {
-              "type": "table-simple",
-              "path": "discovery.Vm",
-              "model": "addresses",
-              "editIdx": -1,
-              "reordering": true,
-              "ipaddress": true,
-              "placeholder": "IP address:port",
-              "tip": [
-                "Addresses may be represented as follows:",
-                "<ul>",
-                "  <li>IP address (e.g. 127.0.0.1, 9.9.9.9, etc);</li>",
-                "  <li>IP address and port (e.g. 127.0.0.1:47500, 9.9.9.9:47501, etc);</li>",
-                "  <li>IP address and port range (e.g. 127.0.0.1:47500..47510, 9.9.9.9:47501..47504, etc);</li>",
-                "  <li>Hostname (e.g. host1.com, host2, etc);</li>",
-                "  <li>Hostname and port (e.g. host1.com:47500, host2:47502, etc).</li>",
-                "  <li>Hostname and port range (e.g. host1.com:47500..47510, host2:47502..47508, etc).</li>",
-                "</ul>",
-                "If port is 0 or not provided then default port will be used (depends on discovery SPI configuration).",
-                "If port range is provided (e.g. host:port1..port2) the following should be considered:",
-                "<ul>",
-                "  <li>port1 < port2 should be true;</li>",
-                "  <li>Both port1 and port2 should be greater than 0.</li>",
-                "</ul>"
-              ]
-            }
-          ]
-        },
-        "Multicast": {
-          "expanded": false,
-          "fields": [
-            {
-              "label": "IP address",
-              "type": "text",
-              "path": "discovery.Multicast",
-              "model": "multicastGroup",
-              "placeholder": "228.1.2.4",
-              "tip": [
-                "IP address of multicast group."
-              ]
-            },
-            {
-              "label": "Port number",
-              "type": "number",
-              "path": "discovery.Multicast",
-              "model": "multicastPort",
-              "max": 65535,
-              "placeholder": 47400,
-              "tip": [
-                "Port number which multicast messages are sent to."
-              ]
-            },
-            {
-              "label": "Waits for reply",
-              "type": "number",
-              "path": "discovery.Multicast",
-              "model": "responseWaitTime",
-              "placeholder": 500,
-              "tip": [
-                "Time in milliseconds IP finder waits for reply to multicast address request."
-              ]
-            },
-            {
-              "label": "Attempts count",
-              "type": "number",
-              "path": "discovery.Multicast",
-              "model": "addressRequestAttempts",
-              "placeholder": 2,
-              "tip": [
-                "Number of attempts to send multicast address request.",
-                "IP finder re-sends request only in case if no reply for previous request is received."
-              ]
-            },
-            {
-              "label": "Local address",
-              "type": "text",
-              "path": "discovery.Multicast",
-              "model": "localAddress",
-              "tip": [
-                "Local host address used by this IP finder.",
-                "If provided address is non-loopback then multicast socket is bound to this interface.",
-                "If local address is not set or is any local address then IP finder creates multicast sockets for all found non-loopback addresses."
-              ]
-            }
-          ]
-        },
-        "S3": {
-          "expanded": true,
-          "fields": [
-            {
-              "label": "Bucket name",
-              "type": "text",
-              "required": true,
-              "path": "discovery.S3",
-              "model": "bucketName",
-              "placeholder": "",
-              "tip": [
-                "Bucket name for IP finder."
-              ]
-            },
-            {
-              "label": "Note, AWS credentials will be generated as stubs.",
-              "type": "label"
-            }
-          ]
-        },
-        "Cloud": {
-          "expanded": true,
-          "fields": [
-            {
-              "label": "Credential",
-              "type": "text",
-              "path": "discovery.Cloud",
-              "model": "credential",
-              "placeholder": "",
-              "tip": [
-                "Credential that is used during authentication on the cloud.",
-                "Depending on a cloud platform it can be a password or access key."
-              ]
-            },
-            {
-              "label": "Path to credential",
-              "type": "text",
-              "path": "discovery.Cloud",
-              "model": "credentialPath",
-              "placeholder": "",
-              "tip": [
-                "Path to a credential that is used during authentication on the cloud.",
-                "Access key or private key should be stored in a plain or PEM file without a passphrase."
-              ]
-            },
-            {
-              "label": "Identity",
-              "type": "text",
-              "required": true,
-              "path": "discovery.Cloud",
-              "model": "identity",
-              "placeholder": "",
-              "tip": [
-                "Identity that is used as a user name during a connection to the cloud.",
-                "Depending on a cloud platform it can be an email address, user name, etc."
-              ]
-            },
-            {
-              "label": "Provider",
-              "type": "text",
-              "required": true,
-              "path": "discovery.Cloud",
-              "model": "provider",
-              "placeholder": "",
-              "tip": [
-                "Cloud provider to use."
-              ]
-            },
-            {
-              "label": "Regions",
-              "type": "table-simple",
-              "path": "discovery.Cloud",
-              "model": "regions",
-              "editIdx": -1,
-              "placeholder": "",
-              "tableTip": [
-                "List of regions where VMs are located.",
-                "If the regions are not set then every region, that a cloud provider has, will be investigated. This could lead to significant performance degradation.",
-                "Note, that some cloud providers, like Google Compute Engine, doesn't have a notion of a region. For such providers a call to this method is redundant."
-              ],
-              "tip": [
-                "Region where VMs are located."
-              ]
-            },
-            {
-              "label": "Zones",
-              "type": "table-simple",
-              "path": "discovery.Cloud",
-              "model": "zones",
-              "editIdx": -1,
-              "placeholder": "",
-              "tableTip": [
-                "List of zones where VMs are located.",
-                "If the zones are not set then every zone from regions, set by {@link #setRegions(Collection)}}, will be taken into account.",
-                "Note, that some cloud providers, like Rackspace, doesn't have a notion of a zone. For such providers a call to this method is redundant."
-              ],
-              "tip": [
-                "Zone where VMs are located."
-              ]
-            }
-          ]
-        },
-        "GoogleStorage": {
-          "expanded": true,
-          "fields": [
-            {
-              "label": "Project name",
-              "type": "text",
-              "required": true,
-              "path": "discovery.GoogleStorage",
-              "model": "projectName",
-              "placeholder": "",
-              "tip": [
-                "Google Cloud Platforms project name.",
-                "Usually this is an auto generated project number (ex. 208709979073) that can be found in 'Overview' section of Google Developer Console."
-              ]
-            },
-            {
-              "label": "Bucket name",
-              "type": "text",
-              "required": true,
-              "path": "discovery.GoogleStorage",
-              "model": "bucketName",
-              "placeholder": "",
-              "tip": [
-                "Google Cloud Storage bucket name.",
-                "If the bucket doesn't exist Ignite will automatically create it.",
-                "However the name must be unique across whole Google Cloud Storage and Service Account Id must be authorized to perform this operation."
-              ]
-            },
-            {
-              "label": "Private key path",
-              "type": "text",
-              "required": true,
-              "path": "discovery.GoogleStorage",
-              "model": "serviceAccountP12FilePath",
-              "placeholder": "",
-              "tip": [
-                "Full path to the private key in PKCS12 format of the Service Account."
-              ]
-            },
-            {
-              "label": "Account id",
-              "type": "text",
-              "required": true,
-              "path": "discovery.GoogleStorage",
-              "model": "accountId",
-              "placeholder": "",
-              "tip": [
-                "Service account ID (typically an e-mail address)."
-              ]
-            }
-          ]
-        },
-        "Jdbc": {
-          "expanded": true,
-          "fields": [
-            {
-              "label": "DB schema should be initialized by Ignite",
-              "type": "check",
-              "path": "discovery.Jdbc",
-              "model": "initSchema",
-              "tip": [
-                "Flag indicating whether DB schema should be initialized by Ignite or was explicitly created by user."
-              ]
-            }
-          ]
-        },
-        "SharedFs": {
-          "expanded": false,
-          "fields": [
-            {
-              "label": "File path",
-              "type": "text",
-              "path": "discovery.SharedFs",
-              "model": "path",
-              "placeholder": "disco/tcp"
-            }
-          ]
-        }
-      }
-    }
-  ],
-  "advanced": [
-    {
-      "label": "Atomics configuration",
-      "tip": [
-        "Configuration for atomic data structures.",
-        "Atomics are distributed across the cluster, essentially enabling performing atomic operations (such as increment-and-get or compare-and-set) with the same globally-visible value."
-      ],
-      "fields": [
-        {
-          "label": "Backups",
-          "type": "number",
-          "path": "atomicConfiguration",
-          "model": "backups",
-          "placeholder": 0,
-          "tip": [
-            "Number of backup nodes."
-          ]
-        },
-        {
-          "label": "Cache mode",
-          "type": "dropdown",
-          "path": "atomicConfiguration",
-          "model": "cacheMode",
-          "placeholder": "PARTITIONED",
-          "items": "cacheModes",
-          "tip": [
-            "Cache modes:",
-            "<ul>",
-            "  <li>Partitioned - in this mode the overall key set will be divided into partitions and all partitions will be split equally between participating nodes.</li>",
-            "  <li>Replicated - in this mode all the keys are distributed to all participating nodes.</li>",
-            "  <li>Local - in this mode caches residing on different grid nodes will not know about each other.</li>",
-            "</ul>"
-          ]
-        },
-        {
-          "label": "Sequence reserve",
-          "type": "number",
-          "path": "atomicConfiguration",
-          "model": "atomicSequenceReserveSize",
-          "placeholder": 1000,
-          "tip": [
-            "Default number of sequence values reserved for IgniteAtomicSequence instances.",
-            "After a certain number has been reserved, consequent increments of sequence will happen locally, without communication with other nodes, until the next reservation has to be made."
-          ]
-        }
-      ]
-    },
-    {
-      "label": "Communication",
-      "tip": [
-        "Cluster communication network properties."
-      ],
-      "fields": [
-        {
-          "label": "Timeout",
-          "type": "number",
-          "model": "networkTimeout",
-          "placeholder": 5000,
-          "tip": [
-            "Maximum timeout in milliseconds for network requests."
-          ]
-        },
-        {
-          "label": "Send retry delay",
-          "type": "number",
-          "model": "networkSendRetryDelay",
-          "placeholder": 1000,
-          "tip": [
-            "Interval in milliseconds between message send retries."
-          ]
-        },
-        {
-          "label": "Send retry count",
-          "type": "number",
-          "model": "networkSendRetryCount",
-          "placeholder": 3,
-          "tip": [
-            "Message send retries count."
-          ]
-        },
-        {
-          "label": "Segment check frequency",
-          "type": "number",
-          "model": "segmentCheckFrequency",
-          "placeholder": 10000,
-          "tip": [
-            "Network segment check frequency in milliseconds.",
-            "If 0, periodic segment check is disabled and segment is checked only on topology changes (if segmentation resolvers are configured)."
-          ]
-        },
-        {
-          "label": "Wait for segment on start",
-          "type": "check",
-          "model": "waitForSegmentOnStart",
-          "tip": [
-            "Wait for segment on start flag.",
-            "<ul>",
-            "  <li>If enabled, node should wait for correct segment on start.</li>",
-            "  <li>If node detects that segment is incorrect on startup and enabled, node waits until segment becomes correct.</li>",
-            "  <li>If segment is incorrect on startup and disabled, exception is thrown.</li>",
-            "</ul>"
-          ]
-        },
-        {
-          "label": "Discovery startup delay",
-          "type": "number",
-          "model": "discoveryStartupDelay",
-          "placeholder": 600000,
-          "tip": [
-            "This value is used to expire messages from waiting list whenever node discovery discrepancies happen."
-          ]
-        }
-      ]
-    },
-    {
-      "label": "Deployment",
-      "tip": [
-        "Task and resources deployment in cluster."
-      ],
-      "fields": [
-        {
-          "label": "Mode",
-          "type": "dropdown",
-          "model": "deploymentMode",
-          "placeholder": "SHARED",
-          "items": "deploymentModes",
-          "tip": [
-            "Task classes and resources sharing mode."
-          ]
-        }
-      ]
-    },
-    {
-      "label": "Events",
-      "tip": [
-        " Grid events are used for notification about what happens within the grid."
-      ],
-      "fields": [
-        {
-          "label": "Include type",
-          "type": "dropdown-multiple",
-          "model": "includeEventTypes",
-          "placeholder": "Choose recorded event types",
-          "items": "events",
-          "tip": [
-            "Array of event types, which will be recorded by GridEventStorageManager#record(Event).",
-            "Note, that either the include event types or the exclude event types can be established."
-          ]
-        }
-      ]
-    },
-    {
-      "label": "Marshaller",
-      "tip": [
-        "Marshaller allows to marshal or unmarshal objects in grid.",
-        "It provides serialization/deserialization mechanism for all instances that are sent across networks or are otherwise serialized."
-      ],
-      "fields": [
-        {
-          "label": "Marshaller",
-          "type": "dropdown-details",
-          "path": "marshaller",
-          "model": "kind",
-          "placeholder": "Choose marshaller",
-          "items": "marshallers",
-          "tip": [
-            "Instance of marshaller to use in grid. If not provided, OptimizedMarshaller will be used on Java HotSpot VM, and JdkMarshaller will be used on other VMs."
-          ],
-          "details": {
-            "OptimizedMarshaller": {
-              "expanded": false,
-              "fields": [
-                {
-                  "label": "Streams pool size",
-                  "type": "number",
-                  "path": "marshaller.OptimizedMarshaller",
-                  "model": "poolSize",
-                  "placeholder": 0,
-                  "tip": [
-                    "Specifies size of cached object streams used by marshaller.",
-                    "Object streams are cached for performance reason to avoid costly recreation for every serialization routine.",
-                    "If 0 (default), pool is not used and each thread has its own cached object stream which it keeps reusing.",
-                    "Since each stream has an internal buffer, creating a stream for each thread can lead to high memory consumption if many large messages are marshalled or unmarshalled concurrently.",
-                    "Consider using pool in this case. This will limit number of streams that can be created and, therefore, decrease memory consumption.",
-                    "NOTE: Using streams pool can decrease performance since streams will be shared between different threads which will lead to more frequent context switching."
-                  ]
-                },
-                {
-                  "label": "Require serializable",
-                  "type": "check",
-                  "path": "marshaller.OptimizedMarshaller",
-                  "model": "requireSerializable",
-                  "tip": [
-                    "Whether marshaller should require Serializable interface or not."
-                  ]
-                }
-              ]
-            }
-          }
-        },
-        {
-          "label": "Marshal local jobs",
-          "type": "check",
-          "model": "marshalLocalJobs",
-          "placeholder": "false",
-          "tip": [
-            "If this flag is enabled, jobs mapped to local node will be marshalled as if it was remote node."
-          ]
-        },
-        {
-          "label": "Keep alive time",
-          "type": "number",
-          "model": "marshallerCacheKeepAliveTime",
-          "placeholder": 10000,
-          "tip": [
-            "Keep alive time of thread pool that is in charge of processing marshaller messages."
-          ]
-        },
-        {
-          "label": "Pool size",
-          "type": "number",
-          "model": "marshallerCacheThreadPoolSize",
-          "placeholder": "max(8, availableProcessors) * 2",
-          "tip": [
-            "Default size of thread pool that is in charge of processing marshaller messages."
-          ]
-        }
-      ]
-    },
-    {
-      "label": "Metrics",
-      "tip": [
-        "Cluster runtime metrics settings."
-      ],
-      "fields": [
-        {
-          "label": "Elapsed time",
-          "type": "number",
-          "model": "metricsExpireTime",
-          "placeholder": "Long.MAX_VALUE",
-          "min": 1,
-          "tip": [
-            "Time in milliseconds after which a certain metric value is considered expired."
-          ]
-        },
-        {
-          "label": "History size",
-          "type": "number",
-          "model": "metricsHistorySize",
-          "placeholder": 10000,
-          "min": 1,
-          "tip": [
-            "Number of metrics kept in history to compute totals and averages."
-          ]
-        },
-        {
-          "label": "Log frequency",
-          "type": "number",
-          "model": "metricsLogFrequency",
-          "placeholder": 60000,
-          "tip": [
-            "Frequency of metrics log print out. To disable set to 0"
-          ]
-        },
-        {
-          "label": "Update frequency",
-          "type": "number",
-          "model": "metricsUpdateFrequency",
-          "placeholder": 60000,
-          "tip": [
-            "Job metrics update frequency in milliseconds.",
-            "<ul>",
-            "  <li>If set to -1 job metrics are never updated.</li>",
-            "  <li>If set to 0 job metrics are updated on each job start and finish.</li>",
-            "  <li>Positive value defines the actual update frequency.</li>",
-            "</ul>"
-          ]
-        }
-      ]
-    },
-    {
-      "label": "Peer Class Loading",
-      "tip": [
-        "Cluster peer class loading settings."
-      ],
-      "fields": [
-        {
-          "label": "Enable peer class loading",
-          "type": "check",
-          "model": "peerClassLoadingEnabled",
-          "tip": [
-            "Enables/disables peer class loading."
-          ]
-        },
-        {
-          "label": "Local class path exclude",
-          "type": "text",
-          "model": "peerClassLoadingLocalClassPathExclude",
-          "placeholder": "[]",
-          "tip": [
-            "List of packages separated by comma from the system classpath that need to be peer-to-peer loaded from task originating node.",
-            "'*' is supported at the end of the package name which means that all sub-packages and their classes are included like in Java package import clause."
-          ]
-        },
-        {
-          "label": "Missed resources cache size",
-          "type": "number",
-          "model": "peerClassLoadingMissedResourcesCacheSize",
-          "placeholder": 100,
-          "tip": [
-            "If size greater than 0, missed resources will be cached and next resource request ignored.",
-            "If size is 0, then request for the resource will be sent to the remote node every time this resource is requested."
-          ]
-        },
-        {
-          "label": "Pool size",
-          "type": "number",
-          "model": "peerClassLoadingThreadPoolSize",
-          "placeholder": "availableProcessors",
-          "tip": [
-            "Thread pool size to use for peer class loading."
-          ]
-        }
-      ]
-    },
-    {
-      "label": "Swap",
-      "tip": [
-        "Settings for overflow data to disk if it cannot fit in memory."
-      ],
-      "fields": [
-        {
-          "label": "Swap space SPI",
-          "type": "dropdown-details",
-          "path": "swapSpaceSpi",
-          "model": "kind",
-          "items": "swapSpaceSpis",
-          "placeholder": "Choose swap SPI",
-          "tip": [
-            "Provides a mechanism in grid for storing data on disk.",
-            "Ignite cache uses swap space to overflow data to disk if it cannot fit in memory."
-          ],
-          "details": {
-            "FileSwapSpaceSpi": {
-              "fields": [
-                {
-                  "label": "Base directory",
-                  "type": "text",
-                  "path": "swapSpaceSpi.FileSwapSpaceSpi",
-                  "model": "baseDirectory",
-                  "placeholder": "swapspace",
-                  "tip": [
-                    "Base directory where to write files."
-                  ]
-                },
-                {
-                  "label": "Read stripe size",
-                  "type": "number",
-                  "path": "swapSpaceSpi.FileSwapSpaceSpi",
-                  "model": "readStripesNumber",
-                  "placeholder": "available CPU cores",
-                  "tip": [
-                    "Read stripe size defines number of file channels to be used concurrently."
-                  ]
-                },
-                {
-                  "label": "Maximum sparsity",
-                  "type": "number",
-                  "path": "swapSpaceSpi.FileSwapSpaceSpi",
-                  "model": "maximumSparsity",
-                  "placeholder": 0.5,
-                  "tip": [
-                    "This property defines maximum acceptable wasted file space to whole file size ratio.",
-                    "When this ratio becomes higher than specified number compacting thread starts working."
-                  ]
-                },
-                {
-                  "label": "Max write queue size",
-                  "type": "number",
-                  "path": "swapSpaceSpi.FileSwapSpaceSpi",
-                  "model": "maxWriteQueueSize",
-                  "placeholder": "1024 * 1024",
-                  "tip": [
-                    "Max write queue size in bytes.",
-                    "If there are more values are waiting for being written to disk then specified size, SPI will block on store operation."
-                  ]
-                },
-                {
-                  "label": "Write buffer size",
-                  "type": "number",
-                  "path": "swapSpaceSpi.FileSwapSpaceSpi",
-                  "model": "writeBufferSize",
-                  "placeholder": "Available CPU cores",
-                  "tip": [
-                    "Write buffer size in bytes.",
-                    "Write to disk occurs only when this buffer is full."
-                  ]
-                }
-              ]
-            }
-          }
-        }
-      ]
-    },
-    {
-      "label": "Time configuration",
-      "tip": [
-        "Time settings for CLOCK write ordering mode."
-      ],
-      "fields": [
-        {
-          "label": "Samples size",
-          "type": "number",
-          "model": "clockSyncSamples",
-          "placeholder": 8,
-          "tip": [
-            "Number of samples used to synchronize clocks between different nodes.",
-            "Clock synchronization is used for cache version assignment in CLOCK order mode."
-          ]
-        },
-        {
-          "label": "Frequency",
-          "type": "number",
-          "model": "clockSyncFrequency",
-          "placeholder": 120000,
-          "tip": [
-            "Frequency at which clock is synchronized between nodes, in milliseconds.",
-            "Clock synchronization is used for cache version assignment in CLOCK order mode."
-          ]
-        },
-        {
-          "label": "Port base",
-          "type": "number",
-          "model": "timeServerPortBase",
-          "max": 65535,
-          "placeholder": 31100,
-          "tip": [
-            "Time server provides clock synchronization between nodes.",
-            "Base UPD port number for grid time server. Time server will be started on one of free ports in range."
-          ]
-        },
-        {
-          "label": "Port range",
-          "type": "number",
-          "model": "timeServerPortRange",
-          "placeholder": 100,
-          "tip": [
-            "Time server port range."
-          ]
-        }
-      ]
-    },
-    {
-      "label": "Thread pools size",
-      "tip": [
-        "Settings for node thread pools."
-      ],
-      "fields": [
-        {
-          "label": "Public",
-          "type": "number",
-          "model": "publicThreadPoolSize",
-          "placeholder": "max(8, availableProcessors) * 2",
-          "tip": [
-            "Thread pool that is in charge of processing ComputeJob, GridJobs and user messages sent to node."
-          ]
-        },
-        {
-          "label": "System",
-          "type": "number",
-          "model": "systemThreadPoolSize",
-          "placeholder": "max(8, availableProcessors) * 2",
-          "tip": [
-            "Thread pool that is in charge of processing internal system messages."
-          ]
-        },
-        {
-          "label": "Management",
-          "type": "number",
-          "model": "managementThreadPoolSize",
-          "placeholder": 4,
-          "tip": [
-            "Thread pool that is in charge of processing internal and Visor ComputeJob, GridJobs."
-          ]
-        },
-        {
-          "label": "IGFS",
-          "type": "number",
-          "model": "igfsThreadPoolSize",
-          "placeholder": "availableProcessors",
-          "tip": [
-            "Thread pool that is in charge of processing outgoing IGFS messages."
-          ]
-        }
-      ]
-    },
-    {
-      "label": "Transactions",
-      "tip": [
-        "Settings for transactions."
-      ],
-      "fields": [
-        {
-          "label": "Concurrency",
-          "type": "dropdown",
-          "path": "transactionConfiguration",
-          "model": "defaultTxConcurrency",
-          "placeholder": "PESSIMISTIC",
-          "items": "transactionConcurrency",
-          "tip": [
-            "Cache transaction concurrency to use when one is not explicitly specified."
-          ]
-        },
-        {
-          "label": "Isolation",
-          "type": "dropdown",
-          "path": "transactionConfiguration",
-          "model": "transactionIsolation",
-          "placeholder": "REPEATABLE_READ",
-          "items": "transactionIsolation",
-          "tip": [
-            "Default transaction isolation."
-          ]
-        },
-        {
-          "label": "Default timeout",
-          "type": "number",
-          "path": "transactionConfiguration",
-          "model": "defaultTxTimeout",
-          "placeholder": 0,
-          "tip": [
-            "Default transaction timeout."
-          ]
-        },
-        {
-          "label": "Pessimistic log cleanup delay",
-          "type": "number",
-          "path": "transactionConfiguration",
-          "model": "pessimisticTxLogLinger",
-          "placeholder": 10000,
-          "tip": [
-            "Delay, in milliseconds, after which pessimistic recovery entries will be cleaned up for failed node."
-          ]
-        },
-        {
-          "label": "Pessimistic log size",
-          "type": "number",
-          "path": "transactionConfiguration",
-          "model": "pessimisticTxLogSize",
-          "placeholder": 0,
-          "tip": [
-            "Size of pessimistic transactions log stored on node in order to recover transaction commit if originating node has left grid before it has sent all messages to transaction nodes."
-          ]
-        },
-        {
-          "label": "Manager lookup",
-          "type": "text",
-          "model": "txManagerLookupClassName",
-          "tip": [
-            "Class name of transaction manager finder for integration for JEE app servers."
-          ]
-        },
-        {
-          "label": "Enable serializable cache transactions",
-          "type": "check",
-          "path": "transactionConfiguration",
-          "model": "txSerializableEnabled",
-          "tip": [
-            "Flag to enable/disable isolation level for cache transactions.",
-            "Serializable level does carry certain overhead and if not used, should be disabled."
-          ]
-        }
-      ]
-    }
-  ]
-}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/nodejs/controllers/models/metadata.json
----------------------------------------------------------------------
diff --git a/modules/web-control-center/nodejs/controllers/models/metadata.json b/modules/web-control-center/nodejs/controllers/models/metadata.json
deleted file mode 100644
index 3248f7a..0000000
--- a/modules/web-control-center/nodejs/controllers/models/metadata.json
+++ /dev/null
@@ -1,230 +0,0 @@
-{
-  "screenTip": {
-    "workflowTitle": "Use Cache Type Metadata view to:",
-    "workflowContent": [
-      "<ul>",
-      "  <li>Manually configure metadata for queries and/or store.</li>",
-      "  <li>Configure metadata from database tables metadata.</li>",
-      "</ul>"
-    ],
-    "whatsNextTitle": "What's next:",
-    "whatsNextContent": [
-      "<ul>",
-      "  <li>Configure clusters.</li>",
-      "  <li>Associate caches with metadata.</li>",
-      "  <li>Generate XML and java code on Summary view.</li>",
-      "</ul>"
-    ]
-  },
-  "templateTip": [
-    "Use following template for metadata:",
-    "<ul>",
-    "  <li>query - Create cache type metadata to use with queries only.</li>",
-    "  <li>store - Create cache type metadata to use with JDBC POJO store only.</li>",
-    "  <li>both - Create cache type metadata to use with query and store.</li>",
-    "</ul>"
-  ],
-  "metadataManual": [
-    {
-      "label": "Name",
-      "type": "text",
-      "model": "name",
-      "required": true,
-      "placeholder": "Input name"
-    },
-    {
-      "label": "Metadata for",
-      "type": "dropdown",
-      "model": "kind",
-      "items": "kinds",
-      "tip": [
-        "Use following template for metadata:",
-        "<ul>",
-        "  <li>query - Create cache type metadata to use with queries only.</li>",
-        "  <li>store - Create cache type metadata to use with JDBC POJO store only.</li>",
-        "  <li>both - Create cache type metadata to use with query and store.</li>",
-        "</ul>"
-      ]
-    },
-    {
-      "label": "Database schema",
-      "type": "text",
-      "model": "databaseSchema",
-      "hide": "backupItem.kind == 'query'",
-      "placeholder": "Input DB schema name",
-      "tip": [
-        "Schema name in database."
-      ]
-    },
-    {
-      "label": "Database table",
-      "type": "text",
-      "model": "databaseTable",
-      "hide": "backupItem.kind == 'query'",
-      "placeholder": "Input DB table name",
-      "tip": [
-        "Table name in database."
-      ]
-    },
-    {
-      "label": "Key type",
-      "type": "text",
-      "model": "keyType",
-      "required": true,
-      "placeholder": "Full class name for Key",
-      "tip": [
-        "Key class used to store key in cache."
-      ]
-    },
-    {
-      "label": "Value type",
-      "type": "text",
-      "model": "valueType",
-      "required": true,
-      "placeholder": "Full class name for Value",
-      "tip": [
-        "Value class used to store value in cache."
-      ]
-    },
-    {
-      "label": "Key fields",
-      "type": "dbFields",
-      "model": "keyFields",
-      "keyName": "name",
-      "valueName": "className",
-      "hide": "backupItem.kind == 'query'",
-      "tip": [
-        "Collection of key fields descriptions for CacheJdbcPojoStore."
-      ]
-    },
-    {
-      "label": "Value fields",
-      "type": "dbFields",
-      "model": "valueFields",
-      "keyName": "name",
-      "valueName": "className",
-      "hide": "backupItem.kind == 'query'",
-      "tip": [
-        "Collection of value fields descriptions for CacheJdbcPojoStore.."
-      ]
-    },
-    {
-      "label": "Query fields",
-      "type": "queryFields",
-      "model": "queryFields",
-      "keyName": "name",
-      "valueName": "className",
-      "hide": "backupItem.kind != 'query'",
-      "tip": [
-        "Collection of name-to-type mappings to be queried, in addition to indexed fields."
-      ]
-    },
-    {
-      "label": "Ascending fields",
-      "type": "queryFields",
-      "model": "ascendingFields",
-      "keyName": "name",
-      "valueName": "className",
-      "hide": "backupItem.kind != 'query'",
-      "tip": [
-        "Collection of name-to-type mappings to index in ascending order."
-      ]
-    },
-    {
-      "label": "Descending fields",
-      "type": "queryFields",
-      "model": "descendingFields",
-      "keyName": "name",
-      "valueName": "className",
-      "hide": "backupItem.kind != 'query'",
-      "tip": [
-        "Collection of name-to-type mappings to index in descending order."
-      ]
-    },
-    {
-      "label": "Text fields",
-      "type": "table-simple",
-      "model": "textFields",
-      "hide": "backupItem.kind != 'query'",
-      "placeholder": "Field name",
-      "tableTip": [
-        "Fields to index as text."
-      ],
-      "tip": [
-        "Field to index as text."
-      ]
-    },
-    {
-      "label": "Groups",
-      "type": "queryGroups",
-      "model": "groups",
-      "hide": "backupItem.kind != 'query'",
-      "tip": [
-        "Collection of group indexes."
-      ]
-    }
-  ],
-  "metadataDb": [
-    {
-      "label": "Name",
-      "type": "text",
-      "model": "name"
-    },
-    {
-      "label": "Database type",
-      "type": "dropdown",
-      "model": "dbType",
-      "placeholder": "Choose database",
-      "items": "databases",
-      "tip": [
-        "Select database type to connect for loading tables metadata."
-      ]
-    },
-    {
-      "label": "Database name",
-      "type": "text",
-      "model": "dbName",
-      "tip": [
-        "Database name to connect for loading tables metadata."
-      ]
-    },
-    {
-      "label": "Host",
-      "type": "text",
-      "model": "host",
-      "placeholder": "IP address or host",
-      "tip": [
-        "IP address or host name where database server deployed."
-      ]
-    },
-    {
-      "label": "Port",
-      "type": "number",
-      "model": "port",
-      "max": 65535,
-      "placeholder": "",
-      "tip": [
-        "Port number for connecting to database."
-      ]
-    },
-    {
-      "label": "User",
-      "type": "text",
-      "model": "user",
-      "placeholder": "",
-      "tip": [
-        "User name for connecting to database."
-      ]
-    },
-    {
-      "label": "Password",
-      "type": "password",
-      "model": "password",
-      "placeholder": "",
-      "tip": [
-        "Password for connecting to database.",
-        "Note, password would not be saved."
-      ]
-    }
-  ]
-}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/nodejs/controllers/models/summary.json
----------------------------------------------------------------------
diff --git a/modules/web-control-center/nodejs/controllers/models/summary.json b/modules/web-control-center/nodejs/controllers/models/summary.json
deleted file mode 100644
index 056291c..0000000
--- a/modules/web-control-center/nodejs/controllers/models/summary.json
+++ /dev/null
@@ -1,163 +0,0 @@
-{
-  "screenTip": {
-    "workflowTitle": "Use Summary view to:",
-    "workflowContent": [
-      "<ul>",
-      "  <li>See XML and java code for server nodes configurations.</li>",
-      "  <li>See XML and java code for client nodes configurations.</li>",
-      "</ul>"
-    ],
-    "whatsNextTitle": "What's next:",
-    "whatsNextContent": [
-      "<ul>",
-      "  <li>Download XML or java code configuration.</li>",
-      "  <li>Start Ignite cluster with downloaded configuration.</li>",
-      "</ul>"
-    ]
-  },
-  "clientFields": [
-    {
-      "label": "Near cache start size",
-      "type": "number",
-      "path": "nearConfiguration",
-      "model": "nearStartSize",
-      "placeholder": 375000,
-      "tip": [
-        "Initial cache size for near cache which will be used to pre-create internal hash table after start."
-      ]
-    },
-    {
-      "label": "Near cache eviction policy",
-      "type": "dropdown-details",
-      "path": "nearConfiguration.nearEvictionPolicy",
-      "model": "kind",
-      "placeholder": "Choose eviction policy",
-      "items": "evictionPolicies",
-      "tip": [
-        "Cache expiration policy."
-      ],
-      "details": {
-        "LRU": {
-          "expanded": false,
-          "fields": [
-            {
-              "label": "Batch size",
-              "type": "number",
-              "path": "nearConfiguration.nearEvictionPolicy.LRU",
-              "model": "batchSize",
-              "placeholder": 1,
-              "tip": [
-                "Number of entries to remove on shrink."
-              ]
-            },
-            {
-              "label": "Max memory size",
-              "type": "number",
-              "path": "nearConfiguration.nearEvictionPolicy.LRU",
-              "model": "maxMemorySize",
-              "placeholder": 0,
-              "tip": [
-                "Maximum allowed cache size in bytes."
-              ]
-            },
-            {
-              "label": "Max size",
-              "type": "number",
-              "path": "nearConfiguration.nearEvictionPolicy.LRU",
-              "model": "maxSize",
-              "placeholder": 100000,
-              "tip": [
-                "Maximum allowed size of cache before entry will start getting evicted."
-              ]
-            }
-          ]
-        },
-        "RND": {
-          "expanded": false,
-          "fields": [
-            {
-              "label": "Max size",
-              "type": "number",
-              "path": "nearConfiguration.nearEvictionPolicy.RND",
-              "model": "maxSize",
-              "placeholder": 100000,
-              "tip": [
-                "Maximum allowed size of cache before entry will start getting evicted."
-              ]
-            }
-          ]
-        },
-        "FIFO": {
-          "expanded": false,
-          "fields": [
-            {
-              "label": "Batch size",
-              "type": "number",
-              "path": "nearConfiguration.nearEvictionPolicy.FIFO",
-              "model": "batchSize",
-              "placeholder": 1,
-              "tip": [
-                "Number of entries to remove on shrink."
-              ]
-            },
-            {
-              "label": "Max memory size",
-              "type": "number",
-              "path": "nearConfiguration.nearEvictionPolicy.FIFO",
-              "model": "maxMemorySize",
-              "placeholder": 0,
-              "tip": [
-                "Maximum allowed cache size in bytes."
-              ]
-            },
-            {
-              "label": "Max size",
-              "type": "number",
-              "path": "nearConfiguration.nearEvictionPolicy.FIFO",
-              "model": "maxSize",
-              "placeholder": 100000,
-              "tip": [
-                "Maximum allowed size of cache before entry will start getting evicted."
-              ]
-            }
-          ]
-        },
-        "SORTED": {
-          "expanded": false,
-          "fields": [
-            {
-              "label": "Batch size",
-              "type": "number",
-              "path": "nearConfiguration.nearEvictionPolicy.SORTED",
-              "model": "batchSize",
-              "placeholder": 1,
-              "tip": [
-                "Number of entries to remove on shrink."
-              ]
-            },
-            {
-              "label": "Max memory size",
-              "type": "number",
-              "path": "nearConfiguration.nearEvictionPolicy.SORTED",
-              "model": "maxMemorySize",
-              "placeholder": 0,
-              "tip": [
-                "Maximum allowed cache size in bytes."
-              ]
-            },
-            {
-              "label": "Max size",
-              "type": "number",
-              "path": "nearConfiguration.nearEvictionPolicy.SORTED",
-              "model": "maxSize",
-              "placeholder": 100000,
-              "tip": [
-                "Maximum allowed size of cache before entry will start getting evicted."
-              ]
-            }
-          ]
-        }
-      }
-    }
-  ]
-}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/nodejs/controllers/profile-controller.js
----------------------------------------------------------------------
diff --git a/modules/web-control-center/nodejs/controllers/profile-controller.js b/modules/web-control-center/nodejs/controllers/profile-controller.js
deleted file mode 100644
index a67df63..0000000
--- a/modules/web-control-center/nodejs/controllers/profile-controller.js
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * 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.
- */
-
-controlCenterModule.controller('profileController', ['$scope', '$http', '$common', function ($scope, $http, $common) {
-    $scope.profileUser = angular.copy($scope.user);
-
-    $scope.saveUser = function () {
-        var profile = $scope.profileUser;
-
-        if (profile) {
-            var userName = profile.username;
-            var changeUsername = userName != $scope.user.username;
-
-            var email = profile.email;
-            var changeEmail = email != $scope.user.email;
-
-            if (changeUsername || changeEmail || profile.changePassword) {
-                $http.post('/profile/saveUser', {
-                    _id: profile._id,
-                    userName: changeUsername ? userName : undefined,
-                    email: changeEmail ? email : undefined,
-                    newPassword: profile.changePassword ? profile.newPassword : undefined
-                }).success(function (user) {
-                    $common.showInfo('Profile saved.');
-
-                    if (changeUsername)
-                        $scope.user.username = userName;
-
-                    if (changeEmail)
-                        $scope.user.email = email;
-                }).error(function (err) {
-                    $common.showError('Failed to save profile: ' + $common.errorMessage(err));
-                });
-            }
-        }
-    };
-}]);
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/nodejs/controllers/summary-controller.js
----------------------------------------------------------------------
diff --git a/modules/web-control-center/nodejs/controllers/summary-controller.js b/modules/web-control-center/nodejs/controllers/summary-controller.js
deleted file mode 100644
index 1291683..0000000
--- a/modules/web-control-center/nodejs/controllers/summary-controller.js
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * 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.
- */
-
-controlCenterModule.controller('summaryController', ['$scope', '$http', '$common', function ($scope, $http, $common) {
-    $scope.joinTip = $common.joinTip;
-    $scope.getModel = $common.getModel;
-
-    $scope.javaClassItems = [
-        {label: 'snippet', value: false},
-        {label: 'factory class', value: true}
-    ];
-
-    $scope.evictionPolicies = [
-        {value: 'LRU', label: 'LRU'},
-        {value: 'RND', label: 'Random'},
-        {value: 'FIFO', label: 'FIFO'},
-        {value: 'SORTED', label: 'Sorted'},
-        {value: undefined, label: 'Not set'}
-    ];
-
-    $scope.oss = ['debian:8', 'ubuntu:14.10'];
-
-    $scope.configServer = {javaClassServer: false, os: undefined};
-    $scope.backupItem = {javaClassClient: false};
-
-    $http.get('/models/summary.json')
-        .success(function (data) {
-            $scope.screenTip = data.screenTip;
-            $scope.clientFields = data.clientFields;
-        })
-        .error(function (errMsg) {
-            $common.showError(errMsg);
-        });
-
-    $scope.clusters = [];
-
-    $scope.aceInit = function (editor) {
-        editor.setReadOnly(true);
-        editor.setOption("highlightActiveLine", false);
-
-        editor.setTheme('ace/theme/chrome');
-    };
-
-    $scope.reloadServer = function () {
-        $scope.javaServer = $scope.configServer.javaClassServer ? $scope.configServer.javaClass : $scope.configServer.javaSnippet;
-
-        if ($scope.configServer.docker) {
-            var os = $scope.configServer.os ? $scope.configServer.os : $scope.oss[0];
-
-            $scope.dockerServer = $scope.configServer.docker.replace(new RegExp('\%OS\%', 'g'), os);
-        }
-    };
-
-    $scope.selectItem = function (cluster) {
-        if (!cluster)
-            return;
-
-        $scope.selectedItem = cluster;
-
-        $scope.$watch('javaClassServer', $scope.reloadServer);
-        $scope.$watch('os', $scope.reloadServer);
-
-        $scope.generateServer(cluster);
-
-        $scope.reloadServer();
-
-        $scope.$watch('configServer', function () {
-            $scope.reloadServer();
-        }, true);
-
-        $scope.$watch('backupItem', function () {
-            $scope.generateClient();
-        }, true);
-    };
-
-    $scope.generateServer = function (cluster) {
-        $http.post('summary/generator', {_id: cluster._id})
-            .success(function (data) {
-                $scope.xmlServer = data.xmlServer;
-
-                $scope.configServer.javaClass = data.javaClassServer;
-                $scope.configServer.javaSnippet = data.javaSnippetServer;
-                $scope.configServer.docker = data.docker;
-            }).error(function (errMsg) {
-                $common.showError('Failed to generate config: ' + errMsg);
-            });
-    };
-
-    $scope.generateClient = function () {
-        $http.post('summary/generator', {
-            _id: $scope.selectedItem._id, javaClass: $scope.backupItem.javaClassClient,
-            clientNearConfiguration: $scope.backupItem.nearConfiguration
-        })
-            .success(function (data) {
-                $scope.xmlClient = data.xmlClient;
-                $scope.javaClient = data.javaClient;
-            }).error(function (errMsg) {
-                $common.showError('Failed to generate config: ' + errMsg);
-            });
-    };
-
-    $scope.download = function () {
-        $http.post('summary/download', {_id: $scope.selectedItem._id, javaClass: $scope.javaClass, os: $scope.os})
-            .success(function (data) {
-                var file = document.createElement('a');
-
-                file.setAttribute('href', 'data:application/octet-stream;charset=utf-8,' + data);
-                file.setAttribute('download', $scope.selectedItem.name + '-configuration.zip');
-
-                file.style.display = 'none';
-
-                document.body.appendChild(file);
-
-                file.click();
-
-                document.body.removeChild(file);
-            })
-            .error(function (errMsg) {
-                $common.showError('Failed to generate zip: ' + errMsg);
-            });
-    };
-
-    $http.post('clusters/list').success(function (data) {
-        $scope.clusters = data.clusters;
-
-        if ($scope.clusters.length > 0) {
-            var restoredId = sessionStorage.summarySelectedId;
-
-            var selectIdx = 0;
-
-            if (restoredId) {
-                var idx = _.findIndex($scope.clusters, function (cluster) {
-                    return cluster._id == restoredId;
-                });
-
-                if (idx >= 0)
-                    selectIdx = idx;
-                else
-                    delete sessionStorage.summarySelectedId;
-            }
-
-            $scope.selectItem($scope.clusters[selectIdx]);
-
-            $scope.$watch('selectedItem', function (val) {
-                if (val)
-                    sessionStorage.summarySelectedId = val._id;
-            }, true);
-        }
-    });
-}]);



[06/10] incubator-ignite git commit: # ignite-843 moved

Posted by an...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/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
deleted file mode 100644
index 4a618fa..0000000
--- a/modules/web-control-center/nodejs/views/includes/controls.jade
+++ /dev/null
@@ -1,322 +0,0 @@
-//-
-    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 block-callout(titleWorkflow, contentWorkflow, whatsNextWorkflow, whatsNextContent)
-    .block-callout-parent.block-callout-border.margin-bottom-dflt
-        .block-callout
-            i.fa.fa-check-square
-            label #{titleWorkflow}
-            p(ng-bind-html=contentWorkflow)
-        .block-callout
-            i.fa.fa-check-square
-            label #{whatsNextWorkflow}
-            p(ng-bind-html=whatsNextContent)
-
-
-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 ico-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 btn-save(show, click)
-    i.tipField.fa.fa-floppy-o(ng-show=show ng-click=click)
-
-mixin btn-add(click)
-    i.tipField.fa.fa-plus(ng-click=click)
-
-mixin btn-remove(click)
-    i.tipField.fa.fa-remove(ng-click=click)
-
-mixin btn-up(show, click)
-    i.tipField.fa.fa-arrow-up(ng-show=show ng-click=click)
-
-mixin btn-down(show, click)
-    i.tipField.fa.fa-arrow-down(ng-show=show ng-click=click)
-
-mixin table-pair-edit(keyModel, valModel, keyPlaceholder, valPlaceholder)
-    .col-sm-6(style='float: right')
-        input.form-control(type='text' ng-model=valModel placeholder=valPlaceholder)
-    label.fieldSep /
-    .input-tip
-        input.form-control(type='text' ng-model=keyModel placeholder=keyPlaceholder)
-
-mixin table-pair(header, tblMdl, keyFld, valFld, keyPlaceholder, valPlaceholder)
-    .col-sm-6
-        label.table-header #{header}:
-        +tipLabel('field.tip')
-        button.btn.btn-primary.fieldButton(ng-click='tableNewItem(field)') Add
-    table.links-edit.col-sm-12(st-table=tblMdl)
-        tbody
-            tr.col-sm-12(ng-repeat='item in #{tblMdl}')
-                td.col-sm-6
-                    div(ng-show='!tableEditing(field, $index)')
-                        a.labelFormField(ng-click='curPair = tableStartEdit(backupItem, field, $index); curKey = curPair.#{keyFld}; curValue = curPair.#{valFld}') {{$index + 1}}) {{item.#{keyFld}}} / {{item.#{valFld}}}
-                        +btn-remove('tableRemove(backupItem, field, $index)')
-                    div(ng-show='tableEditing(field, $index)')
-                        label.labelField {{$index + 1}})
-                        +btn-save('tablePairSaveVisible(curKey, curValue)', 'tablePairSave(tablePairValid, backupItem, field, curKey, curValue, $index)')
-                        +table-pair-edit('curKey', 'curValue', keyPlaceholder, valPlaceholder)
-            tr.col-sm-12(ng-show='tableNewItemActive(field)')
-                td.col-sm-6
-                    +btn-save('tablePairSaveVisible(newKey, newValue)', 'tablePairSave(tablePairValid, backupItem, field, newKey, newValue, -1)')
-                    +table-pair-edit('newKey', 'newValue', keyPlaceholder, valPlaceholder)
-
-mixin details-row
-    - var lblDetailClasses = ['col-sm-4', 'details-label']
-
-    - var detailMdl = 'getModel(backupItem, detail)[detail.model]';
-    - var detailCommon = {'ng-model': detailMdl, 'ng-required': 'detail.required'};
-
-    - var customValidators = {'ng-attr-ipaddress': '{{detail.ipaddress}}'}
-
-    div(ng-switch='detail.type')
-        div(ng-switch-when='label')
-            label {{detail.label}}
-        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 ng-class='{required: detail.required}') {{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 ng-class='{required: detail.required}') {{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)
-                    +ico-exclamation('{{detail.model}}', 'min', 'Value is less than allowable minimum.')
-                    +ico-exclamation('{{detail.model}}', 'max', 'Value is more than allowable maximum.')
-                    +ico-exclamation('{{detail.model}}', 'number', 'Invalid value. Only numbers allowed.')
-        div(ng-switch-when='dropdown')
-            label(class=lblDetailClasses ng-class='{required: detail.required}') {{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 ng-class='{required: detail.required}') {{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')&attributes(detailCommon)
-            div(ng-if='detail.label')
-                label.table-header {{detail.label}}:
-                +tipLabel('detail.tableTip')
-            table.col-sm-12.links-edit-details(st-table='#{detailMdl}')
-                tbody
-                    tr(ng-repeat='item in #{detailMdl} track by $index')
-                        td
-                            div(ng-show='!tableEditing(detail, $index)')
-                                a.labelFormField(ng-click='curValue = tableStartEdit(backupItem, detail, $index)') {{$index + 1}}) {{item}}
-                                +btn-remove('tableRemove(backupItem, detail, $index)')
-                                +btn-down('detail.reordering && tableSimpleDownVisible(backupItem, detail, $index)', 'tableSimpleDown(backupItem, detail, $index)')
-                                +btn-up('detail.reordering && $index > 0', 'tableSimpleUp(backupItem, detail, $index)')
-                            div(ng-show='tableEditing(detail, $index)')
-                                label.labelField {{$index + 1}})
-                                +btn-save('tableSimpleSaveVisible(curValue)', 'tableSimpleSave(tableSimpleValid, backupItem, detail, curValue, $index)')
-                                .input-tip.form-group.has-feedback
-                                    input.form-control(name='{{detail.model}}.edit' type='text' ng-model='curValue' placeholder='{{detail.placeholder}}')&attributes(customValidators)
-                                    +ico-exclamation('{{detail.model}}.edit', 'ipaddress', 'Invalid address, see help for format description.')
-            button.btn.btn-primary.fieldButton(ng-disabled='!newValue' ng-click='tableSimpleSave(tableSimpleValid, backupItem, detail, newValue, -1)') Add
-            +tipField('detail.tip')
-            .input-tip.form-group.has-feedback
-                input.form-control(name='{{detail.model}}' type='text' ng-model='newValue' ng-focus='tableNewItem(detail)' placeholder='{{detail.placeholder}}')&attributes(customValidators)
-                +ico-exclamation('{{detail.model}}', 'ipaddress', 'Invalid address, see help for format description.')
-
-mixin table-db-field-edit(dbName, dbType, javaName, javaType)
-    div(style='width: 22%; float: right')
-        button.form-control(ng-model=javaType bs-select data-placeholder='Java type' bs-options='item.value as item.label for item in {{javaTypes}}')
-    label.fieldSep /
-    div(style='width: 20%; float: right')
-        input.form-control(type='text' ng-model=javaName placeholder='Java name')
-    label.fieldSep /
-    div(style='width: 22%; float: right')
-        button.form-control(ng-model=dbType bs-select data-placeholder='JDBC type' bs-options='item.value as item.label for item in {{jdbcTypes}}')
-    label.fieldSep /
-    .input-tip
-        input.form-control(type='text' ng-model=dbName placeholder='DB name')
-
-mixin table-group-item-edit(fieldName, className, direction)
-    div(style='width: 15%; float: right')
-        button.form-control(ng-model=direction bs-select data-placeholder='Sort' bs-options='item.value as item.label for item in {{sortDirections}}')
-    label.fieldSep /
-    div(style='width: 38%; float: right')
-        input.form-control(type='text' ng-model=className placeholder='Class name')
-    label.fieldSep /
-    .input-tip
-        input.form-control(type='text' ng-model=fieldName placeholder='Field name')
-
-mixin form-row
-    +form-row-custom(['col-sm-2'], ['col-sm-4'])
-
-mixin form-row-custom(lblClasses, fieldClasses)
-    - var fieldMdl = 'getModel(backupItem, field)[field.model]';
-    - var fieldCommon = {'ng-model': fieldMdl, 'ng-required': 'field.required || required(field)'};
-    - var fieldRequiredClass = '{true: "required"}[field.required || required(field)]'
-    - var fieldHide = '{{field.hide}}'
-
-    div(ng-switch='field.type')
-        div.col-sm-6(ng-switch-when='label')
-            label {{field.label}}
-        div.checkbox.col-sm-6(ng-switch-when='check' ng-hide=fieldHide)
-            label
-                input(type='checkbox')&attributes(fieldCommon)
-                | {{field.label}}
-                +tipLabel('field.tip')
-        div(ng-switch-when='text' ng-hide=fieldHide)
-            label(class=lblClasses ng-class=fieldRequiredClass) {{field.label}}:
-            div(class=fieldClasses)
-                +tipField('field.tip')
-                .input-tip
-                    input.form-control(type='text' placeholder='{{field.placeholder}}')&attributes(fieldCommon)
-        div(ng-switch-when='password' ng-hide=fieldHide)
-            label(class=lblClasses ng-class=fieldRequiredClass) {{field.label}}:
-            div(class=fieldClasses)
-                +tipField('field.tip')
-                .input-tip
-                    input.form-control(type='password' placeholder='{{field.placeholder}}')&attributes(fieldCommon)
-        div(ng-switch-when='number' ng-hide=fieldHide)
-            label(class=lblClasses ng-class=fieldRequiredClass) {{field.label}}:
-            div(class=fieldClasses)
-                +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}}')&attributes(fieldCommon)
-                    +ico-exclamation('{{field.model}}', 'min', 'Value is less than allowable minimum.')
-                    +ico-exclamation('{{field.model}}', 'max', 'Value is more than allowable maximum.')
-                    +ico-exclamation('{{field.model}}', 'number', 'Invalid value. Only numbers allowed.')
-        div(ng-switch-when='dropdown' ng-hide=fieldHide)
-            label(class=lblClasses ng-class=fieldRequiredClass) {{field.label}}:
-            div(class=fieldClasses)
-                +tipField('field.tip')
-                .input-tip
-                    button.form-control(bs-select data-placeholder='{{field.placeholder}}' bs-options='item.value as item.label for item in {{field.items}}')&attributes(fieldCommon)
-        div(ng-switch-when='dropdown-multiple' ng-hide=fieldHide)
-            label(class=lblClasses ng-class=fieldRequiredClass) {{field.label}}:
-            div(class=fieldClasses)
-                +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' ng-hide=fieldHide)
-            - var expanded = 'field.details[' + fieldMdl + '].expanded'
-
-            label(class=lblClasses ng-class=fieldRequiredClass) {{field.label}}:
-            div(class=fieldClasses)
-                +tipField('field.tip')
-                .input-tip
-                    button.form-control(bs-select 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' ng-hide=fieldHide)&attributes(fieldCommon)
-            .col-sm-6
-                label.table-header {{field.label}}:
-                +tipLabel('field.tableTip')
-                button.btn.btn-primary.fieldButton(ng-click='tableNewItem(field)') Add
-            table.links-edit.col-sm-12(st-table='#{fieldMdl}')
-                tbody
-                    tr.col-sm-12(ng-repeat='item in #{fieldMdl} track by $index')
-                        td.col-sm-6
-                            div(ng-show='!tableEditing(field, $index)')
-                                a.labelFormField(ng-click='curValue = tableStartEdit(backupItem, field, $index)') {{$index + 1}}) {{item | compact}}
-                                +btn-remove('tableRemove(backupItem, field, $index)')
-                                +btn-down('field.reordering && tableSimpleDownVisible(backupItem, field, $index)', 'tableSimpleDown(backupItem, field, $index)')
-                                +btn-up('field.reordering && $index > 0', 'tableSimpleUp(backupItem, field, $index)')
-                            div(ng-show='tableEditing(field, $index)')
-                                label.labelField {{$index + 1}})
-                                +btn-save('tableSimpleSaveVisible(curValue)', 'tableSimpleSave(tableSimpleValid, backupItem, field, curValue, $index)')
-                                .input-tip
-                                    input.form-control(type='text' ng-model='curValue' placeholder='{{field.placeholder}}')
-                    tr.col-sm-12(ng-show='tableNewItemActive(field)')
-                        td.col-sm-6
-                            +btn-save('tableSimpleSaveVisible(newValue)', 'tableSimpleSave(tableSimpleValid, backupItem, field, newValue, -1)')
-                            .input-tip
-                                input.form-control(type='text' ng-model='newValue' placeholder='{{field.placeholder}}')
-        div(ng-switch-when='indexedTypes')
-            +table-pair('Index key-value type pairs', fieldMdl, 'keyClass', 'valueClass', 'Key class full name', 'Value class full name')
-        div(ng-switch-when='queryFields' ng-hide=fieldHide)
-            +table-pair('{{field.label}}', fieldMdl, 'name', 'className', 'Field name', 'Field class full name')
-        div(ng-switch-when='dbFields' ng-hide=fieldHide)
-            .col-sm-6
-                label.table-header {{field.label}}:
-                +tipLabel('field.tip')
-                button.btn.btn-primary.fieldButton(ng-click='tableNewItem(field)') Add
-            table.links-edit.col-sm-12(st-table=fieldMdl)
-                tbody
-                    tr.col-sm-12(ng-repeat='item in #{fieldMdl}')
-                        td.col-sm-6
-                            div(ng-show='!tableEditing(field, $index)')
-                                a.labelFormField(ng-click='curField = tableStartEdit(backupItem, field, $index); curDbName = curField.dbName; curDbType = curField.dbType; curJavaName = curField.javaName; curJavaType = curField.javaType') {{$index + 1}}) {{item.dbName}} / {{item.dbType}} / {{item.javaName}} / {{item.javaType}}
-                                +btn-remove('tableRemove(backupItem, field, $index)')
-                            div(ng-if='tableEditing(field, $index)')
-                                label.labelField {{$index + 1}})
-                                +btn-save('tableDbFieldSaveVisible(curDbName, curDbType, curJavaName, curJavaType)', 'tableDbFieldSave(field, curDbName, curDbType, curJavaName, curJavaType, $index)')
-                                +table-db-field-edit('curDbName', 'curDbType', 'curJavaName', 'curJavaType')
-                    tr(ng-show='tableNewItemActive(field)')
-                        td.col-sm-6
-                            +btn-save('tableDbFieldSaveVisible(newDbName, newDbType, newJavaName, newJavaType)', 'tableDbFieldSave(field, newDbName, newDbType, newJavaName, newJavaType, -1)')
-                            +table-db-field-edit('newDbName', 'newDbType', 'newJavaName', 'newJavaType')
-        div(ng-switch-when='queryGroups' ng-hide=fieldHide)
-            .col-sm-6
-                label.table-header {{field.label}}:
-                +tipLabel('field.tip')
-                button.btn.btn-primary.fieldButton(ng-click='tableNewItem(field)') Add
-            table.links-edit.col-sm-12(st-table=fieldMdl)
-                tbody
-                    tr.col-sm-12(ng-repeat='group in #{fieldMdl}')
-                        td.col-sm-6
-                            div
-                                .col-sm-12(ng-show='!tableEditing(field, $index)')
-                                    a.labelFormField(ng-click='curGroup = tableStartEdit(backupItem, field, $index); curGroupName = curGroup.name; curFields = curGroup.fields') {{$index + 1}}) {{group.name}}
-                                    +btn-remove('tableRemove(backupItem, field, $index)')
-                                    +btn-add('tableGroupNewItem($index); newDirection = "ASC"')
-                                div(ng-show='tableEditing(field, $index)')
-                                    label.labelField {{$index + 1}})
-                                    +btn-save('tableGroupSaveVisible(curGroupName)', 'tableGroupSave(curGroupName, $index)')
-                                    .input-tip
-                                        input.form-control(type='text' ng-model='curGroupName' placeholder='Index name')
-                                div
-                                    table.links-edit.col-sm-12(st-table='group.fields' ng-init='groupIndex = $index')
-                                        tr(ng-repeat='groupItem in group.fields')
-                                            td
-                                                div(ng-show='!tableGroupItemEditing(groupIndex, $index)')
-                                                    a.labelFormField(ng-click='curGroupItem = tableGroupItemStartEdit(groupIndex, $index); curFieldName = curGroupItem.name; curClassName = curGroupItem.className; curDirection = curGroupItem.direction') {{$index + 1}}) {{groupItem.name}} / {{groupItem.className}} / {{groupItem.direction}}
-                                                    +btn-remove('tableRemoveGroupItem(group, $index)')
-                                                div(ng-show='tableGroupItemEditing(groupIndex, $index)')
-                                                    label.labelField {{$index + 1}})
-                                                    +btn-save('tableGroupItemSaveVisible(curFieldName, curClassName)', 'tableGroupItemSave(curFieldName, curClassName, curDirection, groupIndex, $index)')
-                                                    +table-group-item-edit('curFieldName', 'curClassName', 'curDirection')
-                                        tr.col-sm-12(style='padding-left: 18px' ng-show='tableGroupNewItemActive(groupIndex)')
-                                            td
-                                                +btn-save('tableGroupItemSaveVisible(newFieldName, newClassName)', 'tableGroupItemSave(newFieldName, newClassName, newDirection, groupIndex, -1)')
-                                                +table-group-item-edit('newFieldName', 'newClassName', 'newDirection')
-                    tr.col-sm-12(ng-show='tableNewItemActive(field)')
-                        td.col-sm-6
-                            +btn-save('tableGroupSaveVisible(newGroupName)', 'tableGroupSave(newGroupName, -1)')
-                            .input-tip
-                                input.form-control(type='text' ng-model='newGroupName' placeholder='Group name')
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/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
deleted file mode 100644
index d8ff5d7..0000000
--- a/modules/web-control-center/nodejs/views/includes/footer.jade
+++ /dev/null
@@ -1,22 +0,0 @@
-//-
-    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 Apache Ignite Control Center, version 1.0.0
-            p © 2015 The Apache Software Foundation.
-            p Apache, Apache Ignite, the Apache feather and the Apache Ignite logo are trademarks of The Apache Software Foundation.
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/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
deleted file mode 100644
index ab2d31e..0000000
--- a/modules/web-control-center/nodejs/views/includes/header.jade
+++ /dev/null
@@ -1,39 +0,0 @@
-//-
-    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 header-item(active, ref, txt)
-    li
-        a(ng-class='{active: isActive("#{active}")}' href='#{ref}') #{txt}
-
-header.header(id='header')
-    .viewedUser(ng-show='becomeUsed') Currently assuming "
-        strong {{user.username}}
-        | ",&nbsp;&nbsp;
-        a(href='/admin/become') revert to your identity.
-    .container
-        h1.navbar-brand
-            a(href='/') Apache Ignite Web Configurator
-        .navbar-collapse.collapse(ng-controller='auth')
-            ul.nav.navbar-nav(ng-controller='activeLink' ng-show='user')
-                +header-item('/configuration', '/configuration/clusters', 'Configuration')
-                //+header-item('/monitoring', '/monitoring', 'Monitoring')
-                //+header-item('/sql', '/sql', 'SQL')
-                //+header-item('/deploy', '/deploy', 'Deploy')
-            ul.nav.navbar-nav.pull-right
-                li(ng-if='user')
-                    a.dropdown-toggle(data-toggle='dropdown' bs-dropdown='userDropdown' data-placement='bottom-right') {{user.username}}
-                        span.caret
-                li.nav-login(ng-if='!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/8a335724/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
deleted file mode 100644
index 999c4f8..0000000
--- a/modules/web-control-center/nodejs/views/index.jade
+++ /dev/null
@@ -1,30 +0,0 @@
-//-
-    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 templates/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/8a335724/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
deleted file mode 100644
index 5bb39dd..0000000
--- a/modules/web-control-center/nodejs/views/login.jade
+++ /dev/null
@@ -1,55 +0,0 @@
-//-
-    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 lbl(txt)
-    label.col-sm-3.required #{txt}
-
-.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
-                    a(href='/') Apache Ignite Web Configurator
-                h4.modal-title(style='padding-right: 55px') Authentication
-                p(style='padding-right: 55px') Log in or register in order to collaborate
-            form.form-horizontal(name='loginForm')
-                .modal-body.row
-                    .col-sm-9.login.col-sm-offset-1
-                        .details-row(ng-show='action == "register"')
-                            +lbl('Full Name:')
-                            .col-sm-9
-                                input.form-control(type='text', ng-model='user_info.username', placeholder='John Smith', focus-me='action=="register"', ng-required='action=="register"')
-                        .details-row
-                            +lbl('Email:')
-                            .col-sm-9
-                                input.form-control(type='email', ng-model='user_info.email', placeholder='you@domain.com', focus-me='action=="login"', required)
-                        .details-row
-                            +lbl('Password:')
-                            .col-sm-9
-                                input.form-control(type='password', ng-model='user_info.password', placeholder='Password', required, ng-keyup='action == "login" && $event.keyCode == 13 ? auth(action, user_info) : null')
-                        .details-row(ng-show='action == "register"')
-                            +lbl('Confirm:')
-                            .col-sm-9.input-tip.has-feedback
-                                input.form-control(type='password', ng-model='user_info.confirm', match="user_info.password" placeholder='Confirm password', required, ng-keyup='$event.keyCode == 13 ? auth(action, user_info) : null')
-
-            .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-show='action == "login"' ng-click='auth(action, user_info)') Log In
-                button.btn.btn-primary(ng-show='action == "register"' ng-disabled='loginForm.$invalid || user_info.password != user_info.confirm' ng-click='auth(action, user_info)') Sign Up

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/nodejs/views/settings/admin.jade
----------------------------------------------------------------------
diff --git a/modules/web-control-center/nodejs/views/settings/admin.jade b/modules/web-control-center/nodejs/views/settings/admin.jade
deleted file mode 100644
index 4d50631..0000000
--- a/modules/web-control-center/nodejs/views/settings/admin.jade
+++ /dev/null
@@ -1,58 +0,0 @@
-//-
-    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 ../templates/layout
-
-append scripts
-    script(src='/admin-controller.js')
-
-block container
-    .row(ng-controller='adminController')
-        .docs-content
-            .docs-header
-                h1 List of registered users
-                hr
-            .docs-body
-                table.table.table-striped.admin(st-table='displayedUsers' st-safe-src='users')
-                    thead
-                        tr
-                            th.header(colspan='5')
-                                .col-sm-2.pull-right
-                                    input.form-control(type='text' st-search='' placeholder='Filter users...')
-                        tr
-                            th(st-sort='username') User name
-                            th(st-sort='email') Email
-                            th.col-sm-2(st-sort='lastLogin') Last login
-                            th(width='1%'  st-sort='admin') Admin
-                            th(width='1%') Actions
-                    tbody
-                        tr(ng-repeat='row in displayedUsers')
-                            td {{row.username}}
-                            td
-                                a(ng-href='mailto:{{row.email}}') {{row.email}}
-                            td
-                                span {{row.lastLogin | date:'medium'}}
-                            td(style='text-align: center;')
-                                input(type='checkbox' ng-disabled='row.adminChanging || row._id == user._id'
-                                    ng-model='row.admin' ng-change='toggleAdmin(row)')
-                            td(style='text-align: center;')
-                                a(ng-click='removeUser(row)' ng-show='row._id != user._id' bs-tooltip data-title='Remove user')
-                                    i.fa.fa-remove
-                                a(style='margin-left: 5px' ng-href='admin/become?viewedUserId={{row._id}}' ng-show='row._id != user._id' bs-tooltip data-title='Become this user')
-                                    i.fa.fa-eye
-                    tfoot
-                        tr
-                            td(colspan='5' class="text-right")
-                                div(st-pagination st-items-by-page='15' st-displayed-pages='5')
-

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/nodejs/views/settings/profile.jade
----------------------------------------------------------------------
diff --git a/modules/web-control-center/nodejs/views/settings/profile.jade b/modules/web-control-center/nodejs/views/settings/profile.jade
deleted file mode 100644
index dbc6dea..0000000
--- a/modules/web-control-center/nodejs/views/settings/profile.jade
+++ /dev/null
@@ -1,58 +0,0 @@
-//-
-    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 ../templates/layout
-
-mixin lbl(txt)
-    label.col-sm-2.required.labelFormField #{txt}
-
-append scripts
-    script(src='/profile-controller.js')
-
-block container
-    .row(ng-controller='profileController')
-        .docs-content
-            .docs-header
-                h1 User profile
-                hr
-            .docs-body
-                form.form-horizontal(name='profileForm' novalidate)
-                    .col-sm-10(style='padding: 0')
-                        .details-row
-                            +lbl('User name:')
-                            .col-sm-4
-                                input.form-control(type='text' ng-model='profileUser.username' placeholder='Input name' required)
-                        .details-row
-                            +lbl('Email:')
-                            .col-sm-4
-                                input.form-control(type='email' ng-model='profileUser.email' placeholder='you@domain.com' required)
-                        .details-row
-                            .checkbox
-                                label
-                                    input(type="checkbox" ng-model='profileUser.changePassword')
-                                    | Change password
-                        div(ng-show='profileUser.changePassword')
-                            .details-row
-                                +lbl('New password:')
-                                .col-sm-4
-                                    input.form-control(type='password', ng-model='profileUser.newPassword' placeholder='New password' ng-required='profileUser.changePassword')
-                            .details-row
-                                +lbl('Confirm:')
-                                .col-sm-4
-                                    input.form-control(type='password', ng-model='profileUser.confirmPassword' match='profileUser.newPassword' placeholder='Confirm new password' ng-required='profileUser.changePassword')
-                    .col-sm-12.details-row
-                        button.btn.btn-primary(ng-disabled='profileForm.$invalid' ng-click='saveUser()') Save
-

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/nodejs/views/templates/confirm.jade
----------------------------------------------------------------------
diff --git a/modules/web-control-center/nodejs/views/templates/confirm.jade b/modules/web-control-center/nodejs/views/templates/confirm.jade
deleted file mode 100644
index bdaf9bf..0000000
--- a/modules/web-control-center/nodejs/views/templates/confirm.jade
+++ /dev/null
@@ -1,27 +0,0 @@
-//-
-    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(tabindex='-1' role='dialog')
-    .modal-dialog
-        .modal-content
-            .modal-header
-                button.close(type="button" ng-click="$hide()") &times;
-                h4.modal-title Confirmation
-            .modal-body(ng-show='content')
-                p(ng-bind-html='content' style='text-align: center;')
-            .modal-footer
-                button.btn.btn-default(type="button" ng-click="$hide()") Cancel
-                button.btn.btn-primary(type="button" ng-click="ok()") Confirm
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/nodejs/views/templates/copy.jade
----------------------------------------------------------------------
diff --git a/modules/web-control-center/nodejs/views/templates/copy.jade b/modules/web-control-center/nodejs/views/templates/copy.jade
deleted file mode 100644
index 22cc64c..0000000
--- a/modules/web-control-center/nodejs/views/templates/copy.jade
+++ /dev/null
@@ -1,31 +0,0 @@
-//-
-    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(tabindex='-1' role='dialog')
-    .modal-dialog
-        .modal-content
-            .modal-header
-                button.close(type="button" ng-click="$hide()") &times;
-                h4.modal-title Copy
-            form.form-horizontal(name='inputForm' novalidate)
-                .modal-body.row
-                    .col-sm-9.login.col-sm-offset-1
-                        label.required.labelFormField() New name:&nbsp;
-                        .col-sm-9
-                            input.form-control(type="text" ng-model='newName' required)
-            .modal-footer
-                button.btn.btn-default(type="button" ng-click="$hide()") Cancel
-                button.btn.btn-primary(type="button" ng-disabled='inputForm.$invalid' ng-click="ok(newName)") Confirm
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/nodejs/views/templates/layout.jade
----------------------------------------------------------------------
diff --git a/modules/web-control-center/nodejs/views/templates/layout.jade b/modules/web-control-center/nodejs/views/templates/layout.jade
deleted file mode 100644
index a4191ae..0000000
--- a/modules/web-control-center/nodejs/views/templates/layout.jade
+++ /dev/null
@@ -1,61 +0,0 @@
-//-
-    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-control-center', ng-init='user = #{JSON.stringify(user)}; becomeUsed = #{becomeUsed}')
-    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.10.0/lodash.min.js')
-
-            script(src='//ajax.googleapis.com/ajax/libs/angularjs/1.4.2/angular.js')
-            script(src='//cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.2/angular-sanitize.js')
-            script(src='//cdnjs.cloudflare.com/ajax/libs/angular-strap/2.3.0/angular-strap.js')
-            script(src='//cdnjs.cloudflare.com/ajax/libs/angular-strap/2.3.0/angular-strap.tpl.min.js')
-
-            script(src='//cdnjs.cloudflare.com/ajax/libs/angular-smart-table/2.0.3/smart-table.js')
-
-            script(src='//cdnjs.cloudflare.com/ajax/libs/ace/1.2.0/ace.js')
-            script(src='//angular-ui.github.io/ui-ace/dist/ui-ace.min.js')
-
-            script(src='/common-module.js')
-            script(src='/data-structures.js')
-
-    body.theme-line.body-overlap
-        .wrapper
-            include ../includes/header
-
-            block main-container
-                .container.body-container
-                    .main-content
-                        block container
-
-            include ../includes/footer

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/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
deleted file mode 100644
index 10c1946..0000000
--- a/modules/web-control-center/nodejs/views/templates/select.jade
+++ /dev/null
@@ -1,26 +0,0 @@
-//-
-    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 == undefined' style='margin: 5px 0')
-        a(style='cursor: default; padding: 3px 6px;', role='menuitem', tabindex='-1', ng-class='{active: $isActive($index)}' ng-click='$select($index, $event)')
-            i(class='{{$iconCheckmark}}', ng-if='$isActive($index)' ng-class='{active: $isActive($index)}' style='color: #ec1c24; margin-left: 15px; line-height: 20px; float: right;background-color: transparent;')
-            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/8a335724/modules/web-control-center/src/main/js/.gitignore
----------------------------------------------------------------------
diff --git a/modules/web-control-center/src/main/js/.gitignore b/modules/web-control-center/src/main/js/.gitignore
new file mode 100644
index 0000000..65f2596
--- /dev/null
+++ b/modules/web-control-center/src/main/js/.gitignore
@@ -0,0 +1,4 @@
+node_modules
+*.idea
+*.log
+*.css
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/src/main/js/DEVNOTES.txt
----------------------------------------------------------------------
diff --git a/modules/web-control-center/src/main/js/DEVNOTES.txt b/modules/web-control-center/src/main/js/DEVNOTES.txt
new file mode 100644
index 0000000..aa56011
--- /dev/null
+++ b/modules/web-control-center/src/main/js/DEVNOTES.txt
@@ -0,0 +1,21 @@
+Ignite Web Control Center Instructions
+======================================
+
+How to deploy:
+
+1. Install locally NodeJS using installer from site https://nodejs.org for your OS.
+2. Install locally MongoDB folow instructions from site http://docs.mongodb.org/manual/installation
+3. Checkout ignite-843 branch.
+4. Change directory '$IGNITE_HOME/modules/web-control-center/nodejs'.
+5. Run "npm install" in terminal for download all dependencies.
+
+Steps 1 - 5 should be executed once.
+
+How to run:
+
+1. Run MongoDB.
+ 1.1 In terminal change dir to $MONGO_ISNTALL_DIR/server/3.0/bin.
+ 1.2 Run "mongod".
+2. In new terminal change directory '$IGNITE_HOME/modules/web-control-center/nodejs'.
+3. Start application by executing "npm start".
+4. In browser open: http://localhost:3000
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/src/main/js/app.js
----------------------------------------------------------------------
diff --git a/modules/web-control-center/src/main/js/app.js b/modules/web-control-center/src/main/js/app.js
new file mode 100644
index 0000000..8c347db
--- /dev/null
+++ b/modules/web-control-center/src/main/js/app.js
@@ -0,0 +1,154 @@
+/*
+ * 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 flash = require('connect-flash');
+var express = require('express');
+var path = require('path');
+var favicon = require('serve-favicon');
+var logger = require('morgan');
+var cookieParser = require('cookie-parser');
+var bodyParser = require('body-parser');
+var session = require('express-session');
+var mongoStore = require('connect-mongo')(session);
+
+var publicRoutes = require('./routes/public');
+var clustersRouter = require('./routes/clusters');
+var cachesRouter = require('./routes/caches');
+var metadataRouter = require('./routes/metadata');
+var summary = require('./routes/summary');
+var adminRouter = require('./routes/admin');
+var profileRouter = require('./routes/profile');
+var sqlRouter = require('./routes/sql');
+
+var passport = require('passport');
+
+var db = require('./db');
+
+var app = express();
+
+// Views engine setup.
+app.set('views', path.join(__dirname, 'views'));
+app.set('view engine', 'jade');
+
+// Site favicon.
+app.use(favicon(__dirname + '/public/favicon.ico'));
+
+app.use(logger('dev'));
+
+app.use(bodyParser.json());
+app.use(bodyParser.urlencoded({extended: false}));
+
+app.use(require('less-middleware')(path.join(__dirname, 'public'), {
+    render: {
+        compress: false
+    }
+}));
+
+app.use(express.static(path.join(__dirname, 'public')));
+app.use(express.static(path.join(__dirname, 'controllers')));
+app.use(express.static(path.join(__dirname, 'helpers')));
+
+app.use(cookieParser('keyboard cat'));
+
+app.use(session({
+    secret: 'keyboard cat',
+    resave: false,
+    saveUninitialized: true,
+    store: new mongoStore({
+        mongooseConnection: db.mongoose.connection
+    })
+}));
+
+app.use(flash());
+
+app.use(passport.initialize());
+app.use(passport.session());
+
+passport.serializeUser(db.Account.serializeUser());
+passport.deserializeUser(db.Account.deserializeUser());
+
+passport.use(db.Account.createStrategy());
+
+var mustAuthenticated = function (req, res, next) {
+    req.isAuthenticated() ? next() : res.redirect('/');
+};
+
+var adminOnly = function(req, res, next) {
+    req.isAuthenticated() && req.user.admin ? next() : res.sendStatus(403);
+};
+
+app.all('/configuration/*', mustAuthenticated);
+
+app.all('*', function(req, res, next) {
+    var becomeUsed = req.session.viewedUser && req.user.admin;
+
+    res.locals.user = becomeUsed ? req.session.viewedUser : req.user;
+    res.locals.becomeUsed = becomeUsed;
+
+    req.currentUserId = function() {
+        if (!req.user)
+            return null;
+
+        if (req.session.viewedUser && req.user.admin)
+            return req.session.viewedUser._id;
+
+        return req.user._id;
+    };
+
+    next();
+});
+
+app.use('/', publicRoutes);
+app.use('/admin', mustAuthenticated, adminOnly, adminRouter);
+app.use('/profile', mustAuthenticated, profileRouter);
+
+app.use('/configuration/clusters', clustersRouter);
+app.use('/configuration/caches', cachesRouter);
+app.use('/configuration/metadata', metadataRouter);
+app.use('/configuration/summary', summary);
+app.use('/sql', sqlRouter);
+
+// Catch 404 and forward to error handler.
+app.use(function (req, res, next) {
+    var err = new Error('Not Found: ' + req.originalUrl);
+    err.status = 404;
+    next(err);
+});
+
+// Error handlers.
+
+// Development error handler: will print stacktrace.
+if (app.get('env') === 'development') {
+    app.use(function (err, req, res) {
+        res.status(err.status || 500);
+        res.render('error', {
+            message: err.message,
+            error: err
+        });
+    });
+}
+
+// Production error handler: no stacktraces leaked to user.
+app.use(function (err, req, res) {
+    res.status(err.status || 500);
+    res.render('error', {
+        message: err.message,
+        error: {}
+    });
+});
+
+module.exports = app;

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/src/main/js/bin/www
----------------------------------------------------------------------
diff --git a/modules/web-control-center/src/main/js/bin/www b/modules/web-control-center/src/main/js/bin/www
new file mode 100644
index 0000000..4cf0583
--- /dev/null
+++ b/modules/web-control-center/src/main/js/bin/www
@@ -0,0 +1,85 @@
+#!/usr/bin/env node
+
+/**
+ * Module dependencies.
+ */
+var app = require('../app');
+var config = require('../helpers/configuration-loader.js');
+var debug = require('debug')('ignite-web-control-center:server');
+var http = require('http');
+
+/**
+ * Get port from environment and store in Express.
+ */
+var port = normalizePort(process.env.PORT || config.get('express:port'));
+app.set('port', port);
+
+/**
+ * Create HTTP server.
+ */
+var server = http.createServer(app);
+
+/**
+ * Listen on provided port, on all network interfaces.
+ */
+server.listen(port);
+server.on('error', onError);
+server.on('listening', onListening);
+
+/**
+ * Normalize a port into a number, string, or false.
+ */
+function normalizePort(val) {
+  var port = parseInt(val, 10);
+
+  if (isNaN(port)) {
+    // named pipe
+    return val;
+  }
+
+  if (port >= 0) {
+    // port number
+    return port;
+  }
+
+  return false;
+}
+
+/**
+ * Event listener for HTTP server "error" event.
+ */
+function onError(error) {
+  if (error.syscall !== 'listen') {
+    throw error;
+  }
+
+  var bind = typeof port === 'string'
+    ? 'Pipe ' + port
+    : 'Port ' + port;
+
+  // handle specific listen errors with friendly messages
+  switch (error.code) {
+    case 'EACCES':
+      console.error(bind + ' requires elevated privileges');
+      process.exit(1);
+      break;
+    case 'EADDRINUSE':
+      console.error(bind + ' is already in use');
+      process.exit(1);
+      break;
+    default:
+      throw error;
+  }
+}
+
+/**
+ * Event listener for HTTP server "listening" event.
+ */
+function onListening() {
+  var addr = server.address();
+  var bind = typeof addr === 'string'
+    ? 'pipe ' + addr
+    : 'port ' + addr.port;
+
+  debug('Listening on ' + bind);
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/src/main/js/config/default.json
----------------------------------------------------------------------
diff --git a/modules/web-control-center/src/main/js/config/default.json b/modules/web-control-center/src/main/js/config/default.json
new file mode 100644
index 0000000..72dbd4e
--- /dev/null
+++ b/modules/web-control-center/src/main/js/config/default.json
@@ -0,0 +1,8 @@
+{
+    "express": {
+        "port": 3000
+    },
+    "mongoDB": {
+        "url": "mongodb://localhost/web-control-center"
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/src/main/js/controllers/admin-controller.js
----------------------------------------------------------------------
diff --git a/modules/web-control-center/src/main/js/controllers/admin-controller.js b/modules/web-control-center/src/main/js/controllers/admin-controller.js
new file mode 100644
index 0000000..09490fe
--- /dev/null
+++ b/modules/web-control-center/src/main/js/controllers/admin-controller.js
@@ -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.
+ */
+
+controlCenterModule.controller('adminController', ['$scope', '$http', '$common', '$confirm', function ($scope, $http, $common, $confirm) {
+    $scope.users = null;
+
+    function reload() {
+        $http.post('admin/list')
+            .success(function (data) {
+                $scope.users = data;
+            })
+            .error(function (errMsg) {
+                $common.showError($common.errorMessage(errMsg));
+            });
+    }
+
+    reload();
+
+    $scope.removeUser = function (user) {
+        $confirm.show('Are you sure you want to remove user: "' + user.username + '"?').then(function () {
+            $http.post('admin/remove', {userId: user._id}).success(
+                function () {
+                    var i = _.findIndex($scope.users, function (u) {
+                        return u._id == user._id;
+                    });
+
+                    if (i >= 0)
+                        $scope.users.splice(i, 1);
+
+                    $common.showInfo('User has been removed: "' + user.username + '"');
+                }).error(function (errMsg) {
+                    $common.showError('Failed to remove user: "' + $common.errorMessage(errMsg) + '"');
+                });
+        });
+    };
+
+    $scope.toggleAdmin = function (user) {
+        if (user.adminChanging)
+            return;
+
+        user.adminChanging = true;
+
+        $http.post('admin/save', {userId: user._id, adminFlag: user.admin}).success(
+            function () {
+                $common.showInfo('Admin right was successfully toggled for user: "' + user.username + '"');
+
+                user.adminChanging = false;
+            }).error(function (errMsg) {
+                $common.showError('Failed to toggle admin right for user: "' + $common.errorMessage(errMsg) + '"');
+
+                user.adminChanging = false;
+            });
+    }
+}]);
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/src/main/js/controllers/cache-viewer-controller.js
----------------------------------------------------------------------
diff --git a/modules/web-control-center/src/main/js/controllers/cache-viewer-controller.js b/modules/web-control-center/src/main/js/controllers/cache-viewer-controller.js
new file mode 100644
index 0000000..6e0c130
--- /dev/null
+++ b/modules/web-control-center/src/main/js/controllers/cache-viewer-controller.js
@@ -0,0 +1,77 @@
+/*
+ * 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 demoResults = [
+    {
+        id: 256,
+        s: 'com.foo.User@3213',
+        fields: {
+            id: 256,
+            firstName: 'Ivan',
+            lastName: 'Ivanov',
+            old: 23
+        }
+    },
+
+    {
+        id: 384,
+        s: 'com.foo.User@23214',
+        fields: {
+            id: 384,
+            firstName: 'Sergey',
+            lastName: 'Petrov',
+            old: 28
+        }
+    },
+
+    {
+        id: 923,
+        s: 'com.foo.User@93494',
+        fields: {
+            id: 923,
+            firstName: 'Andrey',
+            lastName: 'Sidorov',
+            old: 28
+        }
+    }
+];
+
+var demoCaches = ['Users', 'Organizations', 'Cities'];
+
+controlCenterModule.controller('cacheViewerController', ['$scope', '$http', '$common', function ($scope, $http, $common) {
+    $scope.results = demoResults;
+
+    $scope.caches = demoCaches;
+
+    $scope.defCache = $scope.caches.length > 0 ? $scope.caches[0] : null;
+
+    var sqlEditor = ace.edit('querySql');
+
+    sqlEditor.setOptions({
+        highlightActiveLine: false,
+        showPrintMargin: false,
+        showGutter: true,
+        theme: "ace/theme/chrome",
+        mode: "ace/mode/sql",
+        fontSize: 14
+    });
+
+    sqlEditor.setValue("select u.id from User u where u.name like 'aaaa';");
+
+    sqlEditor.selection.clearSelection()
+
+}]);

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/src/main/js/controllers/caches-controller.js
----------------------------------------------------------------------
diff --git a/modules/web-control-center/src/main/js/controllers/caches-controller.js b/modules/web-control-center/src/main/js/controllers/caches-controller.js
new file mode 100644
index 0000000..0c23e3b
--- /dev/null
+++ b/modules/web-control-center/src/main/js/controllers/caches-controller.js
@@ -0,0 +1,333 @@
+/*
+ * 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.
+ */
+
+controlCenterModule.controller('cachesController', ['$scope', '$http', '$common', '$confirm', '$copy', '$table', function ($scope, $http, $common, $confirm, $copy, $table) {
+        $scope.joinTip = $common.joinTip;
+        $scope.getModel = $common.getModel;
+
+        $scope.tableNewItem = $table.tableNewItem;
+        $scope.tableNewItemActive = $table.tableNewItemActive;
+        $scope.tableEditing = $table.tableEditing;
+        $scope.tableStartEdit = $table.tableStartEdit;
+        $scope.tableRemove = $table.tableRemove;
+
+        $scope.tableSimpleSave = $table.tableSimpleSave;
+        $scope.tableSimpleSaveVisible = $table.tableSimpleSaveVisible;
+        $scope.tableSimpleUp = $table.tableSimpleUp;
+        $scope.tableSimpleDown = $table.tableSimpleDown;
+        $scope.tableSimpleDownVisible = $table.tableSimpleDownVisible;
+
+        $scope.tablePairSave = $table.tablePairSave;
+        $scope.tablePairSaveVisible = $table.tablePairSaveVisible;
+
+        $scope.atomicities = [
+            {value: 'ATOMIC', label: 'ATOMIC'},
+            {value: 'TRANSACTIONAL', label: 'TRANSACTIONAL'}
+        ];
+
+        $scope.modes = [
+            {value: 'PARTITIONED', label: 'PARTITIONED'},
+            {value: 'REPLICATED', label: 'REPLICATED'},
+            {value: 'LOCAL', label: 'LOCAL'}
+        ];
+
+        $scope.atomicWriteOrderModes = [
+            {value: 'CLOCK', label: 'CLOCK'},
+            {value: 'PRIMARY', label: 'PRIMARY'}
+        ];
+
+        $scope.memoryModes = [
+            {value: 'ONHEAP_TIERED', label: 'ONHEAP_TIERED'},
+            {value: 'OFFHEAP_TIERED', label: 'OFFHEAP_TIERED'},
+            {value: 'OFFHEAP_VALUES', label: 'OFFHEAP_VALUES'}
+        ];
+
+        $scope.evictionPolicies = [
+            {value: 'LRU', label: 'LRU'},
+            {value: 'RND', label: 'Random'},
+            {value: 'FIFO', label: 'FIFO'},
+            {value: 'SORTED', label: 'Sorted'},
+            {value: undefined, label: 'Not set'}
+        ];
+
+        $scope.rebalanceModes = [
+            {value: 'SYNC', label: 'SYNC'},
+            {value: 'ASYNC', label: 'ASYNC'},
+            {value: 'NONE', label: 'NONE'}
+        ];
+
+        $scope.cacheStoreFactories = [
+            {value: 'CacheJdbcPojoStoreFactory', label: 'JDBC POJO store factory'},
+            {value: 'CacheJdbcBlobStoreFactory', label: 'JDBC BLOB store factory'},
+            {value: 'CacheHibernateBlobStoreFactory', label: 'Hibernate BLOB store factory'},
+            {value: undefined, label: 'Not set'}
+        ];
+
+        $scope.cacheStoreJdbcDialects = [
+            {value: 'Oracle', label: 'Oracle'},
+            {value: 'DB2', label: 'IBM DB2'},
+            {value: 'SQLServer', label: 'Microsoft SQL Server'},
+            {value: 'MySQL', label: 'My SQL'},
+            {value: 'PostgreSQL', label: 'Postgre SQL'},
+            {value: 'H2', label: 'H2 database'}
+        ];
+
+        $scope.general = [];
+        $scope.advanced = [];
+
+        $http.get('/models/caches.json')
+            .success(function (data) {
+                $scope.screenTip = data.screenTip;
+                $scope.general = data.general;
+                $scope.advanced = data.advanced;
+            })
+            .error(function (errMsg) {
+                $common.showError(errMsg);
+            });
+
+        $scope.caches = [];
+
+        $scope.required = function (field) {
+            var model = $common.isDefined(field.path) ? field.path + '.' + field.model : field.model;
+
+            var backupItem = $scope.backupItem;
+
+            var memoryMode = backupItem.memoryMode;
+
+            var onHeapTired = memoryMode == 'ONHEAP_TIERED';
+            var offHeapTired = memoryMode == 'OFFHEAP_TIERED';
+
+            var offHeapMaxMemory = backupItem.offHeapMaxMemory;
+
+            if (model == 'offHeapMaxMemory' && offHeapTired)
+                return true;
+
+            if (model == 'evictionPolicy.kind' && onHeapTired)
+                return backupItem.swapEnabled || ($common.isDefined(offHeapMaxMemory) && offHeapMaxMemory >= 0);
+
+            return false;
+        };
+
+        $scope.tableSimpleValid = function (item, field, fx, index) {
+            var model = item[field.model];
+
+            if ($common.isDefined(model)) {
+                var idx = _.indexOf(model, fx);
+
+                // Found itself.
+                if (index >= 0 && index == idx)
+                    return true;
+
+                // Found duplicate.
+                if (idx >= 0) {
+                    $common.showError('SQL function such class name already exists!');
+
+                    return false;
+                }
+            }
+
+            return true;
+        };
+
+        $scope.tablePairValid = function (item, field, keyCls, valCls, index) {
+            var model = item[field.model];
+
+            if ($common.isDefined(model)) {
+                var idx = _.findIndex(model, function (pair) {
+                    return pair.keyClass == keyCls
+                });
+
+                // Found itself.
+                if (index >= 0 && index == idx)
+                    return true;
+
+                // Found duplicate.
+                if (idx >= 0) {
+                    $common.showError('Indexed type with such key class already exists!');
+
+                    return false;
+                }
+            }
+
+            return true;
+        };
+
+        // When landing on the page, get caches and show them.
+        $http.post('caches/list')
+            .success(function (data) {
+                $scope.spaces = data.spaces;
+                $scope.caches = data.caches;
+
+                var restoredItem = angular.fromJson(sessionStorage.cacheBackupItem);
+
+                if (restoredItem) {
+                    if (restoredItem._id) {
+                        var idx = _.findIndex($scope.caches, function (cache) {
+                            return cache._id == restoredItem._id;
+                        });
+
+                        if (idx >= 0) {
+                            $scope.selectedItem = $scope.caches[idx];
+                            $scope.backupItem = restoredItem;
+                        }
+                        else
+                            sessionStorage.removeItem('cacheBackupItem');
+                    }
+                    else
+                        $scope.backupItem = restoredItem;
+                }
+                else if ($scope.caches.length > 0)
+                    $scope.selectItem($scope.caches[0]);
+
+                $scope.$watch('backupItem', function (val) {
+                    if (val)
+                        sessionStorage.cacheBackupItem = angular.toJson(val);
+                }, true);
+            })
+            .error(function (errMsg) {
+                $common.showError(errMsg);
+            });
+
+        $scope.selectItem = function (item) {
+            $table.tableReset();
+
+            $scope.selectedItem = item;
+            $scope.backupItem = angular.copy(item);
+        };
+
+        // Add new cache.
+        $scope.createItem = function () {
+            $table.tableReset();
+
+            $scope.backupItem = {mode: 'PARTITIONED', atomicityMode: 'ATOMIC', readFromBackup: true, copyOnRead: true};
+            $scope.backupItem.space = $scope.spaces[0]._id;
+        };
+
+        // Check cache logical consistency.
+        function validate(item) {
+            var cacheStoreFactorySelected = item.cacheStoreFactory && item.cacheStoreFactory.kind;
+
+            if (cacheStoreFactorySelected && !(item.readThrough || item.writeThrough)) {
+                $common.showError('Store is configured but read/write through are not enabled!');
+
+                return false;
+            }
+
+            if ((item.readThrough || item.writeThrough) && !cacheStoreFactorySelected) {
+                $common.showError('Read / write through are enabled but store is not configured!');
+
+                return false;
+            }
+
+            if (item.writeBehindEnabled && !cacheStoreFactorySelected) {
+                $common.showError('Write behind enabled but store is not configured!');
+
+                return false;
+            }
+
+            return true;
+        }
+
+        // Save cache into database.
+        function save(item) {
+            $http.post('caches/save', item)
+                .success(function (_id) {
+                    var idx = _.findIndex($scope.caches, function (cache) {
+                        return cache._id == _id;
+                    });
+
+                    if (idx >= 0)
+                        angular.extend($scope.caches[idx], item);
+                    else {
+                        item._id = _id;
+
+                        $scope.caches.push(item);
+                    }
+
+                    $scope.selectItem(item);
+
+                    $common.showInfo('Cache "' + item.name + '" saved.');
+                })
+                .error(function (errMsg) {
+                    $common.showError(errMsg);
+                });
+        }
+
+        // Save cache.
+        $scope.saveItem = function () {
+            $table.tableReset();
+
+            var item = $scope.backupItem;
+
+            if (validate(item))
+                save(item);
+        };
+
+        // Save cache with new name.
+        $scope.saveItemAs = function () {
+            $table.tableReset();
+
+            if (validate($scope.backupItem))
+                $copy.show($scope.backupItem.name).then(function (newName) {
+                    var item = angular.copy($scope.backupItem);
+
+                    item._id = undefined;
+                    item.name = newName;
+
+                    save(item);
+                });
+        };
+
+        // Remove cache from db.
+        $scope.removeItem = function () {
+            $table.tableReset();
+
+            var selectedItem = $scope.selectedItem;
+
+            $confirm.show('Are you sure you want to remove cache: "' + selectedItem.name + '"?').then(
+                function () {
+                    var _id = selectedItem._id;
+
+                    $http.post('caches/remove', {_id: _id})
+                        .success(function () {
+                            $common.showInfo('Cache has been removed: ' + selectedItem.name);
+
+                            var caches = $scope.caches;
+
+                            var idx = _.findIndex(caches, function (cache) {
+                                return cache._id == _id;
+                            });
+
+                            if (idx >= 0) {
+                                caches.splice(idx, 1);
+
+                                if (caches.length > 0)
+                                    $scope.selectItem(caches[0]);
+                                else {
+                                    $scope.selectedItem = undefined;
+                                    $scope.backupItem = undefined;
+                                }
+                            }
+                        })
+                        .error(function (errMsg) {
+                            $common.showError(errMsg);
+                        });
+                }
+            );
+        };
+    }]
+);
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/src/main/js/controllers/clusters-controller.js
----------------------------------------------------------------------
diff --git a/modules/web-control-center/src/main/js/controllers/clusters-controller.js b/modules/web-control-center/src/main/js/controllers/clusters-controller.js
new file mode 100644
index 0000000..1ec78a1
--- /dev/null
+++ b/modules/web-control-center/src/main/js/controllers/clusters-controller.js
@@ -0,0 +1,309 @@
+/*
+ * 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.
+ */
+
+controlCenterModule.controller('clustersController', ['$scope', '$http', '$common', '$confirm', '$copy', '$table', function ($scope, $http, $common, $confirm, $copy, $table) {
+        $scope.joinTip = $common.joinTip;
+        $scope.getModel = $common.getModel;
+
+        $scope.tableNewItem = $table.tableNewItem;
+        $scope.tableNewItemActive = $table.tableNewItemActive;
+        $scope.tableEditing = $table.tableEditing;
+        $scope.tableStartEdit = $table.tableStartEdit;
+        $scope.tableRemove = $table.tableRemove;
+
+        $scope.tableSimpleSave = $table.tableSimpleSave;
+        $scope.tableSimpleSaveVisible = $table.tableSimpleSaveVisible;
+        $scope.tableSimpleUp = $table.tableSimpleUp;
+        $scope.tableSimpleDown = $table.tableSimpleDown;
+        $scope.tableSimpleDownVisible = $table.tableSimpleDownVisible;
+
+        $scope.templates = [
+            {
+                value: {discovery: {kind: 'Multicast', Vm: {addresses: ['127.0.0.1:47500..47510']}, Multicast: {}}},
+                label: 'multicast'
+            },
+            {value: {discovery: {kind: 'Vm', Vm: {addresses: ['127.0.0.1:47500..47510']}}}, label: 'local'}
+        ];
+
+        $scope.discoveries = [
+            {value: 'Vm', label: 'static IPs'},
+            {value: 'Multicast', label: 'multicast'},
+            {value: 'S3', label: 'AWS S3'},
+            {value: 'Cloud', label: 'apache jclouds'},
+            {value: 'GoogleStorage', label: 'google cloud storage'},
+            {value: 'Jdbc', label: 'JDBC'},
+            {value: 'SharedFs', label: 'shared filesystem'}
+        ];
+
+        $scope.swapSpaceSpis = [
+            {value: 'FileSwapSpaceSpi', label: 'File-based swap'},
+            {value: undefined, label: 'Not set'}
+        ];
+
+        $scope.events = [];
+
+        for (var eventGroupName in eventGroups) {
+            if (eventGroups.hasOwnProperty(eventGroupName)) {
+                $scope.events.push({value: eventGroupName, label: eventGroupName});
+            }
+        }
+
+        $scope.cacheModes = [
+            {value: 'LOCAL', label: 'LOCAL'},
+            {value: 'REPLICATED', label: 'REPLICATED'},
+            {value: 'PARTITIONED', label: 'PARTITIONED'}
+        ];
+
+        $scope.deploymentModes = [
+            {value: 'PRIVATE', label: 'PRIVATE'},
+            {value: 'ISOLATED', label: 'ISOLATED'},
+            {value: 'SHARED', label: 'SHARED'},
+            {value: 'CONTINUOUS', label: 'CONTINUOUS'}
+        ];
+
+        $scope.transactionConcurrency = [
+            {value: 'OPTIMISTIC', label: 'OPTIMISTIC'},
+            {value: 'PESSIMISTIC', label: 'PESSIMISTIC'}
+        ];
+
+        $scope.transactionIsolation = [
+            {value: 'READ_COMMITTED', label: 'READ_COMMITTED'},
+            {value: 'REPEATABLE_READ', label: 'REPEATABLE_READ'},
+            {value: 'SERIALIZABLE', label: 'SERIALIZABLE'}
+        ];
+
+        $scope.segmentationPolicy = [
+            {value: 'RESTART_JVM', label: 'RESTART_JVM'},
+            {value: 'STOP', label: 'STOP'},
+            {value: 'NOOP', label: 'NOOP'}
+        ];
+
+        $scope.marshallers = [
+            {value: 'OptimizedMarshaller', label: 'OptimizedMarshaller'},
+            {value: 'JdkMarshaller', label: 'JdkMarshaller'}
+        ];
+
+        $scope.tableSimpleValid = function (item, field, val, index) {
+            var model = $common.getModel(item, field)[field.model];
+
+            if ($common.isDefined(model)) {
+                var idx = _.indexOf(model, val);
+
+                // Found itself.
+                if (index >= 0 && index == idx)
+                    return true;
+
+                // Found duplicate.
+                if (idx >= 0) {
+                    var msg = 'Such IP address already exists!';
+
+                    if (field.model == 'regions')
+                        msg = 'Such region already exists!';
+                    if (field.model == 'zones')
+                        msg = 'Such zone already exists!';
+
+                    $common.showError(msg);
+
+                    return false;
+                }
+            }
+
+            return true;
+        };
+
+        $scope.clusters = [];
+
+        $http.get('/models/clusters.json')
+            .success(function (data) {
+                $scope.screenTip = data.screenTip;
+                $scope.templateTip = data.templateTip;
+
+                $scope.general = data.general;
+                $scope.advanced = data.advanced;
+            })
+            .error(function (errMsg) {
+                $common.showError(errMsg);
+            });
+
+        // When landing on the page, get clusters and show them.
+        $http.post('clusters/list')
+            .success(function (data) {
+                $scope.caches = data.caches;
+                $scope.spaces = data.spaces;
+                $scope.clusters = data.clusters;
+
+                var restoredItem = angular.fromJson(sessionStorage.clusterBackupItem);
+
+                if (restoredItem) {
+                    if (restoredItem._id) {
+                        var idx = _.findIndex($scope.clusters, function (cluster) {
+                            return cluster._id == restoredItem._id;
+                        });
+
+                        if (idx >= 0) {
+                            $scope.selectedItem = $scope.clusters[idx];
+                            $scope.backupItem = restoredItem;
+                        }
+                        else
+                            sessionStorage.removeItem('clusterBackupItem');
+                    }
+                    else
+                        $scope.backupItem = restoredItem;
+                }
+                else if ($scope.clusters.length > 0)
+                    $scope.selectItem($scope.clusters[0]);
+
+                $scope.$watch('backupItem', function (val) {
+                    if (val)
+                        sessionStorage.clusterBackupItem = angular.toJson(val);
+                }, true);
+            })
+            .error(function (errMsg) {
+                $common.showError(errMsg);
+            });
+
+        $scope.selectItem = function (item) {
+            $table.tableReset();
+
+            $scope.selectedItem = item;
+            $scope.backupItem = angular.copy(item);
+        };
+
+        // Add new cluster.
+        $scope.createItem = function () {
+            $table.tableReset();
+
+            $scope.backupItem = angular.copy($scope.create.template);
+            $scope.backupItem.space = $scope.spaces[0]._id;
+        };
+
+        $scope.indexOfCache = function (cacheId) {
+            return _.findIndex($scope.caches, function (cache) {
+                return cache.value == cacheId;
+            });
+        };
+
+        // Check cluster logical consistency.
+        function validate(item) {
+            if (!item.swapSpaceSpi || !item.swapSpaceSpi.kind && item.caches) {
+                for (var i = 0; i < item.caches.length; i++) {
+                    var idx = $scope.indexOfCache(item.caches[i]);
+
+                    if (idx >= 0) {
+                        var cache = $scope.caches[idx];
+
+                        if (cache.swapEnabled) {
+                            $common.showError('Swap space SPI is not configured, but cache "' + cache.label + '" configured to use swap!');
+
+                            return false;
+                        }
+                    }
+                }
+            }
+
+            return true;
+        }
+
+        // Save cluster in database.
+        function save(item) {
+            $http.post('clusters/save', item)
+                .success(function (_id) {
+                    var idx = _.findIndex($scope.clusters, function (cluster) {
+                        return cluster._id == _id;
+                    });
+
+                    if (idx >= 0)
+                        angular.extend($scope.clusters[idx], item);
+                    else {
+                        item._id = _id;
+
+                        $scope.clusters.push(item);
+                    }
+
+                    $scope.selectItem(item);
+
+                    $common.showInfo('Cluster "' + item.name + '" saved.');
+                })
+                .error(function (errMsg) {
+                    $common.showError(errMsg);
+                });
+        }
+
+        // Save cluster.
+        $scope.saveItem = function () {
+            $table.tableReset();
+
+            var item = $scope.backupItem;
+
+            if (validate(item))
+                save(item);
+        };
+
+        // Save cluster with new name.
+        $scope.saveItemAs = function () {
+            $table.tableReset();
+
+            if (validate($scope.backupItem))
+                $copy.show($scope.backupItem.name).then(function (newName) {
+                    var item = angular.copy($scope.backupItem);
+
+                    item._id = undefined;
+                    item.name = newName;
+
+                    save(item);
+                });
+        };
+
+        // Remove cluster from db.
+        $scope.removeItem = function () {
+            $table.tableReset();
+
+            var selectedItem = $scope.selectedItem;
+
+            $confirm.show('Are you sure you want to remove cluster: "' + selectedItem.name + '"?').then(
+                function () {
+                    var _id = selectedItem._id;
+
+                    $http.post('clusters/remove', {_id: _id})
+                        .success(function () {
+                            $common.showInfo('Cluster has been removed: ' + selectedItem.name);
+
+                            var clusters = $scope.clusters;
+
+                            var idx = _.findIndex(clusters, function (cluster) {
+                                return cluster._id == _id;
+                            });
+
+                            if (idx >= 0) {
+                                clusters.splice(idx, 1);
+
+                                if (clusters.length > 0)
+                                    $scope.selectItem(clusters[0]);
+                                else {
+                                    $scope.selectedItem = undefined;
+                                    $scope.backupItem = undefined;
+                                }
+                            }
+                        })
+                        .error(function (errMsg) {
+                            $common.showError(errMsg);
+                        });
+                }
+            );
+        };
+    }]
+);
\ No newline at end of file



[08/10] incubator-ignite git commit: # ignite-843 moved

Posted by an...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/nodejs/db.js
----------------------------------------------------------------------
diff --git a/modules/web-control-center/nodejs/db.js b/modules/web-control-center/nodejs/db.js
deleted file mode 100644
index e34272c..0000000
--- a/modules/web-control-center/nodejs/db.js
+++ /dev/null
@@ -1,358 +0,0 @@
-/*
- * 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 config = require('./helpers/configuration-loader.js');
-
-// Mongoose for mongodb.
-var mongoose = require('mongoose'),
-    Schema = mongoose.Schema,
-    ObjectId = mongoose.Schema.Types.ObjectId,
-    passportLocalMongoose = require('passport-local-mongoose');
-
-// Connect to mongoDB database.
-mongoose.connect(config.get('mongoDB:url'), {server: {poolSize: 4}});
-
-// Define account model.
-var AccountSchema = new Schema({
-    username: String,
-    email: String,
-    lastLogin: Date,
-    admin: Boolean
-});
-
-AccountSchema.plugin(passportLocalMongoose, {usernameField: 'email', limitAttempts: true, lastLoginField: 'lastLogin',
-    usernameLowerCase: true});
-
-AccountSchema.set('toJSON', {
-    transform: function(doc, ret) {
-        return {
-            _id: ret._id,
-            email: ret.email,
-            username: ret.username,
-            admin: ret.admin,
-            lastLogin: ret.lastLogin
-        };
-    }
-});
-
-exports.Account = mongoose.model('Account', AccountSchema);
-
-// Define space model.
-exports.Space = mongoose.model('Space', new Schema({
-    name: String,
-    owner: {type: ObjectId, ref: 'Account'},
-    usedBy: [{
-        permission: {type: String, enum: ['VIEW', 'FULL']},
-        account: {type: ObjectId, ref: 'Account'}
-    }]
-}));
-
-// Define cache type metadata model.
-var CacheTypeMetadataSchema = new Schema({
-    space: {type: ObjectId, ref: 'Space'},
-    name: String,
-    kind: {type: String, enum: ['query', 'store', 'both']},
-    databaseSchema: String,
-    databaseTable: String,
-    keyType: String,
-    valueType: String,
-    keyFields: [{dbName: String, dbType: String, javaName: String, javaType: String}],
-    valueFields: [{dbName: String, dbType: String, javaName: String, javaType: String}],
-    queryFields: [{name: String, className: String}],
-    ascendingFields: [{name: String, className: String}],
-    descendingFields:  [{name: String, className: String}],
-    textFields: [String],
-    groups: [{name: String, fields: [{name: String, className: String, direction: String}]}]
-});
-
-exports.CacheTypeMetadata = mongoose.model('CacheTypeMetadata', CacheTypeMetadataSchema);
-
-// Define cache model.
-var CacheSchema = new Schema({
-    space: {type: ObjectId, ref: 'Space'},
-    name: String,
-    mode: {type: String, enum: ['PARTITIONED', 'REPLICATED', 'LOCAL']},
-    atomicityMode: {type: String, enum: ['ATOMIC', 'TRANSACTIONAL']},
-
-    backups: Number,
-    memoryMode: {type: String, enum: ['ONHEAP_TIERED', 'OFFHEAP_TIERED', 'OFFHEAP_VALUES']},
-    offHeapMaxMemory: Number,
-    startSize: Number,
-    swapEnabled: Boolean,
-
-    evictionPolicy: {
-        kind: {type: String, enum: ['LRU', 'RND', 'FIFO', 'Sorted']},
-        LRU: {
-            batchSize: Number,
-            maxMemorySize: Number,
-            maxSize: Number
-        },
-        RND: {
-            maxSize: Number
-        },
-        FIFO: {
-            batchSize: Number,
-            maxMemorySize: Number,
-            maxSize: Number
-        },
-        SORTED: {
-            batchSize: Number,
-            maxMemorySize: Number,
-            maxSize: Number
-        }
-    },
-
-    rebalanceMode: {type: String, enum: ['SYNC', 'ASYNC', 'NONE']},
-    rebalanceThreadPoolSize: Number,
-    rebalanceBatchSize: Number,
-    rebalanceOrder: Number,
-    rebalanceDelay: Number,
-    rebalanceTimeout: Number,
-    rebalanceThrottle: Number,
-
-    cacheStoreFactory: {
-        kind: {
-            type: String,
-            enum: ['CacheJdbcPojoStoreFactory', 'CacheJdbcBlobStoreFactory', 'CacheHibernateBlobStoreFactory']
-        },
-        CacheJdbcPojoStoreFactory: {
-            dataSourceBean: String,
-            dialect: {
-                type: String,
-                enum: ['Oracle', 'DB2', 'SQLServer', 'MySQL', 'PosgreSQL', 'H2']
-            }
-        },
-        CacheJdbcBlobStoreFactory: {
-            user: String,
-            dataSourceBean: String,
-            initSchema: Boolean,
-            createTableQuery: String,
-            loadQuery: String,
-            insertQuery: String,
-            updateQuery: String,
-            deleteQuery: String
-        },
-        CacheHibernateBlobStoreFactory: {
-            hibernateProperties: [String]
-        }
-    },
-    loadPreviousValue: Boolean,
-    readThrough: Boolean,
-    writeThrough: Boolean,
-
-    writeBehindEnabled: Boolean,
-    writeBehindBatchSize: Number,
-    writeBehindFlushSize: Number,
-    writeBehindFlushFrequency: Number,
-    writeBehindFlushThreadCount: Number,
-
-    invalidate: Boolean,
-    defaultLockTimeout: Number,
-    transactionManagerLookupClassName: String,
-
-    sqlEscapeAll: Boolean,
-    sqlOnheapRowCacheSize: Number,
-    longQueryWarningTimeout: Number,
-    indexedTypes: [{keyClass: String, valueClass: String}],
-    sqlFunctionClasses: [String],
-    statisticsEnabled: Boolean,
-    managementEnabled: Boolean,
-    readFromBackup: Boolean,
-    copyOnRead: Boolean,
-    maxConcurrentAsyncOperations: Number,
-    nearConfiguration: {
-        nearStartSize: Number,
-        nearEvictionPolicy: {
-            kind: {type: String, enum: ['LRU', 'RND', 'FIFO', 'Sorted']},
-            LRU: {
-                batchSize: Number,
-                maxMemorySize: Number,
-                maxSize: Number
-            },
-            RND: {
-                maxSize: Number
-            },
-            FIFO: {
-                batchSize: Number,
-                maxMemorySize: Number,
-                maxSize: Number
-            },
-            SORTED: {
-                batchSize: Number,
-                maxMemorySize: Number,
-                maxSize: Number
-            }
-        }
-    }
-});
-
-exports.Cache = mongoose.model('Cache', CacheSchema);
-
-// Define cluster schema.
-var ClusterSchema = new Schema({
-    space: {type: ObjectId, ref: 'Space'},
-    name: String,
-    discovery: {
-        kind: {type: String, enum: ['Vm', 'Multicast', 'S3', 'Cloud', 'GoogleStorage', 'Jdbc', 'SharedFs']},
-        Vm: {
-            addresses: [String]
-        },
-        Multicast: {
-            multicastGroup: String,
-            multicastPort: Number,
-            responseWaitTime: Number,
-            addressRequestAttempts: Number,
-            localAddress: String
-        },
-        S3: {
-            bucketName: String
-        },
-        Cloud: {
-            credential: String,
-            credentialPath: String,
-            identity: String,
-            provider: String,
-            regions: [String],
-            zones:  [String]
-        },
-        GoogleStorage: {
-            projectName: String,
-            bucketName: String,
-            serviceAccountP12FilePath: String,
-            addrReqAttempts: String
-        },
-        Jdbc: {
-            initSchema: Boolean
-        },
-        SharedFs: {
-            path: String
-        }
-    },
-    atomicConfiguration: {
-        backups: Number,
-        cacheMode: {type: String, enum: ['LOCAL', 'REPLICATED', 'PARTITIONED']},
-        atomicSequenceReserveSize: Number
-    },
-    caches: [{type: ObjectId, ref: 'Cache'}],
-    cacheSanityCheckEnabled: Boolean,
-    clockSyncSamples: Number,
-    clockSyncFrequency: Number,
-    deploymentMode: {type: String, enum: ['PRIVATE', 'ISOLATED', 'SHARED', 'CONTINUOUS']},
-    discoveryStartupDelay: Number,
-    igfsThreadPoolSize: Number,
-    includeEventTypes: [{
-        type: String, enum: ['EVTS_CHECKPOINT', 'EVTS_DEPLOYMENT', 'EVTS_ERROR', 'EVTS_DISCOVERY',
-            'EVTS_JOB_EXECUTION', 'EVTS_TASK_EXECUTION', 'EVTS_CACHE', 'EVTS_CACHE_REBALANCE', 'EVTS_CACHE_LIFECYCLE',
-            'EVTS_CACHE_QUERY', 'EVTS_SWAPSPACE', 'EVTS_IGFS']
-    }],
-    managementThreadPoolSize: Number,
-    marshaller: {
-        kind: {type: String, enum: ['OptimizedMarshaller', 'JdkMarshaller']},
-        OptimizedMarshaller: {
-            poolSize: Number,
-            requireSerializable: Boolean
-        }
-    },
-    marshalLocalJobs: Boolean,
-    marshallerCacheKeepAliveTime: Number,
-    marshallerCacheThreadPoolSize: Number,
-    metricsExpireTime: Number,
-    metricsHistorySize: Number,
-    metricsLogFrequency: Number,
-    metricsUpdateFrequency: Number,
-    networkTimeout: Number,
-    networkSendRetryDelay: Number,
-    networkSendRetryCount: Number,
-    peerClassLoadingEnabled: Boolean,
-    peerClassLoadingLocalClassPathExclude: [String],
-    peerClassLoadingMissedResourcesCacheSize: Number,
-    peerClassLoadingThreadPoolSize: Number,
-    publicThreadPoolSize: Number,
-    segmentCheckFrequency: Number,
-    segmentationPolicy: {type: String, enum: ['RESTART_JVM', 'STOP', 'NOOP']},
-    allSegmentationResolversPassRequired: Boolean,
-    segmentationResolveAttempts: Number,
-    swapSpaceSpi: {
-        kind: {type: String, enum: ['FileSwapSpaceSpi']},
-        FileSwapSpaceSpi: {
-            baseDirectory: String,
-            readStripesNumber: Number,
-            maximumSparsity: Number,
-            maxWriteQueueSize: Number,
-            writeBufferSize: Number
-        }
-    },
-    systemThreadPoolSize: Number,
-    timeServerPortBase: Number,
-    timeServerPortRange: Number,
-    transactionConfiguration: {
-        defaultTxConcurrency: {type: String, enum: ['OPTIMISTIC', 'PESSIMISTIC']},
-        transactionIsolation: {type: String, enum: ['READ_COMMITTED', 'REPEATABLE_READ', 'SERIALIZABLE']},
-        defaultTxTimeout: Number,
-        pessimisticTxLogLinger: Number,
-        pessimisticTxLogSize: Number,
-        txSerializableEnabled: Boolean
-    },
-    waitForSegmentOnStart: Boolean
-});
-
-// Define cluster model.
-exports.Cluster = mongoose.model('Cluster', ClusterSchema);
-
-// Define persistence schema.
-var PersistenceSchema = new Schema({
-    space: {type: ObjectId, ref: 'Space'},
-    name: String,
-    dbType: {type: String, enum: ['oracle', 'db2', 'mssql', 'postgre', 'mysql', 'h2']},
-    dbName: String,
-    host: String,
-    user: String,
-    tables: [{
-        use: Boolean,
-        schemaName: String,
-        tableName: String,
-        keyClass: String,
-        valueClass: String,
-        columns: [{
-            use: Boolean,
-            pk: Boolean,
-            ak: Boolean,
-            notNull: Boolean,
-            dbName: String,
-            dbType: Number,
-            javaName: String,
-            javaType: String
-        }]
-    }]
-});
-
-// Define persistence model.
-exports.Persistence = mongoose.model('Persistence', PersistenceSchema);
-
-exports.upsert = function (model, data, cb) {
-    if (data._id) {
-        var id = data._id;
-
-        delete data._id;
-
-        model.findOneAndUpdate({_id: id}, data, cb);
-    }
-    else
-        new model(data).save(cb);
-};
-
-exports.mongoose = mongoose;
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/nodejs/helpers/configuration-loader.js
----------------------------------------------------------------------
diff --git a/modules/web-control-center/nodejs/helpers/configuration-loader.js b/modules/web-control-center/nodejs/helpers/configuration-loader.js
deleted file mode 100644
index 6dbb577..0000000
--- a/modules/web-control-center/nodejs/helpers/configuration-loader.js
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * 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 config = require('nconf');
-
-config.file({'file': 'config/default.json'});
-
-module.exports = config;
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/nodejs/helpers/data-structures.js
----------------------------------------------------------------------
diff --git a/modules/web-control-center/nodejs/helpers/data-structures.js b/modules/web-control-center/nodejs/helpers/data-structures.js
deleted file mode 100644
index 2462708..0000000
--- a/modules/web-control-center/nodejs/helpers/data-structures.js
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * 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.
- */
-
-eventGroups = {
-    EVTS_CHECKPOINT: ['EVT_CHECKPOINT_SAVED', 'EVT_CHECKPOINT_LOADED', 'EVT_CHECKPOINT_REMOVED'],
-    EVTS_DEPLOYMENT: ['EVT_CLASS_DEPLOYED', 'EVT_CLASS_UNDEPLOYED', 'EVT_CLASS_DEPLOY_FAILED', 'EVT_TASK_DEPLOYED',
-        'EVT_TASK_UNDEPLOYED', 'EVT_TASK_DEPLOY_FAILED'],
-    EVTS_ERROR: ['EVT_JOB_TIMEDOUT', 'EVT_JOB_FAILED', 'EVT_JOB_FAILED_OVER', 'EVT_JOB_REJECTED', 'EVT_JOB_CANCELLED',
-        'EVT_TASK_TIMEDOUT', 'EVT_TASK_FAILED', 'EVT_CLASS_DEPLOY_FAILED', 'EVT_TASK_DEPLOY_FAILED',
-        'EVT_TASK_DEPLOYED', 'EVT_TASK_UNDEPLOYED', 'EVT_CACHE_REBALANCE_STARTED', 'EVT_CACHE_REBALANCE_STOPPED'],
-    EVTS_DISCOVERY: ['EVT_NODE_JOINED', 'EVT_NODE_LEFT', 'EVT_NODE_FAILED', 'EVT_NODE_SEGMENTED',
-        'EVT_CLIENT_NODE_DISCONNECTED', 'EVT_CLIENT_NODE_RECONNECTED'],
-    EVTS_JOB_EXECUTION: ['EVT_JOB_MAPPED', 'EVT_JOB_RESULTED', 'EVT_JOB_FAILED_OVER', 'EVT_JOB_STARTED',
-        'EVT_JOB_FINISHED', 'EVT_JOB_TIMEDOUT', 'EVT_JOB_REJECTED', 'EVT_JOB_FAILED', 'EVT_JOB_QUEUED',
-        'EVT_JOB_CANCELLED'],
-    EVTS_TASK_EXECUTION: ['EVT_TASK_STARTED', 'EVT_TASK_FINISHED', 'EVT_TASK_FAILED', 'EVT_TASK_TIMEDOUT',
-        'EVT_TASK_SESSION_ATTR_SET', 'EVT_TASK_REDUCED'],
-    EVTS_CACHE: ['EVT_CACHE_ENTRY_CREATED', 'EVT_CACHE_ENTRY_DESTROYED', 'EVT_CACHE_OBJECT_PUT',
-        'EVT_CACHE_OBJECT_READ', 'EVT_CACHE_OBJECT_REMOVED', 'EVT_CACHE_OBJECT_LOCKED', 'EVT_CACHE_OBJECT_UNLOCKED',
-        'EVT_CACHE_OBJECT_SWAPPED', 'EVT_CACHE_OBJECT_UNSWAPPED', 'EVT_CACHE_OBJECT_EXPIRED'],
-    EVTS_CACHE_REBALANCE: ['EVT_CACHE_REBALANCE_STARTED', 'EVT_CACHE_REBALANCE_STOPPED',
-        'EVT_CACHE_REBALANCE_PART_LOADED', 'EVT_CACHE_REBALANCE_PART_UNLOADED', 'EVT_CACHE_REBALANCE_OBJECT_LOADED',
-        'EVT_CACHE_REBALANCE_OBJECT_UNLOADED', 'EVT_CACHE_REBALANCE_PART_DATA_LOST'],
-    EVTS_CACHE_LIFECYCLE: ['EVT_CACHE_STARTED', 'EVT_CACHE_STOPPED', 'EVT_CACHE_NODES_LEFT'],
-    EVTS_CACHE_QUERY: ['EVT_CACHE_QUERY_EXECUTED', 'EVT_CACHE_QUERY_OBJECT_READ'],
-    EVTS_SWAPSPACE: ['EVT_SWAP_SPACE_CLEARED', 'EVT_SWAP_SPACE_DATA_REMOVED', 'EVT_SWAP_SPACE_DATA_READ',
-        'EVT_SWAP_SPACE_DATA_STORED', 'EVT_SWAP_SPACE_DATA_EVICTED'],
-    EVTS_IGFS: ['EVT_IGFS_FILE_CREATED', 'EVT_IGFS_FILE_RENAMED', 'EVT_IGFS_FILE_DELETED', 'EVT_IGFS_FILE_OPENED_READ',
-        'EVT_IGFS_FILE_OPENED_WRITE', 'EVT_IGFS_FILE_CLOSED_WRITE', 'EVT_IGFS_FILE_CLOSED_READ', 'EVT_IGFS_FILE_PURGED',
-        'EVT_IGFS_META_UPDATED', 'EVT_IGFS_DIR_CREATED', 'EVT_IGFS_DIR_RENAMED', 'EVT_IGFS_DIR_DELETED']
-};
-
-jdbcTypes = {
-    BIT: {value: "BIT", code: -7, label: "BIT"},
-    TINYINT: {value: "TINYINT", code: -6, label: "TINYINT"},
-    SMALLINT: {value: "SMALLINT", code: 5, label: "SMALLINT"},
-    INTEGER: {value: "INTEGER", code: 4, label: "INTEGER"},
-    BIGINT: {value: "BIGINT", code: -5, label: "BIGINT"},
-    FLOAT: {value: "FLOAT", code: 6, label: "FLOAT"},
-    REAL: {value: "REAL", code: 7, label: "REAL"},
-    DOUBLE: {value: "DOUBLE", code: 8, label: "DOUBLE"},
-    NUMERIC: {value: "NUMERIC", code: 2, label: "NUMERIC"},
-    DECIMAL: {value: "DECIMAL", code: 3, label: "DECIMAL"},
-    CHAR: {value: "CHAR", code: 1, label: "CHAR"},
-    VARCHAR: {value: "VARCHAR", code: 12, label: "VARCHAR"},
-    DATE: {value: "DATE", code: 91, label: "DATE"},
-    TIME: {value: "TIME", code: 92, label: "TIME"},
-    TIMESTAMP: {value: "TIMESTAMP", code: 93, label: "TIMESTAMP"},
-    BINARY: {value: "BINARY", code: -2, label: "BINARY"}
-};
-
-javaTypes = {
-    INTEGER: {value: "java.lang.Integer", label: "Integer"},
-    LONG: {value: "java.lang.Long", label: "Long"},
-    BIGDECIMAL: {value: "java.math.BigDecimal", label: "BigDecimal"},
-    FLOAT: {value: "java.lang.Float", label: "Float"},
-    DOUBLE: {value: "java.lang.Double", label: "Double"},
-    STRING: {value: "java.lang.String", label: "String"},
-    BOOLEAN: {value: "java.lang.Boolean", label: "Boolean"},
-    BYTE_ARRAY: {value: "byte[]", label: "byte[]"},
-    DATE: {value: "java.sql.Date", label: "Date"},
-    TIME: {value: "java.sql.Time", label: "Time"},
-    TIMESTAMP: {value: "java.sql.Timestamp", label: "Timestamp"}
-};
-
-if (typeof window === 'undefined') {
-    exports.eventGroups = eventGroups;
-    exports.jdbcTypes = jdbcTypes;
-    exports.javaTypes = javaTypes;
-}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/nodejs/package.json
----------------------------------------------------------------------
diff --git a/modules/web-control-center/nodejs/package.json b/modules/web-control-center/nodejs/package.json
deleted file mode 100644
index 5e5463c..0000000
--- a/modules/web-control-center/nodejs/package.json
+++ /dev/null
@@ -1,50 +0,0 @@
-{
-  "name": "ignite-web-control-center",
-  "version": "1.0.0",
-  "description": "Web application for configuration, monitoring Ignite Cluster",
-  "private": true,
-  "scripts": {
-    "start": "node ./bin/www"
-  },
-  "author": "",
-  "contributors": [
-    {
-      "name": "",
-      "email": ""
-    }
-  ],
-  "license": "Apache-2.0",
-  "keywords": "grid",
-  "homepage": "https://ignite.incubator.apache.org/",
-  "engines": {
-    "node": ">=0.12.4"
-  },
-  "dependencies": {
-    "angular-ui-ace": "^0.2.3",
-    "archiver": "^0.14.4",
-    "body-parser": "~1.12.0",
-    "connect-flash": "^0.1.1",
-    "connect-mongo": "^0.8.1",
-    "cookie-parser": "~1.3.4",
-    "debug": "~2.1.1",
-    "express": "~4.12.2",
-    "express-session": "^1.11.1",
-    "jade": "~1.9.2",
-    "less-middleware": "1.0.x",
-    "lodash": "3.10.0",
-    "mongoose": "^4.0.2",
-    "nconf": "^0.7.1",
-    "passport": "^0.2.1",
-    "passport-local": "^1.0.0",
-    "passport-local-mongoose": "^1.0.0",
-    "pg": "^4.4.0",
-    "serve-favicon": "~2.2.0",
-    "util": "^0.10.3"
-  },
-  "devDependencies": {
-    "morgan": "~1.5.1",
-    "supertest": "^1.0.1",
-    "mocha": "~2.0.1",
-    "should": "~3.1.3"
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/nodejs/public/favicon.ico
----------------------------------------------------------------------
diff --git a/modules/web-control-center/nodejs/public/favicon.ico b/modules/web-control-center/nodejs/public/favicon.ico
deleted file mode 100644
index 74ec626..0000000
Binary files a/modules/web-control-center/nodejs/public/favicon.ico and /dev/null differ

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/nodejs/public/images/docker.png
----------------------------------------------------------------------
diff --git a/modules/web-control-center/nodejs/public/images/docker.png b/modules/web-control-center/nodejs/public/images/docker.png
deleted file mode 100644
index 7ec3aef..0000000
Binary files a/modules/web-control-center/nodejs/public/images/docker.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/nodejs/public/images/java.png
----------------------------------------------------------------------
diff --git a/modules/web-control-center/nodejs/public/images/java.png b/modules/web-control-center/nodejs/public/images/java.png
deleted file mode 100644
index ddb3b8e..0000000
Binary files a/modules/web-control-center/nodejs/public/images/java.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/nodejs/public/images/logo.png
----------------------------------------------------------------------
diff --git a/modules/web-control-center/nodejs/public/images/logo.png b/modules/web-control-center/nodejs/public/images/logo.png
deleted file mode 100644
index c3577c5..0000000
Binary files a/modules/web-control-center/nodejs/public/images/logo.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/nodejs/public/images/xml.png
----------------------------------------------------------------------
diff --git a/modules/web-control-center/nodejs/public/images/xml.png b/modules/web-control-center/nodejs/public/images/xml.png
deleted file mode 100644
index 029065e..0000000
Binary files a/modules/web-control-center/nodejs/public/images/xml.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/nodejs/public/stylesheets/style.less
----------------------------------------------------------------------
diff --git a/modules/web-control-center/nodejs/public/stylesheets/style.less b/modules/web-control-center/nodejs/public/stylesheets/style.less
deleted file mode 100644
index 4900581..0000000
--- a/modules/web-control-center/nodejs/public/stylesheets/style.less
+++ /dev/null
@@ -1,1172 +0,0 @@
-/*
- * 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.
- */
-
-@logo-path: "https://www.filepicker.io/api/file/QagunjDGRFul2JgNCAli";
-@input-height: 28px;
-@ignite-red: #ec1c24;
-@ignite-block-callout-background: #f3f8f3;
-@ignite-block-callout: #50af51;
-
-hr {
-  margin-top: 20px;
-  margin-bottom: 20px;
-}
-
-.main-header .logo {
-  height: auto;
-}
-
-.main-sidebar {
-  padding-top: 60px;
-}
-
-.navbar-default .navbar-brand, .navbar-default .navbar-brand:hover {
-  position: absolute;
-  width: 100%;
-  left: 0;
-  text-align: center;
-}
-
-.modal-backdrop.am-fade {
-  opacity: .5;
-  transition: opacity .15s linear;
-  &.ng-enter {
-    opacity: 0;
-    &.ng-enter-active {
-      opacity: .5;
-    }
-  }
-  &.ng-leave {
-    opacity: .5;
-    &.ng-leave-active {
-      opacity: 0;
-    }
-  }
-}
-
-.modal.center .modal-dialog {
-  position: fixed;
-  top: 50%;
-  left: 50%;
-  -webkit-transform: translateX(-50%) translateY(-50%);
-  transform: translateX(-50%) translateY(-50%);
-}
-
-.border-left {
-  box-shadow: 1px 0 0 0 #eee inset;
-}
-
-.border-right {
-  box-shadow: 1px 0 0 0 #eee;
-}
-
-.theme-line {
-  background-color: #f9f9f9;
-}
-
-.theme-line header {
-  background-color: #fff;
-}
-
-.theme-line header a.btn {
-  border: 0 none;
-  padding: 10px 25px;
-  background-color: rgba(0, 0, 0, 0.15);
-}
-
-.theme-line header a.btn:hover {
-  background-color: rgba(0, 0, 0, 0.25);
-}
-
-.theme-line header a.btn.btn-link {
-  background: transparent;
-  color: rgba(255, 255, 255, 0.8);
-}
-
-.theme-line header a.btn.btn-link:hover {
-  color: #fff;
-  text-decoration: none;
-}
-
-.theme-line .navbar-nav a {
-  background-color: transparent;
-}
-
-.theme-line .navbar-nav a:hover,
-.theme-line .navbar-nav a:active,
-.theme-line .navbar-nav a:focus {
-  background-color: transparent;
-}
-
-.theme-line .main-links {
-  padding-top: 50px;
-}
-
-.theme-line .main-links h3 {
-  margin-top: 0;
-  font-size: 17px;
-}
-
-.theme-line .main-links .links a {
-  color: #888;
-}
-
-.theme-line .main-links .links a:hover {
-  text-decoration: none;
-}
-
-.theme-line #category-columns,
-.theme-solid #category-columns {
-  margin: 50px 30px 0;
-}
-
-.theme-line #category-columns h4 {
-  text-transform: uppercase;
-  font-weight: 300;
-  color: #999;
-  font-size: 14px;
-}
-
-.theme-line #category-columns ul {
-  list-style: none;
-  padding: 0;
-  margin-bottom: 15px;
-}
-
-.theme-line #category-columns ul li a {
-  padding: 5px 0;
-  display: block;
-  font-size: 16px;
-}
-
-.theme-line #category-columns ul .view-all {
-  font-size: 0.85em;
-}
-
-.theme-line .docs-header {
-  color: #999;
-  overflow: hidden;
-}
-
-.theme-line .docs-header h1 {
-  color: #444;
-  margin-top: 0;
-  font-size: 22px;
-}
-
-.theme-line .btn-primary {
-  border: 0 none;
-  background-color: @ignite-red;
-}
-
-.theme-line .btn-primary:hover {
-  background-color: #950d12;
-}
-
-.theme-line .main-content .nav-horizontal a {
-  box-shadow: 0 0;
-  border: 0 none;
-  background-color: #fff;
-  border-radius: 0;
-  color: #aaa;
-  padding: 6px;
-  margin: 0 14px;
-}
-
-.theme-line .main-content .nav-horizontal a:hover {
-  color: #999;
-  border-bottom: 5px solid #ddd;
-}
-
-.theme-line .main-content .nav-horizontal a.active {
-  border-bottom: 5px solid #888;
-}
-
-.theme-line .navbar-nav, .theme-line .sidebar-nav {
-  ul li > a.active {
-    cursor: default;
-    pointer-events: none;
-  }
-}
-
-.theme-line .sidebar-nav {
-  color: #474a54;
-  padding-bottom: 30px;
-
-  ul {
-    padding: 0;
-    list-style: none;
-    font-size: 14px;
-    margin: 3px 0 0;
-    li {
-      color: #666;
-      line-height: @input-height;
-
-      span.fa-stack {
-        margin-right: 5px;
-        font-size: 12px;
-        height: 26px;
-      }
-
-      a {
-        font-size: 18px;
-        color: #666;
-        position: relative;
-        white-space: nowrap;
-        overflow: hidden;
-        -o-text-overflow: ellipsis;
-        text-overflow: ellipsis;
-      }
-    }
-  }
-}
-
-.theme-line .sidebar-nav ul li a:hover {
-  text-decoration: none;
-}
-
-.theme-line .select,
-.theme-line .typeahead {
-  li a {
-    color: #666;
-    background-color: transparent;
-  }
-
-  li a:hover {
-    color: @ignite-red;
-  }
-
-  .active {
-    background-color: #eee;
-  }
-}
-
-.theme-line .sidebar-nav ul li .subcategory {
-  padding-left: 15px;
-}
-
-.theme-line .sidebar-nav h4 {
-  margin-top: 2em;
-  font-weight: normal;
-  text-transform: uppercase;
-  font-size: 11px;
-  margin-bottom: 10px;
-  color: #bbb;
-}
-
-.theme-line .sidebar-nav h4:first-child {
-  margin-top: 0;
-}
-
-.theme-line .sidebar-nav .ask {
-  width: 100%;
-  text-align: center;
-  padding: 10px;
-}
-
-.theme-line .border-left .sidebar-nav {
-  padding-left: 15px;
-}
-
-.theme-line .suggest {
-  padding: 5px;
-  display: inline-block;
-  font-size: 12px;
-}
-
-.header {
-  padding: 15px;
-}
-
-.header .has-github {
-  padding-right: 136px;
-}
-
-.header h1.navbar-brand {
-  height: 40px;
-  width: 200px;
-  padding: 0;
-  margin: 5px 15px 0 0;
-}
-
-.header h1.navbar-brand a {
-  text-indent: -99999px;
-  background: no-repeat center center;
-  display: block;
-  width: 100%;
-  height: 100%;
-  background-size: contain;
-}
-
-.header .nav.navbar-nav.pull-right {
-  position: relative;
-  right: -30px;
-}
-
-.header .nav.navbar-nav .not-link {
-  padding: 15px;
-  display: inline-block;
-}
-
-.header .nav.navbar-nav .stable,
-.header .nav.navbar-nav .beta,
-.header .nav.navbar-nav .private {
-  font-size: 9px;
-  padding: 3px 5px;
-  display: inline-block;
-  line-height: 8px;
-  border-radius: 3px;
-  margin-left: 6px;
-  color: #fff;
-  top: -2px;
-  position: relative;
-  opacity: 0.6;
-  -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=60)";
-  filter: alpha(opacity=60);
-}
-
-.header .nav.navbar-nav a:hover > .stable,
-.header .nav.navbar-nav a:hover > .beta,
-.header .nav.navbar-nav a:hover > .private {
-  opacity: 1;
-  -ms-filter: none;
-  filter: none;
-}
-
-.header .nav.navbar-nav .beta {
-  background-color: #59c3d1;
-}
-
-.header .nav.navbar-nav .stable {
-  background-color: #41b841;
-}
-
-.header .nav.navbar-nav .private {
-  background-color: #333;
-}
-
-.theme-line header {
-  border-bottom: 8px solid;
-}
-
-.theme-line header h2 {
-  color: #aaa;
-}
-
-.theme-line header p {
-  color: #666;
-}
-
-.theme-line header {
-  border-bottom-color: @ignite-red;
-}
-
-.theme-line .navbar-nav {
-  color: #888;
-}
-
-.theme-line .navbar-nav a {
-  color: #bbb;
-}
-
-.theme-line header a.btn {
-  background-color: @ignite-red;
-}
-
-.theme-line header a.btn:hover {
-  background-color: #950d12;
-}
-
-.theme-line header .navbar-nav .tt-cursor {
-  background-color: @ignite-red;
-}
-
-.theme-line header .navbar-nav a:hover, .theme-line header .navbar-nav .open > a {
-  color: @ignite-red;
-}
-
-.theme-line .navbar-nav .active a {
-  //font-weight: bold;
-  color: @ignite-red;
-}
-
-.theme-line .navbar-nav .active a:hover {
-  color: #950d12;
-}
-
-.theme-line .main-links .links a:hover {
-  color: @ignite-red;
-}
-
-.theme-line .main-content a {
-  color: #666;
-}
-
-.theme-line .main-content a:hover {
-  color: #950d12;
-}
-
-.theme-line .sidebar-nav ul li a.active:before {
-  background-color: @ignite-red;
-}
-
-.theme-line .sidebar-nav ul li a.active {
-  color: @ignite-red;
-}
-
-.theme-line .sidebar-nav ul li a:hover, .theme-line .sidebar-nav ul li a.active:hover {
-  color: #950d12;
-}
-
-.theme-line .main-content .nav-horizontal a.active {
-  border-color: @ignite-red;
-  color: @ignite-red;
-}
-
-.theme-line .main-content .nav-horizontal a:hover {
-  color: #950d12;
-}
-
-.theme-line .main-content .nav-horizontal a.active:hover {
-  border-color: #950d12;
-}
-
-.theme-line header .navbar-nav a.active, .theme-line #versions-list li a:hover strong, .theme-line #versions-list li a.active .current, .theme-line #versions-list li a:active .current {
-  color: @ignite-red;
-}
-
-.theme-line header .navbar-nav a {
-  font-size: 18px;
-}
-
-.theme-line.body-threes .section-right .threes-nav .btn-default:hover, .theme-line.page-docs.body-threes .section-right .threes-nav .pull-right a:hover {
-  color: @ignite-red;
-  border-color: @ignite-red;
-}
-
-.theme-line .section-right {
-  padding-left: 30px;
-}
-
-.body-overlap .main-content {
-  margin-top: 30px;
-}
-
-.body-box .main-content,
-.body-overlap .main-content {
-  padding: 30px;
-  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1);
-  background-color: #fff;
-}
-
-body {
-  font-weight: 400;
-  font-family: Roboto Slab, serif;;
-}
-
-h1, h2, h3, h4, h5, h6 {
-  font-weight: 700;
-  font-family: Roboto Slab, serif;
-  margin-bottom: 10px;
-}
-
-.submit-vote.submit-vote-parent.voted a.submit-vote-button, .submit-vote.submit-vote-parent a.submit-vote-button:hover {
-  background-color: @ignite-red;
-}
-
-div.submit-vote.submit-vote-parent.voted a.submit-vote-button:hover {
-  background-color: #950d12;
-}
-
-a, .link .title {
-  color: @ignite-red;
-}
-
-a:hover, .link:hover .title {
-  color: #950d12;
-}
-
-.header h1.navbar-brand a {
-  background-image: url("@{logo-path}");
-}
-
-.header h1.navbar-brand {
-  width: 96px;
-}
-
-.block-edit-parameters {
-  text-align: right;
-  padding-bottom: 5px;
-}
-
-.container-footer {
-  margin-top: 20px;
-}
-
-/* Modal */
-.modal {
-  display: block;
-  overflow: hidden;
-}
-
-.modal .close {
-  position: absolute;
-  top: 10px;
-  right: 10px;
-  float: none;
-}
-
-// Close icon
-.modal-header .close {
-  margin-right: -2px;
-}
-
-.modal .modal-dialog {
-  width: 610px;
-}
-
-.modal .modal-content {
-  border-radius: 0;
-  background-color: #f7f7f7;
-}
-
-.modal .modal-content .modal-header {
-  background-color: #fff;
-  text-align: center;
-  color: #555;
-  padding: 15px;
-  font-family: "myriad-pro", sans-serif;
-}
-
-.modal .modal-content .modal-header h4 {
-  font-family: "myriad-pro", sans-serif;
-  font-size: 22px;
-}
-
-.modal .modal-content .modal-header h4 .fa {
-  display: block;
-  font-size: 41px;
-  color: #ddd;
-  margin-bottom: 5px;
-}
-
-.modal .modal-content .modal-header p {
-  color: #aaa;
-  font-size: 1em;
-  margin: 3px 0 0;
-}
-
-.modal .modal-content .modal-spacer {
-  padding: 10px 10px 0 10px;
-}
-
-.modal .modal-content .modal-footer {
-  margin-top: 0;
-}
-
-.modal-body {
-  padding-top: 15px;
-}
-
-h1.ignite-logo {
-  background-image: url("@{logo-path}");
-}
-
-.block-display-image img {
-  max-width: 100%;
-  max-height: 450px;
-  margin: auto;
-  display: block;
-}
-
-.greedy {
-  min-height: 200px;
-  height: ~"calc(100vh - 290px)";
-}
-
-@media (min-width: 768px) {
-  .navbar-nav > li > a {
-    padding-top: 18px;
-    padding-bottom: 10px;
-  }
-}
-
-.details-row {
-  padding: 0 10px;
-}
-
-.details-row, .settings-row {
-  display: block;
-  margin: 10px 0;
-
-  label.table-header {
-    line-height: @input-height;
-  }
-
-  [class*="col-"] {
-    display: inline-block;
-    vertical-align: middle;
-    float: none;
-
-    padding-left: 0 !important;
-    padding-right: 0 !important;
-  }
-
-  input[type="checkbox"] {
-    line-height: 20px;
-    margin-right: 5px;
-  }
-
-  .checkbox label {
-    line-height: 20px;
-    vertical-align: middle;
-  }
-}
-
-button {
-  margin-right: 5px;
-}
-
-h1,
-h2,
-h3 {
-  user-select: none;
-  font-weight: normal;
-  /* Makes the vertical size of the text the same for all fonts. */
-  line-height: 1;
-}
-
-h3 {
-  color: black;
-  font-size: 1.2em;
-  margin-top: 0;
-  margin-bottom: 1.5em;
-}
-
-table tr:hover {
-  cursor: pointer;
-}
-
-.btn {
-  padding: 3px 6px;
-}
-
-button .caret, .btn .caret {
-  float: right;
-  margin-left: 5px;
-  margin-top: 7px;
-}
-
-.base-control {
-  text-align: left;
-  padding: 3px 3px;
-  height: @input-height;
-}
-
-.form-control:extend(.base-control all) {
-  display: inline-block;
-
-  button {
-    text-align: left;
-  }
-}
-
-.theme-line .panel-heading {
-  padding: 10px 10px;
-  margin: 0;
-
-  h3 {
-    margin-bottom: 0;
-  }
-
-  h3 > a {
-    color: black;
-  }
-}
-
-.theme-line .panel-title {
-  a {
-    color: @ignite-red;
-  }
-
-  h3 {
-    margin-bottom: 20px;
-  }
-}
-
-.theme-line .panel-body {
-  padding: 10px 20px;
-}
-
-.theme-line .main-content a.customize {
-  margin-left: 5px;
-  color: @ignite-red;
-}
-
-.theme-line .panel-collapse {
-  margin: 0;
-}
-
-.theme-line .links table {
-  display: table;
-  table-layout: fixed;
-
-  td {
-    padding-left: 18px;
-  }
-
-  .active a {
-    color: @ignite-red;
-    font-weight: bold;
-  }
-
-  a:hover {
-    color: #950d12;
-  }
-
-  a {
-    color: #666;
-  }
-}
-
-.theme-line table.links-edit:extend(.theme-line .links table all) {
-  margin-top: 5px;
-  margin-bottom: 5px;
-
-  label {
-    line-height: @input-height;
-    color: #666;
-  }
-}
-
-.theme-line table.links-edit-details:extend(.theme-line .links table all) {
-  margin-bottom: 10px;
-
-  label {
-    line-height: @input-height;
-    color: #666;
-  }
-
-  td {
-    padding: 0;
-
-    .input-tip {
-      padding: 0;
-    }
-  }
-}
-
-.theme-line table.admin {
-  tr:hover {
-    cursor: default;
-  }
-
-  thead > tr th.header {
-    padding: 0 0 10px;
-
-    div {
-      padding: 0
-    }
-  }
-
-  margin-bottom: 10px;
-
-  label {
-    line-height: @input-height;
-    color: #666;
-  }
-
-  thead > tr th, td {
-    padding: 10px 10px;
-
-    .input-tip {
-      padding: 0;
-    }
-  }
-
-  tfoot > tr > td {
-    padding: 0;
-
-    .pagination {
-      margin: 10px 0;
-
-      > .active > a {
-        color: @ignite-red;
-        font-weight: bold;
-        border-color: #ddd;
-        background-color: #eee;
-      }
-    }
-  }
-}
-
-.panel-title a {
-  font-size: 14px;
-}
-
-.panel-details {
-  margin-top: 10px;
-
-  padding: 0;
-
-  border-radius: 5px;
-  border: thin dotted lightgrey;
-}
-
-.tooltip.right .tooltip-arrow {
-  border-right-color: @ignite-red;
-}
-
-.tooltip > .tooltip-inner {
-  max-width: 400px;
-  text-align: left;
-  background-color: @ignite-red;
-}
-
-label {
-  font-weight: normal;
-  margin-bottom: 0;
-}
-
-.form-horizontal .checkbox {
-  padding-top: 0;
-}
-
-.input-tip {
-  display: block;
-  overflow: hidden;
-}
-
-.labelField {
-  float: left;
-  margin-right: 5px;
-}
-
-.labelFormField {
-  float: left;
-  line-height: @input-height;
-}
-
-.form-horizontal .form-group {
-  margin: 0;
-}
-
-.form-horizontal .has-feedback .form-control-feedback {
-  right: 0;
-}
-
-.tipField {
-  float: right;
-  line-height: @input-height;
-  margin-left: 5px;
-}
-
-.tipLabel {
-  font-size: 14px;
-  margin-left: 5px;
-}
-
-.fieldSep {
-  float: right;
-  line-height: @input-height;
-  margin: 0 5px;
-}
-
-.fieldButton {
-  float: right;
-  margin-left: 5px;
-  margin-right: 0;
-}
-
-.fa-plus {
-  cursor: pointer;
-}
-
-.fa-remove {
-  color: @ignite-red;
-  cursor: pointer;
-}
-
-.fa-floppy-o {
-  cursor: pointer;
-}
-
-.fa-arrow-up {
-  cursor: pointer;
-}
-
-.fa-arrow-down {
-  cursor: pointer;
-}
-
-label.required:after {
-  color: @ignite-red;
-  content: ' *';
-  display: inline;
-}
-
-.blank {
-  visibility: hidden;
-}
-
-.alert {
-  outline: 0
-}
-
-.alert.bottom, .alert.bottom-left, .alert.bottom-right, .alert.top,
-.alert.top-left, .alert.top-right {
-  position: fixed;
-  z-index: 1050;
-  margin: 20px
-}
-
-.alert.top, .alert.top-left, .alert.top-right {
-  top: 50px
-}
-
-.alert.top {
-  right: 0;
-  left: 0
-}
-
-.alert.top-right {
-  right: 0
-}
-
-.alert.top-right .close {
-  padding-left: 10px
-}
-
-.alert.top-left {
-  left: 0
-}
-
-.alert.top-left .close {
-  padding-right: 10px
-}
-
-.alert.bottom, .alert.bottom-left, .alert.bottom-right {
-  bottom: 0
-}
-
-.alert.bottom {
-  right: 0;
-  left: 0
-}
-
-.alert.bottom-right {
-  right: 0
-}
-
-.alert.bottom-right .close {
-  padding-left: 10px
-}
-
-.alert.bottom-left {
-  left: 0
-}
-
-.alert.bottom-left .close {
-  padding-right: 10px
-}
-
-//  Summary page
-#cfgResult textarea {
-  font-family: monospace;
-  font-size: 12px;
-}
-
-input[type="number"]::-webkit-outer-spin-button,
-input[type="number"]::-webkit-inner-spin-button {
-  -webkit-appearance: none;
-  margin: 0;
-}
-
-input[type="number"] {
-  -moz-appearance: textfield;
-}
-
-input.ng-dirty.ng-invalid, button.ng-dirty.ng-invalid {
-  border-color: @ignite-red;
-
-  :focus {
-    border-color: @ignite-red;
-  }
-}
-
-.form-control-feedback {
-  display: inline-block;
-  color: @ignite-red;
-  right: 18px;
-  line-height: @input-height;
-  pointer-events: initial;
-}
-
-.syntaxhighlighter {
-  padding: 10px 5px;
-  border-radius: 6px;
-}
-
-.theme-line table.links-edit-small-padding:extend(.theme-line .links table all) {
-  label {
-    line-height: @input-height;
-    color: #666;
-  }
-
-  a {
-    line-height: @input-height;
-  }
-
-  input[type="checkbox"] {
-    line-height: 20px;
-    margin-right: 5px;
-  }
-
-  .checkbox label {
-    line-height: 20px;
-    vertical-align: middle;
-  }
-
-  th {
-    text-align: center;
-  }
-
-  td {
-    padding-left: 10px;
-  }
-
-  margin-top: 10px;
-}
-
-.configBox .nav > li > a {
-  padding: 5px 5px;
-}
-
-.viewedUser {
-  position: absolute;
-  width: 100%;
-  left: 0;
-
-  text-align: center;
-
-  margin-top: -15px;
-
-  background-color: #f8d5d8;
-}
-
-a {
-  cursor: pointer;
-}
-
-.st-sort-ascent:after {
-  content: '\25B2';
-}
-
-.st-sort-descent:after {
-  content: '\25BC';
-}
-
-.panel {
-  margin-bottom: 0;
-}
-
-.panel-group {
-  margin-bottom: 0;
-}
-
-.panel-group .panel + .panel {
-  margin-top: 20px;
-}
-
-.margin-top-dflt {
-  margin-top: 10px;
-}
-
-.margin-bottom-dflt {
-  margin-bottom: 10px;
-}
-
-.margin-dflt {
-  margin-top: 10px;
-  margin-bottom: 10px;
-}
-
-.padding-top-dflt {
-  padding-top: 10px;
-}
-
-.padding-bottom-dflt {
-  padding-bottom: 10px;
-}
-
-.padding-dflt {
-  padding-top: 10px;
-  padding-bottom: 10px;
-}
-
-.theme-line .panel-title h3 {
-  margin-top: 20px;
-  margin-bottom: 20px;
-}
-
-.block-callout-parent {
-  background-color: @ignite-block-callout-background;
-  overflow: hidden;
-}
-
-.block-callout {
-  background-color: @ignite-block-callout-background;
-  display: inline-block;
-  vertical-align: top;
-  width: 50%;
-
-  i {
-    padding: 10px 5px 0 10px;
-    color: @ignite-block-callout;
-  }
-
-  ul {
-    padding-left: 20px;
-    margin-bottom: 0;
-  }
-
-  p {
-    padding: 5px 0 10px 20px;
-    margin: 0;
-  }
-
-  label {
-    font-weight: bold;
-    color: @ignite-block-callout;
-  }
-}
-
-.block-callout-border {
-  border-left: 5px solid;
-  border-color: @ignite-block-callout;
-}
-
-.labelHeader {
-  font-weight: bold;
-}
-
-.ace_editor, #ace_document {
-  width: 100%;
-  height: 400px;
-}
-
-

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/nodejs/routes/admin.js
----------------------------------------------------------------------
diff --git a/modules/web-control-center/nodejs/routes/admin.js b/modules/web-control-center/nodejs/routes/admin.js
deleted file mode 100644
index 5af72f7..0000000
--- a/modules/web-control-center/nodejs/routes/admin.js
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * 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 router = require('express').Router();
-var db = require('../db');
-
-router.get('/', function (req, res) {
-    res.render('settings/admin');
-});
-
-/**
- * Get list of user accounts.
- */
-router.post('/list', function (req, res) {
-    db.Account.find({}).sort('username').exec(function (err, users) {
-        if (err)
-            return res.status(500).send(err.message);
-
-        res.json(users);
-    });
-});
-
-router.post('/remove', function (req, res) {
-    var userId = req.body.userId;
-
-    db.Account.findByIdAndRemove(userId, function (err) {
-        if (err)
-            return res.status(500).send(err);
-
-        res.sendStatus(200);
-    });
-});
-
-router.post('/save', function (req, res) {
-    var userId = req.body.userId;
-    var adminFlag = req.body.adminFlag;
-
-    db.Account.findByIdAndUpdate(userId, {admin: adminFlag}, function (err) {
-        if (err)
-            return res.status(500).send(err.message);
-
-        res.sendStatus(200);
-    });
-});
-
-router.get('/become', function (req, res) {
-    var viewedUserId = req.query.viewedUserId;
-
-    if (!viewedUserId) {
-        req.session.viewedUser = null;
-
-        return res.redirect('/admin');
-    }
-
-    db.Account.findById(viewedUserId).exec(function (err, viewedUser) {
-        if (err)
-            return res.sendStatus(404);
-
-        req.session.viewedUser = viewedUser;
-
-        res.redirect('/');
-    })
-});
-
-module.exports = router;
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/nodejs/routes/caches.js
----------------------------------------------------------------------
diff --git a/modules/web-control-center/nodejs/routes/caches.js b/modules/web-control-center/nodejs/routes/caches.js
deleted file mode 100644
index 3fefd37..0000000
--- a/modules/web-control-center/nodejs/routes/caches.js
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * 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 router = require('express').Router();
-var db = require('../db');
-
-/* GET caches page. */
-router.get('/', function (req, res) {
-    res.render('configuration/caches');
-});
-
-/**
- * Get spaces and caches accessed for user account.
- *
- * @param req Request.
- * @param res Response.
- */
-router.post('/list', function (req, res) {
-    var user_id = req.currentUserId();
-
-    // Get owned space and all accessed space.
-    db.Space.find({$or: [{owner: user_id}, {usedBy: {$elemMatch: {account: user_id}}}]}, function (err, spaces) {
-        if (err)
-            return res.status(500).send(err.message);
-
-        var space_ids = spaces.map(function (value) {
-            return value._id;
-        });
-
-        // Get all caches for spaces.
-        db.Cache.find({space: {$in: space_ids}}).sort('name').exec(function (err, caches) {
-            if (err)
-                return res.status(500).send(err.message);
-
-            res.json({spaces: spaces, caches: caches});
-        });
-    });
-});
-
-/**
- * Save cache.
- */
-router.post('/save', function (req, res) {
-    if (req.body._id)
-        db.Cache.update({_id: req.body._id}, req.body, {upsert: true}, function (err) {
-            if (err)
-                return res.status(500).send(err.message);
-
-            res.send(req.body._id);
-        });
-    else {
-        db.Cache.findOne({name: req.body.name}, function (err, cache) {
-            if (err)
-                return res.status(500).send(err.message);
-
-            if (cache)
-                return res.status(500).send('Cache with name: "' + cache.name + '" already exist.');
-
-            (new db.Cache(req.body)).save(function (err, cache) {
-                if (err)
-                    return res.status(500).send(err.message);
-
-                res.send(cache._id);
-            });
-        });
-    }
-});
-
-/**
- * Remove cache by ._id.
- */
-router.post('/remove', function (req, res) {
-    db.Cache.remove(req.body, function (err) {
-        if (err)
-            return res.status(500).send(err.message);
-
-        res.sendStatus(200);
-    })
-});
-
-module.exports = router;
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/nodejs/routes/clusters.js
----------------------------------------------------------------------
diff --git a/modules/web-control-center/nodejs/routes/clusters.js b/modules/web-control-center/nodejs/routes/clusters.js
deleted file mode 100644
index 182130d..0000000
--- a/modules/web-control-center/nodejs/routes/clusters.js
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * 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 router = require('express').Router();
-var db = require('../db');
-
-/* GET clusters page. */
-router.get('/', function (req, res) {
-    res.render('configuration/clusters');
-});
-
-/**
- * Get spaces and clusters accessed for user account.
- *
- * @param req Request.
- * @param res Response.
- */
-router.post('/list', function (req, res) {
-    var user_id = req.currentUserId();
-
-    // Get owned space and all accessed space.
-    db.Space.find({$or: [{owner: user_id}, {usedBy: {$elemMatch: {account: user_id}}}]}, function (err, spaces) {
-        if (err)
-            return res.status(500).send(err.message);
-
-        var space_ids = spaces.map(function (value) {
-            return value._id;
-        });
-
-        db.Cache.find({space: {$in: space_ids}}, '_id name swapEnabled', function (err, caches) {
-            if (err)
-                return res.status(500).send(err);
-
-            // Get all clusters for spaces.
-            db.Cluster.find({space: {$in: space_ids}}).sort('name').exec(function (err, clusters) {
-                if (err)
-                    return res.status(500).send(err.message);
-
-                var cachesJson = caches.map(function (cache) {
-                    return {value: cache._id, label: cache.name, swapEnabled: cache.swapEnabled};
-                });
-
-                res.json({spaces: spaces, caches: cachesJson, clusters: clusters});
-            });
-        });
-    });
-});
-
-/**
- * Save cluster.
- */
-router.post('/save', function (req, res) {
-    if (req.body._id)
-        db.Cluster.update({_id: req.body._id}, req.body, {upsert: true}, function (err) {
-            if (err)
-                return res.status(500).send(err.message);
-
-            res.send(req.body._id);
-        });
-    else {
-        db.Cluster.findOne({name: req.body.name}, function (err, cluster) {
-            if (err)
-                return res.status(500).send(err.message);
-
-            if (cluster)
-                return res.status(500).send('Cluster with name: "' + cluster.name + '" already exist.');
-
-            (new db.Cluster(req.body)).save(function (err, cluster) {
-                if (err)
-                    return res.status(500).send(err.message);
-
-                res.send(cluster._id);
-            });
-        });
-    }
-});
-
-/**
- * Remove cluster by ._id.
- */
-router.post('/remove', function (req, res) {
-    db.Cluster.remove(req.body, function (err) {
-        if (err)
-            return res.status(500).send(err.message);
-
-        res.sendStatus(200);
-    })
-});
-
-module.exports = router;
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/nodejs/routes/generator/common.js
----------------------------------------------------------------------
diff --git a/modules/web-control-center/nodejs/routes/generator/common.js b/modules/web-control-center/nodejs/routes/generator/common.js
deleted file mode 100644
index dcbf156..0000000
--- a/modules/web-control-center/nodejs/routes/generator/common.js
+++ /dev/null
@@ -1,299 +0,0 @@
-/*
- * 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 _ = require('lodash');
-
-exports.isDefined = function (v) {
-    return !(v === undefined || v === null);
-};
-
-exports.mainComment = mainComment;
-
-function mainComment() {
-    return 'This configuration was generated by Ignite Control Center ('
-        + formatDate(new Date()) + ')';
-}
-
-function addLeadingZero(numberStr, minSize) {
-    if (typeof (numberStr) != 'string')
-        numberStr = '' + numberStr;
-
-    while (numberStr.length < minSize) {
-        numberStr = '0' + numberStr;
-    }
-
-    return numberStr;
-}
-
-exports.formatDate = formatDate;
-
-function formatDate(date) {
-    var dd = addLeadingZero(date.getDate(), 2);
-    var mm = addLeadingZero(date.getMonth() + 1, 2);
-
-    var yyyy = date.getFullYear();
-
-    return mm + '/' + dd + '/' + yyyy + ' ' + addLeadingZero(date.getHours(), 2) + ':' + addLeadingZero(date.getMinutes(), 2);
-}
-
-exports.builder = function () {
-    var res = [];
-
-    res.deep = 0;
-    res.lineStart = true;
-
-    res.append = function (s) {
-        if (this.lineStart) {
-            for (var i = 0; i < this.deep; i++)
-                this.push('    ');
-
-            this.lineStart = false;
-        }
-
-        this.push(s);
-
-        return this;
-    };
-
-    res.line = function (s) {
-        if (s)
-            this.append(s);
-
-        this.push('\n');
-        this.lineStart = true;
-
-        return this;
-    };
-
-    res.startBlock = function (s) {
-        if (s)
-            this.append(s);
-
-        this.push('\n');
-        this.lineStart = true;
-        this.deep++;
-
-        return this;
-    };
-
-    res.endBlock = function (s) {
-        this.deep--;
-
-        if (s)
-            this.append(s);
-
-        this.push('\n');
-        this.lineStart = true;
-
-        return this;
-    };
-
-    res.emptyLineIfNeeded = function () {
-        if (this.needEmptyLine) {
-            this.line();
-
-            this.needEmptyLine = false;
-
-            return true;
-        }
-
-        return false;
-    };
-
-    res.imports = {};
-
-    res.importClass = function (fullClassName) {
-        var dotIdx = fullClassName.lastIndexOf('.');
-
-        var shortName;
-
-        if (dotIdx > 0)
-            shortName = fullClassName.substr(dotIdx + 1);
-        else
-            shortName = fullClassName;
-
-        if (this.imports[shortName]) {
-            if (this.imports[shortName] != fullClassName)
-                throw "Class name conflict: " + this.imports[shortName] + ' and ' + fullClassName;
-        }
-        else {
-            this.imports[shortName] = fullClassName;
-        }
-
-        return shortName;
-    };
-
-    res.generateImports = function () {
-        var res = [];
-
-        for (var clsName in this.imports) {
-            if (this.imports.hasOwnProperty(clsName))
-                res.push('import ' + this.imports[clsName] + ';');
-        }
-
-        return res.join('\n')
-    };
-
-    return res;
-};
-
-function ClassDescriptor(className, fields) {
-    this.className = className;
-    this.fields = fields;
-}
-
-exports.evictionPolicies = {
-    'LRU': new ClassDescriptor('org.apache.ignite.cache.eviction.lru.LruEvictionPolicy',
-        {batchSize: null, maxMemorySize: null, maxSize: null}),
-    'RND': new ClassDescriptor('org.apache.ignite.cache.eviction.random.RandomEvictionPolicy', {maxSize: null}),
-    'FIFO': new ClassDescriptor('org.apache.ignite.cache.eviction.fifo.FifoEvictionPolicy',
-        {batchSize: null, maxMemorySize: null, maxSize: null}),
-    'SORTED': new ClassDescriptor('org.apache.ignite.cache.eviction.sorted.SortedEvictionPolicy',
-        {batchSize: null, maxMemorySize: null, maxSize: null})
-};
-
-exports.marshallers = {
-    OptimizedMarshaller: new ClassDescriptor('org.apache.ignite.marshaller.optimized.OptimizedMarshaller', {
-        poolSize: null,
-        requireSerializable: null
-    }),
-    JdkMarshaller: new ClassDescriptor('org.apache.ignite.marshaller.jdk.JdkMarshaller', {})
-};
-
-exports.knownClasses = {
-    Oracle: new ClassDescriptor('org.apache.ignite.cache.store.jdbc.dialect.OracleDialect', {}),
-    DB2: new ClassDescriptor('org.apache.ignite.cache.store.jdbc.dialect.DB2Dialect', {}),
-    SQLServer: new ClassDescriptor('org.apache.ignite.cache.store.jdbc.dialect.SQLServerDialect', {}),
-    MySQL: new ClassDescriptor('org.apache.ignite.cache.store.jdbc.dialect.MySQLDialect', {}),
-    PostgreSQL: new ClassDescriptor('org.apache.ignite.cache.store.jdbc.dialect.BasicJdbcDialect', {}),
-    H2: new ClassDescriptor('org.apache.ignite.cache.store.jdbc.dialect.H2Dialect', {})
-};
-
-exports.dataSources = {
-    Oracle: 'oracle.jdbc.pool.OracleDataSource',
-    DB2: 'com.ibm.db2.jcc.DB2ConnectionPoolDataSource',
-    SQLServer: 'com.microsoft.sqlserver.jdbc.SQLServerDataSource',
-    MySQL: 'com.mysql.jdbc.jdbc2.optional.MysqlDataSource',
-    PostgreSQL: 'org.postgresql.ds.PGPoolingDataSource',
-    H2: 'org.h2.jdbcx.JdbcDataSource'
-};
-
-exports.storeFactories = {
-    CacheJdbcPojoStoreFactory: new ClassDescriptor('org.apache.ignite.cache.store.jdbc.CacheJdbcPojoStoreFactory', {
-        dataSourceBean: null,
-        dialect: {type: 'className'}
-    }),
-
-    CacheJdbcBlobStoreFactory: new ClassDescriptor('org.apache.ignite.cache.store.jdbc.CacheJdbcBlobStoreFactory', {
-        user: null,
-        dataSourceBean: null,
-        initSchema: null,
-        createTableQuery: null,
-        loadQuery: null,
-        insertQuery: null,
-        updateQuery: null,
-        deleteQuery: null
-    }),
-
-    CacheHibernateBlobStoreFactory: new ClassDescriptor('org.apache.ignite.cache.store.hibernate.CacheHibernateBlobStoreFactory', {
-        hibernateProperties: {type: 'propertiesAsList', propVarName: 'props'}
-    })
-};
-
-exports.atomicConfiguration = new ClassDescriptor('org.apache.ignite.configuration.AtomicConfiguration', {
-    backups: null,
-    cacheMode: {type: 'enum', enumClass: 'CacheMode'},
-    atomicSequenceReserveSize: null
-});
-
-exports.swapSpaceSpi = new ClassDescriptor('org.apache.ignite.spi.swapspace.file.FileSwapSpaceSpi', {
-    baseDirectory: null,
-    readStripesNumber: null,
-    maximumSparsity: {type: 'float'},
-    maxWriteQueueSize: null,
-    writeBufferSize: null
-});
-
-exports.transactionConfiguration = new ClassDescriptor('org.apache.ignite.configuration.TransactionConfiguration', {
-    defaultTxConcurrency: {type: 'enum', enumClass: 'TransactionConcurrency'},
-    transactionIsolation: {type: 'TransactionIsolation', setterName: 'defaultTxIsolation'},
-    defaultTxTimeout: null,
-    pessimisticTxLogLinger: null,
-    pessimisticTxLogSize: null,
-    txSerializableEnabled: null
-});
-
-exports.hasProperty = function (obj, props) {
-    for (var propName in props) {
-        if (props.hasOwnProperty(propName)) {
-            if (obj[propName])
-                return true;
-        }
-    }
-
-    return false;
-};
-
-/**
- * Convert some name to valid java name.
- *
- * @param name to convert.
- * @returns {string} Valid java name.
- */
-exports.toJavaName = function (name) {
-    var javaName = name.replace(/[^A-Za-z_0-9]+/, '_');
-
-    return javaName.charAt(0).toLocaleUpperCase() + javaName.slice(1);
-};
-
-/**
- * Generate properties file with properties stubs for stores data sources.
- *
- * @param cluster Configuration to process.
- * @returns {string} Generated content.
- */
-exports.generateProperties = function (cluster) {
-    var res = exports.builder();
-
-    var datasources = [];
-
-    if (cluster.caches && cluster.caches.length > 0) {
-        _.forEach(cluster.caches, function (cache) {
-            if (cache.cacheStoreFactory && cache.cacheStoreFactory.kind) {
-                var storeFactory = cache.cacheStoreFactory[cache.cacheStoreFactory.kind];
-
-                if (storeFactory.dialect) {
-                    var beanId = storeFactory.dataSourceBean;
-
-                    if (!_.contains(datasources, beanId)) {
-                        datasources.push(beanId);
-
-                        res.line(beanId + '.jdbc.url=YOUR_JDBC_URL');
-                        res.line(beanId + '.jdbc.username=YOUR_USER_NAME');
-                        res.line(beanId + '.jdbc.password=YOUR_PASSWORD');
-                        res.line();
-                    }
-                }
-            }
-        });
-    }
-
-    if (datasources.length > 0)
-        return '# ' + mainComment() + '\n\n' + res.join();
-
-    return undefined;
-};

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/nodejs/routes/generator/docker.js
----------------------------------------------------------------------
diff --git a/modules/web-control-center/nodejs/routes/generator/docker.js b/modules/web-control-center/nodejs/routes/generator/docker.js
deleted file mode 100644
index 93faf8e..0000000
--- a/modules/web-control-center/nodejs/routes/generator/docker.js
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * 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.
- */
-
-exports.generateClusterConfiguration = function(cluster, os) {
-    if (!os)
-        os = 'debian:8';
-
-    return "" +
-        "# Start from a OS image.\n"+
-        "FROM " + os + "\n"+
-        "\n"+
-        "# Install tools.\n"+
-        "RUN apt-get update && apt-get install -y --fix-missing \\\n"+
-        "  wget \\\n"+
-        "  dstat \\\n"+
-        "  maven \\\n"+
-        "  git\n"+
-        "\n"+
-        "# Install Oracle JDK.\n"+
-        "RUN mkdir /opt/jdk\n"+
-        "\n"+
-        "RUN wget --header \"Cookie: oraclelicense=accept-securebackup-cookie\" \\\n"+
-        "  http://download.oracle.com/otn-pub/java/jdk/7u79-b15/jdk-7u79-linux-x64.tar.gz\n"+
-        "\n"+
-        "RUN tar -zxf jdk-7u79-linux-x64.tar.gz -C /opt/jdk\n"+
-        "\n"+
-        "RUN rm jdk-7u79-linux-x64.tar.gz\n"+
-        "\n"+
-        "RUN update-alternatives --install /usr/bin/java java /opt/jdk/jdk1.7.0_79/bin/java 100\n"+
-        "\n"+
-        "RUN update-alternatives --install /usr/bin/javac javac /opt/jdk/jdk1.7.0_79/bin/javac 100\n"+
-        "\n"+
-        "# Sets java variables.\n"+
-        "ENV JAVA_HOME /opt/jdk/jdk1.7.0_79/\n"+
-        "\n"+
-        "# Create working directory\n"+
-        "WORKDIR /home\n"+
-        "\n"+
-        "RUN wget -O ignite.zip http://tiny.cc/updater/download_ignite.php && unzip ignite.zip && rm ignite.zip\n"+
-        "\n"+
-        "COPY *.xml /tmp/\n"+
-        "\n"+
-        "RUN mv /tmp/*.xml /home/$(ls)/config";
-};

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8a335724/modules/web-control-center/nodejs/routes/generator/java.js
----------------------------------------------------------------------
diff --git a/modules/web-control-center/nodejs/routes/generator/java.js b/modules/web-control-center/nodejs/routes/generator/java.js
deleted file mode 100644
index 31cd2ac..0000000
--- a/modules/web-control-center/nodejs/routes/generator/java.js
+++ /dev/null
@@ -1,626 +0,0 @@
-/*
- * 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 _ = require('lodash');
-
-var generatorUtils = require("./common");
-
-exports.generateClusterConfiguration = function(cluster, javaClass, clientNearConfiguration) {
-    var res = generatorUtils.builder();
-
-    res.datasourceBeans = [];
-
-    if (javaClass) {
-        res.line('/**');
-        res.line(' * ' + generatorUtils.mainComment());
-        res.line(' */');
-        res.startBlock('public class ConfigurationFactory {');
-        res.line('/**');
-        res.line(' * Configure grid.');
-        res.line(' */');
-        res.startBlock('public IgniteConfiguration createConfiguration() {');
-    }
-    
-    res.importClass('org.apache.ignite.configuration.IgniteConfiguration');
-    
-    res.line('IgniteConfiguration cfg = new IgniteConfiguration();');
-    res.line();
-
-    if (clientNearConfiguration) {
-        res.line('cfg.setClientMode(true);');
-
-        res.line();
-    }
-
-    if (cluster.discovery) {
-        var d = cluster.discovery;
-
-        res.importClass('org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi');
-        res.line('TcpDiscoverySpi discovery = new TcpDiscoverySpi();');
-
-        switch (d.kind) {
-            case 'Multicast':
-                res.importClass('org.apache.ignite.spi.discovery.tcp.ipfinder.multicast.TcpDiscoveryMulticastIpFinder');
-
-                addBeanWithProperties(res, d.Multicast, 'discovery', 'ipFinder', 'ipFinder',
-                    'TcpDiscoveryMulticastIpFinder', {
-                        multicastGroup: null,
-                        multicastPort: null,
-                        responseWaitTime: null,
-                        addressRequestAttempts: null,
-                        localAddress: null
-                    }, true);
-
-                break;
-
-            case 'Vm':
-                res.importClass('org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder');
-
-                addBeanWithProperties(res, d.Vm, 'discovery', 'ipFinder', 'ipFinder', 'TcpDiscoveryVmIpFinder', {
-                        addresses: {type: 'list'}
-                    }, true);
-
-                break;
-
-            case 'S3':
-                res.importClass('org.apache.ignite.spi.discovery.tcp.ipfinder.s3.TcpDiscoveryS3IpFinder');
-
-                if (d.S3)
-                    addBeanWithProperties(res, d.S3, 'discovery', 'ipFinder', 'ipFinder', 'TcpDiscoveryS3IpFinder',
-                        {bucketName: null}, true);
-                else
-                    res.line('discovery.setIpFinder(new TcpDiscoveryS3IpFinder());');
-
-                break;
-
-            case 'Cloud':
-                res.importClass('org.apache.ignite.spi.discovery.tcp.ipfinder.cloud.TcpDiscoveryCloudIpFinder');
-
-                addBeanWithProperties(res, d.Cloud, 'discovery', 'ipFinder', 'ipFinder', 'TcpDiscoveryCloudIpFinder', {
-                        credential: null,
-                        credentialPath: null,
-                        identity: null,
-                        provider: null,
-                        regions: {type: 'list'},
-                        zones: {type: 'list'}
-                    }, true);
-
-                break;
-
-            case 'GoogleStorage':
-                res.importClass('org.apache.ignite.spi.discovery.tcp.ipfinder.gce.TcpDiscoveryGoogleStorageIpFinder');
-
-                addBeanWithProperties(res, d.GoogleStorage, 'discovery', 'ipFinder', 'ipFinder',
-                    'TcpDiscoveryGoogleStorageIpFinder', {
-                        projectName: null,
-                        bucketName: null,
-                        serviceAccountP12FilePath: null
-                    }, true);
-
-                //if (d.GoogleStorage.addrReqAttempts) todo ????
-                //    res.line('<property name="serviceAccountP12FilePath" value="' + escapeAttr(d.GoogleStorage.addrReqAttempts) + '"/>');
-
-                break;
-
-            case 'Jdbc':
-                res.importClass('org.apache.ignite.spi.discovery.tcp.ipfinder.jdbc.TcpDiscoveryJdbcIpFinder');
-                
-                res.line();
-                res.line('TcpDiscoveryJdbcIpFinder ipFinder = new TcpDiscoveryJdbcIpFinder();');
-                res.line('ipFinder.setInitSchema(' + (d.Jdbc.initSchema != null || d.Jdbc.initSchema) + ');');
-                res.line('discovery.setIpFinder(ipFinder);');
-                res.needEmptyLine = true;
-
-                break;
-
-            case 'SharedFs':
-                res.importClass('org.apache.ignite.spi.discovery.tcp.ipfinder.sharedfs.TcpDiscoverySharedFsIpFinder');
-
-                addBeanWithProperties(res, d.SharedFs, 'discovery', 'ipFinder', 'ipFinder',
-                    'TcpDiscoverySharedFsIpFinder', {path: null}, true);
-
-                break;
-
-            default:
-                throw "Unknown discovery kind: " + d.kind;
-        }
-
-        res.emptyLineIfNeeded();
-
-        res.line('cfg.setDiscoverySpi(discovery);');
-
-        res.needEmptyLine = true;
-    }
-
-    if (cluster.caches && cluster.caches.length > 0) {
-        res.emptyLineIfNeeded();
-
-        var names = [];
-
-        for (var i = 0; i < cluster.caches.length; i++) {
-            res.emptyLineIfNeeded();
-
-            var cache = cluster.caches[i];
-
-            var cacheName = 'cache' + generatorUtils.toJavaName(cache.name);
-
-            names.push(cacheName);
-
-            generateCacheConfiguration(cache, cacheName, res);
-
-            res.needEmptyLine = true;
-        }
-
-        res.emptyLineIfNeeded();
-
-        res.append('cfg.setCacheConfiguration(');
-
-        for (i = 0; i < names.length; i++) {
-            if (i > 0)
-                res.append(', ');
-
-            res.append(names[i]);
-        }
-
-        res.line(');');
-
-        res.needEmptyLine = true;
-    }
-
-    addBeanWithProperties(res, cluster.atomicConfiguration, 'cfg', 'atomicConfiguration', 'atomicCfg',
-        generatorUtils.atomicConfiguration.className, generatorUtils.atomicConfiguration.fields);
-
-    res.needEmptyLine = true;
-
-    addProperty(res, cluster, 'cfg', 'networkTimeout');
-    addProperty(res, cluster, 'cfg', 'networkSendRetryDelay');
-    addProperty(res, cluster, 'cfg', 'networkSendRetryCount');
-    addProperty(res, cluster, 'cfg', 'segmentCheckFrequency');
-    addProperty(res, cluster, 'cfg', 'waitForSegmentOnStart');
-    addProperty(res, cluster, 'cfg', 'discoveryStartupDelay');
-
-    res.needEmptyLine = true;
-
-    addProperty(res, cluster, 'cfg', 'deploymentMode', 'DeploymentMode');
-
-    res.needEmptyLine = true;
-
-    if (cluster.includeEventTypes && cluster.includeEventTypes.length > 0) {
-        res.emptyLineIfNeeded();
-        
-        if (cluster.includeEventTypes.length == 1) {
-            res.importClass('org.apache.ignite.events.EventType');
-            
-            res.line('cfg.setIncludeEventTypes(EventType.' + cluster.includeEventTypes[0] + ');');
-        }
-        else {
-            res.append('int[] events = new int[EventType.' + cluster.includeEventTypes[0] + '.length');
-            
-            for (i = 1; i < cluster.includeEventTypes.length; i++) {
-                res.line();
-                
-                res.append('    + EventType.' + cluster.includeEventTypes[i] + '.length');
-            }
-            
-            res.line('];');
-            res.line();
-            res.line('int k = 0;');
-
-            for (i = 0; i < cluster.includeEventTypes.length; i++) {
-                res.line();
-
-                var e = cluster.includeEventTypes[i];
-                
-                res.line('System.arraycopy(EventType.' + e + ', 0, events, k, EventType.' + e + '.length);');
-                res.line('k += EventType.' + e + '.length;');
-            }
-            
-            res.line();
-            res.line('cfg.setIncludeEventTypes(events);');
-        }
-
-        res.needEmptyLine = true;
-    }
-
-    res.needEmptyLine = true;
-
-    var marshaller = cluster.marshaller;
-
-    if (marshaller && marshaller.kind) {
-        var marshallerDesc = generatorUtils.marshallers[marshaller.kind];
-
-        addBeanWithProperties(res, marshaller[marshaller.kind], 'cfg', 'marshaller', 'marshaller',
-            marshallerDesc.className, marshallerDesc.fields, true);
-
-        addBeanWithProperties(res, marshaller[marshaller.kind], 'marshaller', marshallerDesc.className, marshallerDesc.fields, true);
-    }
-
-    addProperty(res, cluster, 'cfg', 'marshalLocalJobs');
-    addProperty(res, cluster, 'cfg', 'marshallerCacheKeepAliveTime');
-    addProperty(res, cluster, 'cfg', 'marshallerCacheThreadPoolSize');
-
-    res.needEmptyLine = true;
-
-    addProperty(res, cluster, 'cfg', 'metricsExpireTime');
-    addProperty(res, cluster, 'cfg', 'metricsHistorySize');
-    addProperty(res, cluster, 'cfg', 'metricsLogFrequency');
-    addProperty(res, cluster, 'cfg', 'metricsUpdateFrequency');
-    res.needEmptyLine = true;
-
-    addProperty(res, cluster, 'cfg', 'peerClassLoadingEnabled');
-    addMultiparamProperty(res, cluster, 'cfg', 'peerClassLoadingLocalClassPathExclude');
-    addProperty(res, cluster, 'cfg', 'peerClassLoadingMissedResourcesCacheSize');
-    addProperty(res, cluster, 'cfg', 'peerClassLoadingThreadPoolSize');
-    res.needEmptyLine = true;
-
-    if (cluster.swapSpaceSpi && cluster.swapSpaceSpi.kind == 'FileSwapSpaceSpi') {
-        addBeanWithProperties(res, cluster.swapSpaceSpi.FileSwapSpaceSpi, 'cfg', 'swapSpaceSpi', 'swapSpi',
-            generatorUtils.swapSpaceSpi.className, generatorUtils.swapSpaceSpi.fields, true);
-
-        res.needEmptyLine = true;
-    }
-
-    addProperty(res, cluster, 'cfg', 'clockSyncSamples');
-    addProperty(res, cluster, 'cfg', 'clockSyncFrequency');
-    addProperty(res, cluster, 'cfg', 'timeServerPortBase');
-    addProperty(res, cluster, 'cfg', 'timeServerPortRange');
-
-    res.needEmptyLine = true;
-
-    addProperty(res, cluster, 'cfg', 'publicThreadPoolSize');
-    addProperty(res, cluster, 'cfg', 'systemThreadPoolSize');
-    addProperty(res, cluster, 'cfg', 'managementThreadPoolSize');
-    addProperty(res, cluster, 'cfg', 'igfsThreadPoolSize');
-
-    res.needEmptyLine = true;
-
-    addBeanWithProperties(res, cluster.transactionConfiguration, 'cfg', 'transactionConfiguration',
-        'transactionConfiguration', generatorUtils.transactionConfiguration.className,
-        generatorUtils.transactionConfiguration.fields);
-
-    res.needEmptyLine = true;
-
-    addProperty(res, cluster, 'cfg', 'cacheSanityCheckEnabled');
-
-    res.needEmptyLine = true;
-
-    if (javaClass) {
-        res.line();
-        res.line('return cfg;');
-        res.endBlock('}');
-        res.endBlock('}');
-        
-        return res.generateImports() + '\n\n' + res.join('')
-    }
-    
-    return res.join('');
-};
-
-function createEvictionPolicy(res, evictionPolicy, varName, propertyName) {
-    if (evictionPolicy && evictionPolicy.kind) {
-        var e = generatorUtils.evictionPolicies[evictionPolicy.kind];
-
-        var obj = evictionPolicy[evictionPolicy.kind.toUpperCase()];
-
-        addBeanWithProperties(res, obj, varName, propertyName, propertyName, e.className, e.fields, true);
-    }
-}
-
-exports.generateCacheConfiguration = generateCacheConfiguration;
-
-/**
- * Generate java code for cache configuration.
- *
- * @param cacheCfg Cache config.
- * @param varName Variable name.
- * @param res Result builder.
- * @returns {*} Append generated java code to builder and return it.
- */
-function generateCacheConfiguration(cacheCfg, varName, res) {
-    if (!res)
-        res = generatorUtils.builder();
-
-    res.emptyLineIfNeeded();
-
-    res.importClass('org.apache.ignite.cache.CacheAtomicityMode');
-    res.importClass('org.apache.ignite.cache.CacheMode');
-    res.importClass('org.apache.ignite.configuration.CacheConfiguration');
-
-    res.line('CacheConfiguration ' + varName + ' = new CacheConfiguration();');
-
-    res.needEmptyLine = true;
-
-    addProperty(res, cacheCfg, varName, 'name');
-    
-    addProperty(res, cacheCfg, varName, 'mode', 'CacheMode', 'cacheMode');
-
-    addProperty(res, cacheCfg, varName, 'atomicityMode', 'CacheAtomicityMode');
-    addProperty(res, cacheCfg, varName, 'backups');
-    addProperty(res, cacheCfg, varName, 'startSize');
-    addProperty(res, cacheCfg, varName, 'readFromBackup');
-
-    res.needEmptyLine = true;
-    
-    addProperty(res, cacheCfg, varName, 'memoryMode', 'CacheMemoryMode');
-    addProperty(res, cacheCfg, varName, 'offHeapMaxMemory');
-    addProperty(res, cacheCfg, varName, 'swapEnabled');
-    addProperty(res, cacheCfg, varName, 'copyOnRead');
-
-    res.needEmptyLine = true;
-
-    createEvictionPolicy(res, cacheCfg.evictionPolicy, varName, 'evictionPolicy');
-
-    if (cacheCfg.nearCacheEnabled) {
-        res.needEmptyLine = true;
-
-        res.importClass('org.apache.ignite.configuration.NearCacheConfiguration');
-
-        addBeanWithProperties(res, cacheCfg.nearConfiguration, varName, 'nearConfiguration', 'nearConfiguration',
-            'NearCacheConfiguration', {nearStartSize: null}, true);
-
-        if (cacheCfg.nearConfiguration && cacheCfg.nearConfiguration.nearEvictionPolicy && cacheCfg.nearConfiguration.nearEvictionPolicy.kind) {
-            createEvictionPolicy(res, cacheCfg.nearConfiguration.nearEvictionPolicy, 'nearConfiguration', 'nearEvictionPolicy');
-        }
-    }
-
-    res.needEmptyLine = true;
-    
-    addProperty(res, cacheCfg, varName, 'sqlEscapeAll');
-    addProperty(res, cacheCfg, varName, 'sqlOnheapRowCacheSize');
-    addProperty(res, cacheCfg, varName, 'longQueryWarningTimeout');
-    
-    if (cacheCfg.indexedTypes && cacheCfg.indexedTypes.length > 0) {
-        res.emptyLineIfNeeded();
-        
-        res.append(varName + '.setIndexedTypes(');
-        
-        for (var i = 0; i < cacheCfg.indexedTypes.length; i++) {
-            if (i > 0)
-                res.append(', ');
-
-            var pair = cacheCfg.indexedTypes[i];
-            
-            res.append(toJavaCode(pair.keyClass, 'class')).append(', ').append(toJavaCode(pair.valueClass, 'class'))
-        }
-        
-        res.line(');');
-    }
-
-    addMultiparamProperty(res, cacheCfg, varName, 'sqlFunctionClasses', 'class');
-    
-    res.needEmptyLine = true;
-
-    addProperty(res, cacheCfg, varName, 'rebalanceMode', 'CacheRebalanceMode');
-    addProperty(res, cacheCfg, varName, 'rebalanceThreadPoolSize');
-    addProperty(res, cacheCfg, varName, 'rebalanceBatchSize');
-    addProperty(res, cacheCfg, varName, 'rebalanceOrder');
-    addProperty(res, cacheCfg, varName, 'rebalanceDelay');
-    addProperty(res, cacheCfg, varName, 'rebalanceTimeout');
-    addProperty(res, cacheCfg, varName, 'rebalanceThrottle');
-
-    res.needEmptyLine = true;
-    
-    if (cacheCfg.cacheStoreFactory && cacheCfg.cacheStoreFactory.kind) {
-        var storeFactory = cacheCfg.cacheStoreFactory[cacheCfg.cacheStoreFactory.kind];
-        var data = generatorUtils.storeFactories[cacheCfg.cacheStoreFactory.kind];
-
-        var sfVarName = 'storeFactory' + generatorUtils.toJavaName(cacheCfg.name);
-        var dsVarName = 'none';
-
-        if (storeFactory.dialect) {
-            var dataSourceBean = storeFactory.dataSourceBean;
-
-            dsVarName = 'dataSource' + generatorUtils.toJavaName(dataSourceBean);
-
-            if (!_.contains(res.datasourceBeans, dataSourceBean)) {
-                res.datasourceBeans.push(dataSourceBean);
-
-                var dataSource = generatorUtils.dataSources[storeFactory.dialect];
-
-                res.line();
-                res.line(dataSource.className + ' ' + dsVarName + ' = new ' + dataSource.className + '();');
-                res.line(dsVarName + '.setURL(_URL_);');
-                res.line(dsVarName + '.setUsername(_User_Name_);');
-                res.line(dsVarName + '.setPassword(_Password_);');
-            }
-        }
-
-        addBeanWithProperties(res, storeFactory, varName, 'cacheStoreFactory', sfVarName, data.className,
-            data.fields, true);
-
-        if (dsVarName != 'none')
-            res.line(sfVarName + '.setDataSource(' + dsVarName + ');');
-    }
-
-    res.needEmptyLine = true;
-
-    addProperty(res, cacheCfg, varName, 'loadPreviousValue');
-    addProperty(res, cacheCfg, varName, 'readThrough');
-    addProperty(res, cacheCfg, varName, 'writeThrough');
-
-    res.needEmptyLine = true;
-    
-    addProperty(res, cacheCfg, varName, 'invalidate');
-    addProperty(res, cacheCfg, varName, 'defaultLockTimeout');
-    addProperty(res, cacheCfg, varName, 'transactionManagerLookupClassName');
-    
-    res.needEmptyLine = true;
-    
-    addProperty(res, cacheCfg, varName, 'writeBehindEnabled');
-    addProperty(res, cacheCfg, varName, 'writeBehindBatchSize');
-    addProperty(res, cacheCfg, varName, 'writeBehindFlushSize');
-    addProperty(res, cacheCfg, varName, 'writeBehindFlushFrequency');
-    addProperty(res, cacheCfg, varName, 'writeBehindFlushThreadCount');
-    
-    res.needEmptyLine = true;
-
-    addProperty(res, cacheCfg, varName, 'statisticsEnabled');
-    addProperty(res, cacheCfg, varName, 'managementEnabled');
-
-    res.needEmptyLine = true;
-
-    addProperty(res, cacheCfg, varName, 'maxConcurrentAsyncOperations');
-    
-    return res;
-}
-
-function toJavaCode(val, type) {
-    if (val == null)
-       return 'null';
-
-    if (type == 'float')
-        return val + 'f';
-    
-    if (type == 'class')
-        return val + '.class';
-    
-    if (type)
-        return type + '.' + val;
-    
-    if (typeof(val) == 'string')
-        return '"' + val.replace('"', '\\"') + '"';
-
-    if (typeof(val) == 'number' || typeof(val) == 'boolean')
-        return '' + val;
-
-    throw "Unknown type: " + typeof(val) + ' (' + val + ')';
-}
-
-function addProperty(res, obj, objVariableName, propName, enumType, setterName) {
-    var val = obj[propName];
-    
-    if (generatorUtils.isDefined(val)) {
-        res.emptyLineIfNeeded();
-
-        res.line(objVariableName + '.' + getSetterName(setterName ? setterName : propName)
-            + '(' + toJavaCode(val, enumType)  + ');');
-    }
-}
-
-function getSetterName(propName) {
-    return 'set' + propName.charAt(0).toLocaleUpperCase() + propName.slice(1);
-}
-
-function addListProperty(res, obj, objVariableName, propName, enumType, setterName) {
-    var val = obj[propName];
-    
-    if (val && val.length > 0) {
-        res.append(objVariableName + '.' + getSetterName(setterName ? setterName : propName) + '(Arrays.asList(');
-
-        for (var i = 0; i < val.length; i++) {
-            if (i > 0)
-                res.append(', ');
-            
-            res.append(toJavaCode(val[i], enumType));
-        }
-        
-        res.line('));');
-    }
-}
-
-function addMultiparamProperty(res, obj, objVariableName, propName, type, setterName) {
-    var val = obj[propName];
-    
-    if (val && val.length > 0) {
-        res.append(objVariableName + '.' + getSetterName(setterName ? setterName : propName) + '(');
-
-        for (var i = 0; i < val.length; i++) {
-            if (i > 0)
-                res.append(', ');
-            
-            res.append(toJavaCode(val[i], type));
-        }
-        
-        res.line(');');
-    }
-}
-
-function addBeanWithProperties(res, bean, objVarName, beanPropName, beanVarName, beanClass, props, createBeanAlthoughNoProps) {
-    if (bean && generatorUtils.hasProperty(bean, props)) {
-        if (!res.emptyLineIfNeeded()) {
-            res.line();
-        }
-        
-        res.line(beanClass + ' ' + beanVarName + ' = new ' + beanClass + '();');
-
-        for (var propName in props) {
-            if (props.hasOwnProperty(propName)) {
-                var descr = props[propName];
-
-                if (descr) {
-                    switch (descr.type) {
-                        case 'list':
-                            addListProperty(res, bean, beanVarName, propName, descr.elementsType, descr.setterName);
-                            break;
-                        
-                        case 'enum':
-                            addProperty(res, bean, beanVarName, propName, descr.enumClass, descr.setterName);
-                            break;
-                        
-                        case 'float':
-                            addProperty(res, bean, beanVarName, propName, 'float', descr.setterName);
-                            break;
-                        
-                        case 'propertiesAsList':
-                            var val = bean[propName];
-                            
-                            if (val && val.length > 0) {
-                                res.line('Properties ' + descr.propVarName + ' = new Properties();');
-                                
-                                for (var i = 0; i < val.length; i++) {
-                                    var nameAndValue = val[i];
-                                    
-                                    var eqIndex = nameAndValue.indexOf('=');
-                                    if (eqIndex >= 0) {
-                                        res.line(descr.propVarName + '.setProperty(' 
-                                            + nameAndValue.substring(0, eqIndex) + ', ' 
-                                            + nameAndValue.substr(eqIndex + 1) + ');');
-                                    }
-
-                                }
-                                
-                                res.line(beanVarName + '.' + getSetterName(propName) + '(' + descr.propVarName + ');');
-                            }
-                            break;
-                        
-                        case 'className':
-                            if (bean[propName]) {
-                                res.line(beanVarName + '.' + getSetterName(propName) + '(new ' + generatorUtils.knownClasses[bean[propName]].className + '());');
-                            }
-
-                            break;
-                        
-                        default:
-                            addProperty(res, bean, beanVarName, propName, null, descr.setterName);
-                    }
-                }
-                else {
-                    addProperty(res, bean, beanVarName, propName);
-                }
-            }
-        }
-        
-        res.line(objVarName + '.' + getSetterName(beanPropName) + '(' + beanVarName + ');');
-        
-        res.needEmptyLine = true;
-    }
-    else if (createBeanAlthoughNoProps) {
-        res.emptyLineIfNeeded();
-        
-        res.line(objVarName + '.' + getSetterName(beanPropName) + '(new ' + beanClass + '());');
-    }
-}