[Kimchi-devel] [PATCH 03/38] Rename remaining wok files

Lucio Correia luciojhc at linux.vnet.ibm.com
Thu May 21 21:33:16 UTC 2015


This patch renames the remaining kimchi-named files in wok.
No code changes, only renames.
---
 contrib/kimchid-upstart.conf.debian |   34 ---
 contrib/kimchid-upstart.conf.fedora |   33 ---
 contrib/kimchid.service.fedora      |   13 -
 contrib/kimchid.sysvinit            |  104 -------
 contrib/wokd-upstart.conf.debian    |   34 +++
 contrib/wokd-upstart.conf.fedora    |   33 +++
 contrib/wokd.service.fedora         |   13 +
 contrib/wokd.sysvinit               |  104 +++++++
 docs/kimchid.8                      |  156 -----------
 docs/wokd.8                         |  156 +++++++++++
 src/kimchi.conf.in                  |   65 -----
 src/kimchid.in                      |   99 -------
 src/nginx/kimchi.conf.in            |   76 -----
 src/nginx/wok.conf.in               |   76 +++++
 src/wok.conf.in                     |   65 +++++
 src/wokd.in                         |   99 +++++++
 ui/js/src/kimchi.cookie.js          |   40 ---
 ui/js/src/kimchi.grid.js            |  528 -----------------------------------
 ui/js/src/kimchi.lang.js            |   50 ----
 ui/js/src/kimchi.login.js           |   72 -----
 ui/js/src/kimchi.main.js            |  366 ------------------------
 ui/js/src/kimchi.message.js         |  116 --------
 ui/js/src/kimchi.object.js          |   85 ------
 ui/js/src/kimchi.popable.js         |   34 ---
 ui/js/src/kimchi.string.js          |   45 ---
 ui/js/src/kimchi.substitute.js      |   45 ---
 ui/js/src/kimchi.topic.js           |   48 ----
 ui/js/src/kimchi.user.js            |   43 ---
 ui/js/src/kimchi.window.js          |   70 -----
 ui/js/src/wok.cookie.js             |   40 +++
 ui/js/src/wok.grid.js               |  528 +++++++++++++++++++++++++++++++++++
 ui/js/src/wok.lang.js               |   50 ++++
 ui/js/src/wok.login.js              |   72 +++++
 ui/js/src/wok.main.js               |  366 ++++++++++++++++++++++++
 ui/js/src/wok.message.js            |  116 ++++++++
 ui/js/src/wok.object.js             |   85 ++++++
 ui/js/src/wok.popable.js            |   34 +++
 ui/js/src/wok.string.js             |   45 +++
 ui/js/src/wok.substitute.js         |   45 +++
 ui/js/src/wok.topic.js              |   48 ++++
 ui/js/src/wok.user.js               |   43 +++
 ui/js/src/wok.window.js             |   70 +++++
 ui/pages/kimchi-ui.html.tmpl        |  141 ----------
 ui/pages/wok-ui.html.tmpl           |  141 ++++++++++
 44 files changed, 2263 insertions(+), 2263 deletions(-)
 delete mode 100644 contrib/kimchid-upstart.conf.debian
 delete mode 100644 contrib/kimchid-upstart.conf.fedora
 delete mode 100644 contrib/kimchid.service.fedora
 delete mode 100644 contrib/kimchid.sysvinit
 create mode 100644 contrib/wokd-upstart.conf.debian
 create mode 100644 contrib/wokd-upstart.conf.fedora
 create mode 100644 contrib/wokd.service.fedora
 create mode 100644 contrib/wokd.sysvinit
 delete mode 100644 docs/kimchid.8
 create mode 100644 docs/wokd.8
 delete mode 100644 src/kimchi.conf.in
 delete mode 100644 src/kimchid.in
 delete mode 100644 src/nginx/kimchi.conf.in
 create mode 100644 src/nginx/wok.conf.in
 create mode 100644 src/wok.conf.in
 create mode 100644 src/wokd.in
 delete mode 100644 ui/js/src/kimchi.cookie.js
 delete mode 100644 ui/js/src/kimchi.grid.js
 delete mode 100644 ui/js/src/kimchi.lang.js
 delete mode 100644 ui/js/src/kimchi.login.js
 delete mode 100644 ui/js/src/kimchi.main.js
 delete mode 100644 ui/js/src/kimchi.message.js
 delete mode 100644 ui/js/src/kimchi.object.js
 delete mode 100644 ui/js/src/kimchi.popable.js
 delete mode 100644 ui/js/src/kimchi.string.js
 delete mode 100644 ui/js/src/kimchi.substitute.js
 delete mode 100644 ui/js/src/kimchi.topic.js
 delete mode 100644 ui/js/src/kimchi.user.js
 delete mode 100644 ui/js/src/kimchi.window.js
 create mode 100644 ui/js/src/wok.cookie.js
 create mode 100644 ui/js/src/wok.grid.js
 create mode 100644 ui/js/src/wok.lang.js
 create mode 100644 ui/js/src/wok.login.js
 create mode 100644 ui/js/src/wok.main.js
 create mode 100644 ui/js/src/wok.message.js
 create mode 100644 ui/js/src/wok.object.js
 create mode 100644 ui/js/src/wok.popable.js
 create mode 100644 ui/js/src/wok.string.js
 create mode 100644 ui/js/src/wok.substitute.js
 create mode 100644 ui/js/src/wok.topic.js
 create mode 100644 ui/js/src/wok.user.js
 create mode 100644 ui/js/src/wok.window.js
 delete mode 100644 ui/pages/kimchi-ui.html.tmpl
 create mode 100644 ui/pages/wok-ui.html.tmpl

