Merge branch 'master' of ssh://git.onelab.eu/git/myslice
authorJordan Augé <jordan.auge@lip6.fr>
Fri, 25 Oct 2013 16:01:54 +0000 (18:01 +0200)
committerJordan Augé <jordan.auge@lip6.fr>
Fri, 25 Oct 2013 16:01:54 +0000 (18:01 +0200)
26 files changed:
apache/myslice.conf
debian/unfold.install
manifold/manifoldapi.py
manifold/static/js/manifold.js
myslice/config.py
myslice/myslice.ini.localhost [moved from myslice/myslice.ini with 100% similarity]
myslice/wsgi.py [moved from apache/myslice.wsgi with 100% similarity]
plugins/hazelnut/static/js/hazelnut.js
plugins/slicestat/__init__.py
plugins/slicestat/static/css/slicestat.css
plugins/slicestat/static/js/slicestat.js
plugins/slicestat/templates/slicestat.html
portal/contactview.py
portal/homeview.py
portal/resourceview.py
portal/sliceview.py
portal/templates/contact.html
portal/templates/registration_view.html
portal/templates/resource.html
portal/templates/slice-request-view.html
setup.py
ui/templates/widget-topmenu.html
ui/topmenu.py
unfold/loginrequired.py
unfold/page.py
unfold/static/css/onelab_marko.css [new file with mode: 0644]

index 9e8a155..b782452 100644 (file)
@@ -1,7 +1,7 @@
 <VirtualHost *:80>
-        WSGIScriptAlias / /usr/share/unfold/apache/myslice.wsgi
-        <Directory /usr/share/unfold/apache>
-        <Files myslice.wsgi>
+        WSGIScriptAlias / /usr/share/unfold/myslice/wsgi.py
+        <Directory /usr/share/unfold/myslice>
+        <Files wsgi.py>
         Order deny,allow
         Allow from all
         </Files>
index 4f3996e..a86e983 100644 (file)
@@ -12,4 +12,3 @@ usr/share/unfold/trash
 usr/share/unfold/debug_platform
 manage.py usr/share/unfold/
 apache/myslice.conf /etc/apache2/sites-available
-apache/myslice.wsgi usr/share/unfold/apache
index 042e127..35fd3d7 100644 (file)
@@ -20,13 +20,13 @@ class ManifoldAPI:
 
     def __init__(self, auth=None, cainfo=None):
         
-        config = Config()
         self.auth = auth
         self.cainfo = cainfo
         self.errors = []
         self.trace = []
         self.calls = {}
         self.multicall = False
+        config = Config()
         self.url = config.manifold_url()
         self.server = xmlrpclib.Server(self.url, verbose=False, allow_none=True)
 
index c4d0ef7..11fad7d 100644 (file)
@@ -738,7 +738,7 @@ var manifold = {
               expires: false,
               speed: 1000
             });
-*/            
+*/
         }
        if (manifold.asynchroneous_debug) 
            messages.debug ("========== asynchroneous_success " + query.object + " -- before process_query_records");
index 31dc7e3..53295c4 100644 (file)
@@ -2,15 +2,19 @@ import os.path
 from ConfigParser import RawConfigParser
 from myslice.settings import ROOT
 
-# myslice/myslice.ini
-# as this code suggests, you have the option to write myslice/myslice.ini
+# as this code suggests, you have the option to override these defaults
+# by writing a file myslice/myslice.ini
 # that looks like this
 #[manifold]
 #url = http://manifold.pl.sophia.inria.fr:7080/
 #admin_user = admin
 #admin_password = admin
 
-class Config:
+# use a singleton instead of staticmethods
+from manifold.util.singleton    import Singleton
+
+class Config(object):
+    __metaclass__ = Singleton
 
     # the OpenLab-wide backend as managed by UPMC
     # xxx production should probably use https of course
@@ -20,40 +24,25 @@ class Config:
     # the INRIA setup is with "http://manifold.pl.sophia.inria.fr:7080/"
 
     default_manifold_admin_user     = 'admin'
