You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by ea...@apache.org on 2017/10/23 21:47:08 UTC

[06/45] qpid-dispatch git commit: DISPATCH-834 Initial commit of config file editor

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/93b9fa51/console/config/bower_components/patternfly/dist/fonts/OpenSans-Bold-webfont.ttf
----------------------------------------------------------------------
diff --git a/console/config/bower_components/patternfly/dist/fonts/OpenSans-Bold-webfont.ttf b/console/config/bower_components/patternfly/dist/fonts/OpenSans-Bold-webfont.ttf
new file mode 100644
index 0000000..fd79d43
Binary files /dev/null and b/console/config/bower_components/patternfly/dist/fonts/OpenSans-Bold-webfont.ttf differ

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/93b9fa51/console/config/bower_components/patternfly/dist/fonts/OpenSans-Bold-webfont.woff
----------------------------------------------------------------------
diff --git a/console/config/bower_components/patternfly/dist/fonts/OpenSans-Bold-webfont.woff b/console/config/bower_components/patternfly/dist/fonts/OpenSans-Bold-webfont.woff
new file mode 100644
index 0000000..f501db0
Binary files /dev/null and b/console/config/bower_components/patternfly/dist/fonts/OpenSans-Bold-webfont.woff differ

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/93b9fa51/console/config/bower_components/patternfly/dist/fonts/OpenSans-Bold-webfont.woff2
----------------------------------------------------------------------
diff --git a/console/config/bower_components/patternfly/dist/fonts/OpenSans-Bold-webfont.woff2 b/console/config/bower_components/patternfly/dist/fonts/OpenSans-Bold-webfont.woff2
new file mode 100644
index 0000000..34aac6f
Binary files /dev/null and b/console/config/bower_components/patternfly/dist/fonts/OpenSans-Bold-webfont.woff2 differ

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/93b9fa51/console/config/bower_components/patternfly/dist/fonts/OpenSans-ExtraBold-webfont.ttf
----------------------------------------------------------------------
diff --git a/console/config/bower_components/patternfly/dist/fonts/OpenSans-ExtraBold-webfont.ttf b/console/config/bower_components/patternfly/dist/fonts/OpenSans-ExtraBold-webfont.ttf
new file mode 100644
index 0000000..21f6f84
Binary files /dev/null and b/console/config/bower_components/patternfly/dist/fonts/OpenSans-ExtraBold-webfont.ttf differ

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/93b9fa51/console/config/bower_components/patternfly/dist/fonts/OpenSans-ExtraBold-webfont.woff
----------------------------------------------------------------------
diff --git a/console/config/bower_components/patternfly/dist/fonts/OpenSans-ExtraBold-webfont.woff b/console/config/bower_components/patternfly/dist/fonts/OpenSans-ExtraBold-webfont.woff
new file mode 100644
index 0000000..af67f18
Binary files /dev/null and b/console/config/bower_components/patternfly/dist/fonts/OpenSans-ExtraBold-webfont.woff differ

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/93b9fa51/console/config/bower_components/patternfly/dist/fonts/OpenSans-ExtraBold-webfont.woff2
----------------------------------------------------------------------
diff --git a/console/config/bower_components/patternfly/dist/fonts/OpenSans-ExtraBold-webfont.woff2 b/console/config/bower_components/patternfly/dist/fonts/OpenSans-ExtraBold-webfont.woff2
new file mode 100644
index 0000000..473b2b4
Binary files /dev/null and b/console/config/bower_components/patternfly/dist/fonts/OpenSans-ExtraBold-webfont.woff2 differ

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/93b9fa51/console/config/bower_components/patternfly/dist/fonts/OpenSans-Regular-webfont.ttf
----------------------------------------------------------------------
diff --git a/console/config/bower_components/patternfly/dist/fonts/OpenSans-Regular-webfont.ttf b/console/config/bower_components/patternfly/dist/fonts/OpenSans-Regular-webfont.ttf
new file mode 100644
index 0000000..db43334
Binary files /dev/null and b/console/config/bower_components/patternfly/dist/fonts/OpenSans-Regular-webfont.ttf differ

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/93b9fa51/console/config/bower_components/patternfly/dist/fonts/OpenSans-Regular-webfont.woff
----------------------------------------------------------------------
diff --git a/console/config/bower_components/patternfly/dist/fonts/OpenSans-Regular-webfont.woff b/console/config/bower_components/patternfly/dist/fonts/OpenSans-Regular-webfont.woff
new file mode 100644
index 0000000..1251d51
Binary files /dev/null and b/console/config/bower_components/patternfly/dist/fonts/OpenSans-Regular-webfont.woff differ

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/93b9fa51/console/config/bower_components/patternfly/dist/fonts/OpenSans-Regular-webfont.woff2
----------------------------------------------------------------------
diff --git a/console/config/bower_components/patternfly/dist/fonts/OpenSans-Regular-webfont.woff2 b/console/config/bower_components/patternfly/dist/fonts/OpenSans-Regular-webfont.woff2
new file mode 100644
index 0000000..0964c7c
Binary files /dev/null and b/console/config/bower_components/patternfly/dist/fonts/OpenSans-Regular-webfont.woff2 differ

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/93b9fa51/console/config/bower_components/patternfly/dist/fonts/OpenSans-Semibold-webfont.ttf
----------------------------------------------------------------------
diff --git a/console/config/bower_components/patternfly/dist/fonts/OpenSans-Semibold-webfont.ttf b/console/config/bower_components/patternfly/dist/fonts/OpenSans-Semibold-webfont.ttf
new file mode 100644
index 0000000..1a7679e
Binary files /dev/null and b/console/config/bower_components/patternfly/dist/fonts/OpenSans-Semibold-webfont.ttf differ

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/93b9fa51/console/config/bower_components/patternfly/dist/fonts/OpenSans-Semibold-webfont.woff
----------------------------------------------------------------------
diff --git a/console/config/bower_components/patternfly/dist/fonts/OpenSans-Semibold-webfont.woff b/console/config/bower_components/patternfly/dist/fonts/OpenSans-Semibold-webfont.woff
new file mode 100644
index 0000000..409c725
Binary files /dev/null and b/console/config/bower_components/patternfly/dist/fonts/OpenSans-Semibold-webfont.woff differ

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/93b9fa51/console/config/bower_components/patternfly/dist/fonts/OpenSans-Semibold-webfont.woff2
----------------------------------------------------------------------
diff --git a/console/config/bower_components/patternfly/dist/fonts/OpenSans-Semibold-webfont.woff2 b/console/config/bower_components/patternfly/dist/fonts/OpenSans-Semibold-webfont.woff2
new file mode 100644
index 0000000..d088697
Binary files /dev/null and b/console/config/bower_components/patternfly/dist/fonts/OpenSans-Semibold-webfont.woff2 differ

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/93b9fa51/console/config/bower_components/patternfly/dist/fonts/fontawesome-webfont.ttf
----------------------------------------------------------------------
diff --git a/console/config/bower_components/patternfly/dist/fonts/fontawesome-webfont.ttf b/console/config/bower_components/patternfly/dist/fonts/fontawesome-webfont.ttf
new file mode 100644
index 0000000..35acda2
Binary files /dev/null and b/console/config/bower_components/patternfly/dist/fonts/fontawesome-webfont.ttf differ

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/93b9fa51/console/config/bower_components/patternfly/dist/fonts/fontawesome-webfont.woff
----------------------------------------------------------------------
diff --git a/console/config/bower_components/patternfly/dist/fonts/fontawesome-webfont.woff b/console/config/bower_components/patternfly/dist/fonts/fontawesome-webfont.woff
new file mode 100644
index 0000000..400014a
Binary files /dev/null and b/console/config/bower_components/patternfly/dist/fonts/fontawesome-webfont.woff differ

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/93b9fa51/console/config/bower_components/patternfly/dist/fonts/fontawesome-webfont.woff2
----------------------------------------------------------------------
diff --git a/console/config/bower_components/patternfly/dist/fonts/fontawesome-webfont.woff2 b/console/config/bower_components/patternfly/dist/fonts/fontawesome-webfont.woff2
new file mode 100644
index 0000000..4d13fc6
Binary files /dev/null and b/console/config/bower_components/patternfly/dist/fonts/fontawesome-webfont.woff2 differ

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/93b9fa51/console/config/config.py
----------------------------------------------------------------------
diff --git a/console/config/config.py b/console/config/config.py
new file mode 100755
index 0000000..193b4ad
--- /dev/null
+++ b/console/config/config.py
@@ -0,0 +1,345 @@
+#!/usr/bin/env python
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+import argparse
+from pprint import pprint
+import os, sys, inspect
+import string
+import random
+from glob import glob
+from mock import *
+import SimpleHTTPServer
+import SocketServer
+import json
+import cStringIO
+
+import pdb
+
+def id_generator(size=6, chars=string.ascii_uppercase + string.digits):
+    return ''.join(random.choice(chars) for _ in range(size))
+
+get_class = lambda x: globals()[x]
+sectionKeys = {"log": "module", "sslProfile": "name", "connector": "port", "listener": "port"}
+
+# borrowed from qpid-dispatch/python/qpid_dispatch_internal/management/config.py
+def _parse(lines):
+    """Parse config file format into a section list"""
+    begin = re.compile(r'([\w-]+)[ \t]*{') # WORD {
+    end = re.compile(r'}')                 # }
+    attr = re.compile(r'([\w-]+)[ \t]*:[ \t]*(.+)') # WORD1: VALUE
+    pattern = re.compile(r'([\w-]+)[ \t]*:[ \t]*([\S]+).*')
+
+    def sub(line):
+        """Do substitutions to make line json-friendly"""
+        line = line.strip()
+        if line.startswith("#"):
+            return ""
+        # 'pattern:' is a special snowflake.  It allows '#' characters in
+        # its value, so they cannot be treated as comment delimiters
+        if line.split(':')[0].strip().lower() == "pattern":
+            line = re.sub(pattern, r'"\1": "\2",', line)
+        else:
+            line = line.split('#')[0].strip()
+            line = re.sub(begin, r'["\1", {', line)
+            line = re.sub(end, r'}],', line)
+            line = re.sub(attr, r'"\1": "\2",', line)
+        return line
+
+    js_text = "[%s]"%("\n".join([sub(l) for l in lines]))
+    spare_comma = re.compile(r',\s*([]}])') # Strip spare commas
+    js_text = re.sub(spare_comma, r'\1', js_text)
+    # Convert dictionary keys to camelCase
+    sections = json.loads(js_text)
+    #Config.transform_sections(sections)
+    return sections
+
+class DirectoryConfigs(object):
+    def __init__(self, path='./'):
+        self.path = path
+        self.configs = {}
+
+        files = glob(path + '*.conf')
+        for file in files:
+            with open(file) as f:
+                self.configs[file] = _parse(f)
+
+    def asSection(self, s):
+        cname = s[0][0].upper() + s[0][1:] + "Section"
+        try:
+            c = get_class(cname)
+            return c(**s[1])
+        except KeyError, e:
+            return None
+
+class Manager(object):
+    def __init__(self, topology, verbose):
+        self.topology = topology
+        self.verbose = verbose
+        self.base = "topologies/"
+
+    def operation(self, op, request):
+        m = op.replace("-", "_")
+        try:
+            method = getattr(self, m)
+        except AttributeError:
+            print op + " is not implemented yet"
+            return None
+        if self.verbose:
+            print "Got request " + op
+        return method(request)
+
+    def GET_LOG(self, request):
+        return []
+
+    def GET_SCHEMA(self, request):
+        with open("schema.json") as fp:
+            data = json.load(fp)
+            return data
+
+    def LOAD(self, request):
+        topology = request["topology"]
+        nodes = []
+        links = []
+
+        dc = DirectoryConfigs('./' + self.base + topology + '/')
+        configs = dc.configs
+
+        port_map = []
+        for index, file in enumerate(configs):
+            port_map.append({'connectors': [], 'listeners': []})
+            node = {}
+            for sect in configs[file]:
+                section = dc.asSection(sect)
+                if section:
+                    if section.type == "router":
+                        node["index"] = index
+                        node["nodeType"] = unicode("inter-router")
+                        node["name"] = section.entries["id"]
+                        node["key"] = "amqp:/_topo/0/" + node["name"] + "/$management"
+                        nodes.append(node)
+
+                    elif section.type in sectionKeys:
+                        # look for a host in a listener
+                        if section.type == 'listener':
+                            host = section.entries.get('host')
+                            if host and 'host' not in node:
+                                node['host'] = host
+
+                        role = section.entries.get('role')
+                        if role == 'inter-router':
+                            # we are processing an inter-router listener or connector: so create a link
+                            port = section.entries.get('port', 'amqp')
+                            if section.type == 'listener':
+                                port_map[index]['listeners'].append(port)
+                            else:
+                                port_map[index]['connectors'].append(port)
+                        else:
+                            if section.type+'s' not in node:
+                                node[section.type+'s'] = {}
+                            key = sectionKeys[section.type]
+                            val = section.entries.get(key)
+                            node[section.type+'s'][val] = section.entries
+
+        for source, ports_for_this_routers in enumerate(port_map):
+            for listener_port in ports_for_this_routers['listeners']:
+                for target, ports_for_other_routers in enumerate(port_map):
+                    if listener_port in ports_for_other_routers['connectors']:
+                        links.append({'source': source, 'target': target, 'dir': unicode("in")})
+
+        return {"nodes": nodes, "links": links, "topology": topology}
+
+    def GET_TOPOLOGY(self, request):
+        if self.verbose:
+            pprint (self.topology)
+        return unicode(self.topology)
+
+    def GET_TOPOLOGY_LIST(self, request):
+        return [unicode(f) for f in os.listdir(self.base) if os.path.isdir(self.base + f)]
+
+    def SWITCH(self, request):
+        self.topology = request["topology"]
+        tdir = './' + self.base + self.topology + '/'
+        if not os.path.exists(tdir):
+            os.makedirs(tdir)
+        return self.LOAD(request)
+
+    def FIND_DIR(self, request):
+        dir = request['relativeDir']
+        files = request['fileList']
+        # find a directory with this name that contains these files
+
+
+    def SHOW_CONFIG(self, request):
+        nodeIndex = request['nodeIndex']
+        return self.PUBLISH(request, nodeIndex)
+
+    def PUBLISH(self, request, nodeIndex=None):
+        nodes = request["nodes"]
+        links = request["links"]
+        topology = request["topology"]
+        settings = request["settings"]
+        http_port = settings.get('http_port', 5675)
+        listen_port = settings.get('internal_port', 2000)
+        default_host = settings.get('default_host', '0.0.0.0')
+
+        if nodeIndex and nodeIndex >= len(nodes):
+            return "Node index out of range"
+
+        if self.verbose:
+            if nodeIndex is None:
+                print("PUBLISHing to " + topology)
+            else:
+                print("Creating config for " + topology + " node " + nodes[nodeIndex]['name'])
+
+        if nodeIndex is None:
+            # remove all .conf files from the output dir. they will be recreated below possibly under new names
+            for f in glob(self.base + topology + "/*.conf"):
+                if self.verbose:
+                    print "Removing", f
+                os.remove(f)
+
+        for link in links:
+            s = nodes[link['source']]
+            t = nodes[link['target']]
+            # keep track of names so we can print them above the sections
+            if 'listen_from' not in s:
+                s['listen_from'] = []
+            if 'conn_to' not in t:
+                t['conn_to'] = []
+            if 'conns' not in t:
+                t['conns'] = []
+
+            # make sure source node has a listener
+            lport = listen_port
+            lhost = s.get('host', default_host)
+            s['listen_from'].append(t['name'])
+            if 'listener' not in s:
+                s['listener'] = listen_port
+                listen_port += 1
+            else:
+                lport = s['listener']
+
+            t['conns'].append({"port": lport, "host": lhost})
+            t['conn_to'].append(s['name'])
+
+        # now process all the routers
+        for node in nodes:
+            if node['nodeType'] == 'inter-router':
+                if self.verbose:
+                    print "------------- processing node", node["name"], "---------------"
+
+                nname = node["name"]
+                if nodeIndex is None:
+                    config_fp = open(self.base + topology + "/" + nname + ".conf", "w+")
+                else:
+                    config_fp = cStringIO.StringIO()
+
+                # add a router section in the config file
+                r = RouterSection(**node)
+                if not node.get('conns') and not node.get('listener'):
+                    r.setEntry('mode', 'standalone')
+                else:
+                    r.setEntry('mode', 'interior')
+                r.setEntry('id', node['name'])
+                config_fp.write(str(r) + "\n")
+
+                # write other sections
+                for sectionKey in sectionKeys:
+                    if sectionKey+'s' in node:
+                        for k in node[sectionKey+'s']:
+                            o = node[sectionKey+'s'][k]
+                            cname = sectionKey[0].upper() + sectionKey[1:] + "Section"
+                            c = get_class(cname)
+                            if sectionKey == "listener" and o['port'] != 'amqp' and int(o['port']) == http_port:
+                                config_fp.write("\n# Listener for a console\n")
+                            config_fp.write(str(c(**o)) + "\n")
+
+                if 'listener' in node:
+                    lhost = node.get('host', default_host)
+                    listenerSection = ListenerSection(node['listener'], **{'host': lhost, 'role': 'inter-router'})
+                    if 'listen_from' in node and len(node['listen_from']) > 0:
+                        config_fp.write("\n# listener for connectors from " + ', '.join(node['listen_from']) + "\n")
+                    config_fp.write(str(listenerSection) + "\n")
+
+                if 'conns' in node:
+                    for idx, conns in enumerate(node['conns']):
+                        conn_port = conns['port']
+                        conn_host = conns['host']
+                        connectorSection = ConnectorSection(conn_port, **{'host': conn_host, 'role': 'inter-router'})
+                        if 'conn_to' in node and len(node['conn_to']) > idx:
+                            config_fp.write("\n# connect to " + node['conn_to'][idx] + "\n")
+                        config_fp.write(str(connectorSection) + "\n")
+
+                # return requested config file as string
+                if node.get('index', -1) == nodeIndex:
+                    val = config_fp.getvalue()
+                    config_fp.close()
+                    return val
+
+                config_fp.close()
+
+        return "published"
+
+class HttpHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
+    # use GET requests to serve the web pages
+    def do_GET(self):
+        SimpleHTTPServer.SimpleHTTPRequestHandler.do_GET(self);
+
+    # use PORT requests to send commands
+    def do_POST(self):
+        content_len = int(self.headers.getheader('content-length', 0))
+        if content_len > 0:
+            body = self.rfile.read(content_len)
+            data = json.loads(body)
+            response = self.server.manager.operation(data['operation'], data)
+            if response is not None:
+                self.send_response(200)
+                self.send_header('Content-Type', 'application/json')
+                self.end_headers()
+
+                self.wfile.write(json.dumps(response));
+                self.wfile.close();
+        else:
+            return SimpleHTTPServer.SimpleHTTPRequestHandler.do_POST(self)
+
+    # only log if verbose was requested
+    def log_request(self, code='-', size='-'):
+        if self.server.verbose:
+            self.log_message('"%s" %s %s', self.requestline, str(code), str(size))
+
+class ConfigTCPServer(SocketServer.TCPServer):
+    def __init__(self, port, manager, verbose):
+        SocketServer.TCPServer.__init__(self, ("", port), HttpHandler)
+        self.manager = manager
+        self.verbose = verbose
+
+Schema.init()
+parser = argparse.ArgumentParser(description='Read/Write Qpid Dispatch Router config files.')
+parser.add_argument('-p', "--port", type=int, default=8000, help='port to listen for requests from browser')
+parser.add_argument('-v', "--verbose", action='store_true', help='verbose output')
+parser.add_argument("-t", "--topology", default="config-2", help="which topology to load (default: %(default)s)")
+args = parser.parse_args()
+
+try:
+    httpd = ConfigTCPServer(args.port, Manager(args.topology, args.verbose), args.verbose)
+    print "serving at port", args.port
+    httpd.serve_forever()
+except KeyboardInterrupt:
+    pass
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/93b9fa51/console/config/css/brokers.ttf
----------------------------------------------------------------------
diff --git a/console/config/css/brokers.ttf b/console/config/css/brokers.ttf
new file mode 100644
index 0000000..ae83968
Binary files /dev/null and b/console/config/css/brokers.ttf differ

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/93b9fa51/console/config/css/dispatch.css
----------------------------------------------------------------------
diff --git a/console/config/css/dispatch.css b/console/config/css/dispatch.css
new file mode 100644
index 0000000..c56b4ce
--- /dev/null
+++ b/console/config/css/dispatch.css
@@ -0,0 +1,734 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+svg {
+  background-color: transparent;
+  cursor: default;
+  -webkit-user-select: none;
+  -moz-user-select: none;
+  -ms-user-select: none;
+  -o-user-select: none;
+  user-select: none;
+}
+
+svg:not(.active):not(.ctrl) {
+  cursor: crosshair;
+}
+#end-arrow-selected, #start-arrow-selected {
+	stroke: #33F;
+	fill: #33F;
+}
+path.link.selected {
+  stroke-dasharray: 10,2;
+  stroke: #33F  !important;
+}
+
+path.link {
+  fill: #000;
+  stroke: #000;
+  stroke-width: 4px;
+  cursor: default;
+}
+
+svg:not(.active):not(.ctrl) path.link {
+  cursor: pointer;
+}
+
+path.link.temp {
+  opacity: 0.3;
+}
+path.link.temp.over {
+  opacity: 0.8;
+  stroke-dasharray: 10,2;
+}
+path.link.small {
+  stroke-width: 2.5;
+  stroke: darkgray;
+}
+path.link.highlighted {
+    stroke: #6F6 !important;
+}
+marker#start-arrow-highlighted,
+marker#end-arrow-highlighted {
+    fill: #6F6;
+}
+marker#start-arrow-small,
+marker#end-arrow-small {
+    fill: darkgray;
+}
+
+path.link.dragline {
+  pointer-events: none;
+}
+
+path.link.hidden {
+  stroke-width: 0;
+}
+
+circle.node {
+  stroke-width: 1.5px;
+  cursor: pointer;
+  stroke: darkgray;
+}
+
+circle.node.reflexive {
+  stroke: #F00 !important;
+  stroke-width: 2.5px;
+}
+circle.node.selected {
+  stroke: #6F6 !important;
+  stroke-width: 2px;
+  fill: #e0e0ff !important;
+}
+circle.node.highlighted {
+  stroke: #6F6;
+}
+circle.node.inter-router {
+    fill: #EAEAEA;
+}
+circle.node.normal {
+    fill: #FFF;
+    stroke: #FFF;
+    fill-opacity: 0;
+    stroke-width: 0;
+}
+circle.node.on-demand {
+    fill: #C0FFC0;
+}
+circle.node.on-demand.artemis {
+	fill: #FCC;
+	/*opacity: 0.2; */
+}
+
+circle.node.fixed {
+    stroke-dasharray: 10,2;
+}
+circle.node.temp {
+    stroke: #f80;
+    fill: #f0f0ff;
+}
+
+text {
+  font: 12px sans-serif;
+  pointer-events: none;
+  /*font-family: monospace;*/
+
+}
+
+.tooltipsy
+{
+    padding: 10px;
+/*    max-width: 320px;*/
+    color: #303030;
+    background-color: #fcfcfe;
+    border: 1px solid #deca7e;
+    border-radius: 5px;
+}
+
+.tiptable {
+
+}
+.tiptable tr {
+	border-bottom: 1px solid #ccc;
+}
+
+.tiptable tr:last-child {
+	border-bottom: 0px;
+}
+
+.tiptable tr:nth-child(even) {
+	background: #fcfcfe;
+}
+.tiptable tr:nth-child(odd) {
+	background: #FFF
+}
+
+text.id {
+  text-anchor: middle;
+  font-weight: bold;
+}
+
+text.label {
+  text-anchor: start;
+  font-weight: bold;
+}
+
+.row-fluid.tertiary {
+  position: relative;
+  left: 20px;
+}
+
+.row-fluid.tertiary.left {
+  float: left;
+}
+
+.row-fluid.tertiary.panel {
+  width: 410px;
+  /*height: 100%; */
+}
+
+div#topologyForm .ngViewport, div#topologyForm .gridStyle {
+  height: auto !important;
+  min-height: initial !important;
+  overflow: initial;
+}
+
+div#multiple_details, div#link_details {
+	height: 300px;
+	width: 700px;
+	display: none;
+	padding: 0.5em;
+    border: 1px solid;
+	position: absolute;
+	background-color: white;
+	max-height: 330px !important;
+    overflow: hidden;
+}
+div#multiple_details div.ngRow.selected {
+	background-color: #c9dde1 !important;
+}
+
+div.grid-values {
+	text-align: right;
+}
+
+div.grid-values.ngCellText span {
+	padding-right: 4px;
+}
+
+.panel-adjacent {
+  margin-left: 430px;
+}
+
+#topologyForm.selected {
+  border: 1px solid blue;
+}
+#topologyForm {
+  border-right: 1px solid lightgray;
+  border-bottom: 1px solid lightgray;
+    /*border: 1px solid white;*/
+    padding: 2px;
+    /* position: relative; */
+    /* top: -8px; */
+}
+div.qdr-topology.pane.left .ngViewport {
+    /* border: 1px solid lightgray; */
+}
+
+#topologyForm > div {
+  width:396px;
+}
+
+/* globe */
+.land {
+  fill: #999;
+  stroke-opacity: 1;
+}
+
+.graticule {
+  fill: none;
+  stroke: black;
+  stroke-width:.5;
+  opacity:.1;
+}
+
+.labels {
+    font: 18px sans-serif;
+    fill: black;
+    opacity: .85;
+	text-anchor: middle;
+}
+
+.noclicks { pointer-events:none; }
+
+.point {  opacity:.6; }
+
+.arcs {
+  opacity:.7;
+  stroke: darkgreen;
+  stroke-width: 3;
+}
+.flyers {
+  stroke-width:1;
+  opacity: 0;
+  stroke: darkred;
+}
+.arc, .flyer {
+  stroke-linejoin: round;
+  fill:none;
+}
+.arc { }
+.arc:hover {
+  stroke: darkred;
+}
+.flyer { }
+.flyer:hover {
+  stroke: darkgreen;
+}
+.arc.inter-router {
+  stroke: darkblue;
+}
+
+#addNodeForm {
+  padding: 1em;
+}
+
+
+li.currentStep {
+  font-weight: bold;
+}
+
+.qdrTopology div.panel {
+  position: absolute;
+}
+/*
+.ui-dialog-titlebar {
+    border: 0;
+    background: transparent;
+}
+*/
+
+/*
+.ui-tabs.ui-tabs-vertical {
+    padding: 0;
+    width: 48em;
+}
+.ui-tabs.ui-tabs-vertical .ui-widget-header {
+    border: none;
+}
+.ui-tabs.ui-tabs-vertical .ui-tabs-nav {
+    float: left;
+    width: 10em;
+    background: #CCC;
+    border-radius: 4px 0 0 4px;
+    border-right: 1px solid gray;
+}
+.ui-tabs.ui-tabs-vertical .ui-tabs-nav li {
+    clear: left;
+    width: 100%;
+    margin: 0.1em 0;
+    border: 1px solid gray;
+    border-width: 1px 0 1px 1px;
+    border-radius: 4px 0 0 4px;
+    overflow: hidden;
+    position: relative;
+    right: -2px;
+    z-index: 2;
+}
+.ui-tabs.ui-tabs-vertical .ui-tabs-nav li a {
+    display: block;
+    width: 100%;
+    padding: 0.1em 1em;
+}
+.ui-tabs.ui-tabs-vertical .ui-tabs-nav li a:hover {
+    cursor: pointer;
+}
+.ui-tabs.ui-tabs-vertical .ui-tabs-nav li.ui-tabs-active {
+    margin-bottom: 0.2em;
+    padding-bottom: 0;
+    border-right: 1px solid white;
+}
+.ui-tabs.ui-tabs-vertical .ui-tabs-nav li:last-child {
+    margin-bottom: 10px;
+}
+.ui-tabs.ui-tabs-vertical .ui-tabs-panel {
+    float: left;
+    width: 34em;
+    border-left: 1px solid gray;
+    border-radius: 0;
+    position: relative;
+    left: -1px;
+}
+
+.ui-tabs .ui-tabs-nav li.ui-tabs-selected {
+    right: -3px !important;
+}
+
+.ui-tabs li i.ui-icon {
+    display: inline-block;
+}
+*/
+.ui-tabs .ui-tabs-panel {
+    /* padding-top: 0 !important; */
+}
+
+.ui-widget-content fieldset {
+  float: left;
+  padding: 0 1em 0 0;
+}
+
+.entity-description {
+  color: #960;
+  font-size: 90%;
+}
+
+.attr-description {
+  padding-top: 1.5em;
+  float: right;
+  width: 27em;
+}
+.attr-annotations {
+    padding-top: 2.5em;
+    clear: both;
+}
+.attr-annotations > span {
+    padding-top: 0.5em;
+    border-top: 1px dashed darkgray;
+    display: block;
+}
+
+.attr-type {
+    color: #330;
+    font-size: 85%;
+}
+.attr-required {
+    color: red;
+    font-size: 85%;
+}
+.attr-unique {
+    color: green;
+    font-size: 85%;
+}
+
+#tabs.nodeEntities {
+  border: 0;
+}
+
+#tabs ul.nodeTabs {
+  background: #fff;
+}
+
+#tabs #Container {
+  border-left: 1px solid #aaa;
+}
+
+#tabs.ui-tabs .ui-tabs-nav li {
+  border-bottom: 1px solid #aaa !important;
+}
+
+.entity-fields {
+  /* height: 400px; */
+  overflow-y: scroll;
+  overflow-x: hidden;
+}
+
+div.boolean label:first-child {
+    float: left;
+    margin-right: 1em;
+}
+.entity-fields label {
+    font-weight: 600;
+    margin-top: 0.5em;
+	display: inline;
+}
+
+.aggregate {
+	text-align: right;
+}
+
+.aggregate i {
+	float: right;
+    margin: 3px 3px 3px 8px;
+}
+
+.aggregate .hastip {
+	padding: 5px;
+}
+
+.subTip .tipsy-inner {
+	background-color: white;
+	color: black;
+	font-size: 1.3em;
+	border: 1px solid black;
+}
+
+.subTip .tipsy-arrow-n { border-bottom-color: black; }
+.subTip .tipsy-arrow-s { border-top-color: black; }
+.subTip .tipsy-arrow-e { border-left-color: black; }
+.subTip .tipsy-arrow-w { border-right-color: black; }
+
+
+.contextMenu {
+  display:none;
+  position:absolute;
+  left:30px;
+  top:-30px;
+  z-index:999;
+	/* width:300px; */
+}
+.contextMenu ul {
+	width:300px;
+	margin:0;
+	padding-left:0;
+	list-style:none;
+	background:#fff;
+	color:#333;
+    font-weight: 600;
+	/* -moz-border-radius:5px; -webkit-border-radius:5px; border-radius:5px; */
+	-moz-box-shadow:5px 5px 5px #ddd; -webkit-box-shadow:5px 5px 5px #999; box-shadow:5px 5px 5px #ddd;
+	border: 1px solid #aaa;
+}
+.contextMenu ul li {
+	padding:5px 10px;
+	/* border-bottom: solid 1px #ccc; */
+}
+.contextMenu ul li:hover {
+	background:#4a90d9; color:#fff;
+}
+.contextMenu ul li:last-child {
+    border:none;
+}
+
+.na {
+    display: none;
+}
+.contextMenu ul li.new {
+    display: block;
+}
+.contextMenu ul li.adding, .contextMenu ul li.adding + li {
+    display: block;
+}
+.contextMenu ul li.force-display {
+    display: block;
+}
+.contextMenu ul li.context-separator {
+    background-color: lightgray;
+    height: 1px;
+    padding: 0;
+}
+
+.ui-tabs.ui-tabs-vertical .ui-tabs-nav li.separated {
+    margin-top: 1em;
+}
+
+#crosssection {
+    display: none;
+    position: absolute;
+    top: 200px;
+    left: 600px;
+}
+
+.node circle {
+/*  fill: rgb(31, 119, 180);
+  fill-opacity: .25; */
+  fill: #cfe2f3;
+  fill-opacity: .98;
+  stroke: black;
+  stroke-width: 3px;
+}
+
+circle.subcircle {
+    stroke-width: 1px;
+    /* stroke-dasharray: 2; */
+    fill-opacity: 0;
+    stroke: darkgray;
+}
+
+.leaf circle {
+  fill: #6fa8dc;
+  fill-opacity: 0.95;
+  stroke-width: 3px;
+}
+
+.leaf circle[title] {
+    font-family: monospace;
+
+}
+
+#svg_legend {
+    position: absolute;
+    top: 110px;
+    right: 0;
+    border: 1px solid #ccc;
+    border-radius: 5px;
+    background-color: #fcfcfc;
+    margin-right: 1.3em;
+	padding: 1em;
+}
+
+#svg_legend svg {
+    height: 235px;
+    width: 180px;
+}
+
+#multiple_details div.gridStyle {
+/*	height: 50em; */
+	min-height: 70px !important;
+	height: auto !important;
+}
+
+#multiple_details .ngViewport {
+    height: auto !important;
+}
+
+#multiple_details .gridCellButton button, #link_details .gridCellButton button {
+    margin: .25em .4em;
+    font-size: 12px;
+    height: 2em;
+	padding-top: .1em;
+}
+
+#linkFilter {
+	display: none;
+	padding: 0.5em;
+	border: 1px solid grey;
+	background-color: #F0F0F0;
+	position: absolute;
+	z-index: 100;
+	right: 1em;
+}
+div.formLine label, div.formLine input {
+	display: inline-block;
+	padding: 0 8px;
+}
+
+span.filter-icon {
+	padding-left: 1em;
+}
+
+button.filter-close {
+    width: 15px;
+    height: 20px;
+    padding: 0;
+    position: absolute;
+    right: 4px;
+    top: 4px;
+}
+
+div.filter-title h6 {
+	margin: 0 0 0.5em 0;
+}
+
+.links button.btn-filter {
+	padding: 0 1em 0 0;
+    margin-left: 1em;
+    font-size: 1em;
+}
+
+button.btn-filter {
+	float: right;
+}
+span.dynatree-expanded button.btn-filter,
+a.dynatree-title:hover button.btn-filter {
+ 	visibility: visible;
+}
+
+div.hdash-button a {
+	color: white;
+}
+
+.linkDirIn {
+	color: red;
+	background-color: #f3f3f3;
+}
+
+.linkDirOut {
+	color: blue;
+	background-color: white;
+}
+
+div.topoGrid .ui-grid-viewport {
+	overflow: hidden !important;
+}
+
+@-moz-document url-prefix() {
+    /*.btn {padding: 2px 12px 8px !important;} */
+    #overview-controller .btn {padding: 4px 12px !important;}
+    #overview-controller .btn.filter-close {padding: 0 !important;}
+}
+
+.ui-fancytree.fancytree-container {
+	font-size: 14px;
+}
+
+.grid-title {
+    background-color: #FAFAFA;
+    background-image: -moz-linear-gradient(top, #ffffff, #f2f2f2);
+    background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#f2f2f2));
+    background-image: -webkit-linear-gradient(top, #ffffff, #f2f2f2);
+    background-image: -o-linear-gradient(top, #ffffff, #f2f2f2);
+    background-image: linear-gradient(to bottom, #ffffff, #f2f2f2);
+    background-repeat: repeat-x;
+    filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFF', endColorstr='#F2F2F2', GradientType=0);
+    border-bottom: 1px solid #d4d4d4;
+    text-shadow: 0 1px 0 #FFFFFF;
+    border-top-left-radius: 5px;
+    border-top-right-radius: 5px;
+	margin: 0 0 10px 0;
+    padding-bottom: 4px;
+}
+
+.expand-collapse {
+	float: right;
+	margin-right: 0.5em;
+}
+
+.pane-viewport {
+	top: 24px !important;
+}
+.dynatree-node.loading {
+  position: initial;
+}
+
+.hideLeft {
+  position: absolute;
+  right: 0.5em;
+  top: 1em;
+  border: 0;
+}
+
+.showLeft {
+  position: absolute;
+  top: 1em;
+  left: 0.5em;
+  border: 0;
+}
+
+.newChart {
+  float: right;
+}
+
+select.unique, input.unique {
+  border: 2px solid blue;
+}
+select.required, input.required {
+  border: 2px solid black;
+}
+
+.required-indicator {
+  padding-left: 0.5em;
+  font-size: 0.85em;
+  vertical-align: super;
+}
+
+.required-indicator::before {
+  content: '(required)'
+}
+
+.unique-indicator {
+  padding-left: 0.5em;
+  font-size: 0.85em;
+  vertical-align: super;
+}
+
+.unique-indicator::before {
+  content: '(must be unique if supplied)'
+}
+
+.unique-indicator
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/93b9fa51/console/config/css/mock.css
----------------------------------------------------------------------
diff --git a/console/config/css/mock.css b/console/config/css/mock.css
new file mode 100644
index 0000000..307ee8c
--- /dev/null
+++ b/console/config/css/mock.css
@@ -0,0 +1,128 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License
+*/
+
+#buttonBar {
+  padding: 1em;
+  border-bottom: 1px solid lightgrey;
+  color: #f5f5f5;
+}
+
+.navbar-primary {
+    font-size: 14px;
+    background-image: linear-gradient(to bottom,#1d1d1d 0,#030303 100%);
+    background-repeat: repeat-x;
+    filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff1d1d1d', endColorstr='#ff030303', GradientType=0);
+}
+
+#buttonBar select {
+    position: relative;
+    top: 2px;
+    margin-left: 0.25em;
+    margin-right: 0.5em;
+    color: black;
+}
+
+path.more {
+  stroke-width: 1;
+  stroke: black;
+}
+
+.edit_input {
+  width: 20em !important;
+}
+
+.pull-right {
+  float: right;
+  margin-left: 0.25em;
+}
+
+.selected-node {
+  margin: 0 5em;
+}
+
+#action_menu {
+  position: absolute;
+}
+
+span.btn-icon {
+  position: relative;
+  top: -2px;
+  padding-left: 2px;
+  font-family: PatternFlyIcons-webfont;
+}
+
+label.form-label {
+  font-weight: 800;
+  margin-top: 1em;
+  margin-bottom: 0;
+}
+
+span.logo {
+    letter-spacing: 4px;
+}
+
+.navbar-brand {
+  padding: 1px !important;
+}
+
+.config-area {
+  max-height: 35em;
+}
+
+.btn .caret {
+  font-weight: 800;
+  padding-right: 2px;
+}
+.btn .down.caret {
+  top: -2px;
+}
+
+.btn .plus.caret:before {
+ content:"\f067";
+}
+
+.btn .down.caret:before {
+ content:"\f0dd";
+}
+
+.tooltip.edit-tooltip .tooltip-inner {
+  min-width: 25em;
+  color: #880000;
+  background-color: #fcfcfc;
+  box-shadow: 0 6px 12px rgba(0,0,0,.175);
+  border: 1px solid #333333;
+}
+.tooltip.edit-tooltip .tooltip-arrow {
+  /* display: none; */
+  color: $ffff68;
+}
+
+
+.form-input-container {
+  display: inline-block;
+  width: 20em;
+}
+
+div.boolean label {
+  margin-bottom: 0;
+}
+
+.alert {
+  max-width: 20em;
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/93b9fa51/console/config/css/plugin.css
----------------------------------------------------------------------
diff --git a/console/config/css/plugin.css b/console/config/css/plugin.css
new file mode 100644
index 0000000..a21af15
--- /dev/null
+++ b/console/config/css/plugin.css
@@ -0,0 +1,986 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+main-display > .span8 {
+  height: 100%;
+  position: relative;
+}
+
+ul.qdrListNodes > li > span {
+  padding: 6px 20px; 6px; 6px;
+  display: block;
+}
+
+.qdrList .gridStyle {
+    width: 20em;
+    margin-right: 0;
+    float: left;
+}
+
+
+.qdrList div.gridDetails {
+    width: auto;
+}
+
+div.gridDetails {
+    margin-left: 1em;
+}
+
+.selectedItems {
+    /* margin-left: 21em; */
+}
+
+.qdrListPane {
+    top: 110px;
+}
+
+.qdrListActions {
+    width: auto;
+    margin-left: 1em;
+}
+
+div.listAttrName {
+    padding-top: 5px;
+}
+
+div.listAttrName i.icon-bar-chart {
+    float: right;
+    margin: 3px 5px;
+}
+
+div.listAttrName i.icon-bar-chart.active, div.hastip i.icon-bar-chart.active, li.haschart i {
+    background-color: #AAFFAA;
+}
+
+div#main div ul.nav li a:not(.btn) {
+    background: initial !important;
+}
+
+div#main div ul.nav li.active a {
+    background-color: #f0f0ff !important;
+}
+
+div#main.qdr {
+    margin-top: 56px !important;
+}
+
+div.charts-header {
+  font-size: 1.2em;
+  color: #666666;
+  margin: 1em 0;
+}
+
+.selectedNode, .selectedAction, .selectedEntity {
+    font-weight: 600;
+    color: #606066;
+}
+
+.okButton {
+    text-align: center;
+    margin: 1em;
+}
+
+span.showChartsLink {
+    border: 1px solid blue;
+    padding: 1px 2px;
+}
+
+div.listGraphs p {
+    margin: 1em 0 2em 2em;
+    text-align: center;
+}
+
+div.centered {
+    text-align: center;
+    margin: 4em;
+}
+
+.modal-body.centered {
+	margin: 0;
+}
+
+/* dialog */
+div.aChart {
+    height: 200px;
+    width:  400px;
+    margin: 1em;
+}
+
+/* dashboard */
+div.aChart.hDash {
+	/* width: 21em; */
+	/* height: 17em; */
+	width: 100%;
+	height: 87%;
+	margin: 0;
+	padding: 0;
+
+}
+div.chartContainer {
+    float: left;
+	width: 100%;
+	height: 100%;
+	overflow: hidden;
+}
+
+/* the x and y axis lines */
+.d3Chart g.axis path.domain {
+    stroke-width: 1;
+    stroke: black;
+}
+
+/* the line surrounding the area chart */
+div.d3Chart path {
+/*    stroke: black; */
+    stroke-width: 0;
+/*	opacity: 0.5; */
+}
+
+/* the line above the area chart */
+/* the color gets overridden */
+div.d3Chart path.line {
+    stroke: steelblue;
+    stroke-width: 1.5;
+    fill: none;
+    opacity: 1;
+}
+
+.mo-rect {
+    fill: #ffffdd;
+    stroke: #f0f0f0;
+    stroke-width: 1;
+}
+
+.mo-guide {
+    fill: none;
+    stroke: #d0d0d0;
+    stroke-width: 2;
+    stroke-dasharray: 3,3;
+}
+
+div.d3Chart .title {
+    text-decoration: underline;
+}
+
+
+.axis line, .axis path {
+  fill: none;
+  shape-rendering: crispEdges;
+  stroke-width: 1;
+  stroke: #000000;
+}
+
+.axis line {
+  stroke: #C0C0C0;
+  stroke-dasharray: 1,1;
+  opacity: 0.5;
+}
+
+.y.axis text, .x.axis text, .focus text, div.d3Chart .title {
+    font-size: 12px;
+}
+
+.y.axis path {
+   stroke: #000;
+ }
+
+.overlay {
+   fill: none;
+   pointer-events: all;
+ }
+
+.focus circle {
+   fill: none;
+   stroke: steelblue;
+ }
+.focus .fo-table {
+	/* box-shadow: 2px 2px 3px #EEE; */
+}
+
+div.d3Chart {
+    padding: 1em 0;
+    border: 1px solid #C0C0C0;
+}
+div.d3Chart.hDash {
+    border: 0px;
+}
+
+div.d3Chart .axis path {
+	display: inherit;
+}
+.c3-circle {
+	display: none;
+}
+
+.fo-table {
+	border: 1px solid darkgray;
+	background-color: white;
+	font-size: .85em;
+}
+
+.fo-table td {
+	padding: 4px;
+	border-left: 1px solid darkgray;
+}
+.fo-table tr.detail td {
+	padding: 1px 4px;
+}
+.fo-title {
+	color: white;
+	background-color: darkgray;
+}
+
+.fo-table-legend {
+	width: 8px;
+	height: 8px;
+	border: 1px solid black;
+	margin: 0 4px;
+	display: inline-block;
+}
+
+svg .legend {
+	dominant-baseline: central;
+}
+
+div.chartContainer div.aChart {
+    margin-top: 0.5em;
+}
+
+#list-controller .tree-header {
+    position: absolute;
+    height: auto;
+}
+
+#list-controller select {
+  height: 25px;
+  float: left;
+  padding: 0;
+}
+
+
+div#main.qdr div ul.nav li.active a {
+  background-color: #e0e0ff !important;
+  color: #000000;
+}
+
+div#main.qdr .selected, .box.selected {
+  color: #000000;
+  text-shadow: none;
+}
+
+/* the selected node on the list page */
+div.qdrList li.active, ul.qdrListNodes li.active {
+    background-color: #e0e0ff;
+}
+
+div.qdr-attributes span.dynatree-selected a {
+    background-color: #e0e0ff;
+}
+div.qdr-attributes.pane, div.qdr-topology.pane {
+	position: absolute;
+	margin-left: 10px;
+}
+div.qdr-overview.pane {
+	position: absolute;
+}
+div.qdr-topology.pane.left {
+	width: auto;
+  /*border-right: 1px solid lightgray; */
+}
+
+/* the selected row in the name table */
+div#main.qdr div.qdrList div.selected {
+  background-color: #e0e0ff !important;
+}
+
+#dialogChart, #dialogEditChart {
+    height: 200px;
+}
+
+.chartOptions .modal-body {
+  overflow-y: initial;
+}
+
+div.qdrCharts p.chartLabels button {
+    float: right;
+}
+
+div.qdrCharts p.chartLabels {
+     padding-right: 1em;;
+ }
+
+p.dialogHeader {
+    text-align: center;
+}
+
+p.dialogHeader input {
+    margin-top: 10px;
+    width: 480px;
+}
+
+.ui-slider-tick {
+  position: absolute;
+  background-color: #666;
+  width: 2px;
+  height: 8px;
+  top: 12px;
+  z-index: -1;
+}
+
+label.rateGroup {
+    float: left;
+}
+
+div.chartOptions div.dlg-slider {
+    float: left;
+    margin-left: 2em;
+    width: 28em;
+    font-size: 14px;
+}
+
+div.chartOptions div.duration {
+  width: 35em !important;
+}
+
+div.chartOptions .slider {
+    margin-top: 1em;
+    margin-bottom: 1em;
+}
+
+input[type="radio"] {
+    margin-top: 0 !important;
+}
+
+div.chartOptions legend {
+    font-size: 1.2em;
+    margin-bottom: 10px;
+}
+
+div.chartOptions span.minicolors-swatch {
+    width: 14px;
+    height: 14px;
+}
+
+.minicolors-input {
+    width: 4em;
+    padding: 0 0 0 24px !important;
+}
+
+div.colorPicker div.colorText {
+	display: inline-block;
+	width: 10em;
+}
+div.colorPicker div:nth-of-type(1), /* first span under div.colorPicker */
+ div.minicolors{
+    float:left;
+    margin-right: 0.5em;
+}
+
+div.chartOptions p.sep {
+    height: 1em;
+}
+
+ul.nav-tabs {
+    border-bottom: 1px solid #ddd !important;
+}
+
+.chartOptions ul.nav-tabs {
+    margin-bottom: 0px !important;
+}
+
+div.tabbable div.tab-content {
+    overflow: visible;
+}
+
+div.tabbable ul.nav-tabs > .active > a {
+  background-color: #f8f8f8;
+  border: 1px solid #ddd;
+  border-bottom-color: transparent;
+}
+
+
+div.tabbable .tab-pane {
+    background-color: #f8f8f8;
+    padding: 12px;
+    border-right: 1px solid #ddd;
+    border-left: 1px solid #ddd;
+    border-bottom: 1px solid #ddd;
+}
+div.dlg-large div.tabbable .tab-pane {
+	margin-left: 11em;
+}
+
+div.tabbable ul.nav-tabs {
+  margin-bottom: 0;
+}
+
+ul.qdrTopoModes {
+    position: relative;
+    top: -10px;
+}
+.overview.section {
+	/* width: 35em; */
+}
+.overview.section .ngGrid {
+	height: 12em !important;
+	min-height: 12em !important;
+}
+
+.overview.routers.section .ngGrid {
+ 	height: 16em !important;
+ 	min-height: 16em !important;
+}
+.overview.routers.section {
+ 	/*width: 15em; */
+ }
+
+.grid-align-value {
+	text-align: right;
+}
+
+.grid-align-value .ngCellText {
+	padding-right: 10px;
+}
+
+.overview .ngRow:hover {
+	background:#e0e0ff;
+}
+
+.overview-cell .ngCell:hover {
+	background:#e0e0ff;
+}
+.overview-cell .ngCell.col0:hover, .overview-cell .ngCell.col1:hover {
+	background: initial;
+}
+
+
+.qdr-overview.pane.left, .qdr-attributes.pane.left {
+	top: 104px;
+}
+.qdr-topology.pane.left {
+	top: 104px;
+}
+.qdr-overview.pane.left, .qdr-attributes.pane.left, .qdr-topology.pane.left {
+	left: 10px;
+}
+
+.treeContainer {
+	width: 100%;
+	float: left;
+}
+
+.pane-content {
+	overflow: auto;
+}
+
+#entityNames {
+    width: 20em;
+    float: left;
+}
+
+.treeDetails {
+	margin-left: 260px;
+}
+
+.gridStyle:not(.noHighlight) .ui-grid-row:hover .ui-grid-cell-contents {
+	background-color: #e0e0ff;
+}
+
+.ngCellText {
+	padding: 4px 0 0 4px;
+}
+
+.overview {
+	border-bottom: 1px solid #d4d4d4;
+}
+
+.ui-grid-row.ui-grid-row-selected > [ui-grid-row] > .ui-grid-cell {
+  background-color: #e0e0ff;
+}
+
+.tab-content .tab-pane {
+    background-color: #f8f8f8;
+    padding: 12px;
+    border-right: 1px solid #ddd;
+    border-left: 1px solid #ddd;
+    border-bottom: 1px solid #ddd;
+}
+
+div.chartOptions ul.nav-tabs > .active > a {
+  background-color: #f8f8f8;
+  border: 1px solid #ddd;
+  border-bottom-color: transparent;
+}
+
+div.chartOptions label:nth-of-type(2) {
+    margin-left: 1em;
+}
+div.chartOptions label {
+	font-weight: normal;
+	display: inline-block;
+}
+
+/*
+.form-horizontal .control-label {
+    float: left;
+    width: 160px;
+    padding-top: 5px;
+    text-align: right;
+}
+
+.form-horizontal .controls {
+    margin-left: 180px;
+}
+
+.form-horizontal input,  {
+    display: inline-block;
+    margin-bottom: 0;
+    vertical-align: middle;
+}
+
+input[type="text"], input[type="number"], input[type="password"] {
+    background-color: #ffffff;
+    border: 1px solid #cccccc;
+    -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+    -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+    box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+    -webkit-transition: border linear 0.2s, box-shadow linear 0.2s;
+    -moz-transition: border linear 0.2s, box-shadow linear 0.2s;
+    -o-transition: border linear 0.2s, box-shadow linear 0.2s;
+    transition: border linear 0.2s, box-shadow linear 0.2s;
+}
+
+input[type="text"], input[type="number"], input[type="password"] {
+    display: inline-block;
+    width: 200px;
+    padding: 4px 6px;
+    margin-bottom: 10px;
+    font-size: 14px;
+    line-height: 20px;
+    color: #555555;
+    vertical-align: middle;
+    -webkit-border-radius: 4px;
+    -moz-border-radius: 4px;
+    border-radius: 4px;
+}
+
+.login input[type="checkbox"] {
+	margin-top: 0.75em;
+}
+*/
+
+#dispatch-login-container {
+	/* width: 18.5em; */
+	margin-top: 2em;
+}
+/*
+div.login.container {
+	width: 550px;
+}
+*/
+
+
+#overtree .fancytree-container {
+	border: 0px;
+}
+
+#overtree span.fancytree-alert-icon.ui-icon-refresh {
+	background-position: -64px -80px;
+}
+#overtree span.fancytree-alert-icon.ui-icon-transfer-e-w {
+	background-position: -112px -80px;
+}
+
+#alerts {
+	position: fixed;
+	right: 0;
+	top: 0;
+	z-index: 100;
+}
+
+.alert-enter,
+.alert-leave,
+.alert-move {
+  -webkit-transition: 1s linear all;
+  -moz-transition: 1s linear all;
+  -o-transition: 1s linear all;
+  transition: 1s linear all;
+  position:relative;
+}
+
+.alert-enter {
+  left:-10px;
+  opacity:0;
+}
+.alert-enter.alert-enter-active {
+  left:0;
+  opacity:1;
+}
+
+.alert-leave {
+  left:0;
+  opacity:1;
+}
+.alert-leave.alert-leave-active {
+  left:-10px;
+  opacity:0;
+}
+
+.alert-move {
+  opacity:0.5;
+}
+.alert-move.alert-move-active {
+  opacity:1;
+}
+
+.overview .table-striped tr:hover  td {
+	background-color: #e0e0ff !important;
+}
+
+#entityNames div.ngViewport {
+	overflow-x: hidden;
+}
+
+.connect-column.connect-form {
+	width: 20em;
+}
+
+.chartLabels button a {
+	text-decoration: none;
+}
+
+.fancytree-ico-c.router .fancytree-icon {
+
+}
+
+.tabs-left .nav-tabs {
+	float: left;
+}
+.tabs-left .nav-tabs > li {
+/*	float: initial; */
+}
+
+div.modal.dlg-large {
+	width: 53em;
+}
+
+button.hdash-button a {
+	text-decoration: none;
+	color: #fff;
+}
+
+div.widget-body > div {
+	height: 100%;
+}
+
+div.qdrCharts {
+	height: 100%;
+}
+
+ul.dispatch-view {
+	margin-bottom: 0 !important;
+}
+
+.qdr-overview.pane.left span:not(.dynatree-has-children) .dynatree-icon:before,
+.qdr-attributes.pane.left span:not(.dynatree-has-children) .dynatree-icon:before {
+    color: green;
+}
+
+span:not(.dynatree-has-children).address .dynatree-icon:before,
+span:not(.dynatree-has-children).router\.address .dynatree-icon:before {
+  font-family: FontAwesome;
+  content: "\f0ac";
+}
+span:not(.dynatree-has-children).address.mobile .dynatree-icon:before,
+span:not(.dynatree-has-children).router\.address.mobile .dynatree-icon:before {
+  font-family: FontAwesome;
+  content: "\f109";
+}
+span:not(.dynatree-has-children).address.internal.mobile .dynatree-icon:before,
+span:not(.dynatree-has-children).router\.address.internal.mobile .dynatree-icon:before {
+  font-family: FontAwesome;
+  content: "\f0ac";
+}
+span:not(.dynatree-has-children).address.router .dynatree-icon:before,
+span:not(.dynatree-has-children).router\.address.router .dynatree-icon:before {
+  font-family: FontAwesome;
+  content: "\f047";
+}
+
+span.address-link .dynatree-icon:before {
+  font-family: FontAwesome;
+  content: "\f0ac";
+}
+
+span:not(.dynatree-has-children).connection.external .dynatree-icon:before {
+  font-family: FontAwesome;
+  content: "\f109";
+}
+span:not(.dynatree-has-children).connection.normal .dynatree-icon:before {
+  font-family: FontAwesome;
+  content: "\f08e";
+}
+span:not(.dynatree-has-children).connection.external.quiesced .dynatree-icon:before {
+  font-family: FontAwesome;
+	content: "\f14c";
+	color: red;
+}
+span:not(.dynatree-has-children).connection.inter-router .dynatree-icon:before {
+  font-family: FontAwesome;
+   content: "\f07e";
+}
+span:not(.dynatree-has-children).connection.router-control .dynatree-icon:before {
+  font-family: FontAwesome;
+   content: "\f013";
+}
+span:not(.dynatree-has-children).no-data .dynatree-icon:before {
+  font-family: FontAwesome;
+  content: "\f05e";
+  color: red !important;
+}
+span:not(.dynatree-has-children).loading .dynatree-icon:before {
+  font-family: FontAwesome;
+  content: "\f254";
+}
+span:not(.dynatree-has-children).connector .dynatree-icon:before {
+  font-family: FontAwesome;
+  content: "\f126";
+}
+span:not(.dynatree-has-children).container .dynatree-icon:before {
+  font-family: FontAwesome;
+  content: "\f16c";
+}
+span:not(.dynatree-has-children).log .dynatree-icon:before {
+  font-family: FontAwesome;
+  content: "\f0f6";
+}
+span:not(.dynatree-has-children).router\.node .dynatree-icon:before {
+  font-family: FontAwesome;
+  content: "\f013";
+}
+span:not(.dynatree-has-children).link.inter-router .dynatree-icon:before,
+span:not(.dynatree-has-children).router\.link.inter-router .dynatree-icon:before{
+  font-family: FontAwesome;
+  content: "\f07e";
+}
+span:not(.dynatree-has-children).link.router-control .dynatree-icon:before,
+span:not(.dynatree-has-children).router\.link.router-control .dynatree-icon:before{
+  font-family: FontAwesome;
+  content: "\f013";
+}
+span:not(.dynatree-has-children).link.endpoint .dynatree-icon:before,
+span:not(.dynatree-has-children).router\.link.endpoint .dynatree-icon:before{
+  font-family: FontAwesome;
+  content: "\f109";
+}
+span:not(.dynatree-has-children).link.console .dynatree-icon:before,
+span:not(.dynatree-has-children).router\.link.console .dynatree-icon:before {
+  font-family: FontAwesome;
+  content: "\f108";
+}
+span:not(.dynatree-has-children).listener .dynatree-icon:before {
+  font-family: FontAwesome;
+  content: "\f025";
+}
+span:not(.dynatree-has-children).connection .dynatree-icon:before {
+  font-family: FontAwesome;
+  content: "\f07e";
+}
+span:not(.dynatree-has-children).connection.console .dynatree-icon:before {
+  font-family: FontAwesome;
+  content: "\f108";
+}
+span:not(.dynatree-has-children).waypoint .dynatree-icon:before {
+  font-family: FontAwesome;
+  content: "\f0ec";
+}
+span:not(.dynatree-has-children).router .dynatree-icon:before {
+  font-family: FontAwesome;
+  content: "\f047";
+}
+span:not(.dynatree-has-children).fixedAddress .dynatree-icon:before {
+  font-family: FontAwesome;
+  content: "\f015";
+}
+span:not(.dynatree-has-children).linkRoutePattern .dynatree-icon:before {
+  font-family: FontAwesome;
+  content: "\f039";
+}
+span:not(.dynatree-has-children).allocator .dynatree-icon:before {
+  font-family: FontAwesome;
+  content: "\f170";
+}
+
+.ngCellText {
+/*    color: #333333; */
+}
+
+.changed {
+    color: #339933;
+}
+
+div.dispatch-router div.help {
+    width: auto;
+    padding: 1em;
+    background-color: lavender;
+    border-radius: 6px;
+    margin-top: 1em;
+    text-align: center;
+}
+
+div.operations tr:nth-child(even) {
+	background: #f3f3f3;
+}
+div.operations tr:nth-child(odd), div.operations tr:last-child {
+	background: #fff;
+}
+
+div.operations tr input {
+	margin: 0;
+	padding: 3px 6px;
+}
+div.operations table {
+    width: 100%;
+}
+div.operations th {
+    width: 50%;
+    border-bottom: 1px solid #cccccc;
+    text-align: left;
+}
+div.operations td:nth-child(odd), div.operations th:nth-child(odd) {
+	border-right: 1px solid #cccccc;
+}
+div.operations td:nth-child(odd) {
+	padding-left: 0;
+}
+div.operations td:nth-child(even), div.operations th:nth-child(even) {
+	padding-left: 5px;
+}
+div.operations th {
+	padding: 5px;
+}
+div.operations .tab-pane.active {
+    padding: 12px 12px 12px 0;
+}
+div.operations label {
+    padding-top: 4px;
+    margin-bottom: 4px;
+}
+.qdrListActions .ngGrid {
+	/*min-height: 40em;
+	height: 100%; */
+}
+div.qdrListActions .ngViewport {
+    height: initial !important;
+}
+
+div.operations .boolean {
+    padding-bottom: 0;
+}
+
+table.log-entry {
+    margin-bottom: 1em;
+    border-top: 1px solid black;
+}
+
+table.log-entry pre {
+    background-color: #f5f5f5;
+    color: inherit;
+    margin: 0;
+}
+
+circle.node.normal.console {
+    fill: lightcyan;
+}
+circle.node.artemis {
+    fill: lightgreen;
+}
+circle.node.route-container {
+    fill: orange;
+}
+
+text.console, text.on-demand, text.normal {
+	font-family: FontAwesome;
+	font-weight: normal;
+	font-size: 16px;
+}
+
+@font-face {
+    font-family:"Brokers";
+    src: url("brokers.ttf") /* TTF file for CSS3 browsers */
+}
+
+text.artemis {
+    font-family: Brokers;
+    font-size: 20px;
+    font-weight: bold;
+}
+
+text.qpid-cpp {
+    font-family: Brokers;
+    font-size: 18px;
+    font-weight: bold;
+}
+
+i.red {
+	color: red;
+}
+
+.qdrListActions div.delete {
+    width: 20em;
+    margin: auto;
+    border: 1px solid #eaeaea;
+    height: 5em;
+    padding: 4em;
+    background-color: #fcfcfc;
+}
+
+.btn:focus {
+    box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);
+}
+
+select:focus, input[type="file"]:focus, input[type="radio"]:focus, input[type="checkbox"]:focus {
+	outline:3px solid rgba(82, 168, 236, 0.6);
+    box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);
+    outline: 5px auto -webkit-focus-ring-color;
+    outline-offset: -2px;
+}
+
+#dispatch-login-container .ng-invalid-range {
+	border-color: #e9322d !important;
+}
+
+div#durationSlider, div#rateSlider {
+	margin-top: 1em;
+}
+
+.list-grid {
+	padding-left: 10px;
+}
+
+.ngViewport.ng-scope {
+  height: auto !important;
+}
+
+div#list-controller {
+    padding-left: 300px;
+}
+
+.listening-on {
+    background-color: #CCFFCC;
+}
\ No newline at end of file


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org