diff --git a/contrib/kimchid-upstart.conf.debian b/contrib/kimchid-upstart.conf.debian
deleted file mode 100644
index a58d3c3..0000000
--- a/contrib/kimchid-upstart.conf.debian
+++ /dev/null
@@ -1,34 +0,0 @@
-#
-# kimchid - Kimchi Web Server
-#
-# Copyright IBM, Corp. 2013
-#
-# This library is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 2.1 of the License, or (at your option) any later version.
-#
-# This library is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-# Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this library; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-#
-
-description	"Kimchi Web Server"
-
-start on started libvirt-bin
-stop on stopped libvirt-bin
-
-respawn
-respawn limit 5 30
-
-pre-start script
-    status libvirt-bin | grep -q "start/running" && exit 0
-    start libvirt-bin || exit 1
-end script
-
-exec /usr/bin/kimchid
diff --git a/contrib/kimchid-upstart.conf.fedora b/contrib/kimchid-upstart.conf.fedora
deleted file mode 100644
index 53e8a39..0000000
--- a/contrib/kimchid-upstart.conf.fedora
+++ /dev/null
@@ -1,33 +0,0 @@
-#
-# kimchid - Kimchi Web Server
-#
-# Copyright IBM, Corp. 2013
-#
-# This library is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 2.1 of the License, or (at your option) any later version.
-#
-# This library is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-# Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this library; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-#
-
-description "Kimchi Web Server"
-
-start on stopped rc RUNLEVEL=[2345]
-
-respawn
-respawn limit 5 30
-
-pre-start script
-    service libvirtd status | grep -q "start/running" && exit 0
-    service libvirtd start || exit 1
-end script
-
-exec /usr/bin/kimchid
diff --git a/contrib/kimchid.service.fedora b/contrib/kimchid.service.fedora
deleted file mode 100644
index 7abe49b..0000000
--- a/contrib/kimchid.service.fedora
+++ /dev/null
@@ -1,13 +0,0 @@
-[Unit]
-Description=Kimchi server
-Requires=libvirtd.service
-After=libvirtd.service
-
-[Service]
-Type=simple
-ExecStart=/usr/bin/kimchid
-ExecStop=/bin/kill -TERM $MAINPID
-EnvironmentFile=/etc/kimchi/kimchi.conf
-
-[Install]
-WantedBy=multi-user.target
diff --git a/contrib/kimchid.sysvinit b/contrib/kimchid.sysvinit
deleted file mode 100644
index 023b34c..0000000
--- a/contrib/kimchid.sysvinit
+++ /dev/null
@@ -1,104 +0,0 @@
-#! /bin/sh
-#
-# kimchid		Kimchi Web Server
-#
-# Copyright IBM, Corp. 2013
-#
-# Author: Aline Manera <alinefm at br.ibm.com>
-#
-# This library is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 2.1 of the License, or (at your option) any later version.
-#
-# This library is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-# Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this library; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-#
-### BEGIN INIT INFO
-# Provides: kimchid
-# Required-Start: libvirtd
-# Required-Stop:
-# Default-Start: 3 5
-# Default-Stop: 0 1 2 6
-# Description: Start the kimchid daemon
-### END INIT INFO
-
-. /etc/rc.status
-
-# Shell functions sourced from /etc/rc.status:
-#      rc_check         check and set local and overall rc status
-#      rc_status        check and set local and overall rc status
-#      rc_status -v     ditto but be verbose in local rc status
-#      rc_status -v -r  ditto and clear the local rc status
-#      rc_failed        set local and overall rc status to failed
-#      rc_reset         clear local rc status (overall remains)
-#      rc_exit          exit appropriate to overall rc status
-
-# First reset status of this service
-rc_reset
-
-case "$1" in
-    start)
-	echo -n "Starting kimchid daemon"
-	## Start daemon with startproc(8). If this fails
-	## the echo return value is set appropriate.
-
-	startproc -f /usr/bin/kimchid > /dev/null 2>&1
-
-	# Remember status and be verbose
-	rc_status -v
-	;;
-    stop)
-	echo -n "Shutting down kimchid daemon"
-	## Stop daemon with killproc(8) and if this fails
-	## set echo the echo return value.
-
-	killproc -TERM /usr/bin/kimchid
-
-	# Remember status and be verbose
-	rc_status -v
-	;;
-    try-restart)
-        ## Stop the service and if this succeeds (i.e. the
-        ## service was running before), start it again.
-        $0 status >/dev/null &&  $0 restart
-
-        # Remember status and be quiet
-        rc_status
-        ;;
-    restart)
-        ## Stop the service and regardless of whether it was
-        ## running or not, start it again.
-        $0 stop
-        $0 start
-
-        # Remember status and be quiet
-        rc_status
-        ;;
-    status)
-	echo -n "Checking for service kimchid "
-        ## Check status with checkproc(8), if process is running
-        ## checkproc will return with exit status 0.
-
-        # Status has a slightly different for the status command:
-        # 0 - service running
-        # 1 - service dead, but /var/run/  pid  file exists
-        # 2 - service dead, but /var/lock/ lock file exists
-        # 3 - service not running
-
-	checkproc /usr/bin/kimchid
-
-	rc_status -v
-	;;
-    *)
-	echo "Usage: $0 {start|stop|status|try-restart|restart}"
-	exit 1
-	;;
-esac
-rc_exit
diff --git a/contrib/wokd-upstart.conf.debian b/contrib/wokd-upstart.conf.debian
new file mode 100644
index 0000000..a58d3c3
--- /dev/null
+++ b/contrib/wokd-upstart.conf.debian
@@ -0,0 +1,34 @@
+#
+# kimchid - Kimchi Web Server
+#
+# Copyright IBM, Corp. 2013
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+#
+
+description	"Kimchi Web Server"
+
+start on started libvirt-bin
+stop on stopped libvirt-bin
+
+respawn
+respawn limit 5 30
+
+pre-start script
+    status libvirt-bin | grep -q "start/running" && exit 0
+    start libvirt-bin || exit 1
+end script
+
+exec /usr/bin/kimchid
diff --git a/contrib/wokd-upstart.conf.fedora b/contrib/wokd-upstart.conf.fedora
new file mode 100644
index 0000000..53e8a39
--- /dev/null
+++ b/contrib/wokd-upstart.conf.fedora
@@ -0,0 +1,33 @@
+#
+# kimchid - Kimchi Web Server
+#
+# Copyright IBM, Corp. 2013
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+#
+
+description "Kimchi Web Server"
+
+start on stopped rc RUNLEVEL=[2345]
+
+respawn
+respawn limit 5 30
+
+pre-start script
+    service libvirtd status | grep -q "start/running" && exit 0
+    service libvirtd start || exit 1
+end script
+
+exec /usr/bin/kimchid
diff --git a/contrib/wokd.service.fedora b/contrib/wokd.service.fedora
new file mode 100644
index 0000000..7abe49b
--- /dev/null
+++ b/contrib/wokd.service.fedora
@@ -0,0 +1,13 @@
+[Unit]
+Description=Kimchi server
+Requires=libvirtd.service
+After=libvirtd.service
+
+[Service]
+Type=simple
+ExecStart=/usr/bin/kimchid
+ExecStop=/bin/kill -TERM $MAINPID
+EnvironmentFile=/etc/kimchi/kimchi.conf
+
+[Install]
+WantedBy=multi-user.target
diff --git a/contrib/wokd.sysvinit b/contrib/wokd.sysvinit
new file mode 100644
index 0000000..023b34c
--- /dev/null
+++ b/contrib/wokd.sysvinit
@@ -0,0 +1,104 @@
+#! /bin/sh
+#
+# kimchid		Kimchi Web Server
+#
+# Copyright IBM, Corp. 2013
+#
+# Author: Aline Manera <alinefm at br.ibm.com>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+#
+### BEGIN INIT INFO
+# Provides: kimchid
+# Required-Start: libvirtd
+# Required-Stop:
+# Default-Start: 3 5
+# Default-Stop: 0 1 2 6
+# Description: Start the kimchid daemon
+### END INIT INFO
+
+. /etc/rc.status
+
+# Shell functions sourced from /etc/rc.status:
+#      rc_check         check and set local and overall rc status
+#      rc_status        check and set local and overall rc status
+#      rc_status -v     ditto but be verbose in local rc status
+#      rc_status -v -r  ditto and clear the local rc status
+#      rc_failed        set local and overall rc status to failed
+#      rc_reset         clear local rc status (overall remains)
+#      rc_exit          exit appropriate to overall rc status
+
+# First reset status of this service
+rc_reset
+
+case "$1" in
+    start)
+	echo -n "Starting kimchid daemon"
+	## Start daemon with startproc(8). If this fails
+	## the echo return value is set appropriate.
+
+	startproc -f /usr/bin/kimchid > /dev/null 2>&1
+
+	# Remember status and be verbose
+	rc_status -v
+	;;
+    stop)
+	echo -n "Shutting down kimchid daemon"
+	## Stop daemon with killproc(8) and if this fails
+	## set echo the echo return value.
+
+	killproc -TERM /usr/bin/kimchid
+
+	# Remember status and be verbose
+	rc_status -v
+	;;
+    try-restart)
+        ## Stop the service and if this succeeds (i.e. the
+        ## service was running before), start it again.
+        $0 status >/dev/null &&  $0 restart
+
+        # Remember status and be quiet
+        rc_status
+        ;;
+    restart)
+        ## Stop the service and regardless of whether it was
+        ## running or not, start it again.
+        $0 stop
+        $0 start
+
+        # Remember status and be quiet
+        rc_status
+        ;;
+    status)
+	echo -n "Checking for service kimchid "
+        ## Check status with checkproc(8), if process is running
+        ## checkproc will return with exit status 0.
+
+        # Status has a slightly different for the status command:
+        # 0 - service running
+        # 1 - service dead, but /var/run/  pid  file exists
+        # 2 - service dead, but /var/lock/ lock file exists
+        # 3 - service not running
+
+	checkproc /usr/bin/kimchid
+
+	rc_status -v
+	;;
+    *)
+	echo "Usage: $0 {start|stop|status|try-restart|restart}"
+	exit 1
+	;;
+esac
+rc_exit
diff --git a/docs/kimchid.8 b/docs/kimchid.8
deleted file mode 100644
index f5fa90a..0000000
--- a/docs/kimchid.8
+++ /dev/null
@@ -1,156 +0,0 @@
-.TH KIMCHI 8 "February 05, 2015" "Version 1.4.0" "Kimchi Manual"
-.SH NAME
-Kimchi \- HTML5 based management tool for KVM
-.SH SYNOPSIS
-.B kimchid
-[\fB-h\fP|\fB--help\fP] [\fB--host\fP \fIhost\fP] [\fB--port\fP \fIport\fP]
-[\fB--ssl-port\fP \fIssl_port\fP] [\fB--cherrypy_port\fP \fIcherrypy_port\fP]
-[\fB--log-level\fP \fIlog_level\fP] [\fB--access-log\fP \fIaccess_log\fP]
-[\fB--error-log\fP \fIerror_log\fP] [\fB--environment\fP \fIenvironment\fP]
-[\fB--federation\fP \fIfederation\fP] [\fB--test\fP]
-.SH DESCRIPTION
-\fBKimchi\fP is an HTML5 based management tool for KVM. It is designed to make
-it as easy as possible to get started with KVM and create your first guest.
-\fBkimchid\fP launches the daemon on the hypervisor host which manages KVM guests through
-libvirt. The management interface is accessed over the web using a browser that
-supports HTML5.
-.SH OPTIONS
-The following options are supported:
-.TP
-\fB-h\fP , \fB--help\fP
-Show this help message and exit.
-.TP
-\fB--host\fP \fIhost\fP
-Specify the hostname or IP to listen on.
-.TP
-\fB--port\fP \fIport\fP
-Specify the HTTP port (default \fI8000\fP).
-.TP
-\fB--ssl-port\fP \fIssl_port\fP
-Specify the HTTPS port (default \fI8001\fP).
-.TP
-\fB--cherrypy_port\fP \fIcherrypy_port\fP
-Specify the Cherrypy server port (default \fI8010\fP).
-.TP
-\fB--log-level\fP [\fIdebug\fP | \fIinfo\fP | \fIwarning\fP | \fIerror\fP | \fIcritical\fP]
-Specify the log level (default \fIdebug\fP).
-.TP
-\fB--access-log\fP \fIaccess_log\fP
-Specify the access log location where kimchi should create the access log file.
-.TP
-\fB--environment\fP [\fIdevelopment\fP | \fIproduction\fP]
-Specify the running environment of kimchi server. Check cherrypy documentation for more details (default \fIproduction\fP).
-.TP
-\fB--federation\fP [\fIon\fP | \fIoff\fP]
-Register and discover Kimchi peers in the same network using OpenSLP. Check
-below the \fBFEDERATION\fP section for more details (default \fIoff\fP).
-.TP
-\fB--test\fP
-Run kimchi on a mock version that does not affect the system. For testing proposals.
-.SH FEDERATION
-Federation feature is a mechanism to discover Kimchi peers in the same network.
-It uses OpenSLP tool (http://www.openslp.org/) to register and find the Kimchi
-servers.
-
-By default this feature is disabled on Kimchi as it is not critical for KVM
-virtualization and requires additional software installation.
-
-To enable it, do the following:
-
-1. Install OpenSLP server package
-
-2. OpenSLP uses port 427 (UDP) and port 427 (TCP) so make sure to open those
-   ports in your firewall configuration
-
-   For system using firewalld, do:
-   sudo firewall-cmd --permanent --add-port=427/udp
-   sudo firewall-cmd --permanent --add-port=427/tcp
-   sudo firewall-cmd --reload
-
-   For openSUSE systems, do:
-   sudo /sbin/SuSEfirewall2 open EXT TCP 427
-   sudo /sbin/SuSEfirewall2 open EXT UDP 427
-
-   For system using iptables, do:
-   sudo iptables -A INPUT -p tcp --dport 427 -j ACCEPT
-   sudo iptables -A INPUT -p udp --dport 427 -j ACCEPT
-
-3. In addition to the OpenSLP ports, you also need to allow multicast in the
-   firewall configuration
-
-   For system using firewalld, do:
-   sudo firewall-cmd --direct --add-rule ipv4 filter INPUT 0 -s <subnet> -j ACCEPT
-
-   For openSUSE systems, do:
-   Add the subnet to the trusted networks listed on FW_TRUSTED_NETS in
-   /etc/sysconfig/SuSEfirewall2 file.
-   Make sure to restart /sbin/SuSEfirewall2 after modifying /etc/sysconfig/SuSEfirewall2
-
-   For system using iptables, do:
-   sudo iptables -A INPUT -s <subnet> -j ACCEPT
-
-4. Start slpd service and make sure it is up while running Kimchi
-   sudo service slpd start
-
-5. Enable federation on Kimchi by editing the /etc/kimchi/kimchi.conf file:
-
-   federation = on
-
-6. Then start Kimchi service
-   sudo service kimchid start
-
-The Kimchi server will be registered on OpenSLP on server starting up and will
-be found by other Kimchi peers (with federation feature enabled) in the same
-network.
-.SH LICENCE
-.br
-Kimchi is distributed pursuant to the terms of two different licenses.
-The user interface (located in ui/ in this distribution) is governed by
-the Apache License version 2.0.
-
-The code under ui/spice-html5 is imported from spice-html5 project
-(http://cgit.freedesktop.org/spice/spice-html5) and the code under ui/libs which is
-imported from JQuery UI (http://jqueryui.com)
-
-The rest of this distribution is governed by the GNU Lesser General Public
-License version 3.
-
-See COPYING.LGPL and COPYING.ASL2.
-.SH BUGS
-Current bugs can be found here : https://github.com/kimchi-project/kimchi/issues
-.br
-If you find any, please open an issue : https://github.com/kimchi-project/kimchi/issues/new
-.SH AUTHOR
-\fBAdam King\fP <rak at linux.vnet.ibm.com>,
-\fBAdam Litke\fP <agl at linux.vnet.ibm.com>,
-\fBAdriano Botega\fP <abotega at linux.vnet.ibm.com>,
-\fBAlexandre Tanaka Hirata\fP <hirata at linux.vnet.ibm.com>,
-\fBAline Manera\fP <alinefm at br.ibm.com>,
-\fBapporc\fP <appleorchard2000 at gmail.com>,
-\fBAnthony Liguori\fP <aliguori at us.ibm.com>,
-\fBBing Bu Cao\fP <mars at linux.vnet.ibm.com>,
-\fBChristy Perez\fP <christy at linux.vnet.ibm.com>,
-\fBCole Robinson\fP <crobinso at redhat.com>,
-\fBCrístian Viana\fP <vianac at linux.vnet.ibm.com>,
-\fBDaniel H Barboza\fP <danielhb at linux.vnet.ibm.com>,
-\fBEduardo Elias Ferreira\fP <edusf at linux.vnet.ibm.com>,
-\fBEli Qiao(Li Yong Qiao)\fP <taget at linux.vnet.ibm.com>,
-\fBHongliang Wang\fP <hlwang at linux.vnet.ibm.com>,
-\fBLeonardo Garcia\fP <lagarcia at br.ibm.com>,
-\fBLise Noble\fP <lwnoble at us.ibm.com>,
-\fBMalcolm Yu\fP <minghaoyusombie at gmail.com>,
-\fBMark Wu\fP <wudxw at linux.vnet.ibm.com>,
-\fBMei Na Zhou\fP <zhoumein at linux.vnet.ibm.com>,
-\fBPaulo Vital\fP <pvital at linux.vnet.ibm.com>,
-\fBPradeep K Surisetty\fP <psuriset at linux.vnet.ibm.com>,
-\fBRamon Medeiros\fP <ramonn at linux.vnet.ibm.com>,
-\fBRodrigo Trujilo\fP <rodrigo.trujillo at linux.vnet.ibm.com>,
-\fBRoyce Lv\fP <lvroyce at linux.vnet.ibm.com>,
-\fBShaoHe Feng\fP <shaohef at linux.vnet.ibm.com>,
-\fBShu Ming\fP <shuming at linux.vnet.ibm.com>,
-\fBToby Allsopp\fP <toby at MI6.GEN.NZ>,
-\fBTony Breeds\fP <tonyb at au1.ibm.com>,
-\fBXin BJ Ding\fP <xinding at cn.ibm.com>,
-\fBYu Xin Huo\fP <huoyuxin at linux.vnet.ibm.com>,
-\fBZhou Zheng Sheng\fP <zhshzhou at linux.vnet.ibm.com>,
-.SH SEE ALSO
diff --git a/docs/wokd.8 b/docs/wokd.8
new file mode 100644
index 0000000..f5fa90a
--- /dev/null
+++ b/docs/wokd.8
@@ -0,0 +1,156 @@
+.TH KIMCHI 8 "February 05, 2015" "Version 1.4.0" "Kimchi Manual"
+.SH NAME
+Kimchi \- HTML5 based management tool for KVM
+.SH SYNOPSIS
+.B kimchid
+[\fB-h\fP|\fB--help\fP] [\fB--host\fP \fIhost\fP] [\fB--port\fP \fIport\fP]
+[\fB--ssl-port\fP \fIssl_port\fP] [\fB--cherrypy_port\fP \fIcherrypy_port\fP]
+[\fB--log-level\fP \fIlog_level\fP] [\fB--access-log\fP \fIaccess_log\fP]
+[\fB--error-log\fP \fIerror_log\fP] [\fB--environment\fP \fIenvironment\fP]
+[\fB--federation\fP \fIfederation\fP] [\fB--test\fP]
+.SH DESCRIPTION
+\fBKimchi\fP is an HTML5 based management tool for KVM. It is designed to make
+it as easy as possible to get started with KVM and create your first guest.
+\fBkimchid\fP launches the daemon on the hypervisor host which manages KVM guests through
+libvirt. The management interface is accessed over the web using a browser that
+supports HTML5.
+.SH OPTIONS
+The following options are supported:
+.TP
+\fB-h\fP , \fB--help\fP
+Show this help message and exit.
+.TP
+\fB--host\fP \fIhost\fP
+Specify the hostname or IP to listen on.
+.TP
+\fB--port\fP \fIport\fP
+Specify the HTTP port (default \fI8000\fP).
+.TP
+\fB--ssl-port\fP \fIssl_port\fP
+Specify the HTTPS port (default \fI8001\fP).
+.TP
+\fB--cherrypy_port\fP \fIcherrypy_port\fP
+Specify the Cherrypy server port (default \fI8010\fP).
+.TP
+\fB--log-level\fP [\fIdebug\fP | \fIinfo\fP | \fIwarning\fP | \fIerror\fP | \fIcritical\fP]
+Specify the log level (default \fIdebug\fP).
+.TP
+\fB--access-log\fP \fIaccess_log\fP
+Specify the access log location where kimchi should create the access log file.
+.TP
+\fB--environment\fP [\fIdevelopment\fP | \fIproduction\fP]
+Specify the running environment of kimchi server. Check cherrypy documentation for more details (default \fIproduction\fP).
+.TP
+\fB--federation\fP [\fIon\fP | \fIoff\fP]
+Register and discover Kimchi peers in the same network using OpenSLP. Check
+below the \fBFEDERATION\fP section for more details (default \fIoff\fP).
+.TP
+\fB--test\fP
+Run kimchi on a mock version that does not affect the system. For testing proposals.
+.SH FEDERATION
+Federation feature is a mechanism to discover Kimchi peers in the same network.
+It uses OpenSLP tool (http://www.openslp.org/) to register and find the Kimchi
+servers.
+
+By default this feature is disabled on Kimchi as it is not critical for KVM
+virtualization and requires additional software installation.
+
+To enable it, do the following:
+
+1. Install OpenSLP server package
+
+2. OpenSLP uses port 427 (UDP) and port 427 (TCP) so make sure to open those
+   ports in your firewall configuration
+
+   For system using firewalld, do:
+   sudo firewall-cmd --permanent --add-port=427/udp
+   sudo firewall-cmd --permanent --add-port=427/tcp
+   sudo firewall-cmd --reload
+
+   For openSUSE systems, do:
+   sudo /sbin/SuSEfirewall2 open EXT TCP 427
+   sudo /sbin/SuSEfirewall2 open EXT UDP 427
+
+   For system using iptables, do:
+   sudo iptables -A INPUT -p tcp --dport 427 -j ACCEPT
+   sudo iptables -A INPUT -p udp --dport 427 -j ACCEPT
+
+3. In addition to the OpenSLP ports, you also need to allow multicast in the
+   firewall configuration
+
+   For system using firewalld, do:
+   sudo firewall-cmd --direct --add-rule ipv4 filter INPUT 0 -s <subnet> -j ACCEPT
+
+   For openSUSE systems, do:
+   Add the subnet to the trusted networks listed on FW_TRUSTED_NETS in
+   /etc/sysconfig/SuSEfirewall2 file.
+   Make sure to restart /sbin/SuSEfirewall2 after modifying /etc/sysconfig/SuSEfirewall2
+
+   For system using iptables, do:
+   sudo iptables -A INPUT -s <subnet> -j ACCEPT
+
+4. Start slpd service and make sure it is up while running Kimchi
+   sudo service slpd start
+
+5. Enable federation on Kimchi by editing the /etc/kimchi/kimchi.conf file:
+
+   federation = on
+
+6. Then start Kimchi service
+   sudo service kimchid start
+
+The Kimchi server will be registered on OpenSLP on server starting up and will
+be found by other Kimchi peers (with federation feature enabled) in the same
+network.
+.SH LICENCE
+.br
+Kimchi is distributed pursuant to the terms of two different licenses.
+The user interface (located in ui/ in this distribution) is governed by
+the Apache License version 2.0.
+
+The code under ui/spice-html5 is imported from spice-html5 project
+(http://cgit.freedesktop.org/spice/spice-html5) and the code under ui/libs which is
+imported from JQuery UI (http://jqueryui.com)
+
+The rest of this distribution is governed by the GNU Lesser General Public
+License version 3.
+
+See COPYING.LGPL and COPYING.ASL2.
+.SH BUGS
+Current bugs can be found here : https://github.com/kimchi-project/kimchi/issues
+.br
+If you find any, please open an issue : https://github.com/kimchi-project/kimchi/issues/new
+.SH AUTHOR
+\fBAdam King\fP <rak at linux.vnet.ibm.com>,
+\fBAdam Litke\fP <agl at linux.vnet.ibm.com>,
+\fBAdriano Botega\fP <abotega at linux.vnet.ibm.com>,
+\fBAlexandre Tanaka Hirata\fP <hirata at linux.vnet.ibm.com>,
+\fBAline Manera\fP <alinefm at br.ibm.com>,
+\fBapporc\fP <appleorchard2000 at gmail.com>,
+\fBAnthony Liguori\fP <aliguori at us.ibm.com>,
+\fBBing Bu Cao\fP <mars at linux.vnet.ibm.com>,
+\fBChristy Perez\fP <christy at linux.vnet.ibm.com>,
+\fBCole Robinson\fP <crobinso at redhat.com>,
+\fBCrístian Viana\fP <vianac at linux.vnet.ibm.com>,
+\fBDaniel H Barboza\fP <danielhb at linux.vnet.ibm.com>,
+\fBEduardo Elias Ferreira\fP <edusf at linux.vnet.ibm.com>,
+\fBEli Qiao(Li Yong Qiao)\fP <taget at linux.vnet.ibm.com>,
+\fBHongliang Wang\fP <hlwang at linux.vnet.ibm.com>,
+\fBLeonardo Garcia\fP <lagarcia at br.ibm.com>,
+\fBLise Noble\fP <lwnoble at us.ibm.com>,
+\fBMalcolm Yu\fP <minghaoyusombie at gmail.com>,
+\fBMark Wu\fP <wudxw at linux.vnet.ibm.com>,
+\fBMei Na Zhou\fP <zhoumein at linux.vnet.ibm.com>,
+\fBPaulo Vital\fP <pvital at linux.vnet.ibm.com>,
+\fBPradeep K Surisetty\fP <psuriset at linux.vnet.ibm.com>,
+\fBRamon Medeiros\fP <ramonn at linux.vnet.ibm.com>,
+\fBRodrigo Trujilo\fP <rodrigo.trujillo at linux.vnet.ibm.com>,
+\fBRoyce Lv\fP <lvroyce at linux.vnet.ibm.com>,
+\fBShaoHe Feng\fP <shaohef at linux.vnet.ibm.com>,
+\fBShu Ming\fP <shuming at linux.vnet.ibm.com>,
+\fBToby Allsopp\fP <toby at MI6.GEN.NZ>,
+\fBTony Breeds\fP <tonyb at au1.ibm.com>,
+\fBXin BJ Ding\fP <xinding at cn.ibm.com>,
+\fBYu Xin Huo\fP <huoyuxin at linux.vnet.ibm.com>,
+\fBZhou Zheng Sheng\fP <zhshzhou at linux.vnet.ibm.com>,
+.SH SEE ALSO
diff --git a/src/kimchi.conf.in b/src/kimchi.conf.in
deleted file mode 100644
index cd141f5..0000000
--- a/src/kimchi.conf.in
+++ /dev/null
@@ -1,65 +0,0 @@
-#
-# Configuration file for Kimchi Web Server
-#
-
-[server]
-# Hostname or IP address to listen on
-#host = 0.0.0.0
-
-# Port to listen on
-#port = 8000
-
-# If present, start an SSL-enabled server on the given port
-#ssl_port = 8001
-
-# Cherrypy server port
-#cherrypy_port = 8010
-
-# The full path to an SSL Certificate in PEM format.  If left unspecified,
-# Kimchi will generate a self-signed certificate automatically.
-#ssl_cert =
-
-# The corresponding private key in PEM format for the SSL Certificate supplied
-# above.  If left blank, Kimchi will generate a self-signed certificate.
-#ssl_key =
-
-# Running environment of the server
-#environment = production
-
-# Federation feature: register Kimchi server on openSLP and discover peers
-# in the same network. Check README-federation for more details.
-#federation = off
-
-# Max request body size in KB, default value is 4GB
-#max_body_size = 4 * 1024 * 1024
-
-# Automatically create ISO pool on server start up
-#create_iso_pool = true
-
-[logging]
-# Log directory
-#log_dir = @localstatedir@/log/kimchi
-
-# Logging level: debug, info, warning, error or critical
-#log_level = debug
-
-[display]
-# Port for websocket proxy to listen on
-#display_proxy_port = 64667
-
-[authentication]
-# Authentication method, available option: pam, ldap.
-# method = pam
-
-# If specified method to ldap, following fields need to be specified.
-# ldap server domain name used to authenticate.
-# ldap_server = "localhost"
-
-# Search tree base in ldap
-# ldap_search_base = "ou=People, dc=kimchi, dc=org"
-
-# User id filter
-# ldap_search_filter = "uid=%(username)s"
-
-# User IDs regarded as kimchi admin
-# ldap_admin_id = "foo at foo.com, bar at bar.com"
diff --git a/src/kimchid.in b/src/kimchid.in
deleted file mode 100644
index 4ea7a42..0000000
--- a/src/kimchid.in
+++ /dev/null
@@ -1,99 +0,0 @@
-#!/usr/bin/env python2
-#
-# Project Kimchi
-#
-# Copyright IBM, Corp. 2013-2015
-#
-# This library is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 2.1 of the License, or (at your option) any later version.
-#
-# This library is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-# Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this library; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
-# MA  02110-1301  USA
-
-import os
-import sys
-sys.path.insert(1, '@pythondir@')
-
-from optparse import OptionParser
-
-import kimchi.server
-import kimchi.config as config
-
-
-if not config.paths.installed:
-    sys.path.append(config.paths.prefix)
-
-ACCESS_LOG = "kimchi-access.log"
-ERROR_LOG = "kimchi-error.log"
-
-
-def main(options):
-    # Script must run as root or with sudo.
-    if not os.geteuid() == 0:
-        sys.exit("\nMust be root to run this script. Exiting ...\n")
-
-    host = config.config.get("server", "host")
-    port = config.config.get("server", "port")
-    ssl_port = config.config.get("server", "ssl_port")
-    cherrypy_port = config.config.get("server", "cherrypy_port")
-    runningEnv = config.config.get("server", "environment")
-    federation = config.config.get("server", "federation")
-    isopool = config.config.get("server", "create_iso_pool")
-    logDir = config.config.get("logging", "log_dir")
-    logLevel = config.config.get("logging", "log_level")
-
-    parser = OptionParser()
-    parser.add_option('--host', type="string", default=host,
-                      help="Hostname to listen on")
-    parser.add_option('--port', type="int", default=port,
-                      help="Port to listen on (default %s)" % port)
-    parser.add_option('--ssl-port', type="int", default=ssl_port,
-                      help="Port to enable SSL (default %s)" % ssl_port)
-    parser.add_option('--cherrypy_port', type="int", default=cherrypy_port,
-                      help="Cherrypy server port (default %s)" % cherrypy_port)
-    parser.add_option('--log-level', default=logLevel,
-                      help="Logging level")
-    parser.add_option('--access-log',
-                      default=os.path.join(logDir, ACCESS_LOG),
-                      help="Access log file")
-    parser.add_option('--error-log',
-                      default=os.path.join(logDir, ERROR_LOG),
-                      help="Error log file")
-    parser.add_option('--environment', default=runningEnv,
-                      help="Running environment of kimchi server")
-    parser.add_option('--federation', default=federation,
-                      help="Register and discover Kimchi peers in the same "
-                           "network using openSLP. Check README-federation for"
-                           " more details.")
-    parser.add_option('--create_iso_pool', default=isopool,
-                      help="Automatically create ISO pool on server start up.")
-    parser.add_option('--test', action='store_true',
-                      help="Run server in mock model")
-    (options, args) = parser.parse_args()
-
-    # Update config.config with the command line values
-    # So the whole application will have access to accurate values
-    for sec in config.config.sections():
-        for item in config.config.options(sec):
-            if hasattr(options, item):
-                config.config.set(sec, item, str(getattr(options, item)))
-
-    # Add non-option arguments
-    setattr(options, 'ssl_cert', config.config.get('server', 'ssl_cert'))
-    setattr(options, 'ssl_key', config.config.get('server', 'ssl_key'))
-    setattr(options, 'max_body_size',
-            config.config.get('server', 'max_body_size'))
-
-    kimchi.server.main(options)
-
-if __name__ == '__main__':
-    sys.exit(main(sys.argv[1:]))
diff --git a/src/nginx/kimchi.conf.in b/src/nginx/kimchi.conf.in
deleted file mode 100644
index 3ecbde4..0000000
--- a/src/nginx/kimchi.conf.in
+++ /dev/null
@@ -1,76 +0,0 @@
-# Project Kimchi
-#
-# Copyright IBM, Corp. 2014-2015
-#
-# This library is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 2.1 of the License, or (at your option) any later version.
-#
-# This library is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-# Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this library; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-# 02110-1301  USA
-
-# This is a template file to be used to generate a nginx
-# proxy config file at kimchid script.
-
-user  ${user};
-worker_processes  1;
-
-error_log  /var/log/nginx/error.log;
-
-events {
-    worker_connections  1024;
-}
-
-http {
-
-    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
-                      '$status $body_bytes_sent "$http_referer" '
-                      '"$http_user_agent" "$http_x_forwarded_for"';
-
-    access_log  /var/log/nginx/access.log  main;
-    sendfile    on;
-
-    client_max_body_size ${max_body_size}k;
-
-    # Timeout set to 10 minutes to avoid the 504 Gateway Timeout
-    # when Kimchi is processing a request.
-    proxy_connect_timeout       600;
-    proxy_send_timeout          600;
-    proxy_read_timeout          600;
-    send_timeout                600;
-
-    server {
-        listen ${proxy_ssl_port} ssl;
-
-        ssl_certificate ${cert_pem};
-        ssl_certificate_key ${cert_key};
-        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
-        ssl_ciphers ECDH at STRENGTH:DH at STRENGTH:HIGH:!RC4:!MD5:!DES:!aNULL:!eNULL;
-
-        add_header Strict-Transport-Security "max-age=31536000; includeSubdomains;";
-        add_header X-Frame-Options DENY;
-        add_header X-Content-Type-Options nosniff;
-        add_header X-XSS-Protection "1; mode=block";
-
-        location / {
-            proxy_pass http://127.0.0.1:${kimchid_port};
-            proxy_set_header Host $host;
-            proxy_set_header X-Real-IP $remote_addr;
-            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
-            proxy_redirect http://127.0.0.1:${kimchid_port}/ https://$host:${proxy_ssl_port}/;
-        }
-    }
-
-    server {
-        listen ${proxy_port};
-        rewrite ^/(.*)$ https://$host:${proxy_ssl_port}/$1 redirect;
-    }
-}
diff --git a/src/nginx/wok.conf.in b/src/nginx/wok.conf.in
new file mode 100644
index 0000000..3ecbde4
--- /dev/null
+++ b/src/nginx/wok.conf.in
@@ -0,0 +1,76 @@
+# Project Kimchi
+#
+# Copyright IBM, Corp. 2014-2015
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301  USA
+
+# This is a template file to be used to generate a nginx
+# proxy config file at kimchid script.
+
+user  ${user};
+worker_processes  1;
+
+error_log  /var/log/nginx/error.log;
+
+events {
+    worker_connections  1024;
+}
+
+http {
+
+    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
+                      '$status $body_bytes_sent "$http_referer" '
+                      '"$http_user_agent" "$http_x_forwarded_for"';
+
+    access_log  /var/log/nginx/access.log  main;
+    sendfile    on;
+
+    client_max_body_size ${max_body_size}k;
+
+    # Timeout set to 10 minutes to avoid the 504 Gateway Timeout
+    # when Kimchi is processing a request.
+    proxy_connect_timeout       600;
+    proxy_send_timeout          600;
+    proxy_read_timeout          600;
+    send_timeout                600;
+
+    server {
+        listen ${proxy_ssl_port} ssl;
+
+        ssl_certificate ${cert_pem};
+        ssl_certificate_key ${cert_key};
+        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
+        ssl_ciphers ECDH at STRENGTH:DH at STRENGTH:HIGH:!RC4:!MD5:!DES:!aNULL:!eNULL;
+
+        add_header Strict-Transport-Security "max-age=31536000; includeSubdomains;";
+        add_header X-Frame-Options DENY;
+        add_header X-Content-Type-Options nosniff;
+        add_header X-XSS-Protection "1; mode=block";
+
+        location / {
+            proxy_pass http://127.0.0.1:${kimchid_port};
+            proxy_set_header Host $host;
+            proxy_set_header X-Real-IP $remote_addr;
+            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+            proxy_redirect http://127.0.0.1:${kimchid_port}/ https://$host:${proxy_ssl_port}/;
+        }
+    }
+
+    server {
+        listen ${proxy_port};
+        rewrite ^/(.*)$ https://$host:${proxy_ssl_port}/$1 redirect;
+    }
+}
diff --git a/src/wok.conf.in b/src/wok.conf.in
new file mode 100644
index 0000000..cd141f5
--- /dev/null
+++ b/src/wok.conf.in
@@ -0,0 +1,65 @@
+#
+# Configuration file for Kimchi Web Server
+#
+
+[server]
+# Hostname or IP address to listen on
+#host = 0.0.0.0
+
+# Port to listen on
+#port = 8000
+
+# If present, start an SSL-enabled server on the given port
+#ssl_port = 8001
+
+# Cherrypy server port
+#cherrypy_port = 8010
+
+# The full path to an SSL Certificate in PEM format.  If left unspecified,
+# Kimchi will generate a self-signed certificate automatically.
+#ssl_cert =
+
+# The corresponding private key in PEM format for the SSL Certificate supplied
+# above.  If left blank, Kimchi will generate a self-signed certificate.
+#ssl_key =
+
+# Running environment of the server
+#environment = production
+
+# Federation feature: register Kimchi server on openSLP and discover peers
+# in the same network. Check README-federation for more details.
+#federation = off
+
+# Max request body size in KB, default value is 4GB
+#max_body_size = 4 * 1024 * 1024
+
+# Automatically create ISO pool on server start up
+#create_iso_pool = true
+
+[logging]
+# Log directory
+#log_dir = @localstatedir@/log/kimchi
+
+# Logging level: debug, info, warning, error or critical
+#log_level = debug
+
+[display]
+# Port for websocket proxy to listen on
+#display_proxy_port = 64667
+
+[authentication]
+# Authentication method, available option: pam, ldap.
+# method = pam
+
+# If specified method to ldap, following fields need to be specified.
+# ldap server domain name used to authenticate.
+# ldap_server = "localhost"
+
+# Search tree base in ldap
+# ldap_search_base = "ou=People, dc=kimchi, dc=org"
+
+# User id filter
+# ldap_search_filter = "uid=%(username)s"
+
+# User IDs regarded as kimchi admin
+# ldap_admin_id = "foo at foo.com, bar at bar.com"
diff --git a/src/wokd.in b/src/wokd.in
new file mode 100644
index 0000000..4ea7a42
--- /dev/null
+++ b/src/wokd.in
@@ -0,0 +1,99 @@
+#!/usr/bin/env python2
+#
+# Project Kimchi
+#
+# Copyright IBM, Corp. 2013-2015
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA  02110-1301  USA
+
+import os
+import sys
+sys.path.insert(1, '@pythondir@')
+
+from optparse import OptionParser
+
+import kimchi.server
+import kimchi.config as config
+
+
+if not config.paths.installed:
+    sys.path.append(config.paths.prefix)
+
+ACCESS_LOG = "kimchi-access.log"
+ERROR_LOG = "kimchi-error.log"
+
+
+def main(options):
+    # Script must run as root or with sudo.
+    if not os.geteuid() == 0:
+        sys.exit("\nMust be root to run this script. Exiting ...\n")
+
+    host = config.config.get("server", "host")
+    port = config.config.get("server", "port")
+    ssl_port = config.config.get("server", "ssl_port")
+    cherrypy_port = config.config.get("server", "cherrypy_port")
+    runningEnv = config.config.get("server", "environment")
+    federation = config.config.get("server", "federation")
+    isopool = config.config.get("server", "create_iso_pool")
+    logDir = config.config.get("logging", "log_dir")
+    logLevel = config.config.get("logging", "log_level")
+
+    parser = OptionParser()
+    parser.add_option('--host', type="string", default=host,
+                      help="Hostname to listen on")
+    parser.add_option('--port', type="int", default=port,
+                      help="Port to listen on (default %s)" % port)
+    parser.add_option('--ssl-port', type="int", default=ssl_port,
+                      help="Port to enable SSL (default %s)" % ssl_port)
+    parser.add_option('--cherrypy_port', type="int", default=cherrypy_port,
+                      help="Cherrypy server port (default %s)" % cherrypy_port)
+    parser.add_option('--log-level', default=logLevel,
+                      help="Logging level")
+    parser.add_option('--access-log',
+                      default=os.path.join(logDir, ACCESS_LOG),
+                      help="Access log file")
+    parser.add_option('--error-log',
+                      default=os.path.join(logDir, ERROR_LOG),
+                      help="Error log file")
+    parser.add_option('--environment', default=runningEnv,
+                      help="Running environment of kimchi server")
+    parser.add_option('--federation', default=federation,
+                      help="Register and discover Kimchi peers in the same "
+                           "network using openSLP. Check README-federation for"
+                           " more details.")
+    parser.add_option('--create_iso_pool', default=isopool,
+                      help="Automatically create ISO pool on server start up.")
+    parser.add_option('--test', action='store_true',
+                      help="Run server in mock model")
+    (options, args) = parser.parse_args()
+
+    # Update config.config with the command line values
+    # So the whole application will have access to accurate values
+    for sec in config.config.sections():
+        for item in config.config.options(sec):
+            if hasattr(options, item):
+                config.config.set(sec, item, str(getattr(options, item)))
+
+    # Add non-option arguments
+    setattr(options, 'ssl_cert', config.config.get('server', 'ssl_cert'))
+    setattr(options, 'ssl_key', config.config.get('server', 'ssl_key'))
+    setattr(options, 'max_body_size',
+            config.config.get('server', 'max_body_size'))
+
+    kimchi.server.main(options)
+
+if __name__ == '__main__':
+    sys.exit(main(sys.argv[1:]))
diff --git a/ui/js/src/kimchi.cookie.js b/ui/js/src/kimchi.cookie.js
deleted file mode 100644
index f1b52db..0000000
--- a/ui/js/src/kimchi.cookie.js
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Project Kimchi
- *
- * Copyright IBM, Corp. 2013-2014
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-kimchi.cookie = {
-    set: function(key, value, expireDays) {
-        value = encodeURIComponent(value);
-        value += '; secure'
-        if (expireDays) {
-            var expireDate = new Date();
-            expireDate.setDate(expireDate.getDate() + expireDays);
-            value += '; expires=' + expireDate.toUTCString();
-        }
-        document.cookie = key + '=' + value;
-    },
-
-    get: function(key) {
-        var cookieRe = new RegExp(';?\\\s*(' + key + ')=(\s*[^;]*);?', 'g');
-        var match = cookieRe.exec(document.cookie);
-        return match ? decodeURIComponent(match[2]) : undefined;
-    },
-
-    remove: function(key) {
-        var utcString = new Date().toUTCString();
-        document.cookie = key + '=; expires=' + utcString;
-    }
-};
diff --git a/ui/js/src/kimchi.grid.js b/ui/js/src/kimchi.grid.js
deleted file mode 100644
index 6fed753..0000000
--- a/ui/js/src/kimchi.grid.js
+++ /dev/null
@@ -1,528 +0,0 @@
-/*
- * Project Kimchi
- *
- * Copyright IBM, Corp. 2013-2015
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-kimchi.widget.Grid = function(opts) {
-    this.opts = $.extend({}, this.opts, opts);
-    this.createDOM();
-    this.reload();
-};
-
-kimchi.widget.Grid.prototype = (function() {
-    var htmlStr = [
-        '<div id="{id}" class="grid">',
-            '<div class="grid-content">',
-                '<div class="grid-header">',
-                    '<div class="grid-frozen-header-view">',
-                        '<table class="grid-frozen-header-container">',
-                        '</table>',
-                    '</div>',
-                    '<div class="grid-header-view">',
-                        '<div class="grid-header-wrapper">',
-                            '<table class="grid-header-container">',
-                            '</table>',
-                        '</div>',
-                    '</div>',
-                '</div>',
-                '<div class="grid-body">',
-                    '<div class="grid-frozen-body-view">',
-                        '<div class="grid-frozen-body-wrapper">',
-                            '<table class="grid-frozen-body-container">',
-                            '</table>',
-                        '</div>',
-                    '</div>',
-                    '<div class="grid-body-view">',
-                        '<div class="grid-body-wrapper">',
-                            '<table class="grid-body-container">',
-                            '</table>',
-                        '</div>',
-                    '</div>',
-                '</div>',
-                '<div class="grid-resizer-leftmost hidden"></div>',
-                '<div class="grid-resizer hidden"></div>',
-            '</div>',
-            '<div class="grid-footer"></div>',
-            '<div class="grid-mask hidden">',
-                '<div class="grid-loading">',
-                    '<div class="grid-loading-icon"></div>',
-                    '<div class="grid-loading-text">',
-                        '{loading}',
-                    '</div>',
-                '</div>',
-            '</div>',
-            '<div class="grid-message hidden">',
-                '<div class="grid-message-text">',
-                    '{message}',
-                    '<button class="retry-button btn-small">',
-                        '{buttonLabel}',
-                    '</button>',
-                '</div>',
-                '<div class="detailed-title">',
-                    '{detailedLabel}',
-                '</div>',
-                '<div class="detailed-text"></div>',
-            '</div>',
-        '</div>'
-    ].join('');
-
-    var CONTAINER_NORMAL = 0, CONTAINER_FROZEN = 1;
-
-    var setupHeaders = function(header, body, fields) {
-        var colGroup = $('<colgroup></colgroup>').appendTo(header);
-        var headerHeader = $('<thead></thead>');
-        var headerRow = $('<tr></tr>').appendTo(headerHeader);
-        $.each(fields || [], function(i, field) {
-            $('<col class="' +
-                field['class'] +
-            '"/>')
-                .appendTo(colGroup);
-            $('<th><div class="cell-text-wrapper">' +
-                field['label'] +
-            '</div></th>').appendTo(headerRow);
-        });
-        headerHeader.appendTo(header);
-
-        var totalWidth = 0;
-        $('col', colGroup).each(function(index, col) {
-            var width = $(col).width();
-            totalWidth += width;
-            $(col).css('width', width + 'px');
-        });
-        $(body).append(colGroup.clone());
-        return totalWidth;
-    };
-
-    var getValue = function(name, obj) {
-        var result=undefined;
-        if(!Array.isArray(name)) {
-            name=name.parseKey();
-        }
-        if(name.length!=0) {
-            var tmpName=name.shift();
-            if(obj[tmpName]!=undefined) {
-                    result=obj[tmpName];
-            }
-            if(name.length!=0) {
-                    result=getValue(name,obj[tmpName]);
-            }
-        }
-        return(result);
-    };
-
-    var fillBody = function(container, fields) {
-        var data = this.data;
-        var tbody = ($('tbody', container).length && $('tbody', container))
-            || $('<tbody></tbody>').appendTo(container);
-        tbody.empty();
-        $.each(data, function(i, row) {
-            var rowNode = $('<tr></tr>').appendTo(tbody);
-            $.each(fields, function(fi, field) {
-                var value = getValue(field['name'], row);
-                $('<td><div class="cell-text-wrapper"' +
-                    (field['makeTitle'] === true
-                        ? ' title="' + value + '"'
-                        : ''
-                    ) + '>' + value.toString() + '</div></td>'
-                ).appendTo(rowNode);
-            });
-        });
-    };
-
-    var fixTableLayout = function(style) {
-        $.each([
-            this.frozenHeaderContainer,
-            this.headerContainer,
-            this.frozenBodyContainer,
-            this.bodyContainer
-        ], function(i, tableNode) {
-            $(tableNode).css('table-layout', style || 'fixed');
-        });
-    };
-
-    var initResizing = function(event) {
-        var resizer = event.data.resizer;
-        var pageX = event.pageX;
-        var tailPos = $(this).width() + $(this).offset()['left'];
-        var atResizer = Math.abs(pageX - tailPos) <= 2;
-        var isResizing = !$(resizer).hasClass('hidden');
-        $('body')[(atResizer || isResizing)
-            ? 'addClass'
-            : 'removeClass'
-        ]('resizing');
-    };
-
-    var clearResizing = function(event) {
-        $(event.data.resizer).hasClass('hidden') &&
-            $('body').removeClass('resizing');
-    };
-
-    var stylingRow = function(row, className, add) {
-        var index = $(row).index() + 1;
-        $('tr', this.frozenBodyContainer)
-            .removeClass(className);
-        $('tr', this.bodyContainer)
-            .removeClass(className);
-
-        if(add === false) {
-            return;
-        }
-
-        $('tr:nth-child(' + index + ')', this.frozenBodyContainer)
-            .addClass(className);
-        $('tr:nth-child(' + index + ')', this.bodyContainer)
-            .addClass(className);
-    };
-
-    var setBodyListeners = function() {
-        if(this['opts']['rowSelection'] != 'disabled') {
-            $('tr', this.gridBody).on('mouseover', {
-                grid: this
-            }, function(event) {
-                if (! $(this).hasClass('no-hover'))
-                    stylingRow.call(event.data.grid, this, 'hover');
-            });
-
-            $('tr', this.gridBody).on('mouseout', {
-                grid: this
-            }, function(event) {
-                stylingRow.call(event.data.grid, this, 'hover', false);
-            });
-
-            $('tr', this.gridBody).on('click', {
-                grid: this
-            }, function(event) {
-                var grid = event.data.grid;
-                grid.selectedIndex = $(this).index();
-                stylingRow.call(grid, this, 'selected');
-                grid['opts']['onRowSelected'] && grid['opts']['onRowSelected']();
-            });
-        }
-
-        $('.grid-body-view', this.domNode).on('scroll', {
-            grid: this
-        }, function(event) {
-            var grid = event.data.grid;
-            $('.grid-header .grid-header-view', grid.domNode)
-                .prop('scrollLeft', this.scrollLeft);
-            $('.grid-body .grid-frozen-body-view', grid.domNode)
-                .prop('scrollTop', this.scrollTop);
-        });
-    };
-
-    var setData = function(data) {
-        this.data = data;
-        fillBody.call(this, this.frozenBodyContainer, this['opts']['frozenFields']);
-        fillBody.call(this, this.bodyContainer, this['opts']['fields']);
-        setBodyListeners.call(this);
-    };
-
-    var getSelected = function() {
-        return this.selectedIndex >= 0
-            ? this.data[this.selectedIndex]
-            : null;
-    };
-
-    var startResizing = function(container, event) {
-        var grid = event.data.grid;
-        kimchi.widget.Grid.beingResized = grid;
-        if(!($('body').hasClass('resizing')
-                && $(grid.resizer).hasClass('hidden'))) {
-            return;
-        }
-
-        grid.columnBeingResized = container;
-        var pageX = event.pageX;
-        var gridOffsetX = grid.domNode.offset()['left'];
-        var leftmostOffsetX = $(container).offset()['left'] - gridOffsetX;
-        var left = pageX - gridOffsetX;
-        var contentHeight = $('.grid-content', grid.domNode).height();
-        $(grid.resizerLeftmost).css({
-            left: leftmostOffsetX + 'px',
-            height: contentHeight + 'px'
-        });
-        $(grid.resizer).css({
-            left: left + 'px',
-            height: contentHeight + 'px'
-        });
-        $(grid.resizerLeftmost).removeClass('hidden');
-        $(grid.resizer).removeClass('hidden');
-        event.preventDefault();
-    };
-
-    var endResizing = function(event) {
-        var grid = kimchi.widget.Grid.beingResized;
-        if(!$('body').hasClass('resizing')) {
-            return;
-        }
-        $(grid.resizerLeftmost).addClass('hidden');
-        $(grid.resizer).addClass('hidden');
-        $('body').removeClass('resizing');
-        var leftmostOffset = $(grid.columnBeingResized).offset()['left'];
-        var left = event.pageX;
-        if(leftmostOffset > left) {
-            return;
-        }
-        resizeColumnWidth.call(
-            grid,
-            $(grid.columnBeingResized).index(),
-            left - leftmostOffset
-        );
-        fixTableLayout.call(grid);
-        grid.columnBeingResized = null;
-        kimchi.widget.Grid.beingResized = null;
-    };
-
-    var resizeColumnWidth = function(index, width) {
-        var width = Math.ceil(width);
-        var widthArray = [];
-        var totalWidth = 0;
-        var header = this.headerContainer;
-        var body = this.bodyContainer;
-        if(this.containerBeingResized === CONTAINER_FROZEN) {
-            header = this.frozenHeaderContainer;
-            body = this.frozenBodyContainer;
-        }
-        $('col', header).each(function(i, colNode) {
-            var w = index === i ? width : $(colNode).width();
-            widthArray.push(w);
-            totalWidth += w;
-        });
-        $.each([header, body], function(i, container) {
-            container.css({
-                'table-layout': 'fixed',
-                width: totalWidth + 'px'
-            });
-            $('col:nth-child(' + (index + 1) + ')', container).css({
-                width: width + 'px'
-            });
-        });
-
-        if(this.containerBeingResized === CONTAINER_FROZEN) {
-            var headerView = $('.grid-header-view', this.domNode);
-            var bodyView = $('.grid-body-view', this.domNode);
-            $.each([headerView, bodyView], function(i, view) {
-                view.css({
-                    left: totalWidth + 'px'
-                });
-            });
-        }
-    };
-
-    var positionResizer = function(event) {
-        var grid = event.data.grid;
-        if($(grid.resizer).hasClass('hidden')) {
-            return;
-        }
-
-        var pageX = event.pageX;
-        var gridOffsetX = $(grid.domNode).offset()['left'];
-        var leftMost = $(grid.resizerLeftmost).position()['left'];
-        var offsetX = pageX - gridOffsetX;
-        offsetX = offsetX >= leftMost ? offsetX : leftMost;
-        $(grid.resizer).css('left', offsetX + 'px');
-    };
-
-    var showMessage = function(msg) {
-        $('.detailed-text', this.messageNode).text(msg);
-        $(this.messageNode).removeClass('hidden');
-    };
-
-    var hideMessage = function() {
-        $(this.messageNode).addClass('hidden');
-    };
-
-    var reload = function() {
-        var data = this['opts']['data'];
-        if(!data) {
-            return;
-        }
-
-        $(this.messageNode).addClass('hidden');
-
-        if($.isArray(data)) {
-            return this.setData(data);
-        }
-
-        if($.isFunction(data)) {
-            var loadData = data;
-            $(this.maskNode).removeClass('hidden');
-            loadData($.proxy(function(data) {
-                this.setData(data);
-                $(this.maskNode).addClass('hidden');
-            }, this));
-        }
-    };
-
-    var destroy = function() {
-        $('body').off('mousemove.grid#' + this['opts']['id'], positionResizer);
-        $('body').off('mouseup.grid#' + this['opts']['id'], endResizing);
-    };
-
-    var createDOM = function() {
-        var containerID = this['opts']['container'];
-        var container = $('#' + containerID);
-        var gridID = this['opts']['id'];
-        var rowSelection = this['opts']['rowSelection'] || 'single';
-        var domNode = $(kimchi.substitute(htmlStr, {
-            id: gridID,
-            loading: i18n['KCHGRD6001M'],
-            message: i18n['KCHGRD6002M'],
-            buttonLabel: i18n['KCHGRD6003M'],
-            detailedLabel: i18n['KCHGRD6004']
-        })).appendTo(container);
-        this.domNode = domNode;
-
-        var height = domNode.height();
-        var width = domNode.width();
-
-        var title = this['opts']['title'];
-        var titleNode = null;
-        if(title) {
-            titleNode = $('<div class="grid-caption">' + title + '</div>')
-                .prependTo(domNode);
-        }
-
-        var toolbarButtons = this['opts']['toolbarButtons'];
-        var toolbarNode = null;
-        if(toolbarButtons) {
-            toolbarNode = $('<div class="grid-toolbar"></div>');
-            if(titleNode) {
-                titleNode.after(toolbarNode);
-            }
-            else {
-                toolbarNode.prependTo(domNode);
-            }
-
-            $.each(toolbarButtons, function(i, button) {
-                var btnHTML = [
-                    '<button',
-                        button['id'] ? (' id="' + button['id'] + '"') : '',
-                        ' class="grid-toolbar-button',
-                            button['class'] ? (' ' + button['class']) : '',
-                            '"',
-                            button['disabled'] === true ? ' disabled' : '',
-                            '>',
-                            button['label'],
-                    '</button>'
-                ].join('');
-                var btnNode = $(btnHTML).appendTo(toolbarNode);
-                button['onClick'] &&
-                    btnNode.on('click', button['onClick']);
-            });
-        }
-
-        var frozenHeaderContainer = $('.grid-frozen-header-container', domNode);
-        var frozenBodyContainer = $('.grid-frozen-body-container', domNode);
-        var frozenWidth = setupHeaders(
-                frozenHeaderContainer,
-                frozenBodyContainer,
-                this['opts']['frozenFields']
-        );
-        this.frozenHeaderContainer = frozenHeaderContainer;
-        this.frozenBodyContainer = frozenBodyContainer;
-
-        var headerContainer = $('.grid-header-container', domNode);
-        var bodyContainer = $('.grid-body-container', domNode);
-        setupHeaders(headerContainer, bodyContainer, this['opts']['fields']);
-        this.headerContainer = headerContainer;
-        this.bodyContainer = bodyContainer;
-
-        fixTableLayout.call(this, 'auto');
-
-        var gridContentNode = $('.grid-content', domNode);
-        var captionHeight = titleNode && $(titleNode).height() || 0;
-        var toolbarHeight = toolbarNode && $(toolbarNode).height() || 0;
-        gridContentNode.css('top', (captionHeight + toolbarHeight) + 'px');
-
-        var maskNode = $('.grid-mask', domNode);
-        maskNode.css('top', captionHeight + 'px');
-        this.maskNode = maskNode;
-
-        var messageNode = $('.grid-message', domNode);
-        messageNode.css('top', captionHeight + 'px');
-        this.messageNode = messageNode;
-
-        var headerView = $('.grid-header-view', domNode);
-        var bodyView = $('.grid-body-view', domNode);
-        headerView.css('left', (frozenWidth) + 'px');
-        bodyView.css('left', (frozenWidth) + 'px');
-
-        var bodyWidth = width - frozenWidth;
-        headerContainer.css('width', bodyWidth + 'px');
-        bodyContainer.css('width', bodyWidth + 'px');
-
-        fixTableLayout.call(this);
-
-        var gridBody = $('.grid-body', domNode);
-        this.gridBody = gridBody;
-        this.resizerLeftmost = $('.grid-resizer-leftmost', domNode);
-        this.resizer = $('.grid-resizer', domNode);
-        var gridHeader = $('.grid-header', domNode);
-        $('th', gridHeader).on('mouseover mousemove', {
-            resizer: this.resizer
-        }, initResizing);
-
-        $('th', gridHeader).on('mouseout', {
-            resizer: this.resizer
-        }, clearResizing);
-
-        this.containerBeingResized = CONTAINER_NORMAL;
-        $('th', frozenHeaderContainer).on('mousedown', {
-            grid: this
-        }, function(event) {
-                event.data.grid.containerBeingResized = CONTAINER_FROZEN;
-                startResizing(this, event);
-        });
-        $('th', headerContainer).on('mousedown', {
-            grid: this
-        }, function(event) {
-                event.data.grid.containerBeingResized = CONTAINER_NORMAL;
-                startResizing(this, event);
-        });
-
-        $('body').on('mousemove.grid#' + this['opts']['id'], {
-            grid: this
-        }, positionResizer);
-        $('body').on('mouseup.grid#' + this['opts']['id'], endResizing);
-
-        var data = this['opts']['data'];
-
-        $('.retry-button', domNode).on('click', {
-            grid: this
-        }, function(event) {
-            event.data.grid.reload();
-        });
-    };
-
-    return {
-        opts: {
-            container: null,
-            id: null,
-            rowSelection: 'single',
-            onRowSelected: null,
-            title: null,
-            toolbarButtons: null,
-            frozenFields: null,
-            fields: null
-        },
-        createDOM: createDOM,
-        setData: setData,
-        getSelected: getSelected,
-        reload: reload,
-        destroy: destroy,
-        showMessage: showMessage
-    };
-})();
diff --git a/ui/js/src/kimchi.lang.js b/ui/js/src/kimchi.lang.js
deleted file mode 100644
index 1d2de4e..0000000
--- a/ui/js/src/kimchi.lang.js
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Project Kimchi
- *
- * Copyright IBM, Corp. 2013-2014
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-kimchi.lang = {
-    all: function() {
-        return {
-          'en_US': 'English (US)',
-          'zh_CN': '中文(简体)',
-          'pt_BR': 'Português (Brasil)',
-          'de_DE': 'Deutsch (Deutschland)',
-          'es_ES': 'Español (España)',
-          'fr_FR': 'Français (France)',
-          'it_IT': 'Italiano (Italia)',
-          'ja_JP': '日本語 (日本)',
-          'ko_KR': '한국어 (대한민국)',
-          'ru_RU': 'Русский (Россия)',
-          'zh_TW': '中文(繁體)'
-        };
-    },
-
-    /**
-     * Language is determined by the following sequence:
-     * 1) Cookie setting; or if not set ->
-     * 2) HTML DOM lang attribute; or if not set ->
-     * 3) DEFAULT (en_US).
-     */
-    get: function() {
-        return kimchi.cookie.get('kimchiLang') ||
-            $('html').prop('lang') ||
-            'en_US';
-    },
-
-    set: function(lang) {
-        kimchi.cookie.set('kimchiLang', lang, 365);
-    }
-};
diff --git a/ui/js/src/kimchi.login.js b/ui/js/src/kimchi.login.js
deleted file mode 100644
index c737d26..0000000
--- a/ui/js/src/kimchi.login.js
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Project Kimchi
- *
- * Copyright IBM, Corp. 2014-2015
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-kimchi.login_main = function() {
-
-    var selectedLanguage = kimchi.lang.get();
-    $('#userLang').val(selectedLanguage);
-
-    $('#userLang').on('change', function() {
-        kimchi.lang.set($(this).val());
-        location.reload();
-    });
-
-    var query = window.location.search;
-    var error = /.*error=(.*?)(&|$)/g.exec(query);
-    if (error && error[1] == "sessionTimeout") {
-        $("#messSession").show();
-    }
-
-    var userNameBox = $('#username');
-    var passwordBox = $('#password');
-    var loginButton = $('#btn-login');
-
-    var login = function(event) {
-        $("#login").hide();
-        $("#logging").show();
-
-        var userName = userNameBox.val();
-        userName && kimchi.user.setUserName(userName);
-        var settings = {
-            username: userName,
-            password: passwordBox.val()
-        };
-
-        kimchi.login(settings, function(data) {
-            var query = window.location.search;
-            var next  = /.*next=(.*?)(&|$)/g.exec(query);
-            if (next) {
-                var next_url = decodeURIComponent(next[1]);
-            }
-            else {
-                var lastPage = kimchi.cookie.get('lastPage');
-                var next_url = lastPage ? lastPage.replace(/\"/g,'') : "/";
-            }
-            kimchi.cookie.set('roles',JSON.stringify(data.roles));
-            window.location.replace(window.location.pathname.replace(/\/+login.html/, '') + next_url)
-        }, function() {
-            $("#messUserPass").show();
-            $("#messSession").hide();
-            $("#logging").hide();
-            $("#login").show();
-        });
-
-        return false;
-    };
-
-    $('#btn-login').bind('click', login);
-};
diff --git a/ui/js/src/kimchi.main.js b/ui/js/src/kimchi.main.js
deleted file mode 100644
index 0d4ad43..0000000
--- a/ui/js/src/kimchi.main.js
+++ /dev/null
@@ -1,366 +0,0 @@
-/*
- * Project Kimchi
- *
- * Copyright IBM, Corp. 2013-2015
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-kimchi.tabMode = {};
-
-kimchi.capabilities = undefined;
-kimchi.getCapabilities(function(result) {
-    kimchi.capabilities = result;
-
-    if(kimchi.capabilities.federation=="on")
-        $('#peers').removeClass('hide-content');
-}, function() {
-    kimchi.capabilities = {};
-});
-
-kimchi.main = function() {
-    kimchi.isLoggingOut = false;
-    kimchi.popable();
-
-    var genTabs = function(tabs) {
-        var tabsHtml = [];
-        $(tabs).each(function(i, tab) {
-            var title = tab['title'];
-            var path = tab['path'];
-            var mode = tab['mode'];
-            if (mode != 'none') {
-                var helpPath = kimchi.checkHelpFile(path);
-                var disableHelp = (helpPath.length == 0 ? "disableHelp" : helpPath);
-                tabsHtml.push(
-                    '<li>',
-                        '<a class="item ', disableHelp,'" href="', path, '">',
-                            title,
-                        '</a>',
-                        '<input id="helpPathId" name="helpPath" value="' + helpPath + '" type="hidden"/>',
-                    '</li>'
-                );
-            }
-        });
-        return tabsHtml.join('');
-    };
-
-    var parseTabs = function(xmlData) {
-        var tabs = [];
-        $(xmlData).find('tab').each(function() {
-            var $tab = $(this);
-            var titleKey = $tab.find('title').text();
-            var title = i18n[titleKey] ? i18n[titleKey] : titleKey;
-            var path = $tab.find('path').text();
-            var roles = kimchi.cookie.get('roles');
-            if (roles) {
-                var role = JSON.parse(roles)[titleKey.toLowerCase()];
-                var mode = $tab.find('[role="' + role + '"]').attr('mode');
-                kimchi.tabMode[titleKey.toLowerCase()] = mode;
-                tabs.push({
-                    title: title,
-                    path: path,
-                    mode: mode
-                });
-            } else {
-                document.location.href = 'login.html';
-            }
-        });
-
-        return tabs;
-    };
-
-    var retrieveTabs = function(url) {
-        var tabs;
-        $.ajax({
-            url : url,
-            async : false,
-            success : function(xmlData) {
-                tabs = parseTabs(xmlData);
-            }
-        });
-        return tabs;
-    };
-
-    var tabConfigUrl = 'config/ui/tabs.xml';
-    var pluginConfigUrl = 'plugins/{plugin}/ui/config/tab-ext.xml';
-    var pluginI18nUrl = 'plugins/{plugin}/i18n.json';
-    var DEFAULT_HASH;
-    var buildTabs = function(callback) {
-        var tabs = retrieveTabs(tabConfigUrl);
-        kimchi.listPlugins(function(plugins) {
-            $(plugins).each(function(i, p) {
-                var url = kimchi.substitute(pluginConfigUrl, {
-                    plugin: p
-                });
-                var i18nUrl = kimchi.substitute(pluginI18nUrl, {
-                    plugin: p
-                });
-                kimchi.getI18n(function(i18nObj){ $.extend(i18n, i18nObj)},
-                               function(i18nObj){ //i18n is not define by plugin
-                               }, i18nUrl, true);
-                tabs.push.apply(tabs, retrieveTabs(url));
-            });
-
-            var defaultTab = tabs[1]
-
-            var defaultTabPath = defaultTab && defaultTab['path']
-            // Remove file extension from 'defaultTabPath'
-            DEFAULT_HASH = defaultTabPath &&
-                defaultTabPath.substring(0, defaultTabPath.lastIndexOf('.'))
-
-            $('#nav-menu').append(genTabs(tabs));
-
-            callback && callback();
-        }, function(data) {
-           kimchi.message.error(data.responseJSON.reason);
-        }, true);
-    };
-
-    var onLanguageChanged = function(lang) {
-        kimchi.lang.set(lang);
-        location.reload();
-    };
-
-    /**
-     * Do the following setup:
-     *   1) Clear any timing events.
-     *   2) If the given URL is invalid (i.e., no corresponding href value in
-     *      page tab list.), then clear location.href and inform the user;
-     *
-     *      Or else:
-     *      Move the page tab indicator to the right position;
-     *      Load the page content via Ajax.
-     */
-    var onKimchiRedirect = function(url) {
-        /*
-         * Find the corresponding tab node and animate the arrow indicator to
-         * point to the tab. If nothing found, inform user the URL is invalid
-         * and clear location.hash to jump to home page.
-         */
-        var tab = $('#nav-menu a[href="' + url + '"]');
-        if (tab.length === 0) {
-            location.hash = '';
-            return;
-        }
-
-        // Animate arrow indicator.
-        var left = $(tab).parent().position().left;
-        var width = $(tab).parent().width();
-        $('.menu-arrow').stop().animate({
-            left : left + width / 2 - 10
-        });
-
-        // Update the visual style of tabs; focus the selected one.
-        $('#nav-menu a').removeClass('current');
-        $(tab).addClass('current');
-        $(tab).focus();
-        // Disable Help button according to selected tab
-        if ($(tab).hasClass("disableHelp")) {
-            $('#btn-help').css('cursor', "not-allowed");
-            $('#btn-help').off("click");
-        }
-        else {
-            $('#btn-help').css('cursor', "pointer");
-            $('#btn-help').on("click", kimchi.openHelp);
-        }
-        // Load page content.
-        loadPage(url);
-    };
-
-    /**
-     * Use Ajax to dynamically load a page without a page refreshing. Handle
-     * arrow cursor animation, DOM node focus, and page content rendering.
-     */
-    var loadPage = function(url) {
-        // Get the page content through Ajax and render it.
-        url && $('#main').load(url, function(responseText, textStatus, jqXHR) {
-            if (jqXHR['status'] === 401 || jqXHR['status'] === 303) {
-                var isSessionTimeout = jqXHR['responseText'].indexOf("sessionTimeout")!=-1;
-                document.location.href= isSessionTimeout ? 'login.html?error=sessionTimeout' : 'login.html';
-                return;
-            }
-        });
-    };
-
-    /*
-     * Update page content.
-     * 1) If user types in the main page URL without hash, then we apply the
-     *    default hash. e.g., http://kimchi.company.com:8000;
-     * 2) If user types a URL with hash, then we publish an "redirect" event
-     *    to load the page, e.g., http://kimchi.company.com:8000/#templates.
-     */
-    var updatePage = function() {
-        // Parse hash string.
-        var hashString = (location.hash && location.hash.substr(1));
-        /*
-         * If hash string is empty, then apply the default one;
-         * or else, publish an "redirect" event to load the page.
-         */
-        if (!hashString) {
-            location.hash = DEFAULT_HASH;
-        }
-        else {
-            kimchi.topic('redirect').publish(hashString + '.html');
-        }
-    };
-
-    /**
-     * Register listeners including:
-     * 1) Kimchi redirect event
-     * 2) hashchange event
-     * 3) Tab list click event
-     * 4) Log-out button click event
-     * 5) About button click event
-     * 6) Help button click event
-     * 7) Peers button click event
-     */
-    var searchingPeers = false;
-    var initListeners = function() {
-        kimchi.topic('languageChanged').subscribe(onLanguageChanged);
-        kimchi.topic('redirect').subscribe(onKimchiRedirect);
-
-        /*
-         * If hash value is changed, then we know the user is intended to load
-         * another page.
-         */
-        window.onhashchange = updatePage;
-
-        /*
-         * Register click listener of tabs. Replace the default reloading page
-         * behavior of <a> with Ajax loading.
-         */
-        $('#nav-menu').on('click', 'a.item', function(event) {
-            var href = $(this).attr('href');
-            // Remove file extension from 'href'
-            location.hash = href.substring(0,href.lastIndexOf('.'))
-            /*
-             * We use the HTML file name for hash, like: guests for guests.html
-             * and templates for templates.html.
-             *     Retrieve hash value from the given URL and update location's
-             * hash part. It has 2 effects: one is to publish Kimchi "redirect"
-             * event to trigger listener, the other is to put an entry into the
-             * browser's address history to make pages be bookmark-able.
-             */
-            // Prevent <a> causing browser redirecting to other page.
-            event.preventDefault();
-        });
-
-        // Perform logging out via Ajax request.
-        $('#btn-logout').on('click', function() {
-            kimchi.logout(function() {
-                kimchi.isLoggingOut = true;
-                document.location.href = "login.html";
-            }, function(err) {
-                kimchi.message.error(err.responseJSON.reason);
-            });
-        });
-
-        // Set handler for about button
-        $('#btn-about').on('click', function(event) {
-            kimchi.window.open({"content": $('#about-tmpl').html()});
-            event.preventDefault();
-            });
-
-        // Set handler for help button
-        $('#btn-help').on('click', kimchi.openHelp);
-
-        // Set handler to peers drop down
-        $('#peers').on('click', function() {
-
-            // Check if any request is in progress
-            if ($('.popover', '#peers').is(':visible') || searchingPeers == true)
-                return
-
-            $('#search-peers').show();
-            $('#no-peers').addClass('hide-content');
-            $('a', '#peers').remove();
-
-            searchingPeers = true;
-
-            kimchi.getPeers(function(data){
-                $('#search-peers').hide();
-                if (data.length == 0)
-                    $('#no-peers').removeClass('hide-content');
-
-                for(var i=0; i<data.length; i++){
-                    $('.dropdown', '#peers').append("<a href='"+data[i]+"' target='_blank'>"+data[i]+"</a>");
-                }
-                searchingPeers = false;
-            });
-        });
-    };
-
-    var initUI = function() {
-        $(document).bind('ajaxError', function(event, jqXHR, ajaxSettings, errorThrown) {
-            if (!ajaxSettings['kimchi']) {
-                return;
-            }
-
-            if (jqXHR['status'] === 401) {
-                var isSessionTimeout = jqXHR['responseText'].indexOf("sessionTimeout")!=-1;
-                kimchi.user.showUser(false);
-                kimchi.previousAjax = ajaxSettings;
-                $(".empty-when-logged-off").empty();
-                $(".remove-when-logged-off").remove();
-                document.location.href= isSessionTimeout ? 'login.html?error=sessionTimeout' : 'login.html';
-                return;
-            }
-            else if((jqXHR['status'] == 0) && ("error"==jqXHR.statusText) && !kimchi.isLoggingOut) {
-                kimchi.message.error(i18n['KCHAPI6007E'].replace("%1", jqXHR.state()));
-            }
-            if(ajaxSettings['originalError']) {
-                ajaxSettings['originalError'](jqXHR, jqXHR.statusText, errorThrown);
-            }
-        });
-
-        kimchi.user.showUser(true);
-        initListeners();
-        updatePage();
-    };
-
-    // Load i18n translation strings first and then render the page.
-    kimchi.getI18n(
-        function(i18nStrings){ //success
-            i18n = i18nStrings;
-            buildTabs(initUI);
-            },
-        function(data){ //error
-            kimchi.message.error(data.responseJSON.reason);
-            });
-};
-
-
-kimchi.checkHelpFile = function(path) {
-    var lang = kimchi.lang.get();
-    var url = ""
-    // Find help page path according to tab name
-    if (/^tabs/.test(path))
-        url = path.replace("tabs", "help/" + lang);
-    else if (/^plugins/.test(path))
-        url = path.slice(0, path.lastIndexOf('/')) + "help/" + lang + path.slice(path.lastIndexOf('/'));
-    // Checking if help page exist.
-    $.ajax({
-        url: url,
-        async: false,
-        error: function() { url = ""; },
-        success: function() { }
-    });
-    return url;
-};
-
-
-kimchi.openHelp = function(e) {
-    var tab = $('#nav-menu a.current');
-    var url = $(tab).parent().find("input[name='helpPath']").val();
-    window.open(url, "Kimchi Help");
-    e.preventDefault();
-};
diff --git a/ui/js/src/kimchi.message.js b/ui/js/src/kimchi.message.js
deleted file mode 100644
index 241626f..0000000
--- a/ui/js/src/kimchi.message.js
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Project Kimchi
- *
- * Copyright IBM, Corp. 2013-2014
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-kimchi.message = function(msg, level, node) {
-    var container = node || $('#messageField');
-    if ($(container).size() < 1) {
-        container = $('<div id="messageField"/>').appendTo(document.body);
-    }
-    var message = '<div class="message ' + (level || '') + '" style="display: none;">';
-    if(!node) {
-        message += '<div class="close">X</div>';
-    }
-    message += '<div class="content">' + msg + '</div>';
-    message += '</div>';
-    var $message = $(message);
-    $(container).append($message);
-    $message.fadeIn(100);
-
-    setTimeout(function() {
-        $message.fadeOut(2000, function() {
-            $(this).remove();
-        });
-    }, 4000);
-
-    $(container).on("click", ".close", function(e) {
-        $(this).parent().fadeOut(200, function() {
-            $(this).remove();
-        });
-    });
-};
-
-/**
- * A public function of confirm box.
- *
- * @param msg
- *            type:[object]
- * @param msg.title
- *            The title of the confirm box.
- * @param msg.content
- *            The main text of the confirm box.
- * @param msg.confirm
- *            The text of the confirm button.
- * @param msg.cancel
- *            the text of the cancel button.
- * @param confirmCallback
- *            the callback function of click the confirm button.
- * @param cancelCallback
- *            The callback function of click the cancel and X button.
- */
-kimchi.confirm = function(settings, confirmCallback, cancelCallback) {
-    if ($('#confirmbox-container ').size() < 1) {
-        $(document.body).append('<div id="confirmbox-container" class="bgmask"></div>');
-    }
-    var confirmboxHtml = '<div class="confirmbox">';
-    confirmboxHtml += '<header>';
-    confirmboxHtml += '<h4 class="title">' + (settings.title || '') + '</h4>';
-    confirmboxHtml += '<div class="close cancel">X</div>';
-    confirmboxHtml += '</header>';
-    confirmboxHtml += '<div class="content">';
-    confirmboxHtml += settings.content + '</div>';
-    confirmboxHtml += '<footer>';
-    confirmboxHtml += '<div class="btn-group">';
-    confirmboxHtml += '<button id="button-confirm" class="btn-small"><span class="text">' + (settings.confirm || i18n['KCHAPI6004M']) + '</span></button>';
-    confirmboxHtml += '<button id="button-cancel" class="btn-small cancel"><span class="text">' + (settings.cancel || i18n['KCHAPI6003M']) + '</span></button>';
-    confirmboxHtml += '</div>';
-    confirmboxHtml += '</footer>';
-    confirmboxHtml += '</div>';
-    var confirmboxNode = $(confirmboxHtml);
-    $('#confirmbox-container').append(confirmboxNode);
-    confirmboxNode.fadeIn();
-
-    $('#confirmbox-container').on("click", "#button-confirm", function(e) {
-        if (confirmCallback) {
-            confirmCallback();
-        }
-        confirmboxNode.fadeOut(1, function() {
-            $('#confirmbox-container').remove();
-        });
-    });
-    $('#confirmbox-container').on("click", ".cancel", function(e) {
-        if (cancelCallback) {
-            cancelCallback();
-        }
-        confirmboxNode.fadeOut(1, function() {
-            $('#confirmbox-container').remove();
-        });
-    });
-};
-
-kimchi.message.warn = function(msg, node) {
-    kimchi.message(msg, 'warn', node);
-};
-kimchi.message.error = function(msg, node) {
-    kimchi.message(msg, 'error', node);
-};
-kimchi.message.error.code = function(code) {
-    msg = code + ": " + i18n[code]
-    kimchi.message(msg, 'error');
-};
-kimchi.message.success = function(msg, node) {
-    kimchi.message(msg, 'success', node);
-};
diff --git a/ui/js/src/kimchi.object.js b/ui/js/src/kimchi.object.js
deleted file mode 100644
index 57ec8d7..0000000
--- a/ui/js/src/kimchi.object.js
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Project Kimchi
- *
- * Copyright IBM, Corp. 2014
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-Object.defineProperty(Object.prototype, "getDeepValue", {
-    value: function(key) {
-        var result=undefined;
-        try {
-            if(!Array.isArray(key)) {
-                key=key.parseKey();
-            }
-            if(key.length!=0) {
-                var tmpName=key.shift();
-                if(this[tmpName]!=undefined) {
-                    result=this[tmpName];
-                }
-                if(key.length!=0) {
-                    result=result.getDeepValue(key);
-                }
-            }
-        }
-        catch (err) {
-            //do nothing
-        }
-        return(result);
-        }
-});
-
-Object.defineProperty(Object.prototype, "setDeepValue", {
-    value: function(key, val) {
-        var keys;
-        if(Array.isArray(key)) {
-            keys=key;
-        }
-        else {
-            keys=key.parseKey();
-        }
-        if(keys.length!=0) {
-            var key=keys.shift();
-            if(keys.length==0) {
-                if(this[key]==undefined) {
-                    this[key]=val;
-                }
-                else if(Array.isArray(this[key])){
-                    this[key].push(val);
-                }
-                else {
-                    var tmpArray=[]
-                    tmpArray.push(this[key]);
-                    tmpArray.push(val);
-                    this[key]=tmpArray;
-                }
-            }
-            else {
-                if(this[key]==undefined) {
-                    this[key]=new Object();
-                    this[key].setDeepValue(keys,val);
-                }
-                else if(Array.isArray(this[key])){
-                    var tmpO=new Object();
-                    this[key].push(tmpO);
-                    tmpO.setDeepValue(keys,val);
-                }
-                else {
-                   this[key].setDeepValue(keys,val);
-                }
-            }
-        }
-        return(this);
-    }
-});
diff --git a/ui/js/src/kimchi.popable.js b/ui/js/src/kimchi.popable.js
deleted file mode 100644
index fb57010..0000000
--- a/ui/js/src/kimchi.popable.js
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Project Kimchi
- *
- * Copyright IBM, Corp. 2013-2014
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-kimchi.popable = function() {
-    $(document).click(function(e) {
-        $('.popable').each(function(i, n) {
-            n === e.target || $.contains(n, e.target) ||
-                $('.popover', n).toggle(false);
-        });
-     });
-     $(document).on('click', '.popable', function(e) {
-        var popup = $('.popover', this)[0];
-        $(popup).toggle();
-
-        // Scroll the popup menu into viewport if invisible.
-        !$(popup).is(':visible') ||
-            kimchi.isElementInViewport(popup) ||
-            popup.scrollIntoView();
-    });
-};
diff --git a/ui/js/src/kimchi.string.js b/ui/js/src/kimchi.string.js
deleted file mode 100644
index 252ae50..0000000
--- a/ui/js/src/kimchi.string.js
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Project Kimchi
- *
- * Copyright IBM, Corp. 2014
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-Object.defineProperty(String.prototype, "parseKey", {
-    value: function(parsedKey) {
-        try {
-            if (!Array.isArray(parsedKey)) {
-                parsedKey=[];
-            }
-        }
-        catch (err) {
-            parsedKey=[];
-        }
-        var openBracket=this.indexOf("[");
-        if (openBracket!=-1) {
-            var id=this.slice(0, openBracket);
-            parsedKey.push(id);
-            var closeBracket=this.lastIndexOf("]");
-            if (closeBracket==-1) {
-                closeBracket=this.length;
-            }
-            var tmpName=this.slice(openBracket+1,closeBracket);
-            tmpName.parseKey(parsedKey);
-        }
-        else {
-            parsedKey.push(this);
-        }
-        return(parsedKey);
-        }
-});
diff --git a/ui/js/src/kimchi.substitute.js b/ui/js/src/kimchi.substitute.js
deleted file mode 100644
index 434d9d3..0000000
--- a/ui/js/src/kimchi.substitute.js
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Project Kimchi
- *
- * Copyright IBM, Corp. 2014
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-kimchi.substitute = function(templateStr, data, tag) {
-    tag = tag || /\{([^\}]+)\}/g;
-
-    var escapeHtml = function(html) {
-        return String(html)
-            .replace(/&/g, '&amp;')
-            .replace(/</g, '&lt;')
-            .replace(/>/g, '&gt;')
-            .replace(/"/g, '&quot;')
-            .replace(/'/g, '&#39;');
-    };
-
-    return templateStr.replace(tag, function(matchResult, express) {
-        var propertyArray = express.split('!');
-        var defaultValue = propertyArray[1] || '';
-        propertyArray = propertyArray[0].split('.');
-        var value = data, i = 0, l = propertyArray.length, property;
-        for (; i < l; i++) {
-            property = propertyArray[i];
-            if (value) {
-                value = value[property];
-            } else {
-                break;
-            }
-        }
-        return escapeHtml((value || value === 0) ? value : defaultValue);
-    });
-};
diff --git a/ui/js/src/kimchi.topic.js b/ui/js/src/kimchi.topic.js
deleted file mode 100644
index fd62ffe..0000000
--- a/ui/js/src/kimchi.topic.js
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Project Kimchi
- *
- * Copyright IBM, Corp. 2013-2014
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**
- * pub/sub
- * Usage:
- *   Publish - kimchi.topic('eventname').publish(params);
- *   Subscribe - kimchi.topic('eventname').subscribe(listener);
- *   Unsubscribe - kimchi.topic('eventname').unsubscribe(listener);
- */
-kimchi.topic = (function() {
-
-    var topics = {};
-
-    return function( id ) {
-        var callbacks,
-            method,
-            topic = id && topics[ id ];
-
-        if ( !topic ) {
-            callbacks = jQuery.Callbacks();
-            topic = {
-                publish: callbacks.fire,
-                subscribe: callbacks.add,
-                unsubscribe: callbacks.remove
-            };
-            if ( id ) {
-                topics[ id ] = topic;
-            }
-        }
-        return topic;
-    };
-})();
diff --git a/ui/js/src/kimchi.user.js b/ui/js/src/kimchi.user.js
deleted file mode 100644
index c036155..0000000
--- a/ui/js/src/kimchi.user.js
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Project Kimchi
- *
- * Copyright IBM, Corp. 2013-2014
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-kimchi.user = (function() {
-    var getUserName = function() {
-        return kimchi.cookie.get('username');
-    };
-
-    var setUserName = function(userName) {
-        kimchi.cookie.set('username', userName, 365);
-    };
-
-    var showUser = function(toShow) {
-        if (toShow) {
-            var userName = getUserName();
-            userName && $('#user-name').text(userName);
-            $('#user').removeClass('not-logged-in');
-            return;
-        }
-
-        $('#user').addClass('not-logged-in');
-    };
-
-    return {
-        getUserName: getUserName,
-        setUserName: setUserName,
-        showUser: showUser
-    };
-})();
diff --git a/ui/js/src/kimchi.window.js b/ui/js/src/kimchi.window.js
deleted file mode 100644
index 3ac8699..0000000
--- a/ui/js/src/kimchi.window.js
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Project Kimchi
- *
- * Copyright IBM, Corp. 2013-2014
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-kimchi.window = (function() {
-    var _windows = [];
-    var _listeners = {};
-    var open = function(settings) {
-        var settings = jQuery.type(settings) === 'object' ? settings : {
-            url: settings
-        };
-
-        var windowID = settings['id'] || 'window-' + _windows.length;
-
-        if ($('#' + windowID).length) {
-            $('#' + windowID).remove();
-        }
-
-        _windows.push(windowID);
-        _listeners[windowID] = settings['close'];
-        var windowNode = $('<div></div>', {
-            id: windowID,
-            'class': settings['class'] ? settings['class'] + ' bgmask remove-when-logged-off' : 'bgmask remove-when-logged-off'
-        });
-
-        $(windowNode).css(settings['style'] || '');
-
-        $(windowNode).appendTo('body').on('click', '.window .close', function() {
-            kimchi.window.close();
-        });
-
-        if (settings['url']) {
-            $(windowNode).load(settings['url']).fadeIn(100);
-            return;
-        }
-
-        settings['content'] && $(windowNode).html(settings['content']);
-    };
-
-    var close = function() {
-        var windowID = _windows.pop();
-        if(_listeners[windowID]) {
-            _listeners[windowID]();
-            _listeners[windowID] = null;
-        }
-        delete _listeners[windowID];
-
-        $('#' + windowID).fadeOut(100, function() {
-            $(this).remove();
-        });
-    };
-
-    return {
-        open: open,
-        close: close
-    };
-})();
diff --git a/ui/js/src/wok.cookie.js b/ui/js/src/wok.cookie.js
new file mode 100644
index 0000000..f1b52db
--- /dev/null
+++ b/ui/js/src/wok.cookie.js
@@ -0,0 +1,40 @@
+/*
+ * Project Kimchi
+ *
+ * Copyright IBM, Corp. 2013-2014
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+kimchi.cookie = {
+    set: function(key, value, expireDays) {
+        value = encodeURIComponent(value);
+        value += '; secure'
+        if (expireDays) {
+            var expireDate = new Date();
+            expireDate.setDate(expireDate.getDate() + expireDays);
+            value += '; expires=' + expireDate.toUTCString();
+        }
+        document.cookie = key + '=' + value;
+    },
+
+    get: function(key) {
+        var cookieRe = new RegExp(';?\\\s*(' + key + ')=(\s*[^;]*);?', 'g');
+        var match = cookieRe.exec(document.cookie);
+        return match ? decodeURIComponent(match[2]) : undefined;
+    },
+
+    remove: function(key) {
+        var utcString = new Date().toUTCString();
+        document.cookie = key + '=; expires=' + utcString;
+    }
+};
diff --git a/ui/js/src/wok.grid.js b/ui/js/src/wok.grid.js
new file mode 100644
index 0000000..6fed753
--- /dev/null
+++ b/ui/js/src/wok.grid.js
@@ -0,0 +1,528 @@
+/*
+ * Project Kimchi
+ *
+ * Copyright IBM, Corp. 2013-2015
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+kimchi.widget.Grid = function(opts) {
+    this.opts = $.extend({}, this.opts, opts);
+    this.createDOM();
+    this.reload();
+};
+
+kimchi.widget.Grid.prototype = (function() {
+    var htmlStr = [
+        '<div id="{id}" class="grid">',
+            '<div class="grid-content">',
+                '<div class="grid-header">',
+                    '<div class="grid-frozen-header-view">',
+                        '<table class="grid-frozen-header-container">',
+                        '</table>',
+                    '</div>',
+                    '<div class="grid-header-view">',
+                        '<div class="grid-header-wrapper">',
+                            '<table class="grid-header-container">',
+                            '</table>',
+                        '</div>',
+                    '</div>',
+                '</div>',
+                '<div class="grid-body">',
+                    '<div class="grid-frozen-body-view">',
+                        '<div class="grid-frozen-body-wrapper">',
+                            '<table class="grid-frozen-body-container">',
+                            '</table>',
+                        '</div>',
+                    '</div>',
+                    '<div class="grid-body-view">',
+                        '<div class="grid-body-wrapper">',
+                            '<table class="grid-body-container">',
+                            '</table>',
+                        '</div>',
+                    '</div>',
+                '</div>',
+                '<div class="grid-resizer-leftmost hidden"></div>',
+                '<div class="grid-resizer hidden"></div>',
+            '</div>',
+            '<div class="grid-footer"></div>',
+            '<div class="grid-mask hidden">',
+                '<div class="grid-loading">',
+                    '<div class="grid-loading-icon"></div>',
+                    '<div class="grid-loading-text">',
+                        '{loading}',
+                    '</div>',
+                '</div>',
+            '</div>',
+            '<div class="grid-message hidden">',
+                '<div class="grid-message-text">',
+                    '{message}',
+                    '<button class="retry-button btn-small">',
+                        '{buttonLabel}',
+                    '</button>',
+                '</div>',
+                '<div class="detailed-title">',
+                    '{detailedLabel}',
+                '</div>',
+                '<div class="detailed-text"></div>',
+            '</div>',
+        '</div>'
+    ].join('');
+
+    var CONTAINER_NORMAL = 0, CONTAINER_FROZEN = 1;
+
+    var setupHeaders = function(header, body, fields) {
+        var colGroup = $('<colgroup></colgroup>').appendTo(header);
+        var headerHeader = $('<thead></thead>');
+        var headerRow = $('<tr></tr>').appendTo(headerHeader);
+        $.each(fields || [], function(i, field) {
+            $('<col class="' +
+                field['class'] +
+            '"/>')
+                .appendTo(colGroup);
+            $('<th><div class="cell-text-wrapper">' +
+                field['label'] +
+            '</div></th>').appendTo(headerRow);
+        });
+        headerHeader.appendTo(header);
+
+        var totalWidth = 0;
+        $('col', colGroup).each(function(index, col) {
+            var width = $(col).width();
+            totalWidth += width;
+            $(col).css('width', width + 'px');
+        });
+        $(body).append(colGroup.clone());
+        return totalWidth;
+    };
+
+    var getValue = function(name, obj) {
+        var result=undefined;
+        if(!Array.isArray(name)) {
+            name=name.parseKey();
+        }
+        if(name.length!=0) {
+            var tmpName=name.shift();
+            if(obj[tmpName]!=undefined) {
+                    result=obj[tmpName];
+            }
+            if(name.length!=0) {
+                    result=getValue(name,obj[tmpName]);
+            }
+        }
+        return(result);
+    };
+
+    var fillBody = function(container, fields) {
+        var data = this.data;
+        var tbody = ($('tbody', container).length && $('tbody', container))
+            || $('<tbody></tbody>').appendTo(container);
+        tbody.empty();
+        $.each(data, function(i, row) {
+            var rowNode = $('<tr></tr>').appendTo(tbody);
+            $.each(fields, function(fi, field) {
+                var value = getValue(field['name'], row);
+                $('<td><div class="cell-text-wrapper"' +
+                    (field['makeTitle'] === true
+                        ? ' title="' + value + '"'
+                        : ''
+                    ) + '>' + value.toString() + '</div></td>'
+                ).appendTo(rowNode);
+            });
+        });
+    };
+
+    var fixTableLayout = function(style) {
+        $.each([
+            this.frozenHeaderContainer,
+            this.headerContainer,
+            this.frozenBodyContainer,
+            this.bodyContainer
+        ], function(i, tableNode) {
+            $(tableNode).css('table-layout', style || 'fixed');
+        });
+    };
+
+    var initResizing = function(event) {
+        var resizer = event.data.resizer;
+        var pageX = event.pageX;
+        var tailPos = $(this).width() + $(this).offset()['left'];
+        var atResizer = Math.abs(pageX - tailPos) <= 2;
+        var isResizing = !$(resizer).hasClass('hidden');
+        $('body')[(atResizer || isResizing)
+            ? 'addClass'
+            : 'removeClass'
+        ]('resizing');
+    };
+
+    var clearResizing = function(event) {
+        $(event.data.resizer).hasClass('hidden') &&
+            $('body').removeClass('resizing');
+    };
+
+    var stylingRow = function(row, className, add) {
+        var index = $(row).index() + 1;
+        $('tr', this.frozenBodyContainer)
+            .removeClass(className);
+        $('tr', this.bodyContainer)
+            .removeClass(className);
+
+        if(add === false) {
+            return;
+        }
+
+        $('tr:nth-child(' + index + ')', this.frozenBodyContainer)
+            .addClass(className);
+        $('tr:nth-child(' + index + ')', this.bodyContainer)
+            .addClass(className);
+    };
+
+    var setBodyListeners = function() {
+        if(this['opts']['rowSelection'] != 'disabled') {
+            $('tr', this.gridBody).on('mouseover', {
+                grid: this
+            }, function(event) {
+                if (! $(this).hasClass('no-hover'))
+                    stylingRow.call(event.data.grid, this, 'hover');
+            });
+
+            $('tr', this.gridBody).on('mouseout', {
+                grid: this
+            }, function(event) {
+                stylingRow.call(event.data.grid, this, 'hover', false);
+            });
+
+            $('tr', this.gridBody).on('click', {
+                grid: this
+            }, function(event) {
+                var grid = event.data.grid;
+                grid.selectedIndex = $(this).index();
+                stylingRow.call(grid, this, 'selected');
+                grid['opts']['onRowSelected'] && grid['opts']['onRowSelected']();
+            });
+        }
+
+        $('.grid-body-view', this.domNode).on('scroll', {
+            grid: this
+        }, function(event) {
+            var grid = event.data.grid;
+            $('.grid-header .grid-header-view', grid.domNode)
+                .prop('scrollLeft', this.scrollLeft);
+            $('.grid-body .grid-frozen-body-view', grid.domNode)
+                .prop('scrollTop', this.scrollTop);
+        });
+    };
+
+    var setData = function(data) {
+        this.data = data;
+        fillBody.call(this, this.frozenBodyContainer, this['opts']['frozenFields']);
+        fillBody.call(this, this.bodyContainer, this['opts']['fields']);
+        setBodyListeners.call(this);
+    };
+
+    var getSelected = function() {
+        return this.selectedIndex >= 0
+            ? this.data[this.selectedIndex]
+            : null;
+    };
+
+    var startResizing = function(container, event) {
+        var grid = event.data.grid;
+        kimchi.widget.Grid.beingResized = grid;
+        if(!($('body').hasClass('resizing')
+                && $(grid.resizer).hasClass('hidden'))) {
+            return;
+        }
+
+        grid.columnBeingResized = container;
+        var pageX = event.pageX;
+        var gridOffsetX = grid.domNode.offset()['left'];
+        var leftmostOffsetX = $(container).offset()['left'] - gridOffsetX;
+        var left = pageX - gridOffsetX;
+        var contentHeight = $('.grid-content', grid.domNode).height();
+        $(grid.resizerLeftmost).css({
+            left: leftmostOffsetX + 'px',
+            height: contentHeight + 'px'
+        });
+        $(grid.resizer).css({
+            left: left + 'px',
+            height: contentHeight + 'px'
+        });
+        $(grid.resizerLeftmost).removeClass('hidden');
+        $(grid.resizer).removeClass('hidden');
+        event.preventDefault();
+    };
+
+    var endResizing = function(event) {
+        var grid = kimchi.widget.Grid.beingResized;
+        if(!$('body').hasClass('resizing')) {
+            return;
+        }
+        $(grid.resizerLeftmost).addClass('hidden');
+        $(grid.resizer).addClass('hidden');
+        $('body').removeClass('resizing');
+        var leftmostOffset = $(grid.columnBeingResized).offset()['left'];
+        var left = event.pageX;
+        if(leftmostOffset > left) {
+            return;
+        }
+        resizeColumnWidth.call(
+            grid,
+            $(grid.columnBeingResized).index(),
+            left - leftmostOffset
+        );
+        fixTableLayout.call(grid);
+        grid.columnBeingResized = null;
+        kimchi.widget.Grid.beingResized = null;
+    };
+
+    var resizeColumnWidth = function(index, width) {
+        var width = Math.ceil(width);
+        var widthArray = [];
+        var totalWidth = 0;
+        var header = this.headerContainer;
+        var body = this.bodyContainer;
+        if(this.containerBeingResized === CONTAINER_FROZEN) {
+            header = this.frozenHeaderContainer;
+            body = this.frozenBodyContainer;
+        }
+        $('col', header).each(function(i, colNode) {
+            var w = index === i ? width : $(colNode).width();
+            widthArray.push(w);
+            totalWidth += w;
+        });
+        $.each([header, body], function(i, container) {
+            container.css({
+                'table-layout': 'fixed',
+                width: totalWidth + 'px'
+            });
+            $('col:nth-child(' + (index + 1) + ')', container).css({
+                width: width + 'px'
+            });
+        });
+
+        if(this.containerBeingResized === CONTAINER_FROZEN) {
+            var headerView = $('.grid-header-view', this.domNode);
+            var bodyView = $('.grid-body-view', this.domNode);
+            $.each([headerView, bodyView], function(i, view) {
+                view.css({
+                    left: totalWidth + 'px'
+                });
+            });
+        }
+    };
+
+    var positionResizer = function(event) {
+        var grid = event.data.grid;
+        if($(grid.resizer).hasClass('hidden')) {
+            return;
+        }
+
+        var pageX = event.pageX;
+        var gridOffsetX = $(grid.domNode).offset()['left'];
+        var leftMost = $(grid.resizerLeftmost).position()['left'];
+        var offsetX = pageX - gridOffsetX;
+        offsetX = offsetX >= leftMost ? offsetX : leftMost;
+        $(grid.resizer).css('left', offsetX + 'px');
+    };
+
+    var showMessage = function(msg) {
+        $('.detailed-text', this.messageNode).text(msg);
+        $(this.messageNode).removeClass('hidden');
+    };
+
+    var hideMessage = function() {
+        $(this.messageNode).addClass('hidden');
+    };
+
+    var reload = function() {
+        var data = this['opts']['data'];
+        if(!data) {
+            return;
+        }
+
+        $(this.messageNode).addClass('hidden');
+
+        if($.isArray(data)) {
+            return this.setData(data);
+        }
+
+        if($.isFunction(data)) {
+            var loadData = data;
+            $(this.maskNode).removeClass('hidden');
+            loadData($.proxy(function(data) {
+                this.setData(data);
+                $(this.maskNode).addClass('hidden');
+            }, this));
+        }
+    };
+
+    var destroy = function() {
+        $('body').off('mousemove.grid#' + this['opts']['id'], positionResizer);
+        $('body').off('mouseup.grid#' + this['opts']['id'], endResizing);
+    };
+
+    var createDOM = function() {
+        var containerID = this['opts']['container'];
+        var container = $('#' + containerID);
+        var gridID = this['opts']['id'];
+        var rowSelection = this['opts']['rowSelection'] || 'single';
+        var domNode = $(kimchi.substitute(htmlStr, {
+            id: gridID,
+            loading: i18n['KCHGRD6001M'],
+            message: i18n['KCHGRD6002M'],
+            buttonLabel: i18n['KCHGRD6003M'],
+            detailedLabel: i18n['KCHGRD6004']
+        })).appendTo(container);
+        this.domNode = domNode;
+
+        var height = domNode.height();
+        var width = domNode.width();
+
+        var title = this['opts']['title'];
+        var titleNode = null;
+        if(title) {
+            titleNode = $('<div class="grid-caption">' + title + '</div>')
+                .prependTo(domNode);
+        }
+
+        var toolbarButtons = this['opts']['toolbarButtons'];
+        var toolbarNode = null;
+        if(toolbarButtons) {
+            toolbarNode = $('<div class="grid-toolbar"></div>');
+            if(titleNode) {
+                titleNode.after(toolbarNode);
+            }
+            else {
+                toolbarNode.prependTo(domNode);
+            }
+
+            $.each(toolbarButtons, function(i, button) {
+                var btnHTML = [
+                    '<button',
+                        button['id'] ? (' id="' + button['id'] + '"') : '',
+                        ' class="grid-toolbar-button',
+                            button['class'] ? (' ' + button['class']) : '',
+                            '"',
+                            button['disabled'] === true ? ' disabled' : '',
+                            '>',
+                            button['label'],
+                    '</button>'
+                ].join('');
+                var btnNode = $(btnHTML).appendTo(toolbarNode);
+                button['onClick'] &&
+                    btnNode.on('click', button['onClick']);
+            });
+        }
+
+        var frozenHeaderContainer = $('.grid-frozen-header-container', domNode);
+        var frozenBodyContainer = $('.grid-frozen-body-container', domNode);
+        var frozenWidth = setupHeaders(
+                frozenHeaderContainer,
+                frozenBodyContainer,
+                this['opts']['frozenFields']
+        );
+        this.frozenHeaderContainer = frozenHeaderContainer;
+        this.frozenBodyContainer = frozenBodyContainer;
+
+        var headerContainer = $('.grid-header-container', domNode);
+        var bodyContainer = $('.grid-body-container', domNode);
+        setupHeaders(headerContainer, bodyContainer, this['opts']['fields']);
+        this.headerContainer = headerContainer;
+        this.bodyContainer = bodyContainer;
+
+        fixTableLayout.call(this, 'auto');
+
+        var gridContentNode = $('.grid-content', domNode);
+        var captionHeight = titleNode && $(titleNode).height() || 0;
+        var toolbarHeight = toolbarNode && $(toolbarNode).height() || 0;
+        gridContentNode.css('top', (captionHeight + toolbarHeight) + 'px');
+
+        var maskNode = $('.grid-mask', domNode);
+        maskNode.css('top', captionHeight + 'px');
+        this.maskNode = maskNode;
+
+        var messageNode = $('.grid-message', domNode);
+        messageNode.css('top', captionHeight + 'px');
+        this.messageNode = messageNode;
+
+        var headerView = $('.grid-header-view', domNode);
+        var bodyView = $('.grid-body-view', domNode);
+        headerView.css('left', (frozenWidth) + 'px');
+        bodyView.css('left', (frozenWidth) + 'px');
+
+        var bodyWidth = width - frozenWidth;
+        headerContainer.css('width', bodyWidth + 'px');
+        bodyContainer.css('width', bodyWidth + 'px');
+
+        fixTableLayout.call(this);
+
+        var gridBody = $('.grid-body', domNode);
+        this.gridBody = gridBody;
+        this.resizerLeftmost = $('.grid-resizer-leftmost', domNode);
+        this.resizer = $('.grid-resizer', domNode);
+        var gridHeader = $('.grid-header', domNode);
+        $('th', gridHeader).on('mouseover mousemove', {
+            resizer: this.resizer
+        }, initResizing);
+
+        $('th', gridHeader).on('mouseout', {
+            resizer: this.resizer
+        }, clearResizing);
+
+        this.containerBeingResized = CONTAINER_NORMAL;
+        $('th', frozenHeaderContainer).on('mousedown', {
+            grid: this
+        }, function(event) {
+                event.data.grid.containerBeingResized = CONTAINER_FROZEN;
+                startResizing(this, event);
+        });
+        $('th', headerContainer).on('mousedown', {
+            grid: this
+        }, function(event) {
+                event.data.grid.containerBeingResized = CONTAINER_NORMAL;
+                startResizing(this, event);
+        });
+
+        $('body').on('mousemove.grid#' + this['opts']['id'], {
+            grid: this
+        }, positionResizer);
+        $('body').on('mouseup.grid#' + this['opts']['id'], endResizing);
+
+        var data = this['opts']['data'];
+
+        $('.retry-button', domNode).on('click', {
+            grid: this
+        }, function(event) {
+            event.data.grid.reload();
+        });
+    };
+
+    return {
+        opts: {
+            container: null,
+            id: null,
+            rowSelection: 'single',
+            onRowSelected: null,
+            title: null,
+            toolbarButtons: null,
+            frozenFields: null,
+            fields: null
+        },
+        createDOM: createDOM,
+        setData: setData,
+        getSelected: getSelected,
+        reload: reload,
+        destroy: destroy,
+        showMessage: showMessage
+    };
+})();
diff --git a/ui/js/src/wok.lang.js b/ui/js/src/wok.lang.js
new file mode 100644
index 0000000..1d2de4e
--- /dev/null
+++ b/ui/js/src/wok.lang.js
@@ -0,0 +1,50 @@
+/*
+ * Project Kimchi
+ *
+ * Copyright IBM, Corp. 2013-2014
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+kimchi.lang = {
+    all: function() {
+        return {
+          'en_US': 'English (US)',
+          'zh_CN': '中文(简体)',
+          'pt_BR': 'Português (Brasil)',
+          'de_DE': 'Deutsch (Deutschland)',
+          'es_ES': 'Español (España)',
+          'fr_FR': 'Français (France)',
+          'it_IT': 'Italiano (Italia)',
+          'ja_JP': '日本語 (日本)',
+          'ko_KR': '한국어 (대한민국)',
+          'ru_RU': 'Русский (Россия)',
+          'zh_TW': '中文(繁體)'
+        };
+    },
+
+    /**
+     * Language is determined by the following sequence:
+     * 1) Cookie setting; or if not set ->
+     * 2) HTML DOM lang attribute; or if not set ->
+     * 3) DEFAULT (en_US).
+     */
+    get: function() {
+        return kimchi.cookie.get('kimchiLang') ||
+            $('html').prop('lang') ||
+            'en_US';
+    },
+
+    set: function(lang) {
+        kimchi.cookie.set('kimchiLang', lang, 365);
+    }
+};
diff --git a/ui/js/src/wok.login.js b/ui/js/src/wok.login.js
new file mode 100644
index 0000000..c737d26
--- /dev/null
+++ b/ui/js/src/wok.login.js
@@ -0,0 +1,72 @@
+/*
+ * Project Kimchi
+ *
+ * Copyright IBM, Corp. 2014-2015
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+kimchi.login_main = function() {
+
+    var selectedLanguage = kimchi.lang.get();
+    $('#userLang').val(selectedLanguage);
+
+    $('#userLang').on('change', function() {
+        kimchi.lang.set($(this).val());
+        location.reload();
+    });
+
+    var query = window.location.search;
+    var error = /.*error=(.*?)(&|$)/g.exec(query);
+    if (error && error[1] == "sessionTimeout") {
+        $("#messSession").show();
+    }
+
+    var userNameBox = $('#username');
+    var passwordBox = $('#password');
+    var loginButton = $('#btn-login');
+
+    var login = function(event) {
+        $("#login").hide();
+        $("#logging").show();
+
+        var userName = userNameBox.val();
+        userName && kimchi.user.setUserName(userName);
+        var settings = {
+            username: userName,
+            password: passwordBox.val()
+        };
+
+        kimchi.login(settings, function(data) {
+            var query = window.location.search;
+            var next  = /.*next=(.*?)(&|$)/g.exec(query);
+            if (next) {
+                var next_url = decodeURIComponent(next[1]);
+            }
+            else {
+                var lastPage = kimchi.cookie.get('lastPage');
+                var next_url = lastPage ? lastPage.replace(/\"/g,'') : "/";
+            }
+            kimchi.cookie.set('roles',JSON.stringify(data.roles));
+            window.location.replace(window.location.pathname.replace(/\/+login.html/, '') + next_url)
+        }, function() {
+            $("#messUserPass").show();
+            $("#messSession").hide();
+            $("#logging").hide();
+            $("#login").show();
+        });
+
+        return false;
+    };
+
+    $('#btn-login').bind('click', login);
+};
diff --git a/ui/js/src/wok.main.js b/ui/js/src/wok.main.js
new file mode 100644
index 0000000..0d4ad43
--- /dev/null
+++ b/ui/js/src/wok.main.js
@@ -0,0 +1,366 @@
+/*
+ * Project Kimchi
+ *
+ * Copyright IBM, Corp. 2013-2015
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+kimchi.tabMode = {};
+
+kimchi.capabilities = undefined;
+kimchi.getCapabilities(function(result) {
+    kimchi.capabilities = result;
+
+    if(kimchi.capabilities.federation=="on")
+        $('#peers').removeClass('hide-content');
+}, function() {
+    kimchi.capabilities = {};
+});
+
+kimchi.main = function() {
+    kimchi.isLoggingOut = false;
+    kimchi.popable();
+
+    var genTabs = function(tabs) {
+        var tabsHtml = [];
+        $(tabs).each(function(i, tab) {
+            var title = tab['title'];
+            var path = tab['path'];
+            var mode = tab['mode'];
+            if (mode != 'none') {
+                var helpPath = kimchi.checkHelpFile(path);
+                var disableHelp = (helpPath.length == 0 ? "disableHelp" : helpPath);
+                tabsHtml.push(
+                    '<li>',
+                        '<a class="item ', disableHelp,'" href="', path, '">',
+                            title,
+                        '</a>',
+                        '<input id="helpPathId" name="helpPath" value="' + helpPath + '" type="hidden"/>',
+                    '</li>'
+                );
+            }
+        });
+        return tabsHtml.join('');
+    };
+
+    var parseTabs = function(xmlData) {
+        var tabs = [];
+        $(xmlData).find('tab').each(function() {
+            var $tab = $(this);
+            var titleKey = $tab.find('title').text();
+            var title = i18n[titleKey] ? i18n[titleKey] : titleKey;
+            var path = $tab.find('path').text();
+            var roles = kimchi.cookie.get('roles');
+            if (roles) {
+                var role = JSON.parse(roles)[titleKey.toLowerCase()];
+                var mode = $tab.find('[role="' + role + '"]').attr('mode');
+                kimchi.tabMode[titleKey.toLowerCase()] = mode;
+                tabs.push({
+                    title: title,
+                    path: path,
+                    mode: mode
+                });
+            } else {
+                document.location.href = 'login.html';
+            }
+        });
+
+        return tabs;
+    };
+
+    var retrieveTabs = function(url) {
+        var tabs;
+        $.ajax({
+            url : url,
+            async : false,
+            success : function(xmlData) {
+                tabs = parseTabs(xmlData);
+            }
+        });
+        return tabs;
+    };
+
+    var tabConfigUrl = 'config/ui/tabs.xml';
+    var pluginConfigUrl = 'plugins/{plugin}/ui/config/tab-ext.xml';
+    var pluginI18nUrl = 'plugins/{plugin}/i18n.json';
+    var DEFAULT_HASH;
+    var buildTabs = function(callback) {
+        var tabs = retrieveTabs(tabConfigUrl);
+        kimchi.listPlugins(function(plugins) {
+            $(plugins).each(function(i, p) {
+                var url = kimchi.substitute(pluginConfigUrl, {
+                    plugin: p
+                });
+                var i18nUrl = kimchi.substitute(pluginI18nUrl, {
+                    plugin: p
+                });
+                kimchi.getI18n(function(i18nObj){ $.extend(i18n, i18nObj)},
+                               function(i18nObj){ //i18n is not define by plugin
+                               }, i18nUrl, true);
+                tabs.push.apply(tabs, retrieveTabs(url));
+            });
+
+            var defaultTab = tabs[1]
+
+            var defaultTabPath = defaultTab && defaultTab['path']
+            // Remove file extension from 'defaultTabPath'
+            DEFAULT_HASH = defaultTabPath &&
+                defaultTabPath.substring(0, defaultTabPath.lastIndexOf('.'))
+
+            $('#nav-menu').append(genTabs(tabs));
+
+            callback && callback();
+        }, function(data) {
+           kimchi.message.error(data.responseJSON.reason);
+        }, true);
+    };
+
+    var onLanguageChanged = function(lang) {
+        kimchi.lang.set(lang);
+        location.reload();
+    };
+
+    /**
+     * Do the following setup:
+     *   1) Clear any timing events.
+     *   2) If the given URL is invalid (i.e., no corresponding href value in
+     *      page tab list.), then clear location.href and inform the user;
+     *
+     *      Or else:
+     *      Move the page tab indicator to the right position;
+     *      Load the page content via Ajax.
+     */
+    var onKimchiRedirect = function(url) {
+        /*
+         * Find the corresponding tab node and animate the arrow indicator to
+         * point to the tab. If nothing found, inform user the URL is invalid
+         * and clear location.hash to jump to home page.
+         */
+        var tab = $('#nav-menu a[href="' + url + '"]');
+        if (tab.length === 0) {
+            location.hash = '';
+            return;
+        }
+
+        // Animate arrow indicator.
+        var left = $(tab).parent().position().left;
+        var width = $(tab).parent().width();
+        $('.menu-arrow').stop().animate({
+            left : left + width / 2 - 10
+        });
+
+        // Update the visual style of tabs; focus the selected one.
+        $('#nav-menu a').removeClass('current');
+        $(tab).addClass('current');
+        $(tab).focus();
+        // Disable Help button according to selected tab
+        if ($(tab).hasClass("disableHelp")) {
+            $('#btn-help').css('cursor', "not-allowed");
+            $('#btn-help').off("click");
+        }
+        else {
+            $('#btn-help').css('cursor', "pointer");
+            $('#btn-help').on("click", kimchi.openHelp);
+        }
+        // Load page content.
+        loadPage(url);
+    };
+
+    /**
+     * Use Ajax to dynamically load a page without a page refreshing. Handle
+     * arrow cursor animation, DOM node focus, and page content rendering.
+     */
+    var loadPage = function(url) {
+        // Get the page content through Ajax and render it.
+        url && $('#main').load(url, function(responseText, textStatus, jqXHR) {
+            if (jqXHR['status'] === 401 || jqXHR['status'] === 303) {
+                var isSessionTimeout = jqXHR['responseText'].indexOf("sessionTimeout")!=-1;
+                document.location.href= isSessionTimeout ? 'login.html?error=sessionTimeout' : 'login.html';
+                return;
+            }
+        });
+    };
+
+    /*
+     * Update page content.
+     * 1) If user types in the main page URL without hash, then we apply the
+     *    default hash. e.g., http://kimchi.company.com:8000;
+     * 2) If user types a URL with hash, then we publish an "redirect" event
+     *    to load the page, e.g., http://kimchi.company.com:8000/#templates.
+     */
+    var updatePage = function() {
+        // Parse hash string.
+        var hashString = (location.hash && location.hash.substr(1));
+        /*
+         * If hash string is empty, then apply the default one;
+         * or else, publish an "redirect" event to load the page.
+         */
+        if (!hashString) {
+            location.hash = DEFAULT_HASH;
+        }
+        else {
+            kimchi.topic('redirect').publish(hashString + '.html');
+        }
+    };
+
+    /**
+     * Register listeners including:
+     * 1) Kimchi redirect event
+     * 2) hashchange event
+     * 3) Tab list click event
+     * 4) Log-out button click event
+     * 5) About button click event
+     * 6) Help button click event
+     * 7) Peers button click event
+     */
+    var searchingPeers = false;
+    var initListeners = function() {
+        kimchi.topic('languageChanged').subscribe(onLanguageChanged);
+        kimchi.topic('redirect').subscribe(onKimchiRedirect);
+
+        /*
+         * If hash value is changed, then we know the user is intended to load
+         * another page.
+         */
+        window.onhashchange = updatePage;
+
+        /*
+         * Register click listener of tabs. Replace the default reloading page
+         * behavior of <a> with Ajax loading.
+         */
+        $('#nav-menu').on('click', 'a.item', function(event) {
+            var href = $(this).attr('href');
+            // Remove file extension from 'href'
+            location.hash = href.substring(0,href.lastIndexOf('.'))
+            /*
+             * We use the HTML file name for hash, like: guests for guests.html
+             * and templates for templates.html.
+             *     Retrieve hash value from the given URL and update location's
+             * hash part. It has 2 effects: one is to publish Kimchi "redirect"
+             * event to trigger listener, the other is to put an entry into the
+             * browser's address history to make pages be bookmark-able.
+             */
+            // Prevent <a> causing browser redirecting to other page.
+            event.preventDefault();
+        });
+
+        // Perform logging out via Ajax request.
+        $('#btn-logout').on('click', function() {
+            kimchi.logout(function() {
+                kimchi.isLoggingOut = true;
+                document.location.href = "login.html";
+            }, function(err) {
+                kimchi.message.error(err.responseJSON.reason);
+            });
+        });
+
+        // Set handler for about button
+        $('#btn-about').on('click', function(event) {
+            kimchi.window.open({"content": $('#about-tmpl').html()});
+            event.preventDefault();
+            });
+
+        // Set handler for help button
+        $('#btn-help').on('click', kimchi.openHelp);
+
+        // Set handler to peers drop down
+        $('#peers').on('click', function() {
+
+            // Check if any request is in progress
+            if ($('.popover', '#peers').is(':visible') || searchingPeers == true)
+                return
+
+            $('#search-peers').show();
+            $('#no-peers').addClass('hide-content');
+            $('a', '#peers').remove();
+
+            searchingPeers = true;
+
+            kimchi.getPeers(function(data){
+                $('#search-peers').hide();
+                if (data.length == 0)
+                    $('#no-peers').removeClass('hide-content');
+
+                for(var i=0; i<data.length; i++){
+                    $('.dropdown', '#peers').append("<a href='"+data[i]+"' target='_blank'>"+data[i]+"</a>");
+                }
+                searchingPeers = false;
+            });
+        });
+    };
+
+    var initUI = function() {
+        $(document).bind('ajaxError', function(event, jqXHR, ajaxSettings, errorThrown) {
+            if (!ajaxSettings['kimchi']) {
+                return;
+            }
+
+            if (jqXHR['status'] === 401) {
+                var isSessionTimeout = jqXHR['responseText'].indexOf("sessionTimeout")!=-1;
+                kimchi.user.showUser(false);
+                kimchi.previousAjax = ajaxSettings;
+                $(".empty-when-logged-off").empty();
+                $(".remove-when-logged-off").remove();
+                document.location.href= isSessionTimeout ? 'login.html?error=sessionTimeout' : 'login.html';
+                return;
+            }
+            else if((jqXHR['status'] == 0) && ("error"==jqXHR.statusText) && !kimchi.isLoggingOut) {
+                kimchi.message.error(i18n['KCHAPI6007E'].replace("%1", jqXHR.state()));
+            }
+            if(ajaxSettings['originalError']) {
+                ajaxSettings['originalError'](jqXHR, jqXHR.statusText, errorThrown);
+            }
+        });
+
+        kimchi.user.showUser(true);
+        initListeners();
+        updatePage();
+    };
+
+    // Load i18n translation strings first and then render the page.
+    kimchi.getI18n(
+        function(i18nStrings){ //success
+            i18n = i18nStrings;
+            buildTabs(initUI);
+            },
+        function(data){ //error
+            kimchi.message.error(data.responseJSON.reason);
+            });
+};
+
+
+kimchi.checkHelpFile = function(path) {
+    var lang = kimchi.lang.get();
+    var url = ""
+    // Find help page path according to tab name
+    if (/^tabs/.test(path))
+        url = path.replace("tabs", "help/" + lang);
+    else if (/^plugins/.test(path))
+        url = path.slice(0, path.lastIndexOf('/')) + "help/" + lang + path.slice(path.lastIndexOf('/'));
+    // Checking if help page exist.
+    $.ajax({
+        url: url,
+        async: false,
+        error: function() { url = ""; },
+        success: function() { }
+    });
+    return url;
+};
+
+
+kimchi.openHelp = function(e) {
+    var tab = $('#nav-menu a.current');
+    var url = $(tab).parent().find("input[name='helpPath']").val();
+    window.open(url, "Kimchi Help");
+    e.preventDefault();
+};
diff --git a/ui/js/src/wok.message.js b/ui/js/src/wok.message.js
new file mode 100644
index 0000000..241626f
--- /dev/null
+++ b/ui/js/src/wok.message.js
@@ -0,0 +1,116 @@
+/*
+ * Project Kimchi
+ *
+ * Copyright IBM, Corp. 2013-2014
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+kimchi.message = function(msg, level, node) {
+    var container = node || $('#messageField');
+    if ($(container).size() < 1) {
+        container = $('<div id="messageField"/>').appendTo(document.body);
+    }
+    var message = '<div class="message ' + (level || '') + '" style="display: none;">';
+    if(!node) {
+        message += '<div class="close">X</div>';
+    }
+    message += '<div class="content">' + msg + '</div>';
+    message += '</div>';
+    var $message = $(message);
+    $(container).append($message);
+    $message.fadeIn(100);
+
+    setTimeout(function() {
+        $message.fadeOut(2000, function() {
+            $(this).remove();
+        });
+    }, 4000);
+
+    $(container).on("click", ".close", function(e) {
+        $(this).parent().fadeOut(200, function() {
+            $(this).remove();
+        });
+    });
+};
+
+/**
+ * A public function of confirm box.
+ *
+ * @param msg
+ *            type:[object]
+ * @param msg.title
+ *            The title of the confirm box.
+ * @param msg.content
+ *            The main text of the confirm box.
+ * @param msg.confirm
+ *            The text of the confirm button.
+ * @param msg.cancel
+ *            the text of the cancel button.
+ * @param confirmCallback
+ *            the callback function of click the confirm button.
+ * @param cancelCallback
+ *            The callback function of click the cancel and X button.
+ */
+kimchi.confirm = function(settings, confirmCallback, cancelCallback) {
+    if ($('#confirmbox-container ').size() < 1) {
+        $(document.body).append('<div id="confirmbox-container" class="bgmask"></div>');
+    }
+    var confirmboxHtml = '<div class="confirmbox">';
+    confirmboxHtml += '<header>';
+    confirmboxHtml += '<h4 class="title">' + (settings.title || '') + '</h4>';
+    confirmboxHtml += '<div class="close cancel">X</div>';
+    confirmboxHtml += '</header>';
+    confirmboxHtml += '<div class="content">';
+    confirmboxHtml += settings.content + '</div>';
+    confirmboxHtml += '<footer>';
+    confirmboxHtml += '<div class="btn-group">';
+    confirmboxHtml += '<button id="button-confirm" class="btn-small"><span class="text">' + (settings.confirm || i18n['KCHAPI6004M']) + '</span></button>';
+    confirmboxHtml += '<button id="button-cancel" class="btn-small cancel"><span class="text">' + (settings.cancel || i18n['KCHAPI6003M']) + '</span></button>';
+    confirmboxHtml += '</div>';
+    confirmboxHtml += '</footer>';
+    confirmboxHtml += '</div>';
+    var confirmboxNode = $(confirmboxHtml);
+    $('#confirmbox-container').append(confirmboxNode);
+    confirmboxNode.fadeIn();
+
+    $('#confirmbox-container').on("click", "#button-confirm", function(e) {
+        if (confirmCallback) {
+            confirmCallback();
+        }
+        confirmboxNode.fadeOut(1, function() {
+            $('#confirmbox-container').remove();
+        });
+    });
+    $('#confirmbox-container').on("click", ".cancel", function(e) {
+        if (cancelCallback) {
+            cancelCallback();
+        }
+        confirmboxNode.fadeOut(1, function() {
+            $('#confirmbox-container').remove();
+        });
+    });
+};
+
+kimchi.message.warn = function(msg, node) {
+    kimchi.message(msg, 'warn', node);
+};
+kimchi.message.error = function(msg, node) {
+    kimchi.message(msg, 'error', node);
+};
+kimchi.message.error.code = function(code) {
+    msg = code + ": " + i18n[code]
+    kimchi.message(msg, 'error');
+};
+kimchi.message.success = function(msg, node) {
+    kimchi.message(msg, 'success', node);
+};
diff --git a/ui/js/src/wok.object.js b/ui/js/src/wok.object.js
new file mode 100644
index 0000000..57ec8d7
--- /dev/null
+++ b/ui/js/src/wok.object.js
@@ -0,0 +1,85 @@
+/*
+ * Project Kimchi
+ *
+ * Copyright IBM, Corp. 2014
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+Object.defineProperty(Object.prototype, "getDeepValue", {
+    value: function(key) {
+        var result=undefined;
+        try {
+            if(!Array.isArray(key)) {
+                key=key.parseKey();
+            }
+            if(key.length!=0) {
+                var tmpName=key.shift();
+                if(this[tmpName]!=undefined) {
+                    result=this[tmpName];
+                }
+                if(key.length!=0) {
+                    result=result.getDeepValue(key);
+                }
+            }
+        }
+        catch (err) {
+            //do nothing
+        }
+        return(result);
+        }
+});
+
+Object.defineProperty(Object.prototype, "setDeepValue", {
+    value: function(key, val) {
+        var keys;
+        if(Array.isArray(key)) {
+            keys=key;
+        }
+        else {
+            keys=key.parseKey();
+        }
+        if(keys.length!=0) {
+            var key=keys.shift();
+            if(keys.length==0) {
+                if(this[key]==undefined) {
+                    this[key]=val;
+                }
+                else if(Array.isArray(this[key])){
+                    this[key].push(val);
+                }
+                else {
+                    var tmpArray=[]
+                    tmpArray.push(this[key]);
+                    tmpArray.push(val);
+                    this[key]=tmpArray;
+                }
+            }
+            else {
+                if(this[key]==undefined) {
+                    this[key]=new Object();
+                    this[key].setDeepValue(keys,val);
+                }
+                else if(Array.isArray(this[key])){
+                    var tmpO=new Object();
+                    this[key].push(tmpO);
+                    tmpO.setDeepValue(keys,val);
+                }
+                else {
+                   this[key].setDeepValue(keys,val);
+                }
+            }
+        }
+        return(this);
+    }
+});
diff --git a/ui/js/src/wok.popable.js b/ui/js/src/wok.popable.js
new file mode 100644
index 0000000..fb57010
--- /dev/null
+++ b/ui/js/src/wok.popable.js
@@ -0,0 +1,34 @@
+/*
+ * Project Kimchi
+ *
+ * Copyright IBM, Corp. 2013-2014
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+kimchi.popable = function() {
+    $(document).click(function(e) {
+        $('.popable').each(function(i, n) {
+            n === e.target || $.contains(n, e.target) ||
+                $('.popover', n).toggle(false);
+        });
+     });
+     $(document).on('click', '.popable', function(e) {
+        var popup = $('.popover', this)[0];
+        $(popup).toggle();
+
+        // Scroll the popup menu into viewport if invisible.
+        !$(popup).is(':visible') ||
+            kimchi.isElementInViewport(popup) ||
+            popup.scrollIntoView();
+    });
+};
diff --git a/ui/js/src/wok.string.js b/ui/js/src/wok.string.js
new file mode 100644
index 0000000..252ae50
--- /dev/null
+++ b/ui/js/src/wok.string.js
@@ -0,0 +1,45 @@
+/*
+ * Project Kimchi
+ *
+ * Copyright IBM, Corp. 2014
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+Object.defineProperty(String.prototype, "parseKey", {
+    value: function(parsedKey) {
+        try {
+            if (!Array.isArray(parsedKey)) {
+                parsedKey=[];
+            }
+        }
+        catch (err) {
+            parsedKey=[];
+        }
+        var openBracket=this.indexOf("[");
+        if (openBracket!=-1) {
+            var id=this.slice(0, openBracket);
+            parsedKey.push(id);
+            var closeBracket=this.lastIndexOf("]");
+            if (closeBracket==-1) {
+                closeBracket=this.length;
+            }
+            var tmpName=this.slice(openBracket+1,closeBracket);
+            tmpName.parseKey(parsedKey);
+        }
+        else {
+            parsedKey.push(this);
+        }
+        return(parsedKey);
+        }
+});
diff --git a/ui/js/src/wok.substitute.js b/ui/js/src/wok.substitute.js
new file mode 100644
index 0000000..434d9d3
--- /dev/null
+++ b/ui/js/src/wok.substitute.js
@@ -0,0 +1,45 @@
+/*
+ * Project Kimchi
+ *
+ * Copyright IBM, Corp. 2014
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+kimchi.substitute = function(templateStr, data, tag) {
+    tag = tag || /\{([^\}]+)\}/g;
+
+    var escapeHtml = function(html) {
+        return String(html)
+            .replace(/&/g, '&amp;')
+            .replace(/</g, '&lt;')
+            .replace(/>/g, '&gt;')
+            .replace(/"/g, '&quot;')
+            .replace(/'/g, '&#39;');
+    };
+
+    return templateStr.replace(tag, function(matchResult, express) {
+        var propertyArray = express.split('!');
+        var defaultValue = propertyArray[1] || '';
+        propertyArray = propertyArray[0].split('.');
+        var value = data, i = 0, l = propertyArray.length, property;
+        for (; i < l; i++) {
+            property = propertyArray[i];
+            if (value) {
+                value = value[property];
+            } else {
+                break;
+            }
+        }
+        return escapeHtml((value || value === 0) ? value : defaultValue);
+    });
+};
diff --git a/ui/js/src/wok.topic.js b/ui/js/src/wok.topic.js
new file mode 100644
index 0000000..fd62ffe
--- /dev/null
+++ b/ui/js/src/wok.topic.js
@@ -0,0 +1,48 @@
+/*
+ * Project Kimchi
+ *
+ * Copyright IBM, Corp. 2013-2014
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * pub/sub
+ * Usage:
+ *   Publish - kimchi.topic('eventname').publish(params);
+ *   Subscribe - kimchi.topic('eventname').subscribe(listener);
+ *   Unsubscribe - kimchi.topic('eventname').unsubscribe(listener);
+ */
+kimchi.topic = (function() {
+
+    var topics = {};
+
+    return function( id ) {
+        var callbacks,
+            method,
+            topic = id && topics[ id ];
+
+        if ( !topic ) {
+            callbacks = jQuery.Callbacks();
+            topic = {
+                publish: callbacks.fire,
+                subscribe: callbacks.add,
+                unsubscribe: callbacks.remove
+            };
+            if ( id ) {
+                topics[ id ] = topic;
+            }
+        }
+        return topic;
+    };
+})();
diff --git a/ui/js/src/wok.user.js b/ui/js/src/wok.user.js
new file mode 100644
index 0000000..c036155
--- /dev/null
+++ b/ui/js/src/wok.user.js
@@ -0,0 +1,43 @@
+/*
+ * Project Kimchi
+ *
+ * Copyright IBM, Corp. 2013-2014
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+kimchi.user = (function() {
+    var getUserName = function() {
+        return kimchi.cookie.get('username');
+    };
+
+    var setUserName = function(userName) {
+        kimchi.cookie.set('username', userName, 365);
+    };
+
+    var showUser = function(toShow) {
+        if (toShow) {
+            var userName = getUserName();
+            userName && $('#user-name').text(userName);
+            $('#user').removeClass('not-logged-in');
+            return;
+        }
+
+        $('#user').addClass('not-logged-in');
+    };
+
+    return {
+        getUserName: getUserName,
+        setUserName: setUserName,
+        showUser: showUser
+    };
+})();
diff --git a/ui/js/src/wok.window.js b/ui/js/src/wok.window.js
new file mode 100644
index 0000000..3ac8699
--- /dev/null
+++ b/ui/js/src/wok.window.js
@@ -0,0 +1,70 @@
+/*
+ * Project Kimchi
+ *
+ * Copyright IBM, Corp. 2013-2014
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+kimchi.window = (function() {
+    var _windows = [];
+    var _listeners = {};
+    var open = function(settings) {
+        var settings = jQuery.type(settings) === 'object' ? settings : {
+            url: settings
+        };
+
+        var windowID = settings['id'] || 'window-' + _windows.length;
+
+        if ($('#' + windowID).length) {
+            $('#' + windowID).remove();
+        }
+
+        _windows.push(windowID);
+        _listeners[windowID] = settings['close'];
+        var windowNode = $('<div></div>', {
+            id: windowID,
+            'class': settings['class'] ? settings['class'] + ' bgmask remove-when-logged-off' : 'bgmask remove-when-logged-off'
+        });
+
+        $(windowNode).css(settings['style'] || '');
+
+        $(windowNode).appendTo('body').on('click', '.window .close', function() {
+            kimchi.window.close();
+        });
+
+        if (settings['url']) {
+            $(windowNode).load(settings['url']).fadeIn(100);
+            return;
+        }
+
+        settings['content'] && $(windowNode).html(settings['content']);
+    };
+
+    var close = function() {
+        var windowID = _windows.pop();
+        if(_listeners[windowID]) {
+            _listeners[windowID]();
+            _listeners[windowID] = null;
+        }
+        delete _listeners[windowID];
+
+        $('#' + windowID).fadeOut(100, function() {
+            $(this).remove();
+        });
+    };
+
+    return {
+        open: open,
+        close: close
+    };
+})();
diff --git a/ui/pages/kimchi-ui.html.tmpl b/ui/pages/kimchi-ui.html.tmpl
deleted file mode 100644
index 8da8acc..0000000
--- a/ui/pages/kimchi-ui.html.tmpl
+++ /dev/null
@@ -1,141 +0,0 @@
-#*
- * Project Kimchi
- *
- * Copyright IBM, Corp. 2013-2015
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *#
-#unicode UTF-8
-#import gettext
-#from kimchi.cachebust import href
-#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True)
-#silent _ = t.gettext
-#silent _t = t.gettext
-#from kimchi.config import get_version
-<!DOCTYPE html>
-<html lang="$lang.lang[0]">
-<head>
-<meta charset="UTF-8">
-<title>Kimchi</title>
-<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
-<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
-<link rel="shortcut icon" href="images/logo.ico">
-<link rel="stylesheet" href="$href('libs/themes/base/jquery-ui.min.css')">
-<link rel="stylesheet" href="$href('css/theme-default.min.css')">
-
-<script src="$href('libs/jquery-1.10.0.min.js')"></script>
-<script src="$href('libs/jquery-ui.min.js')"></script>
-<script src="$href('libs/jquery-ui-i18n.min.js')"></script>
-<script src="$href('js/kimchi.min.js')"></script>
-
-<!-- This is used for detecting if the UI needs to be built -->
-<style type="text/css">
-#buildme {
-    position: fixed;
-    background: rgba(0, 0, 0, 0.5);
-    top: 0;
-    left: 0;
-    width: 100%;
-    height: 100%;
-    z-index: 10000;
-}
-
-#buildme div {
-    background-color: #FFB2C0;
-    border-style: solid;
-    border-color: #FF0000;
-    padding: 30px;
-    width: 75%;
-    margin-left: auto;
-    margin-right: auto;
-    margin-top: 50px;
-    -moz-border-radius: 15px;
-    border-radius: 15px;
-}
-</style>
-</head>
-<body onload="kimchi.main()">
-<div class="container">
-<header class="topbar">
-    <h1 id="logo"><img alt="Project Kimchi" src="images/theme-default/logo-white.png"></h1>
-    <ul class="nav-top">
-        <li>
-            <div id="peers" class="peers hide-content popable">
-                <span>$_("Peers")</span>
-                <span class="arrow"></span>
-                <div class="dropdown popover right-side">
-                    <p id="search-peers">$_("Searching")...</p>
-                    <p id="no-peers" class="hide-content">$_("No peers found.")</p>
-                </div>
-            </div>
-        </li>
-        <li>
-            <div id="user" class="popable">
-                <span id="user-icon"></span>
-                <span id="user-name" class="empty-when-logged-off"></span>
-                <span class="arrow"></span>
-                <div class="action-panel popover right-side">
-                    <a id="btn-help" class="user-menu-item" href="javascript:void(0);">$_("Help")</a>
-                    <br/>
-                    <br/>
-                    <a id="btn-about" class="user-menu-item" href="javascript:void(0);">$_("About")</a>
-                    <br/>
-                    <hr/>
-                    <a id="btn-logout" class="user-menu-item" href="javascript: void(0);">$_("Log out")</a>
-                </div>
-            </div>
-        </li>
-    </ul>
-</header>
-<div class="content">
-    <nav class="navbar">
-        <ul id="nav-menu" class="nav-menu">
-            <li class="menu-arrow"></li>
-        </ul>
-    </nav>
-    <div id="main">
-    </div>
-</div>
-</div>
-
-<div id="buildme">
-    <div><p>Oops!  It looks like I am running from a source tree and you forgot to build!
-    Please run the following command from the kimchi directory and reload this page:</p>
-    <p><code>make</code></p>
-    </div>
-</div>
-
-<script id="about-tmpl" type="kimchi/template">
-    <div class="window about-window">
-        <header>
-            <h1 class="title"><img alt="Kimchi logo" src="images/logo.ico"/> $_("About")</h1>
-            <div class="close">X</div>
-        </header>
-        <div class="content" align="center">
-            <center>
-                <div>
-                    <br/>
-                    <br/>
-                    <img src="images/theme-default/logo-plain.gif"/>
-                    <br/>
-                    <br/>
-                    <h2>Kimchi</h2>
-                    <p>$_("Version:") $get_version()</p>
-                </div>
-            </center>
-        </div>
-    </div>
-</script>
-
-</body>
-</html>
diff --git a/ui/pages/wok-ui.html.tmpl b/ui/pages/wok-ui.html.tmpl
new file mode 100644
index 0000000..8da8acc
--- /dev/null
+++ b/ui/pages/wok-ui.html.tmpl
@@ -0,0 +1,141 @@
+#*
+ * Project Kimchi
+ *
+ * Copyright IBM, Corp. 2013-2015
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *#
+#unicode UTF-8
+#import gettext
+#from kimchi.cachebust import href
+#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True)
+#silent _ = t.gettext
+#silent _t = t.gettext
+#from kimchi.config import get_version
+<!DOCTYPE html>
+<html lang="$lang.lang[0]">
+<head>
+<meta charset="UTF-8">
+<title>Kimchi</title>
+<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
+<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
+<link rel="shortcut icon" href="images/logo.ico">
+<link rel="stylesheet" href="$href('libs/themes/base/jquery-ui.min.css')">
+<link rel="stylesheet" href="$href('css/theme-default.min.css')">
+
+<script src="$href('libs/jquery-1.10.0.min.js')"></script>
+<script src="$href('libs/jquery-ui.min.js')"></script>
+<script src="$href('libs/jquery-ui-i18n.min.js')"></script>
+<script src="$href('js/kimchi.min.js')"></script>
+
+<!-- This is used for detecting if the UI needs to be built -->
+<style type="text/css">
+#buildme {
+    position: fixed;
+    background: rgba(0, 0, 0, 0.5);
+    top: 0;
+    left: 0;
+    width: 100%;
+    height: 100%;
+    z-index: 10000;
+}
+
+#buildme div {
+    background-color: #FFB2C0;
+    border-style: solid;
+    border-color: #FF0000;
+    padding: 30px;
+    width: 75%;
+    margin-left: auto;
+    margin-right: auto;
+    margin-top: 50px;
+    -moz-border-radius: 15px;
+    border-radius: 15px;
+}
+</style>
+</head>
+<body onload="kimchi.main()">
+<div class="container">
+<header class="topbar">
+    <h1 id="logo"><img alt="Project Kimchi" src="images/theme-default/logo-white.png"></h1>
+    <ul class="nav-top">
+        <li>
+            <div id="peers" class="peers hide-content popable">
+                <span>$_("Peers")</span>
+                <span class="arrow"></span>
+                <div class="dropdown popover right-side">
+                    <p id="search-peers">$_("Searching")...</p>
+                    <p id="no-peers" class="hide-content">$_("No peers found.")</p>
+                </div>
+            </div>
+        </li>
+        <li>
+            <div id="user" class="popable">
+                <span id="user-icon"></span>
+                <span id="user-name" class="empty-when-logged-off"></span>
+                <span class="arrow"></span>
+                <div class="action-panel popover right-side">
+                    <a id="btn-help" class="user-menu-item" href="javascript:void(0);">$_("Help")</a>
+                    <br/>
+                    <br/>
+                    <a id="btn-about" class="user-menu-item" href="javascript:void(0);">$_("About")</a>
+                    <br/>
+                    <hr/>
+                    <a id="btn-logout" class="user-menu-item" href="javascript: void(0);">$_("Log out")</a>
+                </div>
+            </div>
+        </li>
+    </ul>
+</header>
+<div class="content">
+    <nav class="navbar">
+        <ul id="nav-menu" class="nav-menu">
+            <li class="menu-arrow"></li>
+        </ul>
+    </nav>
+    <div id="main">
+    </div>
+</div>
+</div>
+
+<div id="buildme">
+    <div><p>Oops!  It looks like I am running from a source tree and you forgot to build!
+    Please run the following command from the kimchi directory and reload this page:</p>
+    <p><code>make</code></p>
+    </div>
+</div>
+
+<script id="about-tmpl" type="kimchi/template">
+    <div class="window about-window">
+        <header>
+            <h1 class="title"><img alt="Kimchi logo" src="images/logo.ico"/> $_("About")</h1>
+            <div class="close">X</div>
+        </header>
+        <div class="content" align="center">
+            <center>
+                <div>
+                    <br/>
+                    <br/>
+                    <img src="images/theme-default/logo-plain.gif"/>
+                    <br/>
+                    <br/>
+                    <h2>Kimchi</h2>
+                    <p>$_("Version:") $get_version()</p>
+                </div>
+            </center>
+        </div>
+    </div>
+</script>
+
+</body>
+</html>
-- 
1.7.1




More information about the Kimchi-devel mailing list