-    default_manifold_admin_password = None
-
-    _config_parser = None
-
-    # having grown tired of screwing up with git stashes 
-    # taking away my local config, we now more properly use
-    # an external config file to override teh default
-    # XXX we might use support from manifold util classes --jordan
-    @staticmethod
-    def manifold_url ():
-        if Config._config_parser: 
-            return Config._config_parser.get('manifold','url')
-        config = RawConfigParser ()
-        config.add_section('manifold')
-        config.set ('manifold', 'url', Config.default_manifold_url)
-        config.read (os.path.join(ROOT,'myslice/myslice.ini'))
-        Config._config_parser=config
-        return Config.manifold_url()
-
-    @staticmethod
-    def manifold_admin_user_password():
-        if Config._config_parser: 
-            admin_user = Config._config_parser.get('manifold','admin_user')
-            admin_password = Config._config_parser.get('manifold','admin_password')
-            return (admin_user, admin_password)
-        config = RawConfigParser ()
-        config.add_section('manifold')
-        config.set ('manifold', 'admin_user', Config.default_manifold_admin_user)
-        config.set ('manifold', 'admin_password', Config.default_manifold_admin_password)
-        config.read (os.path.join(ROOT,'myslice/myslice.ini'))
-        Config._config_parser=config
-        return Config.manifold_admin_user_password()
+    default_manifold_admin_password = 'demo'
+
+
+    def __init__ (self):
+        parser = RawConfigParser ()
+        parser.add_section('manifold')
+        parser.set ('manifold', 'url', Config.default_manifold_url)
+        parser.set ('manifold', 'admin_user', Config.default_manifold_admin_user)
+        parser.set ('manifold', 'admin_password', Config.default_manifold_admin_password)
+        parser.read (os.path.join(ROOT,'myslice/myslice.ini'))
+        self.config_parser=parser
+
+    def manifold_url (self):
+        return self.config_parser.get('manifold','url')
+
+    def manifold_admin_user_password(self):
+        return (self.config_parser.get('manifold','admin_user'),
+                self.config_parser.get('manifold','admin_password'))
 
     # exporting these details to js
-    @staticmethod
-    def manifold_js_export ():
-        return "var MANIFOLD_URL = '%s';\n"%Config.manifold_url();
+    def manifold_js_export (self):
+        return "var MANIFOLD_URL = '%s';\n"%self.manifold_url();
similarity index 100%
rename from apache/myslice.wsgi
rename to myslice/wsgi.py
index 21b23f5..dcd4e1f 100644 (file)
         on_filter_added: function(filter)
         {
             // XXX
+            console.log(filter);
             this.redraw_table();
         },
 
index 14cfdad..dadebd0 100644 (file)
@@ -1,6 +1,6 @@
 from unfold.plugin import Plugin
 
-class Slicestat(Plugin):
+class SliceStat(Plugin):
     
     def __init__ (self, query, **settings):
         Plugin.__init__ (self, **settings)
@@ -12,8 +12,9 @@ class Slicestat(Plugin):
     def requirements (self):
         reqs = {
             'js_files' : [
-                'js/date.js',
-                'js/slicestat.js'
+                
+                'js/slicestat.js',
+
             ],
             'css_files': [
                 'css/slicestat.css',
index e69de29..9962c83 100644 (file)
@@ -0,0 +1,6 @@
+iframe#slicestat_resource {
+    width:100%;
+    height:400px;
+    border:0;
+    overflow: hidden;
+}
index 4c63b84..a815e7f 100644 (file)
@@ -13,7 +13,7 @@
 
 (function($){
 
-    var Slicestat = Plugin.extend({
+    var SliceStat = Plugin.extend({
 
         /** XXX to check
          * @brief Plugin constructor
          */
         init: function(options, element) {
             // Call the parent constructor, see FAQ when forgotten
-            this._super(options, element);
-                       
-                       google.load("visualization", "1.0", {packages:["corechart"]});
-                        
+            this._super(options, element);                      
                        
 
             /* Member variables */
         {
             console.log(record);
             
-            var node = record.hostname;
-                       var slice = 'root';
-                       
-                       google.setOnLoadCallback(function() {
-                       
-                               var options = {
-                                               pointSize: 2,
-                                               lineWidth: 1,
-                                               title: 'Slice '+slice+' last 24 hours', 'width':780, 'height':400,
-                                       vAxes: { 
-                                                       0: {format: '###,##%'},
-                                                       1: {format: '#Kb',}
-                                                       },
-                                       hAxis: { title: "", format: 'HH:mm'},
-                                   series: {
-                                       0: { type: "line", targetAxisIndex: 0},
-                                       1: { type: "line", targetAxisIndex: 0},
-                                       2: { type: "line", targetAxisIndex: 1},
-                                       3: { type: "line", targetAxisIndex: 1}
-                                   }
-                               };
-                       
-                               var jsonData = $.ajax({
-                                       type: 'POST',
-                                       url: "/db/slice",
-                                       dataType: "json",
-                                       async: false,
-                                       data: { period: 'day', resources: 'cpu,pmc_per,asb,arb', slice: slice, node: node },
-                                       success: function(ret) {
-                                               var result = [];
-                                               var data = new google.visualization.DataTable();
-                                                       data.addColumn('datetime', 'Date');
-                                                       data.addColumn('number', 'CPU (%)');
-                                                       data.addColumn('number', 'MEM (%)');
-                                                       data.addColumn('number', 'Traffic Sent (Kb)');
-                                                       data.addColumn('number', 'Traffic Received (Kb)');
-                                                       $.each(ret, function() {
-                                                               result.push([new Date(this[0]), this[1], this[2], this[3], this[4]]);
-                                                       });
-                                                       data.addRows(result);
-                                                       var chart = new google.visualization.LineChart(document.getElementById('graph'));
-                                                       chart.draw(data, options);
-                                       }
-                                   }).responseText;
-                       
-                       });
+            $('iframe#slicestat_resource').attr('src','http://plestats.planet-lab.eu/node.php?node='+record.hostname);
+            
         },
 
         /* INTERNAL FUNCTIONS */
     });
 
     /* Plugin registration */
-    $.plugin('Slicestat', Slicestat);
+    $.plugin('SliceStat', SliceStat);
 
     // TODO Here use cases for instanciating plugins in different ways like in the pastie.
 
index cb9474c..c97cd9e 100644 (file)
@@ -1,4 +1,3 @@
 <div id={{ domid }}>
-<p>Slicestat</p>
-<div id="slicestat_resource"></div>
+<iframe id="slicestat_resource" src=""></iframe> 
 </div>
index 0f2e401..c07f397 100644 (file)
@@ -40,6 +40,6 @@ class ContactView (View):
     def _display (self, request, form):
         return render(request, 'contact.html', {
                 'form': form,
-                'topmenu_items': topmenu_items('Contact Us', request),
+                'topmenu_items': topmenu_items('Contact', request),
                 'username': the_user (request)
                 })
index b9d039a..960c8f0 100644 (file)
@@ -14,8 +14,9 @@ class HomeView (View):
 
     # expose this so we can mention the backend URL on the welcome page
     def default_env (self):
+        config=Config()
         return { 
-                 'MANIFOLD_URL':Config.manifold_url(),
+                 'MANIFOLD_URL':config.manifold_url(),
                  }
 
     def post (self,request):
@@ -56,7 +57,7 @@ class HomeView (View):
     def get (self, request, state=None):
         env = self.default_env()
         env['username']=the_user(request)
-        env['topmenu_items'] = topmenu_items('', request)
+        env['topmenu_items'] = topmenu_items(None, request)
         if state: env['state'] = state
         elif not env['username']: env['state'] = "Please sign in"
         return render_to_response('home-view.html',env, context_instance=RequestContext(request))
index 0421854..0ba8a26 100644 (file)
@@ -8,7 +8,7 @@ from ui.topmenu                  import topmenu_items, the_user
 from plugins.googlemap           import GoogleMap
 from plugins.hazelnut            import Hazelnut
 from plugins.lists.simplelist    import SimpleList
-from plugins.slicestat           import Slicestat
+from plugins.slicestat           import SliceStat
 
 # View for 1 platform and its details
 class ResourceView(TemplateView):
@@ -16,6 +16,8 @@ class ResourceView(TemplateView):
 
     def get_context_data(self, **kwargs):
         page = Page(self.request)
+        
+        page.add_js_files  ( [ "js/common.functions.js" ] )
 
         for key, value in kwargs.iteritems():
             print "%s = %s" % (key, value)       
@@ -64,9 +66,10 @@ class ResourceView(TemplateView):
 #            query = resource_query,
 #        )
 
-        resource_stats = Slicestat(
+        resource_stats = SliceStat(
             title = None,
             page  = page,
+            stats = 'node',
             key   = 'hrn',
             query = resource_query
         )
@@ -81,7 +84,7 @@ class ResourceView(TemplateView):
         # more general variables expected in the template
         context['title'] = 'Information about a resource'
         # the menu items on the top
-        context['topmenu_items'] = topmenu_items('Dashboard', self.request)
+        context['topmenu_items'] = topmenu_items(None, self.request)
         # so we can sho who is logged
         context['username'] = the_user(self.request)
 
index 9d335f4..15a5e51 100644 (file)
@@ -26,7 +26,8 @@ from myslice.config                  import Config
 tmp_default_slice='ple.upmc.myslicedemo'
 
 # temporary : turn off the users part to speed things up
-do_query_users=True
+#do_query_users=True
+do_query_users=False
 
 class SliceView (LoginRequiredAutoLogoutView):
 
@@ -37,7 +38,8 @@ class SliceView (LoginRequiredAutoLogoutView):
         page.add_js_files  ( [ "js/common.functions.js" ] )
         page.add_js_chunks ('$(function() { messages.debug("sliceview: jQuery version " + $.fn.jquery); });')
         page.add_js_chunks ('$(function() { messages.debug("sliceview: users turned %s"); });'%("on" if do_query_users else "off"))
-        page.add_js_chunks ('$(function() { messages.debug("manifold URL %s"); });'%(Config.manifold_url()))
+        config=Config()
+        page.add_js_chunks ('$(function() { messages.debug("manifold URL %s"); });'%(config.manifold_url()))
         page.expose_js_metadata()
     
         metadata = page.get_metadata()
@@ -189,33 +191,33 @@ class SliceView (LoginRequiredAutoLogoutView):
         # --------------------------------------------------------------------------
         # USERS
     
-        if do_query_users:
-            tab_users = Tabs(
-                page                = page,
-                domid               = 'users',
-                outline_complete    = True,
-                togglable           = True,
-                title               = 'Users',
-                active_domid        = 'users-list',
-                )
-            main_stack.insert(tab_users)
-    
-            tab_users.insert(Hazelnut( 
-                page        = page,
-                title       = 'Users List',
-                domid       = 'users-list',
-                # tab's sons preferably turn this off
-                togglable   = False,
-                # this is the query at the core of the slice list
-                query       = sq_user,
-                query_all  = query_user_all,
-                checkboxes  = True,
-                datatables_options = { 
-                    'iDisplayLength' : 25,
-                    'bLengthChange'  : True,
-                    'bAutoWidth'     : True,
-                },
-            ))
+#        if do_query_users:
+#            tab_users = Tabs(
+#                page                = page,
+#                domid               = 'users',
+#                outline_complete    = True,
+#                togglable           = True,
+#                title               = 'Users',
+#                active_domid        = 'users-list',
+#                )
+#            main_stack.insert(tab_users)
+#    
+#            tab_users.insert(Hazelnut( 
+#                page        = page,
+#                title       = 'Users List',
+#                domid       = 'users-list',
+#                # tab's sons preferably turn this off
+#                togglable   = False,
+#                # this is the query at the core of the slice list
+#                query       = sq_user,
+#                query_all  = query_user_all,
+#                checkboxes  = True,
+#                datatables_options = { 
+#                    'iDisplayLength' : 25,
+#                    'bLengthChange'  : True,
+#                    'bAutoWidth'     : True,
+#                },
+#            ))
 # DEMO    
         # --------------------------------------------------------------------------
         # MEASUREMENTS
index 5161971..2652647 100644 (file)
@@ -22,9 +22,7 @@
       <div class="col-xs-4"> {{ field.errors }} {{ field }} <p class="form-hint">{{ field.help_text }}</p> </div>
     </div>
     {% endfor %}
-    <div class="col-xs-offset-4 col-xs-4">
-      <button class="submit btn btn-default" type="submit">Submit</button>
-    </div>
+    <button class="submit btn btn-default col-md-offset-4 col-xs-4" type="submit">Send to Support</button>
   </fieldset>
   </form>
 </div>
index d8abb5d..3d1010c 100644 (file)
       <div class="col-xs-4"><p class="form-hint">Account Delegation: Manual (Advanced Users)</p></div>
     </div>
     <div class="form-group" id="register">
-      <div class="col-xs-offset-4 col-xs-4">
-       <button class="submit btn btn-default" type="submit">Register</button>
-      </div>
+      <button class="submit btn btn-default col-md-offset-4 col-xs-4" type="submit">Register</button>
+    </div>
     </div>
   </fieldset>
   </form>  
index 5bdfdc9..27089a7 100644 (file)
@@ -8,6 +8,6 @@
 
 <h1>Resource</h1>
 {{resource}}
-{{resource_stats}}
 {{resource_as_map}}
+{{resource_stats}}
 {% endblock %}
index f437ae0..6aede04 100644 (file)
@@ -25,9 +25,7 @@
       <div class="col-xs-4"> <p class="form-hint">{{ field.help_text }}</p> </div>
     </div>
     {% endfor %}
-    <div class="col-xs-offset-4 col-xs-4">
-      <button class="submit btn btn-default" type="submit">Submit</button>
-    </div>
+    <button class="submit btn btn-default col-md-offset-4 col-xs-4" type="submit">Request Slice</button>
   </fieldset>
   </form>
 </div>
index 98d1368..157641a 100644 (file)
--- a/setup.py
+++ b/setup.py
@@ -20,5 +20,5 @@ setup(packages = packages,
         ( 'static/img', glob ('static/img/*')),
         ( 'static/fonts', glob ('static/fonts/*')),
         ( 'templates', glob ('templates/*')),
-        ( 'apache', [ 'apache/myslice.conf', 'apache/myslice.wsgi' ]),
+        ( 'apache', [ 'apache/myslice.conf' ]),
         ])
index f5308de..b31b133 100644 (file)
@@ -23,7 +23,7 @@
          <ul class="dropdown-menu">
            {% for dd in d.contents %}
            {% if dd.is_active %}<li class='active'>{% else %}<li class='other'>{% endif %}
-           <a class="dropdown-toggle" href="{{ dd.href }}"> {{ dd.label }} </a> </li>
+           <a href="{{ dd.href }}"> {{ dd.label }} </a> </li>
            {% endfor %}
          </ul>
         </li>
index 72904f9..bdee674 100644 (file)
@@ -7,33 +7,35 @@
 # ### a dropdown
 # { 'label': ..., 'href'=..., 'dropdown':True, 'contents': [ { 'label':.., 'href'} ] }
 # , ..]
+
+# current: the beginning of the label in the menu that you want to outline
 def topmenu_items (current,request=None):
     has_user=request.user.is_authenticated()
     result=[]
     if has_user:
         result.append({'label':'Dashboard', 'href': '/portal/dashboard/'})
         result.append({'label':'Request a slice', 'href': '/portal/slice_request/'})
-        result.append({'label':'My Account', 'href': '/portal/account/'})
-        result.append({'label':'Contact Support', 'href': '/portal/contact/'})
-# Not really useful at this point, is it ?
-# This should probably go into dashboard at some point
-#        result.append({'label':'Platforms', 'href': '/portal/platforms/'})
-# the code for building a dropdown instead - but somehow this is broken
-#        dropdown = [ {'label':'..', 'href': '..'}, ...]
-#        result.append({'label': 'More', 'href':"#", 'dropdown':True, 'contents':dropdown})
+        dropdown = []
+        dropdown.append({'label':'My Account', 'href': '/portal/account/'})
+        dropdown.append({'label':'Contact Support', 'href': '/portal/contact/'})
+        result.append({'label': 'More', 'href':"#", 'dropdown':True, 'contents':dropdown})
     else:
         result.append({'label':'Home', 'href': '/login'})
         # looks like this is accessible to non-logged users
         result.append({'label':'Platforms', 'href': '/portal/platforms/'})
         result.append({'label':'Register', 'href': '/portal/register/'})
         result.append({'label':'Contact Support', 'href': '/portal/contact/'})
-    # mark active
-    for d in result:
-        if 'dropdown' in d:
-            for dd in d['contents']:
-                if dd['label'] == current: dd['is_active']=True
-        else:
-            if d['label'] == current: d['is_active']=True
+    # mark active if the provided 'current', even if shorter, matches the beginning of d['label']
+    
+    if current is not None:
+        current=current.lower()
+        curlen=len(current)
+        def mark_active(d):
+            if d['label'][:curlen].lower() == current: d['is_active']=True
+        for d in result:
+            mark_active(d)
+            if 'dropdown' in d:
+                for dd in d['contents']: mark_active(dd)
     return result
 
 def the_user (request):
index 0f46ff7..ebe33d5 100644 (file)
@@ -32,7 +32,9 @@ def logout_on_manifold_exception (fun_that_returns_httpresponse):
         except ManifoldException, manifold_result:
             # xxx we need a means to display this message to user...
             from django.contrib.auth import logout
-            logout(request)
+            # in some unusual cases, this might fail
+            try: logout(request)
+            except: pass
             return HttpResponseRedirect ('/')
         except Exception, e:
             # xxx we need to sugarcoat this error message in some error template...
index 07879e7..5922ae7 100644 (file)
@@ -34,6 +34,7 @@ class Page:
         self._queue=[]
         # global prelude object
         self.prelude=Prelude(css_files='css/plugin.css')
+        self.prelude=Prelude(css_files='css/onelab_marko.css')
 
     # record known plugins hashed on their domid
     def record_plugin (self, plugin):
@@ -140,7 +141,8 @@ class Page:
         self.add_js_chunks("var MANIFOLD_METADATA =" + self.get_metadata().to_json() + ";")
 
     def expose_js_manifold_config (self):
-        self.add_js_chunks(Config.manifold_js_export())
+        config=Config()
+        self.add_js_chunks(config.manifold_js_export())
 
     #################### requirements/prelude management
     # just forward to self.prelude - see decorator above
diff --git a/unfold/static/css/onelab_marko.css b/unfold/static/css/onelab_marko.css
new file mode 100644 (file)
index 0000000..b31174c
--- /dev/null
@@ -0,0 +1,410 @@
+/* @override 
+       http://test.myslice.info/static/css/plugin.css
+*/
+
+
+
+/*-------------------------------- MARKO'S STYLES -----*/
+
+
+/* GENERAL */
+
+.container {
+       padding: 0 !important;
+       color: #fff;
+}
+
+.container h1 {
+       color: #fff !important;
+       font-family: Ubuntu;
+       margin-top: 60px;
+}
+
+div.plugin-outline-complete, 
+div.plugin-outline-body {
+    border: 0px solid;
+    border-radius: 0;
+    border-color: #ccc;
+    -webkit-transition: padding 200ms ease-out;
+    -moz-transition: padding 200ms ease-out;
+    -o-transition: padding 200ms ease-out;
+    transition: padding 0.2s ease-out;
+    padding: 20px;
+    margin: 0;
+}
+/*
+div.plugin-outline-complete:hover, 
+div.plugin-outline-body:hover {
+    padding: 80px 80px 120px 80px; 
+}
+*/
+a.plugin-tooltip { 
+    font-size: 130%;
+    font-style: normal;
+    font-weight: bold;
+    padding: 5px;
+    color: #333;
+    font-family: Ubuntu, Arial, sans-serif;
+    text-transform: uppercase;
+}
+
+a.plugin-tooltip:hover { 
+    color: #fff; 
+    text-decoration: none;
+}
+
+
+
+/* LIST VIEW */
+
+h2.well.well-lg {
+       border-radius:0;
+       border: 0;
+       font-family: Ubuntu, arial, sans-serif;
+       text-transform: ;
+       font-weight: normal;
+       font-size: 40px;
+       /* color: #30196d; */
+    color: white;
+       margin-bottom: 0px;
+       margin-top: 0;
+       padding: 30px;
+       opacity: 1;
+       text-align: center;
+       background-color: #30196d;
+}
+
+#complete-resources {
+/*    background-color: #92f79e !important; */
+    background-color: #B8B2FF !important;
+}
+
+#complete-filters {
+/*    background-color: #4af25d; */
+    background-color: #add7ff;
+}
+
+#complete-users {
+/*    background-color: #ff7394 !important; */
+    background-color: #add7ff !important;
+}
+
+#complete-measurements {
+    background-color: !important;
+}
+
+#complete-pending {
+/*    background-color: #add7ff !important; */
+    background-color: #B8B2FF !important;
+
+}
+
+#complete-customize-resources {
+    background-color: #efdfdf;
+}
+
+#complete-msgs-pre {
+    background-color: #ccc;
+}
+
+#complete-resources, 
+#complete-filters, 
+#complete-users, 
+#complete-measurements,
+#complete-pending,
+#complete-customize-resources,
+#complete-msgs-pre {
+       opacity: 1;
+       text-align: center;
+       color: #333;
+}
+
+#complete-resources:hover, 
+#complete-filters:hover, 
+#complete-users:hover, 
+#complete-measurements:hover,
+#complete-pending:hover,
+#complete-customize-resources:hover,
+#complete-msgs-pre:hover {
+       opacity: 1;
+}
+
+.nav.nav-tabs {
+       font-family: Ubuntu, Arial, sans-serif;
+       border: 0 !important;
+       border-bottom: 3px solid #fff !important;
+       margin-bottom: 40px;
+}
+
+.nav.nav-tabs li.active a {
+       color: #572bc9;
+       border-left: 0px solid #572bc9;
+       border-top: 0px solid #572bc9;
+       border-right: 0px solid #572bc9;
+}
+
+.nav.nav-tabs li a {
+       color: #333;
+       border: 0 !important;
+       margin-right: 5px;
+}
+
+.nav.nav-tabs li a:hover {
+       color: #333;
+       background: #572bc9;
+       color: #fff;
+       border: 0 !important;
+}
+
+
+
+
+
+/* TOPMENU.CSS */
+
+body {
+       background: #30196d !important;
+    padding-top: 60px;
+    padding-bottom: 0px;
+}
+
+div.topmenu { 
+       padding-top: 0px;
+       font-family: Ubuntu, Arial, sans-serif;
+       font-weight: bold;
+       text-transform: ;
+       background: #fff;
+       -webkit-box-shadow: 0px 10px 10px rgba(50, 50, 50, 0.44);
+       -moz-box-shadow:    0px 10px 10px rgba(50, 50, 50, 0.44);
+       box-shadow:         0px 10px 10px rgba(50, 50, 50, 0.44);
+}
+
+.navbar-nav li a,
+.navbar-nav li.other a {
+       padding-top: 25px;
+       padding-bottom: 20px;
+}
+
+.navbar-nav li a:hover {
+       color: #572bc9 !important;
+}
+
+.navbar-nav li.active a {
+.navbar-nav li.active a {
+       background: #eee !important;
+}
+
+ul.logged-in { 
+    padding-top: 25px; 
+}
+button.logged-in { 
+    font-size: 1em;
+    font-weight: bold; 
+    margin-left: 5px;
+    margin-top: -5px;
+    background: #572bc9;
+    border: 2px solid #572bc9;
+    color: #eee;
+    padding: 5px 15px;
+    border-radius:5px;
+}
+
+button.logged-in:hover { 
+    background: #4af25d;
+    border: 2px solid #4af25d;
+    color: #333;
+}
+li.username {
+    margin-bottom: 10px;
+    font-size: 0.8em;
+    text-transform: none;
+    font-weight: normal; 
+    color: #999;
+}
+
+
+/* BOOTSTRAP */
+
+
+ul.pagination li a {
+       background: ;
+       color: #572bc9;
+       font-family: Ubuntu, Arial, sans-serif;
+}
+
+ul.pagination li.active a {
+       background: #572bc9;
+       border: 1px solid #572bc9;
+}
+
+.btn.btn-default {
+       background: #572bc9;
+       color: #ccc;
+       font-family: Ubuntu, Arial, sans-serif;
+       font-weight: bold;
+       border: 0px;
+}
+
+.btn.btn-default:hover {
+       background: #4af25d;
+       color: #333;
+       font-family: Ubuntu, Arial, sans-serif;
+       font-weight: bold;
+       border: 0px;
+}
+
+input {
+       border-radius: 3px;
+       border: none;
+       border: 1px solid #ccc;
+}
+
+
+div.dataTables_length label, 
+div.dataTables_filter label,
+div.dataTables_info {
+       font-family: Ubuntu, Arial, sans-serif !important;
+}
+
+
+
+
+/* HAZELNUT */
+
+div.Hazelnut table.dataTable th {
+    font: bold 12px/22px Ubuntu, Arial, sans-serif;
+    color: #333 !important;
+    border-right: 0px solid #333 !important;
+    border-bottom: 0px solid #C1DAD7 !important;
+    border-top: 0px solid #C1DAD7 !important;
+    letter-spacing: 1px;
+    text-transform: uppercase;
+    text-align: left;
+    padding: 8px 12px 4px 20px;
+    vertical-align:middle;
+    background: # url(../img/tablesort-header.jpg) no-repeat !important; 
+}
+
+div.Hazelnut table.dataTable td, div.Hazelnut table.dataTable textarea, div.Hazelnut table.dataTable input [type="text"] {
+    font: normal 12px Ubuntu, Arial, Helvetica, sans-serif;
+    border-right: 0px solid #fff !important;
+    border-bottom: 1px solid #fff !important;
+}
+
+div.Hazelnut table.dataTable thead { 
+    background: url('../img/tablesort-header.png') repeat-x !important;
+    background-color: #caebea;
+}
+
+div.Hazelnut table.dataTable tfoot { 
+    background: url('../img/tablesort-header.png') repeat-x !important;
+    background-color: # !important;
+}
+
+
+/* QUERY EDITOR */
+
+table.query-editor {
+    margin: 40px auto !important;
+    clear: both;
+    /* width: 80%;*/
+    width: 100% !important;
+    font-family: Ubuntu;
+}
+
+.query-editor-spacer,
+.plugin.ResourcesSelected,
+.plugin.Tabs {
+    margin-top: 60px !important;
+}
+
+table.query-editor td {
+    padding: 5px 5px !important;
+    font: normal 12px Ubuntu, Arial, sans-serif !important;
+}
+
+
+
+/* DASHBOARD */
+
+#ms-dashboard-profile,
+#ms-dashboard-testbeds,
+#ms-dashboard-slices {
+       -webkit-transition: all 50ms ease-out;
+    -moz-transition: all 50ms ease-out;
+    -o-transition: all 50ms ease-out;
+    transition: all 0.05s ease-out;
+       padding-top: 140px;
+       padding-bottom: 60px;
+       margin-top: 60px;
+       color: #fff;
+       font-family: Ubuntu, Arial, sans-serif;
+       text-align: center;
+       
+}
+
+#ms-dashboard-profile:hover,
+#ms-dashboard-testbeds:hover,
+#ms-dashboard-slices:hover {
+       margin-top: 65px;
+}
+
+#ms-dashboard-profile {
+       background: url("../img/icon_users_color.png") top center no-repeat;
+       
+}
+
+#ms-dashboard-testbeds {
+       background: url("../img/icon_testbed_color.png") top center no-repeat;
+}
+
+#ms-dashboard-slices {
+       background: url("../img/icon_slices_color.png") top center no-repeat;
+}
+
+.ms-dashboard-content ul {
+       list-style-type: none !important;
+       padding-left: 0;
+       text-align: center !important;
+}
+
+.ms-dashboard-content {
+       padding: 0 !important;
+}
+
+.ms-dashboard-content a {
+       color: /*#572bc9*/ #ff7394 !important;
+}
+
+.ms-dashboard-caption h2 {
+       font-family: Ubuntu, Arial, sans-serif;
+       border-bottom: 0 !important;
+       text-transform: uppercase;
+}
+
+#ms-dashboard-profile>div.ms-dashboard-caption {
+    background: no-repeat url(#) !important;
+    padding-left: 0 !important;
+}   
+
+#ms-dashboard-testbeds>div.ms-dashboard-caption {
+    background: no-repeat url(#) !important;
+    padding-left: 0 !important;
+}   
+
+#ms-dashboard-slices>div.ms-dashboard-caption {
+    background: no-repeat url(#) !important;
+    padding-left: 0 !important;
+}   
+
+.simplelist {
+       font-size: 100%;
+       text-align: center !important;
+       margin: 0 auto;
+}
+
+
+
+
+
+