--- /dev/null
+unfold.wsgi
\ No newline at end of file
--- /dev/null
+NameVirtualHost *:80
+<VirtualHost *:80>
+ ServerName 200.130.15.182
+ ServerSignature Off
+
+ # Redirecionamento para SSL
+ #RewriteEngine on
+ #RewriteCond %{HTTPS} !=on
+ #RewriteRule ^(.*) https://%{SERVER_NAME}/$1 [R,L]
+
+ DocumentRoot /var/www/
+ <Directory /var/www/>
+ Options Indexes FollowSymLinks MultiViews
+ AllowOverride None
+ Order allow,deny
+ allow from all
+ </Directory>
+
+ ErrorLog /var/log/apache2/error.log
+ # Possible values include: debug, info, notice, warn, error, crit,
+ # alert, emerg.
+ LogLevel info
+ CustomLog /var/log/apache2/sp-access-80.log combined
+</VirtualHost>
--- /dev/null
+NameVirtualHost *:443
+<IfModule mod_ssl.c>
+<VirtualHost *:443>
+ ServerAdmin support-myslice@myslice.info
+ ServerName portal.fibre.br
+
+ DocumentRoot /var/www/myslice
+ WSGIScriptAlias / /var/www/myslice/apache/unfold.wsgi
+
+ <Directory /var/www/myslice>
+ Options Indexes FollowSymLinks MultiViews
+ AllowOverride All
+ Order allow,deny
+ allow from all
+ </Directory>
+
+ Alias /static/ /var/www/myslice/static/
+ <Directory /var/www/myslice/static>
+ Order deny,allow
+ Allow from all
+ </Directory>
+
+ #Alias /certificates/ /var/certificates-f4f/
+ ErrorLog ${APACHE_LOG_DIR}/error.log
+
+ LogLevel warn
+
+ CustomLog ${APACHE_LOG_DIR}/ssl_access.log combined
+
+ # SSL
+ SSLEngine on
+ SSLProtocol all -SSLv2
+ SSLCipherSuite ALL:!ADH:!EXPORT:!SSLv2:RC4+RSA:+HIGH:+MEDIUM:+LOW
+ SSLCertificateKeyFile /etc/ssl/private/fibre.key
+ SSLCertificateFile /etc/ssl/certs/fibre.crt
+ SSLOptions +StdEnvVars +ExportCertData
+ SSLCACertificatePath /etc/sfa/trusted_roots
+ SSLVerifyClient optional_no_ca
+ #SSLVerifyClient require
+ SSLVerifyDepth 5
+ ServerSignature On
+
+ <FilesMatch "\.(cgi|shtml|phtml|php)$">
+ SSLOptions +StdEnvVars
+ </FilesMatch>
+ <Directory /usr/lib/cgi-bin>
+ SSLOptions +StdEnvVars
+ </Directory>
+
+ BrowserMatch "MSIE [2-6]" \
+ nokeepalive ssl-unclean-shutdown \
+ downgrade-1.0 force-response-1.0
+ BrowserMatch "MSIE [17-9]" ssl-unclean-shutdown
+
+</VirtualHost>
+</IfModule>
--- /dev/null
+<VirtualHost 200.130.15.182:443>
+ ServerName 200.130.15.182
+ ServerSignature Off
+
+ SSLEngine on
+ #SSLCertificateFile /etc/unfold/trusted_roots
+ SSLCertificateFile /etc/ssl/certs/fibre.crt
+ SSLCertificateKeyFile /etc/ssl/private/fibre.key
+
+ #ShibURLScheme https
+
+ DocumentRoot /var/www/
+ <Directory /var/www/>
+ Options -Indexes FollowSymLinks -MultiViews
+ AllowOverride None
+ Order deny,allow
+ Allow from all
+ </Directory>
+
+# WSGIScriptAlias / /usr/share/unfold/apache/myslice.wsgi
+# <Directory /usr/share/unfold/apache>
+# <Files myslice.wsgi>
+# Order deny,allow
+# Allow from all
+# </Files>
+# </Directory>
+# Alias /static/ /usr/share/unfold/static/
+# <Directory /usr/share/unfold/static>
+# Order deny,allow
+# Allow from all
+# </Directory>
+
+
+#<Location myslice/secure>
+# AuthType Shibboleth
+# ShibRequestSetting requireSession true
+# ShibRequestSetting applicationId default
+# Require valid-user
+#</Location>
+
+<Location /Shibboleth.sso>
+ SetHandler shib
+</Location>
+<Location /shibboleth-sp2>
+ SetHandler shib
+</Location>
+
+
+# <Location /moodle/auth/shibboleth>
+# AuthType shibboleth
+# ShibRequireSession On
+# require valid-user
+# </Location>
+
+ # Possible values include: debug, info, notice, warn, error, crit,
+ # alert, emerg.
+ ErrorLog /var/log/apache2/error.log
+ LogLevel info
+ CustomLog /var/log/apache2/sp-access-443.log combined
+
+</VirtualHost>
# see also unfold-ssl.conf
<VirtualHost *:80>
- WSGIDaemonProcess unfold processes=2 threads=25
- WSGIProcessGroup unfold
- CustomLog ${APACHE_LOG_DIR}/unfold-access.log common
- ErrorLog ${APACHE_LOG_DIR}/unfold-error.log
- WSGIScriptAlias / /usr/share/unfold/apache/unfold.wsgi
- <Directory /usr/share/unfold/apache/>
- <Files unfold.wsgi>
+ WSGIDaemonProcess myslice processes=2 threads=25
+ WSGIProcessGroup myslice
+ CustomLog ${APACHE_LOG_DIR}/myslice-access.log common
+ ErrorLog ${APACHE_LOG_DIR}/myslice-error.log
+ WSGIScriptAlias / /var/www/myslice/apache/myslice.wsgi
+ <Directory /var/www/myslice/myslice/apache/>
+ <Files myslice.wsgi>
Order deny,allow
Allow from all
</Files>
</Directory>
- Alias /static/ /usr/share/unfold/static/
- <Directory /usr/share/unfold/static>
+ Alias /static/ /var/www/myslice/myslice/static/
+ <Directory /var/www/myslicee/myslice/static>
Order deny,allow
Allow from all
</Directory>
import os
import sys
-path = '/var/myslice-f4f'
+#site.addsitedir('/var/www/myslice')
+
+path = '/var/www/myslice'
if path not in sys.path:
- sys.path.append(path)
+ sys.path = [path] + sys.path
+print sys.path
os.environ['DJANGO_SETTINGS_MODULE'] = 'myslice.settings'
import django.core.handlers.wsgi
application = django.core.handlers.wsgi.WSGIHandler()
-
--- /dev/null
+import time
+
+# import ldap for LDAP authentication - Edelberto
+import ldap
+
+from django.contrib.auth.models import User
+
+from manifoldapi.manifoldapi import ManifoldAPI, ManifoldException, ManifoldResult
+from manifold.core.query import Query
+
+# Name my backend 'ManifoldBackend'
+class ManifoldBackend:
+
+
+ # Create an authentication method
+ # This is called by the standard Django login procedure
+ def authenticate(self, token=None):
+
+ # LDAP local/global var
+ checkldap = None
+
+ if not token:
+ return None
+
+ try:
+ #usernameldap is from LDAP user form. If it is filled - See portal/homeview.py too
+ usernameldap = token['usernameldap']
+ username = token['username']
+ password = token['password']
+ request = token['request']
+
+ # if data are not from LDAP form then normal (local) login
+ if not usernameldap:
+ auth = {'AuthMethod': 'password', 'Username': username, 'AuthString': password}
+ api = ManifoldAPI(auth)
+ sessions_result = api.forward(Query.create('local:session').to_dict())
+ print "result"
+ sessions = sessions_result.ok_value()
+ print "ok"
+ if not sessions:
+ print "GetSession failed", sessions_result.error()
+ return
+ print "first", sessions
+ session = sessions[0]
+
+ # Change to session authentication
+ api.auth = {'AuthMethod': 'session', 'session': session['session']}
+ self.api = api
+
+ # Get account details
+ # the new API would expect Get('local:user') instead
+ persons_result = api.forward(Query.get('local:user').to_dict())
+ persons = persons_result.ok_value()
+ if not persons:
+ print "GetPersons failed",persons_result.error()
+ return
+ person = persons[0]
+ print "PERSON=", person
+
+ request.session['manifold'] = {'auth': api.auth, 'person': person, 'expires': session['expires']}
+ ################################
+ # Edelberto LDAP authentication
+ # if data are from LDAP form, so
+ else:
+ # XXX UGLY
+ # Needing to create an specific entries at settings.py (or myslice.ini) for these vars
+ ##################################################
+ # Edelberto - UFF - esilva@ic.uff.br
+ # v1 - ldap authentication module
+ # Note: focus on LDAP FIBRE-BR for DN
+ # if uses other DN, configuration are needed
+ ###################################################
+ #Searching an LDAP Directory
+
+ try:
+ #uid = "debora@uff.br"
+
+ # Receiving an email address, how can we split and mount it in DN format?
+ #mail = "debora@uff.br"
+ mail = usernameldap
+ login = mail.split('@')[0]
+ org = mail.split('@')[1]
+ o = org.split('.')[0]
+ dc = org.split('.')[1]
+ '''
+ print mail
+ print login
+ print org
+ print o
+ print dc
+ '''
+
+ # DN format to authenticate - IMPORTANT!
+ #FIBRE-BR format
+ uid = "uid="+mail+",ou=people,o="+o+",dc="+dc
+ #uid = "uid=debora@uff.br,ou=people,o=uff,dc=br"
+ # User password from LDAP form
+ #userPassword = "fibre"
+ userPassword = password
+
+ # testing with:
+ # wrong password for test
+ # userPassword = "fibre2"
+
+ # Parameters to connect on LDAP
+ ldap.set_option(ldap.OPT_REFERRALS, 0)
+ # LDAP Server Address
+ l = ldap.open("127.0.0.1")
+ # LDAP version
+ l.protocol_version = ldap.VERSION3
+
+ #l.simple_bind(uid, userPassword)
+ # l.bind_s is necessary to do the authentication with a normal LDAP user
+ l.bind_s(uid, userPassword, ldap.AUTH_SIMPLE)
+ #print l.bind_s(uid, userPassword, ldap.AUTH_SIMPLE)
+
+ # DN base - Our root dc (dc=br)
+ baseDN="dc="+dc
+ searchScope = ldap.SCOPE_SUBTREE
+ retrieveAttributes = None
+ # User only can see its credentials. He search only his attributes
+ searchFilter = "uid="+mail
+
+ # Getting all attributes
+ try:
+ ldap_result_id = l.search(baseDN, searchScope, searchFilter, retrieveAttributes)
+ result_set = []
+ # while exist attributes, save them in a list!
+ while 1:
+ # print l.result(ldap_result_id, 0)
+ result_type, result_data = l.result(ldap_result_id, 0)
+ if (result_data == []):
+ #print ("User %s don't allowed to bind in LDAP", uid)
+ break
+ else:
+ ## Appendng to a list
+ if result_type == ldap.RES_SEARCH_ENTRY:
+ result_set.append(result_data)
+ # print result_set
+ except ldap.LDAPError, e:
+ print e
+
+ # Matching if the user is really who his say
+ #checkldap = None
+ if l.compare_s(uid, 'uid', mail):
+ # DEBUG
+ checkldap = True
+ print "match"
+
+ # Now, based on default Manifold Auth
+ auth = {'AuthMethod': 'password', 'Username': usernameldap, 'AuthString': password}
+ api = ManifoldAPI(auth)
+ sessions_result = api.forward(Query.create('local:session').to_dict())
+ print "result"
+ sessions = sessions_result.ok_value()
+ print "ok"
+ if not sessions:
+ print "GetSession failed", sessions_result.error()
+ return
+ print "first", sessions
+ session = sessions[0]
+
+ # Change to session authentication
+ api.auth = {'AuthMethod': 'session', 'session': session['session']}
+ self.api = api
+
+ # Get account details
+ # the new API would expect Get('local:user') instead
+ persons_result = api.forward(Query.get('local:user').to_dict())
+ persons = persons_result.ok_value()
+ if not persons:
+ print "GetPersons failed",persons_result.error()
+ return
+ person = persons[0]
+ print "PERSON=", person
+
+ request.session['manifold'] = {'auth': api.auth, 'person': person, 'expires': session['expires']}
+
+ else:
+ print "no match. User doesnt allowed"
+ checkldap = False
+
+ except ldap.LDAPError, e:
+ print "E: LDAP Search user", e
+ # end of LDAP
+
+ # Follow the same of Manifold
+ except ManifoldException, e:
+ print "ManifoldBackend.authenticate caught ManifoldException, returning corresponding ManifoldResult"
+ return e.manifold_result
+ except Exception, e:
+ print "E: manifoldbackend", e
+ import traceback
+ traceback.print_exc()
+ return None
+
+ if not usernameldap:
+ try:
+ # Check if the user exists in Django's local database
+ user = User.objects.get(username=username)
+ except User.DoesNotExist:
+ # Create a user in Django's local database
+ user = User.objects.create_user(username, usernamep, 'passworddoesntmatter')
+ user.first_name = "DUMMY_FIRST_NAME" #person['first_name']
+ user.last_name = "DUMMY LAST NAME" # person['last_name']
+ user.email = person['email']
+ return user
+ else:
+ if checkldap:
+ try:
+ # Check if the user exists in Django's local database
+ user = User.objects.get(username=usernameldap)
+ except User.DoesNotExist:
+ # Create a user in Django's local database
+ user = User.objects.create_user(username, usernameldap, 'passworddoesntmatter')
+ user.first_name = "DUMMY_FIRST_NAME" #person['first_name']
+ user.last_name = "DUMMY LAST NAME" # person['last_name']
+ user.email = person['email']
+ return user
+
+ # Required for your backend to work properly - unchanged in most scenarios
+ def get_user(self, user_id):
+ try:
+ return User.objects.get(pk=user_id)
+ except User.DoesNotExist:
+ return None
+
+
import time
+# import ldap for LDAP authentication - Edelberto
+import ldap
+
from django.contrib.auth.models import User
from manifoldapi.manifoldapi import ManifoldAPI, ManifoldException, ManifoldResult
# Name my backend 'ManifoldBackend'
class ManifoldBackend:
+
# Create an authentication method
# This is called by the standard Django login procedure
def authenticate(self, token=None):
+
+ # LDAP local/global var
+ checkldap = None
+
if not token:
return None
try:
+ print "ManifoldBackend authenticate()"
+ # Mandatory fields in token
username = token['username']
- password = token['password']
request = token['request']
- auth = {'AuthMethod': 'password', 'Username': username, 'AuthString': password}
- api = ManifoldAPI(auth)
- sessions_result = api.forward(Query.create('local:session').to_dict())
- print "result"
- sessions = sessions_result.ok_value()
- print "ok"
- if not sessions:
- print "GetSession failed", sessions_result.error()
- return
- print "first", sessions
- session = sessions[0]
-
- # Change to session authentication
- api.auth = {'AuthMethod': 'session', 'session': session['session']}
- self.api = api
-
- # Get account details
- # the new API would expect Get('local:user') instead
- persons_result = api.forward(Query.get('local:user').to_dict())
- persons = persons_result.ok_value()
- if not persons:
- print "GetPersons failed",persons_result.error()
- return
- person = persons[0]
- print "PERSON=", person
-
- request.session['manifold'] = {'auth': api.auth, 'person': person, 'expires': session['expires']}
+ # usernameldap is optional - from LDAP user form.
+ # If it is filled - See portal/homeview.py too
+ if 'usernameldap' in token:
+ usernameldap = token['usernameldap']
+ else:
+ usernameldap = None
+ password = token['password']
+ # if data are not from LDAP form then normal (local) login
+ if not usernameldap:
+ print "not userldap ManifoldBackend authenticate()"
+ auth = {'AuthMethod': 'password', 'Username': username, 'AuthString': password}
+ api = ManifoldAPI(auth)
+ sessions_result = api.forward(Query.create('local:session').to_dict())
+ print "result"
+ sessions = sessions_result.ok_value()
+ print "ok"
+ if not sessions:
+ print "GetSession failed", sessions_result.error()
+ return
+ print "first", sessions
+ session = sessions[0]
+
+ # Change to session authentication
+ api.auth = {'AuthMethod': 'session', 'session': session['session']}
+ self.api = api
+
+ # Get account details
+ # the new API would expect Get('local:user') instead
+ persons_result = api.forward(Query.get('local:user').to_dict())
+ persons = persons_result.ok_value()
+ if not persons:
+ print "GetPersons failed",persons_result.error()
+ return
+ person = persons[0]
+ print "PERSON=", person
+
+ request.session['manifold'] = {'auth': api.auth, 'person': person, 'expires': session['expires']}
+ ################################
+ # Edelberto LDAP authentication
+ # if data are from LDAP form, so
+ else:
+ print "userldap ManifoldBackend authenticate()"
+ # XXX UGLY
+ # Needing to create an specific entries at settings.py (or myslice.ini) for these vars
+ ##################################################
+ # Edelberto - UFF - esilva@ic.uff.br
+ # v1 - ldap authentication module
+ # Note: focus on LDAP FIBRE-BR for DN
+ # if uses other DN, configuration are needed
+ ###################################################
+ #Searching an LDAP Directory
+
+ try:
+ #uid = "debora@uff.br"
+
+ # Receiving an email address, how can we split and mount it in DN format?
+ #mail = "debora@uff.br"
+ mail = usernameldap
+ login = mail.split('@')[0]
+ org = mail.split('@')[1]
+ o = org.split('.')[0]
+ dc = org.split('.')[1]
+ '''
+ print mail
+ print login
+ print org
+ print o
+ print dc
+ '''
+
+ # DN format to authenticate - IMPORTANT!
+ #FIBRE-BR format
+ uid = "uid="+mail+",ou=people,o="+o+",dc="+dc
+ #uid = "uid=debora@uff.br,ou=people,o=uff,dc=br"
+ # User password from LDAP form
+ #userPassword = "fibre"
+ userPassword = password
+
+ # testing with:
+ # wrong password for test
+ # userPassword = "fibre2"
+
+ # Parameters to connect on LDAP
+ ldap.set_option(ldap.OPT_REFERRALS, 0)
+ # LDAP Server Address
+ l = ldap.open("127.0.0.1")
+ # LDAP version
+ l.protocol_version = ldap.VERSION3
+
+ #l.simple_bind(uid, userPassword)
+ # l.bind_s is necessary to do the authentication with a normal LDAP user
+ l.bind_s(uid, userPassword, ldap.AUTH_SIMPLE)
+ #print l.bind_s(uid, userPassword, ldap.AUTH_SIMPLE)
+
+ # DN base - Our root dc (dc=br)
+ baseDN="dc="+dc
+ searchScope = ldap.SCOPE_SUBTREE
+ retrieveAttributes = None
+ # User only can see its credentials. He search only his attributes
+ searchFilter = "uid="+mail
+
+ # Getting all attributes
+ try:
+ ldap_result_id = l.search(baseDN, searchScope, searchFilter, retrieveAttributes)
+ result_set = []
+ # while exist attributes, save them in a list!
+ while 1:
+ # print l.result(ldap_result_id, 0)
+ result_type, result_data = l.result(ldap_result_id, 0)
+ if (result_data == []):
+ #print ("User %s don't allowed to bind in LDAP", uid)
+ break
+ else:
+ ## Appendng to a list
+ if result_type == ldap.RES_SEARCH_ENTRY:
+ result_set.append(result_data)
+ # print result_set
+ except ldap.LDAPError, e:
+ print e
+
+ # Matching if the user is really who his say
+ #checkldap = None
+ if l.compare_s(uid, 'uid', mail):
+ # DEBUG
+ checkldap = True
+ print "match"
+
+ # Now, based on default Manifold Auth
+ auth = {'AuthMethod': 'password', 'Username': usernameldap, 'AuthString': password}
+ api = ManifoldAPI(auth)
+ sessions_result = api.forward(Query.create('local:session').to_dict())
+ print "result"
+ sessions = sessions_result.ok_value()
+ print "ok"
+ if not sessions:
+ print "GetSession failed", sessions_result.error()
+ return
+ print "first", sessions
+ session = sessions[0]
+
+ # Change to session authentication
+ api.auth = {'AuthMethod': 'session', 'session': session['session']}
+ self.api = api
+
+ # Get account details
+ # the new API would expect Get('local:user') instead
+ persons_result = api.forward(Query.get('local:user').to_dict())
+ persons = persons_result.ok_value()
+ if not persons:
+ print "GetPersons failed",persons_result.error()
+ return
+ person = persons[0]
+ print "PERSON=", person
+
+ request.session['manifold'] = {'auth': api.auth, 'person': person, 'expires': session['expires']}
+
+ else:
+ print "no match. User doesnt allowed"
+ checkldap = False
+
+ except ldap.LDAPError, e:
+ print "E: LDAP Search user", e
+ # end of LDAP
+
+ # Follow the same of Manifold
except ManifoldException, e:
print "ManifoldBackend.authenticate caught ManifoldException, returning corresponding ManifoldResult"
return e.manifold_result
import traceback
traceback.print_exc()
return None
-
- try:
- # Check if the user exists in Django's local database
- user = User.objects.get(username=username)
- except User.DoesNotExist:
- # Create a user in Django's local database
- user = User.objects.create_user(username, username, 'passworddoesntmatter')
- user.email = person['email']
+
+ if not usernameldap:
+ try:
+ # Check if the user exists in Django's local database
+ user = User.objects.get(username=username)
+ except User.DoesNotExist:
+ # Create a user in Django's local database
+ user = User.objects.create_user(username, usernamep, 'passworddoesntmatter')
+ user.email = person['email']
+ else:
+ if checkldap:
+ try:
+ # Check if the user exists in Django's local database
+ user = User.objects.get(username=usernameldap)
+ except User.DoesNotExist:
+ # Create a user in Django's local database
+ user = User.objects.create_user(username, usernameldap, 'passworddoesntmatter')
+ user.email = person['email']
if 'firstname' in person:
user.first_name = person['firstname']
user.last_name = person['lastname']
return user
-
# Required for your backend to work properly - unchanged in most scenarios
def get_user(self, user_id):
try:
--- /dev/null
+import time
+
+from django.contrib.auth.models import User
+
+from manifoldapi.manifoldapi import ManifoldAPI, ManifoldException, ManifoldResult
+from manifold.core.query import Query
+
+# Name my backend 'ManifoldBackend'
+class ManifoldBackend:
+
+ # Create an authentication method
+ # This is called by the standard Django login procedure
+ def authenticate(self, token=None):
+ if not token:
+ return None
+
+ try:
+ username = token['username']
+ password = token['password']
+ request = token['request']
+
+ auth = {'AuthMethod': 'password', 'Username': username, 'AuthString': password}
+ api = ManifoldAPI(auth)
+ sessions_result = api.forward(Query.create('local:session').to_dict())
+ print "result"
+ sessions = sessions_result.ok_value()
+ print "ok"
+ if not sessions:
+ print "GetSession failed", sessions_result.error()
+ return
+ print "first", sessions
+ session = sessions[0]
+
+ # Change to session authentication
+ api.auth = {'AuthMethod': 'session', 'session': session['session']}
+ self.api = api
+
+ # Get account details
+ # the new API would expect Get('local:user') instead
+ persons_result = api.forward(Query.get('local:user').to_dict())
+ persons = persons_result.ok_value()
+ if not persons:
+ print "GetPersons failed",persons_result.error()
+ return
+ person = persons[0]
+ print "PERSON=", person
+
+ request.session['manifold'] = {'auth': api.auth, 'person': person, 'expires': session['expires']}
+ except ManifoldException, e:
+ print "ManifoldBackend.authenticate caught ManifoldException, returning corresponding ManifoldResult"
+ return e.manifold_result
+ except Exception, e:
+ print "E: manifoldbackend", e
+ import traceback
+ traceback.print_exc()
+ return None
+
+ try:
+ # Check if the user exists in Django's local database
+ user = User.objects.get(username=username)
+ except User.DoesNotExist:
+ # Create a user in Django's local database
+ user = User.objects.create_user(username, username, 'passworddoesntmatter')
+ user.first_name = "DUMMY_FIRST_NAME" #person['first_name']
+ user.last_name = "DUMMY LAST NAME" # person['last_name']
+ user.email = person['email']
+ return user
+
+ # Required for your backend to work properly - unchanged in most scenarios
+ def get_user(self, user_id):
+ try:
+ return User.objects.get(pk=user_id)
+ except User.DoesNotExist:
+ return None
+
+
admin_user, admin_password = ConfigEngine().manifold_admin_user_password()
manifold_api_session_auth = {'AuthMethod': 'password', 'Username': admin_user, 'AuthString': admin_password}
else:
+ print manifold_query
print request.session['manifold']
manifold_api_session_auth = request.session['manifold']['auth']
var self = this;
var query_ext = this.find_analyzed_query_ext(query_uuid);
var record_key = manifold.metadata.get_key(query_ext.query.object);
+
$.each(records, function(i, record) {
- var key = manifold.metadata.get_key(query_ext.query.object);
+ //var key = manifold.metadata.get_key(query_ext.query.object);
// ["start_time", "resource", "end_time"]
// ["urn"]
-
var record_key_value = manifold.record_get_value(record, record_key);
+
query_ext.records.put(record_key_value, record);
if (!(query_ext.state.get(record_key_value)))
default_manifold_admin_user = 'admin'
default_manifold_admin_password = 'demo'
- default_myslice_theme = 'onelab'
+ default_myslice_theme = 'fibre'
def __init__ (self):
parser.add_section('googlemap')
parser.set ('googlemap','api_key', None)
+ print os.path.join(ROOT,'myslice/myslice.ini')
parser.read (os.path.join(ROOT,'myslice/myslice.ini'))
+ print parser
self.config_parser=parser
def __getattr__(self, section):
# when deployed from a package
# this code is run by collectstatic too, so we cannot
# assume we have ./static present already
-HTTPROOT="/var/myslice-f4f"
+HTTPROOT="/var/www/myslice"
# the place to store local data, like e.g. the sqlite db
-DATAROOT="/var/unfold"
+DATAROOT="/var/www/myslice"
# if not there, then we assume it's from a devel tree
if not os.path.isdir (os.path.join(HTTPROOT,"static")):
HTTPROOT=ROOT
# Python dotted path to the WSGI application used by Django's runserver.
WSGI_APPLICATION = 'unfold.wsgi.application'
+#WSGI_APPLICATION = 'myslice.wsgi.application'
TEMPLATE_DIRS = [ ]
# Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
# put stuff under static/
# IA_MEDIA_PREFIX = '/code/'
+SESSION_ENGINE = 'django.contrib.sessions.backends.file'
+
####SLA#####
SLA_MANAGER_URL = "http://157.193.215.125:4000/sla-service"
SLA_MANAGER_USER = "normal_user"
-SLA_MANAGER_PASSWORD = "password"
\ No newline at end of file
+SLA_MANAGER_PASSWORD = "password"
import portal.homeview
import portal.newsview
+import plugins.cafe.edelberto
+
from portal.registrationview import RegistrationView
from portal.termsview import TermsView
urls.append ( url ( r'^%s/'%aux, include ('%s.urls'%aux )))
urlpatterns = patterns(*urls)
+
+# Shibboleth - Edelberto
+urlpatterns += patterns('',
+ url(r'^cafe/', plugins.cafe.edelberto.EdelbertoView.as_view()),
+ #url(r'^cafe/', 'plugins.cafe.edelberto.index'),
+)
+
//alert("1");\r
</script>\r
</div>\r
+</div>\r
--- /dev/null
+from django.http import HttpResponse
+from manifold.core.query import Query
+from manifoldapi.manifoldapi import execute_query,execute_admin_query
+from portal.models import PendingUser, PendingSlice, PendingAuthority
+import json
+
+from django.contrib.auth.models import User
+from django.template.loader import render_to_string
+from django.core.mail import EmailMultiAlternatives
+
+from theme import ThemeView
+
+theme = ThemeView()
+
+# Thierry: moving this right into the code so
+# most people can use myslice without having to install sfa
+# XXX tmp sfa dependency, should be moved to SFA gateway
+#from sfa.util.xrn import Xrn
+
+
+# Get the list of authorities
+
+def authority_get_pis(request, authority_hrn):
+ query = Query.get('authority').filter_by('authority_hrn', '==', authority_hrn).select('pi_users')
+ results = execute_admin_query(request, query)
+ # NOTE: temporarily commented. Because results is giving empty list.
+ # Needs more debugging
+ #if not results:
+ # raise Exception, "Authority not found: %s" % authority_hrn
+ #result, = results
+ #return result['pi_users']
+ return results
+
+def authority_get_pi_emails(request, authority_hrn):
+ pi_users = authority_get_pis(request,authority_hrn)
+ if any(d['pi_users'] == None for d in pi_users):
+ theme.template_name = 'email_default_recipients.txt'
+ default_email = render_to_string(theme.template, request)
+ default_email = default_email.replace('\n', '')
+ return default_email
+ else:
+ pi_user_hrns = [ hrn for x in pi_users for hrn in x['pi_users'] ]
+ query = Query.get('user').filter_by('user_hrn', 'included', pi_user_hrns).select('user_email')
+ results = execute_admin_query(request, query)
+ return [result['user_email'] for result in results]
+
+def is_pi(wsgi_request, user_hrn, authority_hrn):
+ # XXX could be done in a single query !
+
+ # select pi_authorities from user where user_hrn == "ple.upmc.jordan_auge"
+ query = Query.get('user').filter_by('user_hrn', '==', user_hrn).select('pi_authorities')
+ results = execute_admin_query(wsgi_request, query)
+ if not results:
+ # XXX Warning ?
+ return False
+ result = results[0]
+ user_authority_hrns = result.get('pi_authorities', [])
+ return authority_hrn in user_authority_hrns
+
+# SFA get record
+
+def sfa_get_user(request, user_hrn, pub):
+ query_sfa_user = Query.get('user').filter_by('user_hrn', '==', user_hrn)
+ result_sfa_user = execute_query(request, query_sfa_user)
+ return result_sfa_user
+
+def sfa_update_user(request, user_hrn, user_params):
+ # user_params: keys [public_key]
+ if 'email' in user_params:
+ user_params['user_email'] = user_params['email']
+ query = Query.update('user').filter_by('user_hrn', '==', user_hrn).set(user_params).select('user_hrn')
+ results = execute_query(request,query)
+ return results
+
+def sfa_add_authority(request, authority_params):
+ query = Query.create('authority').set(authority_params).select('authority_hrn')
+ results = execute_query(request, query)
+ print "sfa_add_auth results=",results
+ if not results:
+ raise Exception, "Could not create %s. Already exists ?" % authority_params['hrn']
+ return results
+
+def sfa_add_user_to_slice(request, user_hrn, slice_params):
+# UPDATE myslice:slice SET researcher=['ple.upmc.jordan_auge','ple.inria.thierry_parmentelat','ple.upmc.loic_baron','ple.upmc.ciro_scognamiglio','ple.upmc.mohammed-yasin_rahman','ple.upmc.azerty'] where slice_hrn=='ple.upmc.myslicedemo'
+ query_current_users = Query.get('slice').select('user').filter_by('slice_hrn','==',slice_params['hrn'])
+ results_current_users = execute_query(request, query_current_users)
+ slice_params['researcher'] = slice_params['researcher'] | results_current_users
+ query = Query.update('slice').filter_by('user_hrn', '==', user_hrn).set(slice_params).select('slice_hrn')
+ results = execute_query(request, query)
+# Also possible but not supported yet
+# UPDATE myslice:user SET slice=['ple.upmc.agent','ple.upmc.myslicedemo','ple.upmc.tophat'] where user_hrn=='ple.upmc.azerty'
+ if not results:
+ raise Exception, "Could not create %s. Already exists ?" % slice_params['hrn']
+ return results
+
+# Propose hrn
+
+def manifold_add_user(wsgi_request, request):
+ """Add a Manifold user corresponding to a user request.
+
+ Args:
+ wsgi_request: a WSGIRequest instance
+ request (dict): a dictionary containing the user request built from the
+ form.
+
+ Returns:
+ The user_id of the inserted user.
+
+ Raises:
+ ?
+
+ """
+ USER_CONFIG = '{"firstname": "%(first_name)s", "lastname": "%(last_name)s", "authority": "%(authority_hrn)s"}'
+
+ user_params = {
+ 'email' : request['email'],
+ 'password' : request['password'],
+ 'config' : USER_CONFIG % request,
+ 'status' : 1,
+ }
+
+ query = Query.create('local:user').set(user_params).select('email')
+ results = execute_admin_query(request, query)
+ if not results:
+ raise Exception, "Failed creating manifold user: %s" % user_params['email']
+ result = results[0]
+ return result['email']
+
+def manifold_update_user(request, email, user_params):
+ # user_params: password, config e.g.,
+ query = Query.update('local:user').filter_by('email', '==', email).set(user_params).select('email')
+ results = execute_admin_query(request,query)
+ # NOTE: results remains empty and goes to Exception. However, it updates the manifold DB.
+ # That's why I commented the exception part. -- Yasin
+ #if not results:
+ # raise Exception, "Failed updating manifold user: %s" % user_params['email']
+ #result, = results
+ return results
+
+def manifold_add_account(request, account_params):
+ query = Query.create('local:account').set(account_params).select(['user', 'platform'])
+ results = execute_admin_query(request,query)
+ if not results:
+ raise Exception, "Failed creating manifold account on platform %s for user: %s" % (account_params['platform'], account_params['user'])
+ result, = results
+ return result['user_id']
+
+def manifold_update_account(request,user_id,account_params):
+ # account_params: config
+ query = Query.update('local:account').filter_by('platform', '==', 'myslice').filter_by('user_id', '==', user_id).set(account_params).select('user_id')
+ results = execute_admin_query(request,query)
+ return results
+
+#explicitly mention the platform_id
+def manifold_delete_account(request, platform_id, user_id, account_params):
+ query = Query.delete('local:account').filter_by('platform_id', '==', platform_id).filter_by('user_id', '==', user_id).set(account_params).select('user_id')
+ results = execute_admin_query(request,query)
+ return results
+
+
+#not tested
+def manifold_add_platform(request, platform_params):
+ query = Query.create('local:platform').set(platform_params).select(['user', 'platform'])
+ results = execute_admin_query(request,query)
+ if not results:
+ raise Exception, "Failed creating manifold platform %s for user: %s" % (platform_params['platform'], platform_params['user'])
+ result, = results
+ return result['platform_id']
+
+
+def make_request_user(user):
+ request = {}
+ request['type'] = 'user'
+ request['id'] = user.id
+ request['timestamp'] = user.created # XXX in DB ?
+ request['authority_hrn'] = user.authority_hrn
+ request['first_name'] = user.first_name
+ request['last_name'] = user.last_name
+ request['email'] = user.email
+ request['login'] = user.login
+ request['user_hrn'] = user.user_hrn
+ request['public_key'] = user.public_key
+ request['private_key'] = user.private_key
+ return request
+
+def make_request_slice(slice):
+ request = {}
+ request['type'] = 'slice'
+ request['id'] = slice.id
+ request['user_hrn'] = slice.user_hrn
+ request['timestamp'] = slice.created
+ request['authority_hrn'] = slice.authority_hrn
+ request['slice_name'] = slice.slice_name
+ request['number_of_nodes'] = slice.number_of_nodes
+ request['type_of_nodes'] = slice.type_of_nodes
+ request['purpose'] = slice.purpose
+ return request
+
+def make_request_authority(authority):
+ request = {}
+ request['type'] = 'authority'
+ request['id'] = authority.id
+ request['site_name'] = authority.site_name
+ request['site_latitude'] = authority.site_latitude
+ request['site_longitude'] = authority.site_longitude
+ request['site_url'] = authority.site_url
+ request['site_authority'] = authority.site_authority
+ request['site_abbreviated_name'] = authority.site_abbreviated_name
+ request['address_line1'] = authority.address_line1
+ request['address_line2'] = authority.address_line2
+ request['address_line3'] = authority.address_line3
+ request['address_city'] = authority.address_city
+ request['address_postalcode'] = authority.address_postalcode
+ request['address_state'] = authority.address_state
+ request['address_country'] = authority.address_country
+ request['authority_hrn'] = authority.authority_hrn
+ request['timestamp'] = authority.created
+ return request
+
+def make_requests(pending_users, pending_slices, pending_authorities):
+ requests = []
+ for user in pending_users:
+ requests.append(make_request_user(user))
+ for slice in pending_slices:
+ requests.append(make_request_slice(slice))
+ for authority in pending_authorities:
+ requests.append(make_request_authority(authority))
+ return requests
+
+def get_request_by_id(ids):
+ sorted_ids = { 'user': [], 'slice': [], 'authority': [] }
+ for type__id in ids:
+ type, id = type__id.split('__')
+ sorted_ids[type].append(id)
+
+ if not ids:
+ pending_users = PendingUser.objects.all()
+ pending_slices = PendingSlice.objects.all()
+ pending_authorities = PendingAuthority.objects.all()
+ else:
+ pending_users = PendingUser.objects.filter(id__in=sorted_ids['user']).all()
+ pending_slices = PendingSlice.objects.filter(id__in=sorted_ids['slice']).all()
+ pending_authorities = PendingAuthority.objects.filter(id__in=sorted_ids['authority']).all()
+
+ return make_requests(pending_users, pending_slices, pending_authorities)
+
+def get_requests(authority_hrns=None):
+ print "get_request_by_authority auth_hrns = ", authority_hrns
+ if not authority_hrns:
+ pending_users = PendingUser.objects.all()
+ pending_slices = PendingSlice.objects.all()
+ pending_authorities = PendingAuthority.objects.all()
+ else:
+ pending_users = PendingUser.objects.filter(authority_hrn__in=authority_hrns).all()
+ pending_slices = PendingSlice.objects.filter(authority_hrn__in=authority_hrns).all()
+ pending_authorities = PendingAuthority.objects.filter(authority_hrn__in=authority_hrns).all()
+
+ return make_requests(pending_users, pending_slices, pending_authorities)
+
+# XXX Is it in sync with the form fields ?
+
+def portal_validate_request(wsgi_request, request_ids):
+ status = {}
+
+ if not isinstance(request_ids, list):
+ request_ids = [request_ids]
+
+ requests = get_request_by_id(request_ids)
+ for request in requests:
+ # type, id, timestamp, details, allowed -- MISSING: authority_hrn
+ # CAREFUL about details
+ # user : first name, last name, email, password, keypair
+ # slice : number of nodes, type of nodes, purpose
+
+ request_status = {}
+
+ if request['type'] == 'user':
+
+ try:
+ create_user(wsgi_request, request)
+ request_status['SFA user'] = {'status': True }
+
+ except Exception, e:
+ request_status['SFA user'] = {'status': False, 'description': str(e)}
+
+# user_params = {'status':2}
+# manifold_update_user(request, request['email'], user_params)
+
+ # MANIFOLD user should be added beforehand, during registration
+ #try:
+ # manifold_user_params = { key: request[key] for key in MANIFOLD_USER_KEYS }
+ # # XXX # manifold_add_user(manifold_user_params)
+ # request_status['MySlice user'] = {'status': True }
+ #except Exception, e:
+ # request_status['MySlice user'] = {'status': False, 'description': str(e)}
+
+ # XXX
+ #manifold_account_params = { key: request[key] for key in MANIFOLD_ACCOUNT_KEYS }
+ #manifold_add_account(manifold_account_params)
+ #request_status['MySlice testbed accounts'] = {'status': False }
+
+ elif request['type'] == 'slice':
+ try:
+ create_slice(wsgi_request, request)
+ request_status['SFA slice'] = {'status': True }
+
+ except Exception, e:
+ request_status['SFA slice'] = {'status': False, 'description': str(e)}
+
+ elif request['type'] == 'authority':
+ try:
+ #hrn = "%s.%s" % (request['authority_hrn'], request['site_authority'])
+ hrn = request['site_authority']
+ # XXX tmp sfa dependency
+ from sfa.util.xrn import Xrn
+ urn = Xrn(hrn, request['type']).get_urn()
+
+ sfa_authority_params = {
+ 'hrn' : hrn,
+ 'urn' : urn,
+ 'type' : request['type'],
+ #'pi' : None,
+ 'enabled' : True
+ }
+ print "ADD Authority"
+ sfa_add_authority(wsgi_request, sfa_authority_params)
+ request_status['SFA authority'] = {'status': True }
+
+ except Exception, e:
+ request_status['SFA authority'] = {'status': False, 'description': str(e)}
+
+ # XXX Remove from Pendings in database
+
+ status['%s__%s' % (request['type'], request['id'])] = request_status
+
+ return status
+
+
+def validate_action(request, **kwargs):
+ ids = filter(None, kwargs['id'].split('/'))
+ status = portal_validate_request(request, ids)
+ json_answer = json.dumps(status)
+ return HttpResponse (json_answer, mimetype="application/json")
+
+# Django and ajax
+# http://djangosnippets.org/snippets/942/
+
+
+
+#-------------------------------------------------------------------------------
+# REQUESTS - Slices
+#-------------------------------------------------------------------------------
+
+def create_slice(wsgi_request, request):
+ """
+ Arguments:
+ wsgi_request (~ WSGIRequest) :
+ request (dict) : the slice request in our own dict format
+
+ Raises:
+ Exception
+ """
+ hrn = "%s.%s" % (request['authority_hrn'], request['slice_name'])
+ # XXX tmp sfa dependency
+ from sfa.util.xrn import Xrn
+ urn = Xrn(hrn, request['type']).get_urn()
+
+ # Add User to Slice if we have the user_hrn in pendingslice table
+ user_hrn = request.get('user_hrn', None)
+ user_hrns = list([user_hrn]) if user_hrn else list()
+
+ # XXX We should create a slice with Manifold terminology
+ slice_params = {
+ 'slice_hrn' : hrn,
+ 'slice_urn' : urn,
+ 'slice_type' : request['type'],
+ 'users' : user_hrns,
+ 'slice_enabled' : True
+ }
+ # ignored in request: id, timestamp, number_of_nodes, type_of_nodes, purpose
+
+ query = Query.create('slice').set(slice_params).select('slice_hrn')
+ results = execute_query(wsgi_request, query)
+ if not results:
+ raise Exception, "Could not create %s. Already exists ?" % slice_params['hrn']
+ return results
+
+def create_pending_slice(wsgi_request, request, email):
+ """
+ """
+
+ # Insert an entry in the PendingSlice table
+ s = PendingSlice(
+ slice_name = request['slice_name'],
+ user_hrn = request['user_hrn'],
+ authority_hrn = request['authority_hrn'],
+ number_of_nodes = request['number_of_nodes'],
+ purpose = request['purpose'],
+ )
+ s.save()
+
+ try:
+ # Send an email: the recipients are the PI of the authority
+ recipients = authority_get_pi_emails(wsgi_request, request['authority_hrn'])
+
+ theme.template_name = 'slice_request_email.txt'
+ text_content = render_to_string(theme.template, request)
+
+ theme.template_name = 'slice_request_email.html'
+ html_content = render_to_string(theme.template, request)
+
+ theme.template_name = 'slice_request_email_subject.txt'
+ subject = render_to_string(theme.template, request)
+ subject = subject.replace('\n', '')
+
+ sender = email
+ msg = EmailMultiAlternatives(subject, text_content, sender, [recipients])
+ print msg
+ msg.attach_alternative(html_content, "text/html")
+ msg.send()
+ except Exception, e:
+ print "Failed to send email, please check the mail templates and the SMTP configuration of your server"
+
+#-------------------------------------------------------------------------------
+# REQUESTS - Users
+#-------------------------------------------------------------------------------
+
+def manifold_add_reference_user_accounts(wsgi_request, request):
+ """When a new user is created, add reference accounts to the reference platform.
+ """
+ # XXX XXX XXX The rest of this function has to be checked XXX XXX XXX
+
+ # Retrieve user information
+ user_query = Query().get('local:user') \
+ .select('user_id', 'config', 'email', 'status') \
+ .filter_by('email', '==', request['email'])
+ user_details = execute_admin_query(wsgi_request, user_query)
+
+ # USER MAIN ACCOUNT != reference
+ #print 'USER MAIN ACCOUNT != reference'
+ list_accounts_query = Query().get('local:account') \
+ .select('user_id', 'platform_id', 'auth_type', 'config') \
+ .filter_by('user_id', '==', user_details[0]['user_id']) \
+ .filter_by('auth_type', '!=', 'reference')
+ list_accounts = execute_admin_query(wsgi_request, list_accounts_query)
+
+ # XXX main_platform is being erased several times ???
+ for account in list_accounts:
+ main_platform_query = Query().get('local:platform') \
+ .select('platform_id', 'platform') \
+ .filter_by('platform_id', '==', account['platform_id'])
+ main_platform = execute_admin_query(wsgi_request, main_platform_query)
+
+ # Add reference accounts on SFA enabled platforms
+ platforms_query = Query().get('local:platform') \
+ .filter_by('disabled', '==', '0') \
+ .filter_by('gateway_type', '==', 'sfa') \
+ .select('platform_id', 'gateway_type')
+ platforms = execute_admin_query(wsgi_request, platforms_query)
+ for platform in platforms:
+ #print "add reference to platform ",platform
+ manifold_account_params = {
+ 'user_id' : user_details[0]['user_id'],
+ 'platform_id' : platform['platform_id'],
+ 'auth_type' : 'reference',
+ 'config' : '{"reference_platform": "' + main_platform[0]['platform'] + '"}',
+ }
+ manifold_add_account(wsgi_request, manifold_account_params)
+
+def sfa_create_user(wsgi_request, request):
+ """
+ Arguments:
+ wsgi_request (~ WSGIRequest) :
+ request (dict) : the user request in our own dict format
+
+ Raises:
+ Exception
+ """
+ from sfa.util.xrn import Xrn
+
+ auth_pi = request.get('pi', None)
+ auth_pi = list([auth_pi]) if auth_pi else list()
+
+ # We create a user request with Manifold terminology
+ sfa_user_params = {
+ 'user_hrn' : request['user_hrn'],
+ 'user_email' : request['email'],
+ 'user_urn' : Xrn(request['user_hrn'], request['type']).get_urn(),
+ 'user_type' : request['type'],
+ 'keys' : request['public_key'],
+ 'user_first_name' : request['first_name'],
+ 'user_last_name' : request['last_name'],
+ 'pi_authorities' : auth_pi,
+ 'user_enabled' : True
+ }
+
+ query = Query.create('user').set(sfa_user_params).select('user_hrn')
+ results = execute_query(wsgi_request, query)
+ if not results:
+ raise Exception, "Could not create %s. Already exists ?" % sfa_user_params['user_hrn']
+ return results
+
+#def ldap_create_user
+
+def create_user(wsgi_request, request):
+
+ # XXX This has to be stored centrally
+ USER_STATUS_ENABLED = 2
+
+ # NOTE : if we were to create a user directly (just like we create slices,
+ # we would have to perform the steps in create_pending_user too
+
+ # Add the user to the SFA registry
+ sfa_create_user(wsgi_request, request)
+
+ # Update Manifold user status
+ manifold_update_user(wsgi_request, request['email'], {'status': USER_STATUS_ENABLED})
+
+ # Add reference accounts for platforms
+ manifold_add_reference_user_accounts(wsgi_request, request)
+
+def create_pending_user(wsgi_request, request, user_detail):
+ """
+ """
+
+ # Insert an entry in the PendingUser table
+ b = PendingUser(
+ first_name = request['first_name'],
+ last_name = request['last_name'],
+ authority_hrn = request['authority_hrn'],
+ email = request['email'],
+ password = request['password'],
+ public_key = request['public_key'],
+ private_key = request['private_key'],
+ user_hrn = request['user_hrn'],
+ pi = '', # XXX Why not None ?
+ )
+ b.save()
+
+ # saves the user to django auth_user table [needed for password reset]
+ user = User.objects.create_user(request['email'], request['email'], request['password'])
+
+ # Creating a manifold user
+ user_id = manifold_add_user(wsgi_request, request)
+
+ # Creating a Manifold account on the MySlice platform
+ # Note the JSON representation of public and private keys already includes quotes
+ account_config = {
+ 'user_hrn' : request['user_hrn'],
+ 'user_public_key' : request['public_key'],
+ }
+ if request['private_key']:
+ account_config['user_private_key'] = request['private_key']
+
+ user_id = user_detail['user_id'] + 1 # the user_id for the newly created user in local:user
+
+ # XXX TODO: Require a myslice platform
+ # ALERT: this will disapear with ROUTERV2 of Manifold
+ # We have to consider the case where several registries can be used
+ # Removed hardcoded platform = 5
+ # This platform == 'myslice' is a TMP FIX !!
+ try:
+ reg_platform_query = Query().get('local:platform') \
+ .filter_by('platform', '==', 'myslice') \
+ .select('platform_id')
+ reg_platform = execute_admin_query(wsgi_request, reg_platform_query)
+
+ registry_platform_id = reg_platform[0]['platform_id']
+ account_params = {
+ 'platform_id' : reg_platform_id, # XXX ALERT !!
+ 'user_id' : user_id,
+ 'auth_type' : request['auth_type'],
+ 'config' : json.dumps(account_config),
+ }
+ manifold_add_account(wsgi_request, account_params)
+ except Exception, e:
+ print "Failed creating manifold account on platform %s for user: %s" % ('myslice', request['email'])
+
+ try:
+ # Send an email: the recipients are the PI of the authority
+ # If No PI is defined for this Authority, send to a default email (different for each theme)
+ recipients = authority_get_pi_emails(wsgi_request, request['authority_hrn'])
+
+ theme.template_name = 'user_request_email.html'
+ html_content = render_to_string(theme.template, request)
+
+ theme.template_name = 'user_request_email.txt'
+ text_content = render_to_string(theme.template, request)
+
+ theme.template_name = 'user_request_email_subject.txt'
+ subject = render_to_string(theme.template, request)
+ subject = subject.replace('\n', '')
+
+ theme.template_name = 'email_default_sender.txt'
+ sender = render_to_string(theme.template, request)
+ sender = sender.replace('\n', '')
+
+ msg = EmailMultiAlternatives(subject, text_content, sender, [recipients])
+ msg.attach_alternative(html_content, "text/html")
+ msg.send()
+ except Exception, e:
+ print "Failed to send email, please check the mail templates and the SMTP configuration of your server"
raise Exception, "Could not create %s. Already exists ?" % sfa_user_params['user_hrn']
return results
+def ldap_create_user(wsgi_request, request, user_detail):
+ """
+ Populating LDAP withuser data - Edelberto 10/03/2014
+ """
+ # import needed modules
+ import ldap
+ import ldap.modlist as modlist
+
+ # Open a connection
+ # XXX We need to create this in settings
+ # ldap.open is deprecated!
+ #l = ldap.open("127.0.0.1")
+ l = ldap.initialize('ldap://127.0.0.1:389')
+
+ # you should set this to ldap.VERSION2 if you're using a v2 directory
+ l.protocol_version = ldap.VERSION3
+
+ # Bind/authenticate with a user with apropriate rights to add objects
+ # XXX Now we set the force rootd but after we need to set this in settings file for could change the dn and password of root
+ l.simple_bind_s("cn=Manager,dc=br","fibre")
+
+ # The dn of our new entry/object
+ #dn="uid=addtest@uff.br,ou=people,o=uff,dc=br"
+
+ # we need to create the dn entry
+ # Receiving an email address, how can we split and mount it in DN format?
+ #mail = "debora@uff.br"
+ mail = request['email']
+ login = mail.split('@')[0]
+ org = mail.split('@')[1]
+ o = org.split('.')[-2]
+ dc = org.split('.')[-1]
+
+ # DN format to authenticate - IMPORTANT!
+ #FIBRE-BR format
+ dn = "uid="+mail+",ou=people,o="+o+",dc="+dc
+
+ # DEBUG
+ print "dn:"+dn
+ print request['password']
+
+ # Creating a unique uidNumber - Necessary for experiments
+ # Was defined to began in 100000
+ unique = int(user_detail['user_id']) + 100000
+ #unique = int(unique)
+ print unique
+
+ # A dict to help build the "body" of the object
+ attrs = {}
+ attrs['objectclass'] = ['person','inetOrgPerson','posixAccount','eduPerson','brPerson','schacPersonalCharacteristics','fibre', 'ldapPublicKey']
+ # XXX Converting all unicodes to string
+ attrs['uid'] = mail.encode('utf-8')
+ attrs['cn'] = request['first_name'].encode('latin1')
+ attrs['sn'] = request['last_name'].encode('latin1')
+ # XXX we need to set a unique uidNumber. How?
+ attrs['uidNumber'] = str(unique)
+ attrs['gidNumber'] = '500'
+ attrs['homeDirectory'] = "/home/"+org+"/"+mail
+ attrs['homeDirectory'] = attrs['homeDirectory'].encode('utf-8')
+ attrs['mail'] = mail.encode('utf-8')
+ attrs['eppn'] = mail.encode('utf8')
+ attrs['userPassword'] = request['password'].encode('utf-8')
+ attrs['sshPublicKey'] = request['public_key'].encode('utf-8')
+ # XXX We really set TRUE for those attributes?
+ #attrs['userEnable'] = 'TRUE'
+ # set FALSE and change after when the user is validated
+ attrs['userEnable'] = 'FALSE'
+ attrs['omfAdmin'] = 'TRUE'
+
+ # Convert our dict to nice syntax for the add-function using modlist-module
+ ldif = modlist.addModlist(attrs)
+
+ # DEBUG
+ print attrs['userPassword']
+ print attrs['cn']
+ print attrs['sn']
+ print attrs['homeDirectory']
+ #print ldif
+
+ # Do the actual synchronous add-operation to the ldapserver
+ l.add_s(dn,ldif)
+
+ # Its nice to the server to disconnect and free resources when done
+ l.unbind_s()
+
+ return ldif
+
+def ldap_modify_user(wsgi_request, request):
+ #Modify entries in an LDAP Directory
+
+ #Synchrounous modify
+ # import needed modules
+ import ldap
+ import ldap.modlist as modlist
+
+ # Open a connection
+ l = ldap.initialize("ldap://localhost:389/")
+
+ # Bind/authenticate with a user with apropriate rights to add objects
+ l.simple_bind_s("cn=Manager,dc=br","fibre")
+
+ # we need to create the dn entry
+ # Receiving an email address, how can we split and mount it in DN format?
+ #mail = "debora@uff.br"
+ mail = request['email']
+ login = mail.split('@')[0]
+ org = mail.split('@')[1]
+ o = org.split('.')[-2]
+ dc = org.split('.')[-1]
+
+ # DN format to authenticate - IMPORTANT!
+ #FIBRE-BR format
+ dn = "uid="+mail+",ou=people,o="+o+",dc="+dc
+
+ # The dn of our existing entry/object
+ #dn="uid=mario@uff.br,ou=people,o=uff,dc=br"
+
+ # Some place-holders for old and new values
+ old = {'userEnable':'FALSE'}
+ new = {'userEnable':'TRUE'}
+
+ # Convert place-holders for modify-operation using modlist-module
+ ldif = modlist.modifyModlist(old,new)
+
+ # Do the actual modification
+ l.modify_s(dn,ldif)
+
+ # Its nice to the server to disconnect and free resources when done
+ l.unbind_s()
+
+ return ldif
+
def create_user(wsgi_request, request):
# XXX This has to be stored centrally
# NOTE : if we were to create a user directly (just like we create slices,
# we would have to perform the steps in create_pending_user too
-
+
+ # Edelberto - I put this more below
# Add the user to the SFA registry
- sfa_create_user(wsgi_request, request)
+ #sfa_create_user(wsgi_request, request)
# Update Manifold user status
manifold_update_user(wsgi_request, request['email'], {'status': USER_STATUS_ENABLED})
# Add reference accounts for platforms
manifold_add_reference_user_accounts(wsgi_request, request)
+
+# Add the user to the SFA registry
+ sfa_create_user(wsgi_request, request)
+ '''
+ # LDAP update user userEnabled = True
+ try:
+ mail = request['email']
+ login = mail.split('@')[0]
+ org = mail.split('@')[1]
+ o = org.split('.')[-2]
+ dc = org.split('.')[-1]
+ # To know if user is a LDAP user - Need to has a 'dc' identifier
+ if dc == 'br' or 'eu':
+ ldap_modify_user(wsgi_request, request)
+ except Exception, e:
+ "LDAP create user failed"
+ '''
def create_pending_user(wsgi_request, request, user_detail):
"""
"""
.filter_by('platform', '==', 'myslice') \
.select('platform_id')
reg_platform = execute_admin_query(wsgi_request, reg_platform_query)
-
reg_platform_id = reg_platform[0]['platform_id']
account_params = {
'platform_id' : reg_platform_id, # XXX ALERT !!
}
manifold_add_account(wsgi_request, account_params)
except Exception, e:
- print "Failed creating manifold account on platform %s for user: %s" % ('myslice', request['email'])
+ print "Failed creating manifold account on platform %s for user: %s" % ('myslice', request['email'])
+
+ # Add user to LDAP userEnabled = False
+ # Not more here. Create before directly to the registrationview.py
+ # After we change userEnable = TRUE when validate the user
try:
# Send an email: the recipients are the PI of the authority
username = request.POST.get('username')
password = request.POST.get('password')
+
+ # LDAP form - If FIBRE, then get the possibilite to authenticate using usernameldap
+ #if self.theme == 'fibre':
+ usernameldap = request.POST.get('usernameldap')
+ token = {'usernameldap': usernameldap, 'username': username ,'password': password, 'request': request}
+ #else:
- # pass request within the token, so manifold session key can be attached to the request session.
- token = {'username': username, 'password': password, 'request': request}
+ # Follow original code
+ ## pass request within the token, so manifold session key can be attached to the request session.
+ #token = {'username': username, 'password': password, 'request': request}
# our authenticate function returns either
# . a ManifoldResult - when something has gone wrong, like e.g. backend is unreachable
# XXX Something like an invalid session seems to make the execute fail sometimes, and thus gives an error on the main page
platform_details = execute_query(self.request, platform_query)
account_details = execute_query(self.request, account_query)
- for platform_detail in platform_details:
- for account_detail in account_details:
- if platform_detail['platform_id'] == account_detail['platform_id']:
- if 'config' in account_detail and account_detail['config'] is not '':
- account_config = json.loads(account_detail['config'])
- if 'myslice' in platform_detail['platform']:
- acc_auth_cred = account_config.get('delegated_authority_credentials','N/A')
+ if platform_details:
+ for platform_detail in platform_details:
+ for account_detail in account_details:
+ if platform_detail['platform_id'] == account_detail['platform_id']:
+ if 'config' in account_detail and account_detail['config'] is not '':
+ account_config = json.loads(account_detail['config'])
+ if 'myslice' in platform_detail['platform']:
+ acc_auth_cred = account_config.get('delegated_authority_credentials','N/A')
# assigning values
if acc_auth_cred=={} or acc_auth_cred=='N/A':
pi = "is_not_pi"
from manifold.core.query import Query
from portal.models import PendingUser
-from portal.actions import create_pending_user
+#from portal.actions import create_pending_user
+# Edelberto - LDAP
+from portal.actions import create_pending_user, ldap_create_user
from myslice.theme import ThemeView
"""
errors = []
- authorities_query = Query.get('authority').select('name', 'authority_hrn')
+ authorities_query = Query.get('authority').select('name','authority_hrn')
authorities = execute_admin_query(wsgi_request, authorities_query)
if authorities is not None:
authorities = sorted(authorities)
current_site = Site.objects.get_current()
current_site = current_site.domain
+ #authorities_query = Query.get('authority').select('name', 'authority_hrn')
+ #authorities = execute_admin_query(wsgi_request, authorities_query)
+
for authority in authorities:
if authority['name'] == wsgi_request.POST.get('org_name', ''):
authority_hrn = authority['authority_hrn']
user_request['public_key'] = file_content
if not errors:
+ '''
+ try:
+ # verify if is a LDAP
+ mail = user_detail['email']
+ login = mail.split('@')[0]
+ org = mail.split('@')[1]
+ o = org.split('.')[-2]
+ dc = org.split('.')[-1]
+ # To know if user is a LDAP user - Need to has a 'dc' identifier
+ if dc == 'br' or 'eu':
+ # LDAP insert directly - but with userEnable = FALSE
+ ldap_create_user(wsgi_request, user_request, user_detail)
+
+ except Exception, e:
+ print "LDAP: problem em access the LDAP with this credentail"
+ '''
create_pending_user(wsgi_request, user_request, user_detail)
self.template_name = 'user_register_complete.html'
+
return render(wsgi_request, self.template, {'theme': self.theme})
else:
'exp_url': exp_url,
'pi': pi,
'authority_name': authority_name,
- 'authority_hrn': user_authority,
+ 'authority_hrn': user_authority,
'cc_myself': True,
'authorities': authorities,
'theme': self.theme,
from plugins.filter_status import FilterStatusPlugin
from plugins.testbeds import TestbedsPlugin
from plugins.scheduler2 import Scheduler2
+
+# Bristol plugin
+from plugins.univbrisfoam import UnivbrisFoam
+from plugins.univbrisfv import UnivbrisFv
+from plugins.univbrisfvf import UnivbrisFvf
+
from plugins.columns_editor import ColumnsEditor
from plugins.sladialog import SlaDialog
from plugins.lists.simplelist import SimpleList
metadata = page.get_metadata()
page.expose_js_metadata()
+ # Bristol
+ univbrisfoam_query=Query().get('ofelia-bristol-of:resource').select('urn')
+ page.enqueue_query(univbrisfoam_query)
+
+
resource_md = metadata.details_by_object('resource')
resource_fields = [column['name'] for column in resource_md['column']]
query = main_query,
username = request.user,
)
+
+ # Bristol plugin
+ univbrisfoamlist = UnivbrisFoam(
+ page = page,
+ title = 'univbris_foam_ports_selection',
+ domid = 'univbris_foam_ports_selection',
+ query = univbrisfoam_query,
+ query_all = univbrisfoam_query,
+ checkboxes = False,
+ datatables_options = {
+ 'iDisplayLength': 10,
+ 'bLengthChange' : True,
+ 'bAutoWidth' : True,
+ },
+ )
+
+ #plugin which manages the different flowspaces that the user creates, and also sends flowspaces to manifold
+ univbrisfvlist = UnivbrisFv(
+ page = page,
+ title = 'univbris_flowspace_selection',
+ domid = 'univbris_flowspace_selection',
+ query = None,
+ query_all = None,
+ datatables_options = {
+ 'iDisplayLength': 5,
+ 'bLengthChange' : True,
+ 'bAutoWidth' : True,
+ },
+ )
+
+ #plugin which allows the definition of a single flowspace
+ univbrisfvform = UnivbrisFvf(
+ page = page,
+ title = 'univbris_flowspace_form',
+ domid = 'univbris_flowspace_form',
+ query = None,
+ query_all = None,
+ datatables_options = {
+ 'iDisplayLength': 3,
+ 'bLengthChange' : True,
+ 'bAutoWidth' : True,
+ },
+ )
+
# --------------------------------------------------------------------------
template_env['map_resources'] = map_resources.render(self.request)
template_env['scheduler'] = resources_as_scheduler2.render(self.request)
+
+ # Bristol plugin
+ template_env['resources'] = univbrisfoamlist.render(self.request)
+ template_env['flowspaces']= univbrisfvlist.render(self.request)
+ template_env['flowspaces_form']= univbrisfvform.render(self.request)
+
+
# template_env['pending_resources'] = pending_resources.render(self.request)
template_env['sla_dialog'] = '' # sla_dialog.render(self.request)
template_env["theme"] = self.theme
--- /dev/null
+@import url("../fonts/opensans_bold_macroman/stylesheet.css");
+
+html { height: 100% }
+
+body {
+ background-color:white;
+ color:black;
+ margin:0;
+ padding:0;
+ height: 100%;
+}
+a, a:active, a:focus {
+ outline: 0;
+ text-decoration:none;
+}
+
+h1 {
+ border-bottom:1px solid #DDDDDD;
+ padding:0 0 0 0;
+ margin:15px 0 15px 0;
+ font-size:14pt;
+}
+h1 img {
+ vertical-align:middle;
+ margin-bottom:4px;
+ margin-right:10px;
+}
+h2 {
+ font-size:14pt;
+ color:#333333;
+}
+h3 {
+ font-size:13pt;
+ color:#201E62;
+}
+input[type=text], input[type=password], input[type=email], input[type=tel], input[type=number], select, option {
+ min-width:260px;
+ padding:6px;
+ border:1pt solid #22606D;
+ vertical-align:bottom;
+ border-radius:0;
+}
+
+textarea {
+ padding:6px;
+ border:1pt solid #22606D !important;
+ border-radius:0 !important;
+}
+
+span.label {
+ font-size:11pt;
+ color:gray;
+ font-weight:normal;
+ padding:0;
+}
+div.el {
+ padding-bottom:15px;
+}
+div.breadcrumbs {
+ margin:15px 0;
+ color:gray;
+ font-size:10pt;
+}
+/* buttons */
+button.btn, input.btn {
+ padding:6px 10px;
+ border-radius:5px;
+ font-size:10pt;
+ font-weight:normal;
+}
+button.btn span.glyphicon {
+ margin-right:6px;
+}
+button.btn-default {
+ border-bottom:3px solid #cccccc;
+}
+button.btn-default:hover {
+ background-color:white;
+ border:1px solid #ADADAD;
+ border-bottom:3px solid #ADADAD;
+}
+button.btn-default:active {
+ background-color:white;
+ border:1px solid #ADADAD;
+ border-bottom:1px solid #ADADAD;
+ margin-top:2px;
+ box-shadow:none;
+}
+button.btn-primary {
+ border-bottom:3px solid #3071A9;
+}
+button.btn-primary:hover {
+ box-shadow:none;
+ background-color:#428bca;
+ border:1px solid #357ebd;
+ border-bottom:3px solid #3071A9;
+}
+button.btn-primary:active {
+ box-shadow:none;
+ border-bottom:1px solid #3071A9;
+ margin-top:2px;
+}
+button.btn-danger {
+ border-bottom:3px solid #A13F3A;
+}
+button.btn-danger:hover {
+ box-shadow:none;
+ background-color:#d9534f;
+ border:1px solid #d43f3a;
+ border-bottom:3px solid #A13F3A;
+}
+button.btn-danger:active {
+ border:1px solid #d43f3a;
+ box-shadow:none;
+ margin-top:2px;
+}
+button.btn-onelab, input.btn-onelab {
+ border:0;
+ border-bottom:3px solid #760073;
+ background-color:#302562;
+ color:white;
+}
+button.btn-onelab:hover, input.btn-onelab:hover {
+ border:0;
+ border-bottom:3px solid #760073;
+ background-color:#302562;
+ color:white;
+}
+button.btn-onelab:active, input.btn-onelab:active {
+ box-shadow:none;
+ border-bottom:1px solid #760073;
+ margin-top:2px;
+}
+
+.container-resource button {
+ padding:2px 4px;
+ border-radius:3px;
+ font-size:9pt;
+ font-weight:normal;
+}
+.container-resource select,.container-resource option, .container-resource input {
+ padding:2px 4px;
+ font-size:9pt;
+}
+.badge {
+ font-size:9pt;
+ margin-left:4px;
+}
+/***** Notifications *****/
+.warning {
+ border: 1px solid red;
+ margin: 20px 60px;
+ padding: 10px 20px;
+ color: red;
+ background-color: #f2dbdb;
+ text-align: center;
+}
+
+/* HOME DASHBOARD */
+div#home-dashboard {
+ color:black;
+ margin:0 auto 25px auto;
+}
+div#home-dashboard table {
+ margin:25px;
+ width:100%;
+}
+div#home-dashboard table td {
+ text-align:center;
+ padding:15px 0;
+ width:33%;
+}
+div#home-dashboard table tr:first-child td {
+ font-size:12pt;
+ font-weight:bold;
+ color:#270A5A;
+}
+div#home-dashboard table tr:last-child td {
+ vertical-align:top;
+ padding:25px 0;
+}
+div#home-dashboard table tr:last-child td.logged-in {
+ border-right:1px solid #DDDDDD;
+ padding:25px;
+}
+div#home-dashboard table tr:last-child td.support {
+ border-left:1px solid #DDDDDD;
+ padding:25px;
+}
+div#home-dashboard table tr:last-child td:first-child {
+}
+div#home-dashboard table tr:last-child td:last-child {
+ border-right:0;
+}
+div#home-dashboard table tr:last-child td.logged-in div {
+ text-align:left;
+ padding:25px 0;
+}
+div#home-dashboard table tr:last-child td.support div {
+ text-align:left;
+ padding:25px 0;
+}
+div#home-dashboard div.login-widget {
+ padding:20px;
+}
+div#home-dashboard table td.support {
+}
+div#home-dashboard table td.support a {
+}
+div#home-dashboard table td.support a:hover {
+ text-decoration:none;
+}
+
+div#home-dashboard div#manager {
+ display:none;
+}
+
+div#home-dashboard div#home-slice-list {
+ margin:25px 0;
+ padding:0 25px;
+ text-align:left;
+}
+div#home-dashboard div#home-slice-list ul {
+ list-style: none;
+ padding:0;
+ margin:0;
+}
+div#home-dashboard div#home-slice-list li {
+
+}
+
+/**/
+
+/**/
+/* WELL */
+div.well {
+}
+/**/
+/* TABLE */
+table.table {
+ margin:0;
+}
+table.table thead {
+ padding:0;
+}
+table.table tbody {
+ padding:0;
+}
+table.table tr {
+ padding:0;
+}
+table.table td {
+ padding:0;
+}
+/* INSTITUTION */
+div#institution {
+ color:black;
+}
+.form-hint {
+ font-size:11pt;
+ font-style:italic;
+ color:gray;
+}
+
+
+.form-hint {
+ font-size:11pt;
+ font-style:italic;
+ color:gray;
+}
+
+
+
+/* TICKET REQUEST */
+div#ticket-request {
+ color:black;
+}
+.form-hint {
+ font-size:11pt;
+ font-style:italic;
+ color:gray;
+}
+div#ticket-request p {
+ margin:20px 0;
+}
+
+ul.nav-tabs {
+ margin:0 0 15px 0;
+}
+ul.nav-tabs ul {}
+ul.nav-tabs li {}
+
+ul.nav-section li a {
+ color:black;
+ border-bottom:0;
+}
+ul.nav-section li:first-child {
+ padding:0;
+}
+ul.nav-section li:first-child a {
+}
+ul.nav-section li:first-child.active a {
+}
+
+ul.nav-resources {
+ margin:15px 0;
+}
+ul.nav-resources a {
+ padding: 4px 10px 5px 10px;
+}
+
+/* SLICE VIEW */
+div.container-resource, div.container-slice {
+ padding-right:15px;
+ padding-left:15px;
+}
+.table th {
+ border-top:0 !important;
+}
+div#slice-view {
+ margin:0;
+}
+div.list-group-item {
+ border:0;
+ -moz-border-radius: 0;
+ border-radius: 0;
+ background-color:white;
+ font-weight:bold;
+ padding-left:0;
+}
+a.list-group-item {
+ -moz-border-radius: 0;
+ border-radius: 0;
+ border:0;
+ background-color:white;
+ padding:3px 2px 3px 10px;
+ border-left:2pt white solid;
+}
+a.list-group-item.active, a.list-group-item.active:hover, a.list-group-item.active:focus {
+ -moz-border-radius: 0;
+ border-radius: 0;
+ font-weight: bold;
+ color:black;
+ background-color:#F5F5F5;
+ border-left:2pt blue solid;
+}
+
+a.list-group-item:hover {
+ -moz-border-radius: 0;
+ border-radius: 0;
+ border-left:2pt blue solid;
+}
+a.list-group-item p.list-group-item-text {
+ -moz-border-radius: 0;
+ border-radius: 0;
+ font-size:9pt;
+ font-style:italic;
+ font-weight: normal;
+ color: black !important;
+}
+
+span.sl-resources {
+ font-size:9pt;
+ color:gray;
+}
+a.sl-resources, a.sl-resources:hover {
+ font-size:9pt;
+ border:0;
+ padding:2px 4px;
+ -moz-border-radius: 4px;
+ border-radius: 4px;
+}
+a.sl-resources.active, a.sl-resources.active:hover, a.sl-resources.active:focus {
+ border:0;
+ -moz-border-radius: 4px;
+ border-radius: 4px;
+}
+
+div#slice-info {
+ margin-top:25px;
+}
+div#slice-info table {
+ width:100%;
+ margin:0 auto;
+}
+div#slice-info table td:first-child {
+ text-align:right;
+ font-weight:bold;
+ padding-right:15px;
+}
+div#slice-info td {
+ padding:5px;
+}
+
+/* SLICE VIEW sections */
+.slice-sections, .slice-pending {
+ margin:0;
+ padding:0;
+}
+.slice-sections ul, .slice-pending ul {
+ margin:0;
+ padding:0;
+}
+.slice-pending ul {
+ width:400px;
+ margin:0 auto 15px auto;
+}
+.slice-sections li {
+ text-align:left;
+ margin:0;
+ padding:0;
+}
+.slice-pending li {
+ padding-right:15px;
+}
+.slice-sections li a, .slice-pending li a {
+ font-size:14px;
+ color:black;
+ padding:0;
+}
+.slice-sections li.active a, .slice-pending li.active a {
+ color:#201E62;
+ background-color:#EFEFEF;
+ text-decoration:underline;
+ padding:0;
+}
+.slice-sections ul.nav-pills li a:hover, .slice-pending ul.nav-pills li a:hover {
+ text-decoration:underline;
+ background-color:#EFEFEF;
+ color:black;
+}
+.slice-sections ul.nav-pills li.active, .slice-pending ul.nav-pills li.active {
+
+}
+.slice-sections li:first-child, .slice-sections li:first-child a {
+ color:#201E62;
+ font-weight:bold;
+}
+.slice-experiment {
+ text-align:right;
+ padding:0;
+}
+.slice-experiment button {
+ margin:3px 0 0 0;
+ background-color:#CC4125;
+ color:white;
+}
+
+.slice-pending {
+}
+.slice-pending button {
+ font-size:9pt;
+ margin:-2px 0 0 0;
+ padding:3px 5px;
+}
+.slice-pending button.apply {
+}
+.slice-pending button.clear {
+}
+tr.active, tr.active td {
+ background-color:#FFFFCC !important;
+}
+div.dataTables_filter label{
+ float:left;
+ width:400px;
+}
+
+/* HEADER */
+
+
+.header {
+ -moz-box-shadow: 0 0 1px rgba(82,82,82,0.6);
+ -webkit-box-shadow: 0 0 1px rgba(82,82,82,0.6);
+ box-shadow: 0 0 1px rgba(82,82,82,0.6);
+ height:61px;
+ background-color:white;
+ margin-bottom: 35px;
+}
+
+div.navigation {
+
+}
+div.navigation ul {
+ margin:26px 0 0 0;
+ padding:0;
+ display: inline-block;
+ list-style-type: none;
+ white-space: nowrap;
+}
+
+div.navigation li {
+ color:#0C0047;
+ font-family:open_sansbold, sans-serif;
+ font-size:9pt;
+ font-weight:normal;
+ line-height:0.8em;
+ letter-spacing:0.4pt;
+ list-style:none;
+ float:left;
+ padding:0 15px;
+ margin:0;
+ text-transform:uppercase;
+}
+div.navigation li:hover {
+}
+div.navigation li a {
+ color:#0C0047;
+}
+div.navigation li a:hover, div.navigation li a.current {
+ color:#760073;
+ text-decoration:none;
+}
+
+div.navigation li:last-child {
+ margin-right:0;
+}
+
+
+div.navigation .dropdown-menu {
+ color:black;
+ -moz-box-shadow: 1px 1px 0px 0 rgba(58, 48, 100,0.8);
+ -webkit-box-shadow: 1px 1px 0px 0 rgba(58, 48, 100,0.8);
+ box-shadow: 1px 1px 0px 0 rgba(58, 48, 100,0.8);
+ border-radius:2px;
+ padding:0 5px 5px 5px;
+ margin-top:5px;
+ margin-left:20px;
+}
+div.navigation .dropdown-menu ul {
+ margin:0;
+ padding:15px 5px 5px 5px;
+ display:list-item;
+}
+div.navigation .dropdown-menu li {
+ margin:0 10px 0 0;
+ padding:0 0 8px 0;
+ display:list-item;
+ float:none;
+ text-transform: none;
+}
+
+div.navigation .dropdown-menu a {
+ font-family:Helvetica,sans-serif;
+ font-size:10pt;
+ color:black;
+}
+div.navigation .dropdown-menu li.title {
+ margin-bottom:10px;
+}
+div.navigation .dropdown-menu li.title a {
+ font-family:open_sansbold, sans-serif;
+}
+
+
+div.navigation .dropdown-menu li:first-child {
+ border-bottom:1px solid white;
+ padding-bottom:5px;
+
+}
+
+div.secondary {
+ text-align:right;
+}
+
+div.secondary ul {
+ margin:6px 0 0 0;
+ padding:0;
+}
+
+div.secondary li {
+ font-size:9pt;
+ display:inline;
+ list-style:none;
+ margin:0px;
+ padding:0;
+ margin-right:15px;
+ color:#747474;
+ letter-spacing:0.4px;
+}
+div.secondary li:last-child {
+ margin-right:0;
+}
+div.secondary li a {
+ color:#747474;
+}
+div.secondary li a:hover {
+ text-decoration:none;
+}
+div.secondary .button {
+ width:300px;
+ margin-top:15px;
+}
+div.secondary .account {
+ margin-top:10px;
+ padding:0;
+ font-size:9pt;
+ color:gray;
+ text-align:right;
+}
+div.secondary .account span {
+ font-size:8pt;
+}
+div.secondary .account a {
+ color:black;
+}
+div.home {
+ font-size:11pt;
+ line-height:1.2em;
+ letter-spacing:0.3pt;
+ min-height:500px;
+ background-image: url('../img/optical_fibre.jpg');
+ background-repeat:no-repeat;
+ background-size:cover;
+ background-position:center top;
+ background-color:#013ADF;
+ padding:100px 0;
+}
+div.home h2 {
+ color:white;
+ line-height:1.2em;
+ font-size:18pt;
+}
+div.home h3 {
+ color:white;
+ line-height:1.4em;
+}
+div.dashboard {
+ text-align:center;
+}
+div.dashboard div {
+ margin:25px 0;
+}
+div.dashboard ul {
+ text-align:left;
+ margin-left:24px;
+ list-style:none;
+}
+div.registration-form {
+ padding-top:150px;
+ text-align:center;
+}
+
+.login-form input {
+ width:320px;
+}
+.login-form input[type=submit] {
+ width:108px;
+}
+
+.login-submit {
+ vertical-align:middle;
+ padding:0;
+}
+.lost-password {
+ font-size:10pt;
+ color:black;
+ text-align:right;
+ padding:0px;
+}
+.lost-password a {
+ color:white;
+ text-shadow:0.5px 0.5px black;
+}
+.login-signup {
+ font-size:12pt;
+ color:white;
+ text-shadow:0.5px 0.5px black;
+ margin-top:45px;
+ padding:5px 0 0 4px;
+
+}
+.login-signup a {
+ color:white;
+ text-shadow:0.5px 0.5px black;
+ padding-bottom:2px;
+ border-bottom:2pt solid white;
+}
+.login-signup a:hover {
+ text-decoration:none;
+}
+.login-signup button {
+ padding:8px;
+ border:0;
+ border-bottom:2px solid #540086;
+ background-color:#302562;
+ color:white;
+ width:100px;
+ border-radius:5px;
+ font-size:12pt;
+}
+div.slogan {
+ text-align:center;
+ color:white;
+ padding-top:60px;
+ text-shadow: 1px 1px #013540;
+}
--- /dev/null
+/* @override unfold/static/css/plugin.css */
+
+/*-------------------------------- MARKO'S STYLES -----*/
+
+/* GENERAL */
+
+a, a:visited {
+ color: rgb(13, 187, 255) !important;
+ text-decoration: none !important;
+}
+
+a:hover {
+ color: blue !important;
+ text-decoration: none !important;
+}
+
+.container {
+ /*padding: 0 !important;*/
+ padding-top: 60px !important;
+ color: #fff;
+/* background: url(http://new.fit-equipex.fr/images/background.jpg) no-repeat; */
+ background-color: rgb(237, 241, 243);
+ margin: 0;
+ width: 100%;
+ max-width: 100%;
+ min-height: 100%;
+ height: 100%;
+}
+
+.container h1, .container h2 {
+ color: #fff !important;
+}
+
+.navbar-brand {
+ padding: 5px !important;
+}
+
+.nav {
+ padding-top: 30px !important;
+ padding-left: 20px !important;
+}
+
+.navbar-default {
+ background-color: #fff !important;
+}
+
+p.login-status {
+ color: blue !important;
+}
+
+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 */
+div.well-lg {
+ background-color: rgba(168, 32, 202, 0.5) !important;
+}
+div.onelab-title {
+ background-color: #3A5FCD !important;
+ /*background-color: rgba(168, 32, 202, 0.5) !important;*/
+}
+div.well {
+ /*background-color: rgba(0, 0, 0, 0.5) !important;*/
+ background-color: #fff !important;
+ color: rgb(37, 37, 37) !important;
+}
+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: 40px;
+ 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;
+}
+
+
+
+/* if window enlarged wider than background picture */
+body {
+ background: rgb(237, 241, 243) !important;
+ /*background: black !important;*/
+}
+
+/* TOPMENU.CSS */
+
+/* Thierry : turning this off
+body {
+ *//* background: #30196d !important; *//*
+ background: black !important;
+ padding-top: 60px;
+ padding-bottom: 0px;
+}
+Thierry */
+
+/* Thierry : turning this off
+div.topmenu {
+ padding-top: 0px;
+ font-family: Ubuntu, Arial, sans-serif;
+ font-weight: bold;
+ 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);
+}
+Thierry */
+
+/* Thierry : turning this off
+.navbar-nav li a,
+.navbar-nav li.other a {
+ padding-top: 25px;
+ padding-bottom: 20px;
+}
+Thierry */
+
+.navbar-nav li a:hover {
+ color: #572bc9 !important;
+}
+
+.navbar-nav li.active a {
+ background: #eee !important;
+}
+
+/* Thierry : turning this off
+ul.logged-in {
+ padding-top: 25px;
+}
+Thierry */
+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; */
+ background: #ff7394;
+ border: 2px solid #ff7394;
+ 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; */
+ background: #ff7394;
+ 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;
+}
+
+
+
+
+/* QUERYTABLE */
+
+div.QueryTable 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.png') no-repeat !important;
+}
+
+div.QueryTable table.dataTable td, div.QueryTable table.dataTable textarea, div.QueryTable 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.QueryTable table.dataTable thead {
+ background: url('../img/tablesort-header.png') repeat-x !important;
+ background-color: #caebea;
+}
+
+div.QueryTable 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.QueryUpdater,
+/* Thierry : turning this off
+.plugin.Tabs
+Thierry */
+{
+ 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: #ff7394 !important;
+/* color: #ff0099 !important; */
+}
+
+.ms-dashboard-content a:hover {
+ color: white !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;
+}
+
/* qTip2 v2.2.0 tips modal viewport svg imagemap ie6 | qtip2.com | Licensed MIT, GPL | Thu Nov 21 2013 20:34:59 */
(function(t,e,i){(function(t){"use strict";"function"==typeof define&&define.amd?define(["jquery"],t):jQuery&&!jQuery.fn.qtip&&t(jQuery)})(function(s){"use strict";function o(t,e,i,o){this.id=i,this.target=t,this.tooltip=E,this.elements={target:t},this._id=X+"-"+i,this.timers={img:{}},this.options=e,this.plugins={},this.cache={event:{},target:s(),disabled:k,attr:o,onTooltip:k,lastClass:""},this.rendered=this.destroyed=this.disabled=this.waiting=this.hiddenDuringWait=this.positioning=this.triggering=k}function n(t){return t===E||"object"!==s.type(t)}function r(t){return!(s.isFunction(t)||t&&t.attr||t.length||"object"===s.type(t)&&(t.jquery||t.then))}function a(t){var e,i,o,a;return n(t)?k:(n(t.metadata)&&(t.metadata={type:t.metadata}),"content"in t&&(e=t.content,n(e)||e.jquery||e.done?e=t.content={text:i=r(e)?k:e}:i=e.text,"ajax"in e&&(o=e.ajax,a=o&&o.once!==k,delete e.ajax,e.text=function(t,e){var n=i||s(this).attr(e.options.content.attr)||"Loading...",r=s.ajax(s.extend({},o,{context:e})).then(o.success,E,o.error).then(function(t){return t&&a&&e.set("content.text",t),t},function(t,i,s){e.destroyed||0===t.status||e.set("content.text",i+": "+s)});return a?n:(e.set("content.text",n),r)}),"title"in e&&(n(e.title)||(e.button=e.title.button,e.title=e.title.text),r(e.title||k)&&(e.title=k))),"position"in t&&n(t.position)&&(t.position={my:t.position,at:t.position}),"show"in t&&n(t.show)&&(t.show=t.show.jquery?{target:t.show}:t.show===W?{ready:W}:{event:t.show}),"hide"in t&&n(t.hide)&&(t.hide=t.hide.jquery?{target:t.hide}:{event:t.hide}),"style"in t&&n(t.style)&&(t.style={classes:t.style}),s.each(R,function(){this.sanitize&&this.sanitize(t)}),t)}function h(t,e){for(var i,s=0,o=t,n=e.split(".");o=o[n[s++]];)n.length>s&&(i=o);return[i||t,n.pop()]}function l(t,e){var i,s,o;for(i in this.checks)for(s in this.checks[i])(o=RegExp(s,"i").exec(t))&&(e.push(o),("builtin"===i||this.plugins[i])&&this.checks[i][s].apply(this.plugins[i]||this,e))}function c(t){return G.concat("").join(t?"-"+t+" ":" ")}function d(i){return i&&{type:i.type,pageX:i.pageX,pageY:i.pageY,target:i.target,relatedTarget:i.relatedTarget,scrollX:i.scrollX||t.pageXOffset||e.body.scrollLeft||e.documentElement.scrollLeft,scrollY:i.scrollY||t.pageYOffset||e.body.scrollTop||e.documentElement.scrollTop}||{}}function p(t,e){return e>0?setTimeout(s.proxy(t,this),e):(t.call(this),i)}function u(t){return this.tooltip.hasClass(ee)?k:(clearTimeout(this.timers.show),clearTimeout(this.timers.hide),this.timers.show=p.call(this,function(){this.toggle(W,t)},this.options.show.delay),i)}function f(t){if(this.tooltip.hasClass(ee))return k;var e=s(t.relatedTarget),i=e.closest(U)[0]===this.tooltip[0],o=e[0]===this.options.show.target[0];if(clearTimeout(this.timers.show),clearTimeout(this.timers.hide),this!==e[0]&&"mouse"===this.options.position.target&&i||this.options.hide.fixed&&/mouse(out|leave|move)/.test(t.type)&&(i||o))try{t.preventDefault(),t.stopImmediatePropagation()}catch(n){}else this.timers.hide=p.call(this,function(){this.toggle(k,t)},this.options.hide.delay,this)}function g(t){return this.tooltip.hasClass(ee)||!this.options.hide.inactive?k:(clearTimeout(this.timers.inactive),this.timers.inactive=p.call(this,function(){this.hide(t)},this.options.hide.inactive),i)}function m(t){this.rendered&&this.tooltip[0].offsetWidth>0&&this.reposition(t)}function v(t,i,o){s(e.body).delegate(t,(i.split?i:i.join(he+" "))+he,function(){var t=T.api[s.attr(this,H)];t&&!t.disabled&&o.apply(t,arguments)})}function y(t,i,n){var r,h,l,c,d,p=s(e.body),u=t[0]===e?p:t,f=t.metadata?t.metadata(n.metadata):E,g="html5"===n.metadata.type&&f?f[n.metadata.name]:E,m=t.data(n.metadata.name||"qtipopts");try{m="string"==typeof m?s.parseJSON(m):m}catch(v){}if(c=s.extend(W,{},T.defaults,n,"object"==typeof m?a(m):E,a(g||f)),h=c.position,c.id=i,"boolean"==typeof c.content.text){if(l=t.attr(c.content.attr),c.content.attr===k||!l)return k;c.content.text=l}if(h.container.length||(h.container=p),h.target===k&&(h.target=u),c.show.target===k&&(c.show.target=u),c.show.solo===W&&(c.show.solo=h.container.closest("body")),c.hide.target===k&&(c.hide.target=u),c.position.viewport===W&&(c.position.viewport=h.container),h.container=h.container.eq(0),h.at=new z(h.at,W),h.my=new z(h.my),t.data(X))if(c.overwrite)t.qtip("destroy",!0);else if(c.overwrite===k)return k;return t.attr(Y,i),c.suppress&&(d=t.attr("title"))&&t.removeAttr("title").attr(se,d).attr("title",""),r=new o(t,c,i,!!l),t.data(X,r),t.one("remove.qtip-"+i+" removeqtip.qtip-"+i,function(){var t;(t=s(this).data(X))&&t.destroy(!0)}),r}function b(t){return t.charAt(0).toUpperCase()+t.slice(1)}function w(t,e){var s,o,n=e.charAt(0).toUpperCase()+e.slice(1),r=(e+" "+be.join(n+" ")+n).split(" "),a=0;if(ye[e])return t.css(ye[e]);for(;s=r[a++];)if((o=t.css(s))!==i)return ye[e]=s,o}function _(t,e){return Math.ceil(parseFloat(w(t,e)))}function x(t,e){this._ns="tip",this.options=e,this.offset=e.offset,this.size=[e.width,e.height],this.init(this.qtip=t)}function q(t,e){this.options=e,this._ns="-modal",this.init(this.qtip=t)}function C(t){this._ns="ie6",this.init(this.qtip=t)}var T,j,z,M,I,W=!0,k=!1,E=null,S="x",L="y",A="width",B="height",D="top",F="left",O="bottom",P="right",N="center",$="flipinvert",V="shift",R={},X="qtip",Y="data-hasqtip",H="data-qtip-id",G=["ui-widget","ui-tooltip"],U="."+X,Q="click dblclick mousedown mouseup mousemove mouseleave mouseenter".split(" "),J=X+"-fixed",K=X+"-default",Z=X+"-focus",te=X+"-hover",ee=X+"-disabled",ie="_replacedByqTip",se="oldtitle",oe={ie:function(){for(var t=3,i=e.createElement("div");(i.innerHTML="<!--[if gt IE "+ ++t+"]><i></i><![endif]-->")&&i.getElementsByTagName("i")[0];);return t>4?t:0/0}(),iOS:parseFloat((""+(/CPU.*OS ([0-9_]{1,5})|(CPU like).*AppleWebKit.*Mobile/i.exec(navigator.userAgent)||[0,""])[1]).replace("undefined","3_2").replace("_",".").replace("_",""))||k};j=o.prototype,j._when=function(t){return s.when.apply(s,t)},j.render=function(t){if(this.rendered||this.destroyed)return this;var e,i=this,o=this.options,n=this.cache,r=this.elements,a=o.content.text,h=o.content.title,l=o.content.button,c=o.position,d=("."+this._id+" ",[]);return s.attr(this.target[0],"aria-describedby",this._id),this.tooltip=r.tooltip=e=s("<div/>",{id:this._id,"class":[X,K,o.style.classes,X+"-pos-"+o.position.my.abbrev()].join(" "),width:o.style.width||"",height:o.style.height||"",tracking:"mouse"===c.target&&c.adjust.mouse,role:"alert","aria-live":"polite","aria-atomic":k,"aria-describedby":this._id+"-content","aria-hidden":W}).toggleClass(ee,this.disabled).attr(H,this.id).data(X,this).appendTo(c.container).append(r.content=s("<div />",{"class":X+"-content",id:this._id+"-content","aria-atomic":W})),this.rendered=-1,this.positioning=W,h&&(this._createTitle(),s.isFunction(h)||d.push(this._updateTitle(h,k))),l&&this._createButton(),s.isFunction(a)||d.push(this._updateContent(a,k)),this.rendered=W,this._setWidget(),s.each(R,function(t){var e;"render"===this.initialize&&(e=this(i))&&(i.plugins[t]=e)}),this._unassignEvents(),this._assignEvents(),this._when(d).then(function(){i._trigger("render"),i.positioning=k,i.hiddenDuringWait||!o.show.ready&&!t||i.toggle(W,n.event,k),i.hiddenDuringWait=k}),T.api[this.id]=this,this},j.destroy=function(t){function e(){if(!this.destroyed){this.destroyed=W;var t=this.target,e=t.attr(se);this.rendered&&this.tooltip.stop(1,0).find("*").remove().end().remove(),s.each(this.plugins,function(){this.destroy&&this.destroy()}),clearTimeout(this.timers.show),clearTimeout(this.timers.hide),this._unassignEvents(),t.removeData(X).removeAttr(H).removeAttr(Y).removeAttr("aria-describedby"),this.options.suppress&&e&&t.attr("title",e).removeAttr(se),this._unbind(t),this.options=this.elements=this.cache=this.timers=this.plugins=this.mouse=E,delete T.api[this.id]}}return this.destroyed?this.target:(t===W&&"hide"!==this.triggering||!this.rendered?e.call(this):(this.tooltip.one("tooltiphidden",s.proxy(e,this)),!this.triggering&&this.hide()),this.target)},M=j.checks={builtin:{"^id$":function(t,e,i,o){var n=i===W?T.nextid:i,r=X+"-"+n;n!==k&&n.length>0&&!s("#"+r).length?(this._id=r,this.rendered&&(this.tooltip[0].id=this._id,this.elements.content[0].id=this._id+"-content",this.elements.title[0].id=this._id+"-title")):t[e]=o},"^prerender":function(t,e,i){i&&!this.rendered&&this.render(this.options.show.ready)},"^content.text$":function(t,e,i){this._updateContent(i)},"^content.attr$":function(t,e,i,s){this.options.content.text===this.target.attr(s)&&this._updateContent(this.target.attr(i))},"^content.title$":function(t,e,s){return s?(s&&!this.elements.title&&this._createTitle(),this._updateTitle(s),i):this._removeTitle()},"^content.button$":function(t,e,i){this._updateButton(i)},"^content.title.(text|button)$":function(t,e,i){this.set("content."+e,i)},"^position.(my|at)$":function(t,e,i){"string"==typeof i&&(t[e]=new z(i,"at"===e))},"^position.container$":function(t,e,i){this.rendered&&this.tooltip.appendTo(i)},"^show.ready$":function(t,e,i){i&&(!this.rendered&&this.render(W)||this.toggle(W))},"^style.classes$":function(t,e,i,s){this.rendered&&this.tooltip.removeClass(s).addClass(i)},"^style.(width|height)":function(t,e,i){this.rendered&&this.tooltip.css(e,i)},"^style.widget|content.title":function(){this.rendered&&this._setWidget()},"^style.def":function(t,e,i){this.rendered&&this.tooltip.toggleClass(K,!!i)},"^events.(render|show|move|hide|focus|blur)$":function(t,e,i){this.rendered&&this.tooltip[(s.isFunction(i)?"":"un")+"bind"]("tooltip"+e,i)},"^(show|hide|position).(event|target|fixed|inactive|leave|distance|viewport|adjust)":function(){if(this.rendered){var t=this.options.position;this.tooltip.attr("tracking","mouse"===t.target&&t.adjust.mouse),this._unassignEvents(),this._assignEvents()}}}},j.get=function(t){if(this.destroyed)return this;var e=h(this.options,t.toLowerCase()),i=e[0][e[1]];return i.precedance?i.string():i};var ne=/^position\.(my|at|adjust|target|container|viewport)|style|content|show\.ready/i,re=/^prerender|show\.ready/i;j.set=function(t,e){if(this.destroyed)return this;var o,n=this.rendered,r=k,c=this.options;return this.checks,"string"==typeof t?(o=t,t={},t[o]=e):t=s.extend({},t),s.each(t,function(e,o){if(n&&re.test(e))return delete t[e],i;var a,l=h(c,e.toLowerCase());a=l[0][l[1]],l[0][l[1]]=o&&o.nodeType?s(o):o,r=ne.test(e)||r,t[e]=[l[0],l[1],o,a]}),a(c),this.positioning=W,s.each(t,s.proxy(l,this)),this.positioning=k,this.rendered&&this.tooltip[0].offsetWidth>0&&r&&this.reposition("mouse"===c.position.target?E:this.cache.event),this},j._update=function(t,e){var i=this,o=this.cache;return this.rendered&&t?(s.isFunction(t)&&(t=t.call(this.elements.target,o.event,this)||""),s.isFunction(t.then)?(o.waiting=W,t.then(function(t){return o.waiting=k,i._update(t,e)},E,function(t){return i._update(t,e)})):t===k||!t&&""!==t?k:(t.jquery&&t.length>0?e.empty().append(t.css({display:"block",visibility:"visible"})):e.html(t),this._waitForContent(e).then(function(t){t.images&&t.images.length&&i.rendered&&i.tooltip[0].offsetWidth>0&&i.reposition(o.event,!t.length)}))):k},j._waitForContent=function(t){var e=this.cache;return e.waiting=W,(s.fn.imagesLoaded?t.imagesLoaded():s.Deferred().resolve([])).done(function(){e.waiting=k}).promise()},j._updateContent=function(t,e){this._update(t,this.elements.content,e)},j._updateTitle=function(t,e){this._update(t,this.elements.title,e)===k&&this._removeTitle(k)},j._createTitle=function(){var t=this.elements,e=this._id+"-title";t.titlebar&&this._removeTitle(),t.titlebar=s("<div />",{"class":X+"-titlebar "+(this.options.style.widget?c("header"):"")}).append(t.title=s("<div />",{id:e,"class":X+"-title","aria-atomic":W})).insertBefore(t.content).delegate(".qtip-close","mousedown keydown mouseup keyup mouseout",function(t){s(this).toggleClass("ui-state-active ui-state-focus","down"===t.type.substr(-4))}).delegate(".qtip-close","mouseover mouseout",function(t){s(this).toggleClass("ui-state-hover","mouseover"===t.type)}),this.options.content.button&&this._createButton()},j._removeTitle=function(t){var e=this.elements;e.title&&(e.titlebar.remove(),e.titlebar=e.title=e.button=E,t!==k&&this.reposition())},j.reposition=function(i,o){if(!this.rendered||this.positioning||this.destroyed)return this;this.positioning=W;var n,r,a=this.cache,h=this.tooltip,l=this.options.position,c=l.target,d=l.my,p=l.at,u=l.viewport,f=l.container,g=l.adjust,m=g.method.split(" "),v=h.outerWidth(k),y=h.outerHeight(k),b=0,w=0,_=h.css("position"),x={left:0,top:0},q=h[0].offsetWidth>0,C=i&&"scroll"===i.type,T=s(t),j=f[0].ownerDocument,z=this.mouse;if(s.isArray(c)&&2===c.length)p={x:F,y:D},x={left:c[0],top:c[1]};else if("mouse"===c)p={x:F,y:D},!z||!z.pageX||!g.mouse&&i&&i.pageX?i&&i.pageX||((!g.mouse||this.options.show.distance)&&a.origin&&a.origin.pageX?i=a.origin:(!i||i&&("resize"===i.type||"scroll"===i.type))&&(i=a.event)):i=z,"static"!==_&&(x=f.offset()),j.body.offsetWidth!==(t.innerWidth||j.documentElement.clientWidth)&&(r=s(e.body).offset()),x={left:i.pageX-x.left+(r&&r.left||0),top:i.pageY-x.top+(r&&r.top||0)},g.mouse&&C&&z&&(x.left-=(z.scrollX||0)-T.scrollLeft(),x.top-=(z.scrollY||0)-T.scrollTop());else{if("event"===c?i&&i.target&&"scroll"!==i.type&&"resize"!==i.type?a.target=s(i.target):i.target||(a.target=this.elements.target):"event"!==c&&(a.target=s(c.jquery?c:this.elements.target)),c=a.target,c=s(c).eq(0),0===c.length)return this;c[0]===e||c[0]===t?(b=oe.iOS?t.innerWidth:c.width(),w=oe.iOS?t.innerHeight:c.height(),c[0]===t&&(x={top:(u||c).scrollTop(),left:(u||c).scrollLeft()})):R.imagemap&&c.is("area")?n=R.imagemap(this,c,p,R.viewport?m:k):R.svg&&c&&c[0].ownerSVGElement?n=R.svg(this,c,p,R.viewport?m:k):(b=c.outerWidth(k),w=c.outerHeight(k),x=c.offset()),n&&(b=n.width,w=n.height,r=n.offset,x=n.position),x=this.reposition.offset(c,x,f),(oe.iOS>3.1&&4.1>oe.iOS||oe.iOS>=4.3&&4.33>oe.iOS||!oe.iOS&&"fixed"===_)&&(x.left-=T.scrollLeft(),x.top-=T.scrollTop()),(!n||n&&n.adjustable!==k)&&(x.left+=p.x===P?b:p.x===N?b/2:0,x.top+=p.y===O?w:p.y===N?w/2:0)}return x.left+=g.x+(d.x===P?-v:d.x===N?-v/2:0),x.top+=g.y+(d.y===O?-y:d.y===N?-y/2:0),R.viewport?(x.adjusted=R.viewport(this,x,l,b,w,v,y),r&&x.adjusted.left&&(x.left+=r.left),r&&x.adjusted.top&&(x.top+=r.top)):x.adjusted={left:0,top:0},this._trigger("move",[x,u.elem||u],i)?(delete x.adjusted,o===k||!q||isNaN(x.left)||isNaN(x.top)||"mouse"===c||!s.isFunction(l.effect)?h.css(x):s.isFunction(l.effect)&&(l.effect.call(h,this,s.extend({},x)),h.queue(function(t){s(this).css({opacity:"",height:""}),oe.ie&&this.style.removeAttribute("filter"),t()})),this.positioning=k,this):this},j.reposition.offset=function(t,i,o){function n(t,e){i.left+=e*t.scrollLeft(),i.top+=e*t.scrollTop()}if(!o[0])return i;var r,a,h,l,c=s(t[0].ownerDocument),d=!!oe.ie&&"CSS1Compat"!==e.compatMode,p=o[0];do"static"!==(a=s.css(p,"position"))&&("fixed"===a?(h=p.getBoundingClientRect(),n(c,-1)):(h=s(p).position(),h.left+=parseFloat(s.css(p,"borderLeftWidth"))||0,h.top+=parseFloat(s.css(p,"borderTopWidth"))||0),i.left-=h.left+(parseFloat(s.css(p,"marginLeft"))||0),i.top-=h.top+(parseFloat(s.css(p,"marginTop"))||0),r||"hidden"===(l=s.css(p,"overflow"))||"visible"===l||(r=s(p)));while(p=p.offsetParent);return r&&(r[0]!==c[0]||d)&&n(r,1),i};var ae=(z=j.reposition.Corner=function(t,e){t=(""+t).replace(/([A-Z])/," $1").replace(/middle/gi,N).toLowerCase(),this.x=(t.match(/left|right/i)||t.match(/center/)||["inherit"])[0].toLowerCase(),this.y=(t.match(/top|bottom|center/i)||["inherit"])[0].toLowerCase(),this.forceY=!!e;var i=t.charAt(0);this.precedance="t"===i||"b"===i?L:S}).prototype;ae.invert=function(t,e){this[t]=this[t]===F?P:this[t]===P?F:e||this[t]},ae.string=function(){var t=this.x,e=this.y;return t===e?t:this.precedance===L||this.forceY&&"center"!==e?e+" "+t:t+" "+e},ae.abbrev=function(){var t=this.string().split(" ");return t[0].charAt(0)+(t[1]&&t[1].charAt(0)||"")},ae.clone=function(){return new z(this.string(),this.forceY)},j.toggle=function(t,i){var o=this.cache,n=this.options,r=this.tooltip;if(i){if(/over|enter/.test(i.type)&&/out|leave/.test(o.event.type)&&n.show.target.add(i.target).length===n.show.target.length&&r.has(i.relatedTarget).length)return this;o.event=d(i)}if(this.waiting&&!t&&(this.hiddenDuringWait=W),!this.rendered)return t?this.render(1):this;if(this.destroyed||this.disabled)return this;var a,h,l,c=t?"show":"hide",p=this.options[c],u=(this.options[t?"hide":"show"],this.options.position),f=this.options.content,g=this.tooltip.css("width"),m=this.tooltip.is(":visible"),v=t||1===p.target.length,y=!i||2>p.target.length||o.target[0]===i.target;return(typeof t).search("boolean|number")&&(t=!m),a=!r.is(":animated")&&m===t&&y,h=a?E:!!this._trigger(c,[90]),this.destroyed?this:(h!==k&&t&&this.focus(i),!h||a?this:(s.attr(r[0],"aria-hidden",!t),t?(o.origin=d(this.mouse),s.isFunction(f.text)&&this._updateContent(f.text,k),s.isFunction(f.title)&&this._updateTitle(f.title,k),!I&&"mouse"===u.target&&u.adjust.mouse&&(s(e).bind("mousemove."+X,this._storeMouse),I=W),g||r.css("width",r.outerWidth(k)),this.reposition(i,arguments[2]),g||r.css("width",""),p.solo&&("string"==typeof p.solo?s(p.solo):s(U,p.solo)).not(r).not(p.target).qtip("hide",s.Event("tooltipsolo"))):(clearTimeout(this.timers.show),delete o.origin,I&&!s(U+'[tracking="true"]:visible',p.solo).not(r).length&&(s(e).unbind("mousemove."+X),I=k),this.blur(i)),l=s.proxy(function(){t?(oe.ie&&r[0].style.removeAttribute("filter"),r.css("overflow",""),"string"==typeof p.autofocus&&s(this.options.show.autofocus,r).focus(),this.options.show.target.trigger("qtip-"+this.id+"-inactive")):r.css({display:"",visibility:"",opacity:"",left:"",top:""}),this._trigger(t?"visible":"hidden")},this),p.effect===k||v===k?(r[c](),l()):s.isFunction(p.effect)?(r.stop(1,1),p.effect.call(r,this),r.queue("fx",function(t){l(),t()})):r.fadeTo(90,t?1:0,l),t&&p.target.trigger("qtip-"+this.id+"-inactive"),this))},j.show=function(t){return this.toggle(W,t)},j.hide=function(t){return this.toggle(k,t)},j.focus=function(t){if(!this.rendered||this.destroyed)return this;var e=s(U),i=this.tooltip,o=parseInt(i[0].style.zIndex,10),n=T.zindex+e.length;return i.hasClass(Z)||this._trigger("focus",[n],t)&&(o!==n&&(e.each(function(){this.style.zIndex>o&&(this.style.zIndex=this.style.zIndex-1)}),e.filter("."+Z).qtip("blur",t)),i.addClass(Z)[0].style.zIndex=n),this},j.blur=function(t){return!this.rendered||this.destroyed?this:(this.tooltip.removeClass(Z),this._trigger("blur",[this.tooltip.css("zIndex")],t),this)},j.disable=function(t){return this.destroyed?this:("toggle"===t?t=!(this.rendered?this.tooltip.hasClass(ee):this.disabled):"boolean"!=typeof t&&(t=W),this.rendered&&this.tooltip.toggleClass(ee,t).attr("aria-disabled",t),this.disabled=!!t,this)},j.enable=function(){return this.disable(k)},j._createButton=function(){var t=this,e=this.elements,i=e.tooltip,o=this.options.content.button,n="string"==typeof o,r=n?o:"Close tooltip";e.button&&e.button.remove(),e.button=o.jquery?o:s("<a />",{"class":"qtip-close "+(this.options.style.widget?"":X+"-icon"),title:r,"aria-label":r}).prepend(s("<span />",{"class":"ui-icon ui-icon-close",html:"×"})),e.button.appendTo(e.titlebar||i).attr("role","button").click(function(e){return i.hasClass(ee)||t.hide(e),k})},j._updateButton=function(t){if(!this.rendered)return k;var e=this.elements.button;t?this._createButton():e.remove()},j._setWidget=function(){var t=this.options.style.widget,e=this.elements,i=e.tooltip,s=i.hasClass(ee);i.removeClass(ee),ee=t?"ui-state-disabled":"qtip-disabled",i.toggleClass(ee,s),i.toggleClass("ui-helper-reset "+c(),t).toggleClass(K,this.options.style.def&&!t),e.content&&e.content.toggleClass(c("content"),t),e.titlebar&&e.titlebar.toggleClass(c("header"),t),e.button&&e.button.toggleClass(X+"-icon",!t)},j._storeMouse=function(t){(this.mouse=d(t)).type="mousemove"},j._bind=function(t,e,i,o,n){var r="."+this._id+(o?"-"+o:"");e.length&&s(t).bind((e.split?e:e.join(r+" "))+r,s.proxy(i,n||this))},j._unbind=function(t,e){s(t).unbind("."+this._id+(e?"-"+e:""))};var he="."+X;s(function(){v(U,["mouseenter","mouseleave"],function(t){var e="mouseenter"===t.type,i=s(t.currentTarget),o=s(t.relatedTarget||t.target),n=this.options;e?(this.focus(t),i.hasClass(J)&&!i.hasClass(ee)&&clearTimeout(this.timers.hide)):"mouse"===n.position.target&&n.hide.event&&n.show.target&&!o.closest(n.show.target[0]).length&&this.hide(t),i.toggleClass(te,e)}),v("["+H+"]",Q,g)}),j._trigger=function(t,e,i){var o=s.Event("tooltip"+t);return o.originalEvent=i&&s.extend({},i)||this.cache.event||E,this.triggering=t,this.tooltip.trigger(o,[this].concat(e||[])),this.triggering=k,!o.isDefaultPrevented()},j._bindEvents=function(t,e,o,n,r,a){if(n.add(o).length===n.length){var h=[];e=s.map(e,function(e){var o=s.inArray(e,t);return o>-1?(h.push(t.splice(o,1)[0]),i):e}),h.length&&this._bind(o,h,function(t){var e=this.rendered?this.tooltip[0].offsetWidth>0:!1;(e?a:r).call(this,t)})}this._bind(o,t,r),this._bind(n,e,a)},j._assignInitialEvents=function(t){function e(t){return this.disabled||this.destroyed?k:(this.cache.event=d(t),this.cache.target=t?s(t.target):[i],clearTimeout(this.timers.show),this.timers.show=p.call(this,function(){this.render("object"==typeof t||o.show.ready)},o.show.delay),i)}var o=this.options,n=o.show.target,r=o.hide.target,a=o.show.event?s.trim(""+o.show.event).split(" "):[],h=o.hide.event?s.trim(""+o.hide.event).split(" "):[];/mouse(over|enter)/i.test(o.show.event)&&!/mouse(out|leave)/i.test(o.hide.event)&&h.push("mouseleave"),this._bind(n,"mousemove",function(t){this._storeMouse(t),this.cache.onTarget=W}),this._bindEvents(a,h,n,r,e,function(){clearTimeout(this.timers.show)}),(o.show.ready||o.prerender)&&e.call(this,t)},j._assignEvents=function(){var i=this,o=this.options,n=o.position,r=this.tooltip,a=o.show.target,h=o.hide.target,l=n.container,c=n.viewport,d=s(e),p=(s(e.body),s(t)),v=o.show.event?s.trim(""+o.show.event).split(" "):[],y=o.hide.event?s.trim(""+o.hide.event).split(" "):[];s.each(o.events,function(t,e){i._bind(r,"toggle"===t?["tooltipshow","tooltiphide"]:["tooltip"+t],e,null,r)}),/mouse(out|leave)/i.test(o.hide.event)&&"window"===o.hide.leave&&this._bind(d,["mouseout","blur"],function(t){/select|option/.test(t.target.nodeName)||t.relatedTarget||this.hide(t)}),o.hide.fixed?h=h.add(r.addClass(J)):/mouse(over|enter)/i.test(o.show.event)&&this._bind(h,"mouseleave",function(){clearTimeout(this.timers.show)}),(""+o.hide.event).indexOf("unfocus")>-1&&this._bind(l.closest("html"),["mousedown","touchstart"],function(t){var e=s(t.target),i=this.rendered&&!this.tooltip.hasClass(ee)&&this.tooltip[0].offsetWidth>0,o=e.parents(U).filter(this.tooltip[0]).length>0;e[0]===this.target[0]||e[0]===this.tooltip[0]||o||this.target.has(e[0]).length||!i||this.hide(t)}),"number"==typeof o.hide.inactive&&(this._bind(a,"qtip-"+this.id+"-inactive",g),this._bind(h.add(r),T.inactiveEvents,g,"-inactive")),this._bindEvents(v,y,a,h,u,f),this._bind(a.add(r),"mousemove",function(t){if("number"==typeof o.hide.distance){var e=this.cache.origin||{},i=this.options.hide.distance,s=Math.abs;(s(t.pageX-e.pageX)>=i||s(t.pageY-e.pageY)>=i)&&this.hide(t)}this._storeMouse(t)}),"mouse"===n.target&&n.adjust.mouse&&(o.hide.event&&this._bind(a,["mouseenter","mouseleave"],function(t){this.cache.onTarget="mouseenter"===t.type}),this._bind(d,"mousemove",function(t){this.rendered&&this.cache.onTarget&&!this.tooltip.hasClass(ee)&&this.tooltip[0].offsetWidth>0&&this.reposition(t)})),(n.adjust.resize||c.length)&&this._bind(s.event.special.resize?c:p,"resize",m),n.adjust.scroll&&this._bind(p.add(n.container),"scroll",m)},j._unassignEvents=function(){var i=[this.options.show.target[0],this.options.hide.target[0],this.rendered&&this.tooltip[0],this.options.position.container[0],this.options.position.viewport[0],this.options.position.container.closest("html")[0],t,e];this._unbind(s([]).pushStack(s.grep(i,function(t){return"object"==typeof t})))},T=s.fn.qtip=function(t,e,o){var n=(""+t).toLowerCase(),r=E,h=s.makeArray(arguments).slice(1),l=h[h.length-1],c=this[0]?s.data(this[0],X):E;return!arguments.length&&c||"api"===n?c:"string"==typeof t?(this.each(function(){var t=s.data(this,X);if(!t)return W;if(l&&l.timeStamp&&(t.cache.event=l),!e||"option"!==n&&"options"!==n)t[n]&&t[n].apply(t,h);else{if(o===i&&!s.isPlainObject(e))return r=t.get(e),k;t.set(e,o)}}),r!==E?r:this):"object"!=typeof t&&arguments.length?i:(c=a(s.extend(W,{},t)),this.each(function(t){var e,o;return o=s.isArray(c.id)?c.id[t]:c.id,o=!o||o===k||1>o.length||T.api[o]?T.nextid++:o,e=y(s(this),o,c),e===k?W:(T.api[o]=e,s.each(R,function(){"initialize"===this.initialize&&this(e)}),e._assignInitialEvents(l),i)}))},s.qtip=o,T.api={},s.each({attr:function(t,e){if(this.length){var i=this[0],o="title",n=s.data(i,"qtip");if(t===o&&n&&"object"==typeof n&&n.options.suppress)return 2>arguments.length?s.attr(i,se):(n&&n.options.content.attr===o&&n.cache.attr&&n.set("content.text",e),this.attr(se,e))}return s.fn["attr"+ie].apply(this,arguments)},clone:function(t){var e=(s([]),s.fn["clone"+ie].apply(this,arguments));return t||e.filter("["+se+"]").attr("title",function(){return s.attr(this,se)}).removeAttr(se),e}},function(t,e){if(!e||s.fn[t+ie])return W;var i=s.fn[t+ie]=s.fn[t];s.fn[t]=function(){return e.apply(this,arguments)||i.apply(this,arguments)}}),s.ui||(s["cleanData"+ie]=s.cleanData,s.cleanData=function(t){for(var e,i=0;(e=s(t[i])).length;i++)if(e.attr(Y))try{e.triggerHandler("removeqtip")}catch(o){}s["cleanData"+ie].apply(this,arguments)}),T.version="2.2.0",T.nextid=0,T.inactiveEvents=Q,T.zindex=15e3,T.defaults={prerender:k,id:k,overwrite:W,suppress:W,content:{text:W,attr:"title",title:k,button:k},position:{my:"top left",at:"bottom right",target:k,container:k,viewport:k,adjust:{x:0,y:0,mouse:W,scroll:W,resize:W,method:"flipinvert flipinvert"},effect:function(t,e){s(this).animate(e,{duration:200,queue:k})}},show:{target:k,event:"mouseenter",effect:W,delay:90,solo:k,ready:k,autofocus:k},hide:{target:k,event:"mouseleave",effect:W,delay:0,fixed:k,inactive:k,leave:"window",distance:k},style:{classes:"",widget:k,width:k,height:k,def:W},events:{render:E,move:E,show:E,hide:E,toggle:E,visible:E,hidden:E,focus:E,blur:E}};var le,ce="margin",de="border",pe="color",ue="background-color",fe="transparent",ge=" !important",me=!!e.createElement("canvas").getContext,ve=/rgba?\(0, 0, 0(, 0)?\)|transparent|#123456/i,ye={},be=["Webkit","O","Moz","ms"];if(me)var we=t.devicePixelRatio||1,_e=function(){var t=e.createElement("canvas").getContext("2d");return t.backingStorePixelRatio||t.webkitBackingStorePixelRatio||t.mozBackingStorePixelRatio||t.msBackingStorePixelRatio||t.oBackingStorePixelRatio||1}(),xe=we/_e;else var qe=function(t,e,i){return"<qtipvml:"+t+' xmlns="urn:schemas-microsoft.com:vml" class="qtip-vml" '+(e||"")+' style="behavior: url(#default#VML); '+(i||"")+'" />'};s.extend(x.prototype,{init:function(t){var e,i;i=this.element=t.elements.tip=s("<div />",{"class":X+"-tip"}).prependTo(t.tooltip),me?(e=s("<canvas />").appendTo(this.element)[0].getContext("2d"),e.lineJoin="miter",e.miterLimit=1e5,e.save()):(e=qe("shape",'coordorigin="0,0"',"position:absolute;"),this.element.html(e+e),t._bind(s("*",i).add(i),["click","mousedown"],function(t){t.stopPropagation()},this._ns)),t._bind(t.tooltip,"tooltipmove",this.reposition,this._ns,this),this.create()},_swapDimensions:function(){this.size[0]=this.options.height,this.size[1]=this.options.width},_resetDimensions:function(){this.size[0]=this.options.width,this.size[1]=this.options.height},_useTitle:function(t){var e=this.qtip.elements.titlebar;return e&&(t.y===D||t.y===N&&this.element.position().top+this.size[1]/2+this.options.offset<e.outerHeight(W))},_parseCorner:function(t){var e=this.qtip.options.position.my;return t===k||e===k?t=k:t===W?t=new z(e.string()):t.string||(t=new z(t),t.fixed=W),t},_parseWidth:function(t,e,i){var s=this.qtip.elements,o=de+b(e)+"Width";return(i?_(i,o):_(s.content,o)||_(this._useTitle(t)&&s.titlebar||s.content,o)||_(s.tooltip,o))||0},_parseRadius:function(t){var e=this.qtip.elements,i=de+b(t.y)+b(t.x)+"Radius";return 9>oe.ie?0:_(this._useTitle(t)&&e.titlebar||e.content,i)||_(e.tooltip,i)||0},_invalidColour:function(t,e,i){var s=t.css(e);return!s||i&&s===t.css(i)||ve.test(s)?k:s},_parseColours:function(t){var e=this.qtip.elements,i=this.element.css("cssText",""),o=de+b(t[t.precedance])+b(pe),n=this._useTitle(t)&&e.titlebar||e.content,r=this._invalidColour,a=[];return a[0]=r(i,ue)||r(n,ue)||r(e.content,ue)||r(e.tooltip,ue)||i.css(ue),a[1]=r(i,o,pe)||r(n,o,pe)||r(e.content,o,pe)||r(e.tooltip,o,pe)||e.tooltip.css(o),s("*",i).add(i).css("cssText",ue+":"+fe+ge+";"+de+":0"+ge+";"),a},_calculateSize:function(t){var e,i,s,o=t.precedance===L,n=this.options.width,r=this.options.height,a="c"===t.abbrev(),h=(o?n:r)*(a?.5:1),l=Math.pow,c=Math.round,d=Math.sqrt(l(h,2)+l(r,2)),p=[this.border/h*d,this.border/r*d];return p[2]=Math.sqrt(l(p[0],2)-l(this.border,2)),p[3]=Math.sqrt(l(p[1],2)-l(this.border,2)),e=d+p[2]+p[3]+(a?0:p[0]),i=e/d,s=[c(i*n),c(i*r)],o?s:s.reverse()},_calculateTip:function(t,e,i){i=i||1,e=e||this.size;var s=e[0]*i,o=e[1]*i,n=Math.ceil(s/2),r=Math.ceil(o/2),a={br:[0,0,s,o,s,0],bl:[0,0,s,0,0,o],tr:[0,o,s,0,s,o],tl:[0,0,0,o,s,o],tc:[0,o,n,0,s,o],bc:[0,0,s,0,n,o],rc:[0,0,s,r,0,o],lc:[s,0,s,o,0,r]};return a.lt=a.br,a.rt=a.bl,a.lb=a.tr,a.rb=a.tl,a[t.abbrev()]},_drawCoords:function(t,e){t.beginPath(),t.moveTo(e[0],e[1]),t.lineTo(e[2],e[3]),t.lineTo(e[4],e[5]),t.closePath()},create:function(){var t=this.corner=(me||oe.ie)&&this._parseCorner(this.options.corner);return(this.enabled=!!this.corner&&"c"!==this.corner.abbrev())&&(this.qtip.cache.corner=t.clone(),this.update()),this.element.toggle(this.enabled),this.corner},update:function(e,i){if(!this.enabled)return this;var o,n,r,a,h,l,c,d,p=this.qtip.elements,u=this.element,f=u.children(),g=this.options,m=this.size,v=g.mimic,y=Math.round;e||(e=this.qtip.cache.corner||this.corner),v===k?v=e:(v=new z(v),v.precedance=e.precedance,"inherit"===v.x?v.x=e.x:"inherit"===v.y?v.y=e.y:v.x===v.y&&(v[e.precedance]=e[e.precedance])),n=v.precedance,e.precedance===S?this._swapDimensions():this._resetDimensions(),o=this.color=this._parseColours(e),o[1]!==fe?(d=this.border=this._parseWidth(e,e[e.precedance]),g.border&&1>d&&!ve.test(o[1])&&(o[0]=o[1]),this.border=d=g.border!==W?g.border:d):this.border=d=0,c=this.size=this._calculateSize(e),u.css({width:c[0],height:c[1],lineHeight:c[1]+"px"}),l=e.precedance===L?[y(v.x===F?d:v.x===P?c[0]-m[0]-d:(c[0]-m[0])/2),y(v.y===D?c[1]-m[1]:0)]:[y(v.x===F?c[0]-m[0]:0),y(v.y===D?d:v.y===O?c[1]-m[1]-d:(c[1]-m[1])/2)],me?(r=f[0].getContext("2d"),r.restore(),r.save(),r.clearRect(0,0,6e3,6e3),a=this._calculateTip(v,m,xe),h=this._calculateTip(v,this.size,xe),f.attr(A,c[0]*xe).attr(B,c[1]*xe),f.css(A,c[0]).css(B,c[1]),this._drawCoords(r,h),r.fillStyle=o[1],r.fill(),r.translate(l[0]*xe,l[1]*xe),this._drawCoords(r,a),r.fillStyle=o[0],r.fill()):(a=this._calculateTip(v),a="m"+a[0]+","+a[1]+" l"+a[2]+","+a[3]+" "+a[4]+","+a[5]+" xe",l[2]=d&&/^(r|b)/i.test(e.string())?8===oe.ie?2:1:0,f.css({coordsize:c[0]+d+" "+(c[1]+d),antialias:""+(v.string().indexOf(N)>-1),left:l[0]-l[2]*Number(n===S),top:l[1]-l[2]*Number(n===L),width:c[0]+d,height:c[1]+d}).each(function(t){var e=s(this);e[e.prop?"prop":"attr"]({coordsize:c[0]+d+" "+(c[1]+d),path:a,fillcolor:o[0],filled:!!t,stroked:!t}).toggle(!(!d&&!t)),!t&&e.html(qe("stroke",'weight="'+2*d+'px" color="'+o[1]+'" miterlimit="1000" joinstyle="miter"'))})),t.opera&&setTimeout(function(){p.tip.css({display:"inline-block",visibility:"visible"})},1),i!==k&&this.calculate(e,c)},calculate:function(t,e){if(!this.enabled)return k;var i,o,n=this,r=this.qtip.elements,a=this.element,h=this.options.offset,l=(r.tooltip.hasClass("ui-widget"),{});return t=t||this.corner,i=t.precedance,e=e||this._calculateSize(t),o=[t.x,t.y],i===S&&o.reverse(),s.each(o,function(s,o){var a,c,d;o===N?(a=i===L?F:D,l[a]="50%",l[ce+"-"+a]=-Math.round(e[i===L?0:1]/2)+h):(a=n._parseWidth(t,o,r.tooltip),c=n._parseWidth(t,o,r.content),d=n._parseRadius(t),l[o]=Math.max(-n.border,s?c:h+(d>a?d:-a)))
}),l[t[i]]-=e[i===S?0:1],a.css({margin:"",top:"",bottom:"",left:"",right:""}).css(l),l},reposition:function(t,e,s){function o(t,e,i,s,o){t===V&&l.precedance===e&&c[s]&&l[i]!==N?l.precedance=l.precedance===S?L:S:t!==V&&c[s]&&(l[e]=l[e]===N?c[s]>0?s:o:l[e]===s?o:s)}function n(t,e,o){l[t]===N?g[ce+"-"+e]=f[t]=r[ce+"-"+e]-c[e]:(a=r[o]!==i?[c[e],-r[e]]:[-c[e],r[e]],(f[t]=Math.max(a[0],a[1]))>a[0]&&(s[e]-=c[e],f[e]=k),g[r[o]!==i?o:e]=f[t])}if(this.enabled){var r,a,h=e.cache,l=this.corner.clone(),c=s.adjusted,d=e.options.position.adjust.method.split(" "),p=d[0],u=d[1]||d[0],f={left:k,top:k,x:0,y:0},g={};this.corner.fixed!==W&&(o(p,S,L,F,P),o(u,L,S,D,O),l.string()===h.corner.string()||h.cornerTop===c.top&&h.cornerLeft===c.left||this.update(l,k)),r=this.calculate(l),r.right!==i&&(r.left=-r.right),r.bottom!==i&&(r.top=-r.bottom),r.user=this.offset,(f.left=p===V&&!!c.left)&&n(S,F,P),(f.top=u===V&&!!c.top)&&n(L,D,O),this.element.css(g).toggle(!(f.x&&f.y||l.x===N&&f.y||l.y===N&&f.x)),s.left-=r.left.charAt?r.user:p!==V||f.top||!f.left&&!f.top?r.left+this.border:0,s.top-=r.top.charAt?r.user:u!==V||f.left||!f.left&&!f.top?r.top+this.border:0,h.cornerLeft=c.left,h.cornerTop=c.top,h.corner=l.clone()}},destroy:function(){this.qtip._unbind(this.qtip.tooltip,this._ns),this.qtip.elements.tip&&this.qtip.elements.tip.find("*").remove().end().remove()}}),le=R.tip=function(t){return new x(t,t.options.style.tip)},le.initialize="render",le.sanitize=function(t){if(t.style&&"tip"in t.style){var e=t.style.tip;"object"!=typeof e&&(e=t.style.tip={corner:e}),/string|boolean/i.test(typeof e.corner)||(e.corner=W)}},M.tip={"^position.my|style.tip.(corner|mimic|border)$":function(){this.create(),this.qtip.reposition()},"^style.tip.(height|width)$":function(t){this.size=[t.width,t.height],this.update(),this.qtip.reposition()},"^content.title|style.(classes|widget)$":function(){this.update()}},s.extend(W,T.defaults,{style:{tip:{corner:W,mimic:k,width:6,height:6,border:W,offset:0}}});var Ce,Te,je="qtip-modal",ze="."+je;Te=function(){function t(t){if(s.expr[":"].focusable)return s.expr[":"].focusable;var e,i,o,n=!isNaN(s.attr(t,"tabindex")),r=t.nodeName&&t.nodeName.toLowerCase();return"area"===r?(e=t.parentNode,i=e.name,t.href&&i&&"map"===e.nodeName.toLowerCase()?(o=s("img[usemap=#"+i+"]")[0],!!o&&o.is(":visible")):!1):/input|select|textarea|button|object/.test(r)?!t.disabled:"a"===r?t.href||n:n}function i(t){1>c.length&&t.length?t.not("body").blur():c.first().focus()}function o(t){if(h.is(":visible")){var e,o=s(t.target),a=n.tooltip,l=o.closest(U);e=1>l.length?k:parseInt(l[0].style.zIndex,10)>parseInt(a[0].style.zIndex,10),e||o.closest(U)[0]===a[0]||i(o),r=t.target===c[c.length-1]}}var n,r,a,h,l=this,c={};s.extend(l,{init:function(){return h=l.elem=s("<div />",{id:"qtip-overlay",html:"<div></div>",mousedown:function(){return k}}).hide(),s(e.body).bind("focusin"+ze,o),s(e).bind("keydown"+ze,function(t){n&&n.options.show.modal.escape&&27===t.keyCode&&n.hide(t)}),h.bind("click"+ze,function(t){n&&n.options.show.modal.blur&&n.hide(t)}),l},update:function(e){n=e,c=e.options.show.modal.stealfocus!==k?e.tooltip.find("*").filter(function(){return t(this)}):[]},toggle:function(t,o,r){var c=(s(e.body),t.tooltip),d=t.options.show.modal,p=d.effect,u=o?"show":"hide",f=h.is(":visible"),g=s(ze).filter(":visible:not(:animated)").not(c);return l.update(t),o&&d.stealfocus!==k&&i(s(":focus")),h.toggleClass("blurs",d.blur),o&&h.appendTo(e.body),h.is(":animated")&&f===o&&a!==k||!o&&g.length?l:(h.stop(W,k),s.isFunction(p)?p.call(h,o):p===k?h[u]():h.fadeTo(parseInt(r,10)||90,o?1:0,function(){o||h.hide()}),o||h.queue(function(t){h.css({left:"",top:""}),s(ze).length||h.detach(),t()}),a=o,n.destroyed&&(n=E),l)}}),l.init()},Te=new Te,s.extend(q.prototype,{init:function(t){var e=t.tooltip;return this.options.on?(t.elements.overlay=Te.elem,e.addClass(je).css("z-index",T.modal_zindex+s(ze).length),t._bind(e,["tooltipshow","tooltiphide"],function(t,i,o){var n=t.originalEvent;if(t.target===e[0])if(n&&"tooltiphide"===t.type&&/mouse(leave|enter)/.test(n.type)&&s(n.relatedTarget).closest(Te.elem[0]).length)try{t.preventDefault()}catch(r){}else(!n||n&&"tooltipsolo"!==n.type)&&this.toggle(t,"tooltipshow"===t.type,o)},this._ns,this),t._bind(e,"tooltipfocus",function(t,i){if(!t.isDefaultPrevented()&&t.target===e[0]){var o=s(ze),n=T.modal_zindex+o.length,r=parseInt(e[0].style.zIndex,10);Te.elem[0].style.zIndex=n-1,o.each(function(){this.style.zIndex>r&&(this.style.zIndex-=1)}),o.filter("."+Z).qtip("blur",t.originalEvent),e.addClass(Z)[0].style.zIndex=n,Te.update(i);try{t.preventDefault()}catch(a){}}},this._ns,this),t._bind(e,"tooltiphide",function(t){t.target===e[0]&&s(ze).filter(":visible").not(e).last().qtip("focus",t)},this._ns,this),i):this},toggle:function(t,e,s){return t&&t.isDefaultPrevented()?this:(Te.toggle(this.qtip,!!e,s),i)},destroy:function(){this.qtip.tooltip.removeClass(je),this.qtip._unbind(this.qtip.tooltip,this._ns),Te.toggle(this.qtip,k),delete this.qtip.elements.overlay}}),Ce=R.modal=function(t){return new q(t,t.options.show.modal)},Ce.sanitize=function(t){t.show&&("object"!=typeof t.show.modal?t.show.modal={on:!!t.show.modal}:t.show.modal.on===i&&(t.show.modal.on=W))},T.modal_zindex=T.zindex-200,Ce.initialize="render",M.modal={"^show.modal.(on|blur)$":function(){this.destroy(),this.init(),this.qtip.elems.overlay.toggle(this.qtip.tooltip[0].offsetWidth>0)}},s.extend(W,T.defaults,{show:{modal:{on:k,effect:W,blur:W,stealfocus:W,escape:W}}}),R.viewport=function(i,s,o,n,r,a,h){function l(t,e,i,o,n,r,a,h,l){var c=s[n],p=_[t],b=x[t],w=i===V,q=p===n?l:p===r?-l:-l/2,C=b===n?h:b===r?-h:-h/2,T=v[n]+y[n]-(f?0:u[n]),j=T-c,z=c+l-(a===A?g:m)-T,M=q-(_.precedance===t||p===_[e]?C:0)-(b===N?h/2:0);return w?(M=(p===n?1:-1)*q,s[n]+=j>0?j:z>0?-z:0,s[n]=Math.max(-u[n]+y[n],c-M,Math.min(Math.max(-u[n]+y[n]+(a===A?g:m),c+M),s[n],"center"===p?c-q:1e9))):(o*=i===$?2:0,j>0&&(p!==n||z>0)?(s[n]-=M+o,d.invert(t,n)):z>0&&(p!==r||j>0)&&(s[n]-=(p===N?-M:M)+o,d.invert(t,r)),v>s[n]&&-s[n]>z&&(s[n]=c,d=_.clone())),s[n]-c}var c,d,p,u,f,g,m,v,y,b=o.target,w=i.elements.tooltip,_=o.my,x=o.at,q=o.adjust,C=q.method.split(" "),T=C[0],j=C[1]||C[0],z=o.viewport,M=o.container,I=i.cache,W={left:0,top:0};return z.jquery&&b[0]!==t&&b[0]!==e.body&&"none"!==q.method?(u=M.offset()||W,f="static"===M.css("position"),c="fixed"===w.css("position"),g=z[0]===t?z.width():z.outerWidth(k),m=z[0]===t?z.height():z.outerHeight(k),v={left:c?0:z.scrollLeft(),top:c?0:z.scrollTop()},y=z.offset()||W,("shift"!==T||"shift"!==j)&&(d=_.clone()),W={left:"none"!==T?l(S,L,T,q.x,F,P,A,n,a):0,top:"none"!==j?l(L,S,j,q.y,D,O,B,r,h):0},d&&I.lastClass!==(p=X+"-pos-"+d.abbrev())&&w.removeClass(i.cache.lastClass).addClass(i.cache.lastClass=p),W):W},R.polys={polygon:function(t,e){var i,s,o,n={width:0,height:0,position:{top:1e10,right:0,bottom:0,left:1e10},adjustable:k},r=0,a=[],h=1,l=1,c=0,d=0;for(r=t.length;r--;)i=[parseInt(t[--r],10),parseInt(t[r+1],10)],i[0]>n.position.right&&(n.position.right=i[0]),i[0]<n.position.left&&(n.position.left=i[0]),i[1]>n.position.bottom&&(n.position.bottom=i[1]),i[1]<n.position.top&&(n.position.top=i[1]),a.push(i);if(s=n.width=Math.abs(n.position.right-n.position.left),o=n.height=Math.abs(n.position.bottom-n.position.top),"c"===e.abbrev())n.position={left:n.position.left+n.width/2,top:n.position.top+n.height/2};else{for(;s>0&&o>0&&h>0&&l>0;)for(s=Math.floor(s/2),o=Math.floor(o/2),e.x===F?h=s:e.x===P?h=n.width-s:h+=Math.floor(s/2),e.y===D?l=o:e.y===O?l=n.height-o:l+=Math.floor(o/2),r=a.length;r--&&!(2>a.length);)c=a[r][0]-n.position.left,d=a[r][1]-n.position.top,(e.x===F&&c>=h||e.x===P&&h>=c||e.x===N&&(h>c||c>n.width-h)||e.y===D&&d>=l||e.y===O&&l>=d||e.y===N&&(l>d||d>n.height-l))&&a.splice(r,1);n.position={left:a[0][0],top:a[0][1]}}return n},rect:function(t,e,i,s){return{width:Math.abs(i-t),height:Math.abs(s-e),position:{left:Math.min(t,i),top:Math.min(e,s)}}},_angles:{tc:1.5,tr:7/4,tl:5/4,bc:.5,br:.25,bl:.75,rc:2,lc:1,c:0},ellipse:function(t,e,i,s,o){var n=R.polys._angles[o.abbrev()],r=0===n?0:i*Math.cos(n*Math.PI),a=s*Math.sin(n*Math.PI);return{width:2*i-Math.abs(r),height:2*s-Math.abs(a),position:{left:t+r,top:e+a},adjustable:k}},circle:function(t,e,i,s){return R.polys.ellipse(t,e,i,i,s)}},R.svg=function(t,i,o){for(var n,r,a,h,l,c,d,p,u,f,g,m=s(e),v=i[0],y=s(v.ownerSVGElement),b=1,w=1,_=!0;!v.getBBox;)v=v.parentNode;if(!v.getBBox||!v.parentNode)return k;n=y.attr("width")||y.width()||parseInt(y.css("width"),10),r=y.attr("height")||y.height()||parseInt(y.css("height"),10);var x=(parseInt(i.css("stroke-width"),10)||0)/2;switch(x&&(b+=x/n,w+=x/r),v.nodeName){case"ellipse":case"circle":f=R.polys.ellipse(v.cx.baseVal.value,v.cy.baseVal.value,(v.rx||v.r).baseVal.value+x,(v.ry||v.r).baseVal.value+x,o);break;case"line":case"polygon":case"polyline":for(u=v.points||[{x:v.x1.baseVal.value,y:v.y1.baseVal.value},{x:v.x2.baseVal.value,y:v.y2.baseVal.value}],f=[],p=-1,c=u.numberOfItems||u.length;c>++p;)d=u.getItem?u.getItem(p):u[p],f.push.apply(f,[d.x,d.y]);f=R.polys.polygon(f,o);break;default:f=v.getBoundingClientRect(),f={width:f.width,height:f.height,position:{left:f.left,top:f.top}},_=!1}return g=f.position,y=y[0],_&&(y.createSVGPoint&&(a=v.getScreenCTM(),u=y.createSVGPoint(),u.x=g.left,u.y=g.top,h=u.matrixTransform(a),g.left=h.x,g.top=h.y),y.viewBox&&(l=y.viewBox.baseVal)&&l.width&&l.height&&(b*=n/l.width,w*=r/l.height)),g.left+=m.scrollLeft(),g.top+=m.scrollTop(),f},R.imagemap=function(t,e,i){e.jquery||(e=s(e));var o,n,r,a,h,l=e.attr("shape").toLowerCase().replace("poly","polygon"),c=s('img[usemap="#'+e.parent("map").attr("name")+'"]'),d=s.trim(e.attr("coords")),p=d.replace(/,$/,"").split(",");if(!c.length)return k;if("polygon"===l)a=R.polys.polygon(p,i);else{if(!R.polys[l])return k;for(r=-1,h=p.length,n=[];h>++r;)n.push(parseInt(p[r],10));a=R.polys[l].apply(this,n.concat(i))}return o=c.offset(),o.left+=Math.ceil((c.outerWidth(k)-c.width())/2),o.top+=Math.ceil((c.outerHeight(k)-c.height())/2),a.position.left+=o.left,a.position.top+=o.top,a};var Me,Ie='<iframe class="qtip-bgiframe" frameborder="0" tabindex="-1" src="javascript:\'\';" style="display:block; position:absolute; z-index:-1; filter:alpha(opacity=0); -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";"></iframe>';s.extend(C.prototype,{_scroll:function(){var e=this.qtip.elements.overlay;e&&(e[0].style.top=s(t).scrollTop()+"px")},init:function(i){var o=i.tooltip;1>s("select, object").length&&(this.bgiframe=i.elements.bgiframe=s(Ie).appendTo(o),i._bind(o,"tooltipmove",this.adjustBGIFrame,this._ns,this)),this.redrawContainer=s("<div/>",{id:X+"-rcontainer"}).appendTo(e.body),i.elements.overlay&&i.elements.overlay.addClass("qtipmodal-ie6fix")&&(i._bind(t,["scroll","resize"],this._scroll,this._ns,this),i._bind(o,["tooltipshow"],this._scroll,this._ns,this)),this.redraw()},adjustBGIFrame:function(){var t,e,i=this.qtip.tooltip,s={height:i.outerHeight(k),width:i.outerWidth(k)},o=this.qtip.plugins.tip,n=this.qtip.elements.tip;e=parseInt(i.css("borderLeftWidth"),10)||0,e={left:-e,top:-e},o&&n&&(t="x"===o.corner.precedance?[A,F]:[B,D],e[t[1]]-=n[t[0]]()),this.bgiframe.css(e).css(s)},redraw:function(){if(1>this.qtip.rendered||this.drawing)return this;var t,e,i,s,o=this.qtip.tooltip,n=this.qtip.options.style,r=this.qtip.options.position.container;return this.qtip.drawing=1,n.height&&o.css(B,n.height),n.width?o.css(A,n.width):(o.css(A,"").appendTo(this.redrawContainer),e=o.width(),1>e%2&&(e+=1),i=o.css("maxWidth")||"",s=o.css("minWidth")||"",t=(i+s).indexOf("%")>-1?r.width()/100:0,i=(i.indexOf("%")>-1?t:1)*parseInt(i,10)||e,s=(s.indexOf("%")>-1?t:1)*parseInt(s,10)||0,e=i+s?Math.min(Math.max(e,s),i):e,o.css(A,Math.round(e)).appendTo(r)),this.drawing=0,this},destroy:function(){this.bgiframe&&this.bgiframe.remove(),this.qtip._unbind([t,this.qtip.tooltip],this._ns)}}),Me=R.ie6=function(t){return 6===oe.ie?new C(t):k},Me.initialize="render",M.ie6={"^content|style$":function(){this.redraw()}}})})(window,document);
-//@ sourceMappingURL=http://cdnjs.cloudflare.com/ajax/libs/qtip2/2.2.0/jquery.qtip.min.map
\ No newline at end of file
+//@ sourceMappingURL=https://cdnjs.cloudflare.com/ajax/libs/qtip2/2.2.0/jquery.qtip.min.map
<div id="header">
<div class="wrapper">
<div class="logo">
- <a href="/"><img src="{{ STATIC_URL }}img/onelab-portal.png" alt="OneLab - Future Internet Testbeds" /></a>
+ <a href="/"><img src="{{ STATIC_URL }}img/fibre-logo.gif" alt="FIBRE - Future Internet Testbeds Experimentation Between Brazil and Europe" width="150px" height="75px" /></a>
</div>
<div id="secondary">
<ul>
- <li><a href="/news">News</a></li>
<li><a href="/portal/about">About</a></li>
- <li><a target="_blank" href="http://www.onelab.eu">Public Website</a></li>
- <li><a target="_blank" href="http://intranet.onelab.eu">Intranet</a></li>
+ <li><a target="_blank" href="http://www.fibre-ict.eu/">Public Website</a></li>
</ul>
</div>
</div>
<body ng-app="ManifoldApp">
{% block container %}
{% block topmenu %}
- {% widget "_widget-topmenu.html" %}
+ {% widget "__widget-topmenu.html" %}
{% endblock topmenu %}
{% include 'messages-transient.html' %}
{% block base_content %}
--- /dev/null
+<div class="well login-widget" style="background:none;border:none;width:400px;">
+ {% if state %}
+ <span class="help-block">{{ state }}</span>
+ {% endif %}
+ <form action="/login/" method="post" role="form">
+ {% csrf_token %}
+ {% if next %}
+ <input type="hidden" name="next" value="{{ next }}" />
+ {% endif %}
+ <div class="form-group" style="color:white;">
+ <label for="fed"></label>
+ <input type="radio" name="base" value="br" checked>
+ <img src="{{ STATIC_URL }}img/fibre/br.png" alt="Brazil" height="32" width="40" />
+ <input type="radio" name="base" value="eu">
+ <img src="{{ STATIC_URL }}img/fibre/eu.png" alt="Europe Union" height="32" width="32" />
+ <input type="radio" name="base" value="local"> Local User
+ </div>
+
+ <div class="form-group">
+ <label for="username">Email address / Username</label>
+ <input type="email" class="form-control" name="username" placeholder="Enter Email / username">
+ </div>
+ <div class="form-group">
+ <label for="password">Password</label>
+ <input type="password" class="form-control" name="password" placeholder="Password">
+ </div>
+ <div class="login-submit">
+ <input class="btn btn-default" type="submit" value="Sign In" />
+ <span class="lost-password"> | <a href="/portal/pass_reset/">Can't access your account?</a></span>
+ </div>
+ <div class="login-signup">
+ Don't have an account? <a href="/portal/register">Sign up now</a>
+ </div>
+ </form>
+</div>
--- /dev/null
+<div class="well">
+ {% if state %}
+ <span class="help-block">{{ state }}</span>
+ {% endif %}
+ <form action="/login/" method="post" role="form">
+ {% csrf_token %}
+ {% if next %}
+ <input type="hidden" name="next" value="{{ next }}" />
+ {% endif %}
+ <div class="form-group">
+ <label for="username">Email address / Username</label>
+ <input type="email" class="form-control" name="username" placeholder="Enter Email / username">
+ </div>
+ <div class="form-group">
+ <label for="password">Password</label>
+ <input type="password" class="form-control" name="password" placeholder="Password">
+ </div>
+ <div class="login-submit">
+ <input class="btn btn-default" type="submit" value="Sign In" />
+ <span class="lost-password"> | <a href="/portal/pass_reset/">Can't access your account?</a></span>
+ </div>
+ <div class="login-signup">
+ <a href="/portal/register">Try</a>, <a href="/portal/register">Sign Up</a> or <a href="/portal/join">Join</a>
+ </div>
+ </form>
+</div>
--- /dev/null
+{% load portal_filters %}
+<div class="header">
+<div class="container">
+ <div class="row">
+ <div class="col-sm-3 col-md-3 logo">
+ <a href="/"><img src="{{ STATIC_URL }}img/fibre-logo.gif" alt="FIBRE - Future Internet Testbeds Experimentation Between Brazil and Europe" width="150px" height="75px" /></a>
+ </div>
+ {% if username %}
+ <div class="col-sm-4 col-md-4 navigation">
+ <ul>
+ <li>
+ <a class="dropdown-toggle" data-toggle="dropdown" href="#">
+ EXPERIMENT <span class="caret"></span>
+ </a>
+
+ <div class="dropdown-menu" style="z-index:99;">
+ <ul id="dropdown-slice-list">
+ <li class="title"><a href="/portal/slice_request/">Request Slice</a></li>
+ </ul>
+ </div>
+ </li>
+ {%if 'is_pi' in pi %}
+ <li id="nav-institution" class=""><a href="/portal/institution">MANAGEMENT</a></li>
+ {%endif%}
+ <li><a href="/portal/support/">SUPPORT</a></li>
+ </ul>
+ </div>
+ {% else %}
+ <div class="col-sm-4 col-md-4 navigation">
+ </div>
+ {% endif %}
+ <div class="col-sm-5 col-md-5 secondary">
+ <ul>
+ <li><a href="/portal/about">About</a></li>
+ <li><a target="_blank" href="http://www.fibre-ict.eu/">Public Website</a></li>
+ </ul>
+ {% if username %}
+ <div class="account">You are logged in as <a href="/portal/account/">{{ username }}</a> | <a id="logout" style="cursor:pointer;" data-username="{{ username }}"><span class="glyphicon glyphicon-off"></span> Logout</a></div>
+ {% endif %}
+ </div>
+ </div>
+</div>
+</div>
+
+<div class="row">
+{% widget '_widget-message.html' %}
+</div>
+<script>
+ $(document).ready(function() {
+ $('li.slices').mouseenter(function() {
+ $('div#menu-slice-list').fadeIn(100);
+ });
+ $('div#menu-slice-list').mouseleave(function(e) {
+ if (!$('li.slices').is(":hover")) {
+ $(this).fadeOut(100);
+ }
+ });
+ // var slices = localStorage.getItem('slices');
+ // if (slices.length == 0) {
+ // $.post("/rest/user/",{'filters':{'user_hrn':'$user_hrn'}}, function( data ) {
+ // var items = [];
+ // localStorage.setItem('slices', data[0].slice);
+ // });
+ // }
+ // $.each(slices, function( key, val ) {
+ // items.push( "<li><a href=\"/slice/"+val.slice_hrn+"\">" + val.slice_hrn + "</a></li>" );
+ // });
+ // $("div#home-slice-list").html($( "<ul/>", { html: items.join( "" ) }));
+ });
+</script>
--- /dev/null
+{% extends "layout.html" %}
+
+{% block content %}
+<div class="row">
+ <div class="col-md-12">
+ <div class="breadcrumbs">
+ </div>
+ </div>
+</div>
+<div class="row">
+ <div class="col-md-12">
+ <ul class="nav nav-tabs nav-section">
+ <li class="active"><a href="#about">About</a></li>
+ <li><a href="#components">Underlying technologies</a></li>
+ </ul>
+ </div>
+</div>
+
+
+<div class="tab-content">
+ <div class="tab-pane active row" id="about">
+ <div class="col-md-12">
+ <p>
+ OneLab Portal is a central place to get acess to all OneLab testbeds.In order to get access to the portal,
+ an experimenter needs to <a href="/portal/register">register</a> to the portal. The portal administrative body
+ is responsible to accept or reject newly registered users.
+ </p>
+ <p>
+ To learn more about OneLab visit: <a href="http://onelab.eu/" target="_blank">http://onelab.eu/</a>
+ </p>
+ <p>
+ If you have any questions regarding using the portal visit: <a href="/portal/support">OneLab support</a>
+ </p>
+ <p>
+ OneLab portal is a community effot. To get more information about OneLab portal team visit:
+ <a href="http://myslice.info/community" target="_blank">http://myslice.info/community</a>
+ </p>
+ </div>
+ </div>
+ <div class="tab-pane row" id="components">
+ <div class="col-md-12">
+ <h3>A ready-made and easily customisable user interface for your testbed.</h3>
+ <p>
+ MySlice is an ambitious project aiming to support researchers throughout the lifecycle of experiments that can run on a variety
+ of testbeds spanning different administrative domains and networking technologies. Its basic principle is to bring together
+ available resources with useful information (characteristics, performance, network measurements).
+ </p>
+ <p>
+ MySlice inititiave started in Janury 2011 by offering annotation services for the first ederated experimental resources. Today,
+ MySlice has taken a big step toward becoming a tand-alone web framework, which will present all available resources from testbeds
+ across the world, interconnected through the Slice-based Facility Architecture (SFA) and annotated by the TopHat measurement system.
+ </p>
+ <p>
+ Our framework is built with standard programming tools (python and javascript for the front-end and python for the back-end)
+ and has a modular structure based on the concept of plugins for implementing different core functionalities (query editing,
+ data display, and resource allocation).
+ </p>
+ <p>
+ The goal is to enable developers with expertise on different testbed technologies and different experimental
+ practices to work in parallel for optimizing the tools presented to the users allowing them for a wide range of choices
+ according to their own requirements. Opening in this way the development of web-based user tools for experimentation and
+ sharing effort and information can increase significantly the chances for the achievement of our challenging objective.
+ </p>
+ </div>
+ <div class="col-md-12">
+ <h3>Portal Components</h3>
+ <h5>Myslice (Web Frontend)</h5>
+ <p>
+ A full-fledged and modular web portal for a testbed federation allowing user to register,
+ request slices and browse and book resources, with a strong emphasis on measurements.
+ </p>
+ <p> More Info: <a href="http://myslice.info/" target="_blank">http://myslice.info/</a></p>
+ <p> Code: <a href="http://git.onelab.eu/?p=myslice.git;a=summary" target="_blank">Git Repository</a> (read only)</p>
+ <p>
+ If you need write access to the git repository you need first to send your public key to <a href="mailto:support@myslice.info">support@myslice.info</a>.
+ </p>
+
+
+ <h5>Manifold (Portal backend)</h5>
+ <p>
+ Manifold is the backend that is running behind the portal. It is a component allowing the integration of distributed
+ and heterogeneous data sources, such as measurement platforms or data repositories.
+ </p>
+ <p> Documentation: <a href="http://trac.myslice.info/" target="_blank">http://trac.myslice.info/</a></p>
+ <p> Code: <a href="https://git.top-hat.info/?p=tophat.git;a=shortlog;h=refs/heads/devel" target="_blank">Git Repository</a> (read only)</p>
+
+ <h5>OneLab Registry</h5>
+ <p>It's a SFA registry. SFA Registry is a specific installation mode of the SFAWrapper (Registry Only mode).</p>
+ <p> More Info: <a href="http://svn.planet-lab.org/wiki/SfaDeveloperRegistryTutorial#RunninginRegistry-Onlymode" target="_blank">SFA Registry</a></p>
+ </div>
+ </div>
+</div>
+
+<script>
+$(document).ready(function() {
+ $('.nav-tabs a').click(function (e) {
+ e.preventDefault();
+ $(this).tab('show');
+ });
+});
+</script>
+
+
+{% endblock %}
--- /dev/null
+{% extends "layout.html" %}
+{% block content %}
+
+<div class="row">
+ <div class="col-md-12">
+ <div class="breadcrumbs">
+ Account > {{ person.email }}
+ </div>
+ </div>
+</div>
+{% if messages %}
+<ul class="messages">
+ {% for message in messages %}
+ <li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</li>
+ {% endfor %}
+</ul>
+{% endif %}
+<div class="row">
+ <div class="col-md-12">
+ <ul class="nav nav-tabs nav-section">
+ <li class="active"><a href="#profile">User Profile</a></li>
+ <li><a href="#account">Account</a></li>
+ <li><a href="#access">Testbed Access</a></li>
+ </ul>
+ </div>
+</div>
+<div class="tab-content">
+ <div class="tab-pane active row" id="profile">
+
+ <div class="col-md-12">
+
+ <form id="editForm" method="post" action="account_process" enctype="multipart/form-data">
+ {% csrf_token %}
+ <table class="profile">
+ <tr>
+ <td colspan="2">
+ <div><h3>Platform: Myslice</h3></div>
+ </td>
+ </tr>
+ <tr>
+ <td class="key">Email</td>
+ <td class="value">
+ <span id="emailval" class="value" >{{ person.email }}</span>
+ <button class="btn btn-default" type="button" id="edit_email" onclick="editAlert();" title="To change your affiliation please contact the administrator">
+ <span class="glyphicon glyphicon-question-sign"></span> Edit
+ </button>
+ </td>
+ </tr>
+ <tr class="odd">
+ <td class="key">Password</td>
+ <td class="value">
+ <button class="btn btn-default btn-xs" type="button" title="Password" name="edit_pass" id="edit_pass">
+ <span class="glyphicon glyphicon-edit"></span> Edit
+ </button>
+ <span id="passval"class="value">******** </span>
+ <span class="hide_this" id="span_pass">
+ <button type="button" class="btn btn-default btn-xs" title="Cancel" id="cancel_pass_change"> Cancel </button>
+ <div style='display:none;' id="pass_form">
+ <input type='hidden' value='' /></div>
+ <table id="edit_password">
+ <tr>
+ <td>Enter password: </td>
+ <td class="field"> <input type="password" name="password" id="password" /> </td>
+ </tr>
+ <tr>
+ <td>Confirm password: </td>
+ <td class="field">
+ <input type="password" name="confirmpassword" id="confirmpassword" />
+ <input type="submit" class="btn btn-default btn-xs" name="submit_pass" value="Save"/>
+ </td>
+ </tr>
+ </table>
+ </span>
+ </td>
+ </tr>
+ <tr class="even">
+ <td class="key">Full Name</td>
+ <td class="value">
+ <span id="nameval" class="value" >{{ fullname }} </span>
+ <span class="hide_this" id="span_name">
+ <button type="button" class="btn btn-default btn-xs" title="Cancel" id="cancel_name_change"> Cancel </button>
+ <div style='display:none;'><input type='hidden' name='nameform' /></div>
+ <input id="fname" type="text" name="fname" class="required" maxlength="200" value="{{firstname}}" />
+ <input id="lname" type="text" name="lname" class="required" maxlength="200" value="{{lastname}}" />
+ <input type="submit" class="btn btn-default btn-xs" name="submit_name" value="Save"/>
+ </span>
+ <button class="btn btn-default btn-xs" type="button"title="Full Name" id="edit_name">
+ <span class="glyphicon glyphicon-edit"></span> Edit
+ </button>
+ </td>
+ </tr>
+ <tr class="odd">
+ <td class="key">Authority</td>
+ <td class="value">
+ <span id="affval" class="value">{{ authority }}</span>
+ <button class="btn btn-default btn-xs" type="button" id="edit_auth" onclick="editAlert()" title="To change your authority please contact the administrator">
+ <span class="glyphicon glyphicon-question-sign"></span> Edit
+ </button>
+ </td>
+ </tr>
+ {%if 'Enabled' in user_status %}
+ <tr class="even">
+ <td class="key">Generate Keys</td>
+ <td>
+ <input type="submit" name="generate" class="btn btn-primary" value="Generate a new Key Pair" id="generate_keypair"
+ onclick="return confirm('Are you sure? If you do so, your current credentials will be overwritten.');"
+ title="It will generate a new key Pair and your current credentials will be overwritten."/>
+ </td>
+ </tr>
+ <tr class="odd">
+ <td class="key">Public Key</td>
+ <td class="value">
+ <span id="keyval" class="value">******** </span>
+ <span class="hide_this" id="span_upload">
+ <button type="button" class="btn btn-default" title="Cancel" id="cancel_upload"> Cancel </button>
+ <div style='display:none;'>
+ <input type='hidden' name='upload' /></div>
+ <input type="file" name="pubkey" class="required" id="pubkey"/>
+ <input class="btn btn-default btn-xs" name="upload_key" id="upload_key" type="submit" title="Upload your public key" value="Upload"
+ onclick="return confirm('Are you sure? It will overwrite your current credentials and you have delegate it manually.');"/>
+ </span>
+ <div style='display:none;'> <input type='hidden' name='dload' /> </div>
+ <button type="submit" name="dl_pubkey" class="btn btn-default btn-xs" title="Download your public key" id="dl_file">
+ <span class="glyphicon glyphicon-download"></span> Download
+ </button>
+ <button class="btn btn-default btn-xs" id="upload_file" type="button" title="Upload a public key">
+ <span class="glyphicon glyphicon-upload"></span> Upload
+ </button>
+ </td>
+ </tr>
+ <tr class="even" id="pkey_row">
+ {%if 'N/A' not in user_private_key%}
+ <td class="key">Private Key </td> <!-- Hide if priv_key doesn't exist in myslice platform -->
+ <td class="value">********<a href="#"></a>
+ <button type="submit" name="dl_pkey" class="btn btn-default" title="Download your privaye key" id="dl_pkey">
+ <span class="glyphicon glyphicon-download"></span> Download
+ </button>
+ <input class="btn btn-danger btn-xs" id="delete" name="delete" type="submit" value="Delete" title="Delete your private key"
+ onclick="return confirm('Are you sure? If you do so, you have to delegate your credentials manually.');"/>
+ </td>
+ {%else%}
+ <td class="key">Private Key </td> <!-- Hide if priv_key doesn't exist in myslice platform -->
+ <td class="value">********<a href="#"></a>
+ <button type="submit" name="dl_pkey" class="btn btn-default disabled" title="Download your privaye key" id="dl_pkey">
+ <span class="glyphicon glyphicon-download"></span> Download
+ </button>
+ <input class="btn btn-danger btn-xs disabled" id="delete" name="delete" type="submit" title="Delete your private key" value="Delete" />
+ </td>
+ {%endif%}
+ </tr>
+ <tr class="even">
+ <td colspan="2">
+ <p class="message" id="pkey_del_msg"><b> Tradeoff:</b> Ease-of-use vs Security.<br>
+ <b>Ease-of-use:</b> Automatic account delegation. Don't delete private key.<br>
+ <b>Security:</b> Manual account delegation. Download & Delete private key.
+ </p>
+ </td>
+ </tr>
+ {%endif%}
+ </table>
+
+ </div>
+ </div>
+
+ <div class="tab-pane row" id="account">
+ <div class="col-md-12">
+
+ <h3>Principal Account <small>Account used for delegating credentials</small></h3>
+ <table class="table">
+ <tr class="odd">
+ <th>Platform</th>
+ <th>Account Type</th>
+ <th>Account Delegation</th>
+ <th>User hrn</th>
+ <th>User Status</th>
+ <!--<th>Pub Key</th> -->
+ </tr>
+ {% for row in principal_acc %}
+ <tr class="border_bottom">
+ <td class="odd"> {{ row.platform_name }} </td>
+ <td class="odd"> {{ row.account_type }} </td>
+ <td class="odd"> {{ row.delegation_type }} </td>
+ <td class="odd"> {{ row.usr_hrn }} </td>
+ <td class="odd"> {{ row.user_status }} </td>
+ <!-- <td class="even"> {{ row.usr_pubkey }} </td> -->
+ </tr>
+ {%endfor%}
+ </table>
+
+ </div>
+
+
+ {%if 'Enabled' in user_status %}
+ <div class="col-md-12">
+ <h3>Credentials <small>Delegated to Principal Account</small></h3>
+ <table class="table">
+ <caption><b>Delegated User Credential</b></caption>
+ <tr class="odd">
+ <th>Expiration Date</th>
+ <th>Download</th>
+ </tr>
+ {% for row in my_users %}
+ <tr class="border_bottom">
+ <td class="odd"> {{ row.cred_exp }} </td>
+ <td class="odd">
+ <button class="btn btn-default btn-xs" name= "dl_user_cred" type="submit" title="Download User Credential">
+ <span class="glyphicon glyphicon-download"></span> Credential
+ </button>
+ <button class="btn btn-default btn-xs" name= "dl_user_cert" type="submit" title="Download User Certificate">
+ <span class="glyphicon glyphicon-download"></span> Certificate
+ </button>
+ <button class="btn btn-default btn-xs" name= "dl_user_p12" type="submit" title="Download User PKCS12">
+ <span class="glyphicon glyphicon-download"></span> PKCS p12
+ </button>
+ </td>
+ </tr>
+ {%endfor%}
+ </table>
+ <p></p>
+ <table class="mytable table table-bordered table-hover">
+ <caption><b>Delegated Slice Credentials</b></caption>
+ <tr class="odd">
+ <th>Slice Name</th>
+ <th>Expiration Date</th>
+ <th>Download</th>
+ </tr>
+ {% for row in my_slices %}
+ <tr class="border_bottom">
+ <td class="odd"> {{ row.slice_name }} </td>
+ <td class="odd"> {{ row.cred_exp }} </td>
+ <td class="odd">
+ <button class="btn btn-default btn-xs" name= "dl_{{row.slice_name}}" type="submit" title="Download Slice Credentials">
+ <span class="glyphicon glyphicon-download"></span> Download
+ </button>
+ </td>
+ </tr>
+ {%endfor%}
+ </table>
+ <p></p>
+ <table class="mytable table table-bordered table-hover">
+ <caption><b>Delegated Authority Credentials</b></caption>
+ <tr class="odd">
+ <th>Authority Name</th>
+ <th>Expiration Date</th>
+ <th>Download</th>
+ </tr>
+ {% for row in my_auths %}
+ <tr class="border_bottom">
+ <td class="odd"> {{ row.auth_name }} </td>
+ <td class="odd"> {{ row.cred_exp }} </td>
+ <td class="odd">
+ <button class="btn btn-default btn-xs" name= "dl_{{row.auth_name}}" type="submit" title="Download Authority Credentials">
+ <span class="glyphicon glyphicon-download"></span> Download
+ </button>
+ </td>
+ </tr>
+ {%endfor%}
+ </table>
+ <p></p>
+ {%if '' not in my_users%}
+ <p><button class="btn btn-danger btn-lg btn-block" name= "clear_cred" type="submit" title="Clear All Credentials">Clear Credentials</button></p>
+ {%else%}
+ <p><button class="btn btn-danger btn-lg btn-block disabled" name= "clear_cred" type="submit" title="Clear All Credentials">Clear Credentials</button></p>
+ {%endif%}
+ </div>
+ </div>
+
+ <div class="tab-pane row" id="access">
+ <div class="col-md-12">
+
+ <h3>Testbed Access <small>Reference Accounts in the following testbeds</small></h3>
+ <table class="mytable table table-bordered table-hover">
+ <tr class="odd">
+ <th>Platform</th>
+ <th>Account Type</th>
+ <th>Reference to</th>
+ <th>Remove Account</th>
+ </tr>
+ {% for row in ref_acc %}
+ <tr class="border_bottom">
+ <td class="odd"> {{ row.platform_name }} </td>
+ <td class="odd"> {{ row.account_type }} </td>
+ <td class="odd"> {{ row.account_reference }} </td>
+ <td class="odd">
+ <button class="btn btn-danger" name="delete_{{row.platform_name}}" type="submit" title="Delete account from this platform">
+ <span class="glyphicon glyphicon-minus"></span>
+ </button>
+ </td>
+ </tr>
+ {%endfor%}
+ </table>
+
+
+ <h3>Add reference account to the following testbeds</h3>
+ <table class="mytable table table-bordered table-hover">
+ <tr class="odd">
+ <th>Platforms</th>
+ <th>Add Account</th>
+ </tr>
+ {% for platform in platform_list %}
+ <tr class="border_bottom">
+ <td class="odd"> {{ platform.platform_no_access }} </td>
+ <td class="odd">
+ <button class="btn btn-success btn-sm" name= "add_{{platform.platform_no_access}}" type="submit" title="Add account to this platform">
+ <span class="glyphicon glyphicon-plus"></span>
+ </button>
+ </td>
+ </tr>
+ {%endfor%}
+ </table>
+ </div>
+{%endif%}
+</div>
+</form>
+</div>
+
+<script>
+ $(document).ready(function() {
+ $('.nav-tabs a').click(function (e) {
+ e.preventDefault();
+ $(this).tab('show');
+ id = $(this).attr('href').substr(1);
+
+ });
+
+ $('button#createslice').click(function() {
+ window.location="/portal/slice_request/";
+ });
+ });
+</script>
+
+{% endblock %}
--- /dev/null
+{# This is required by insert_above #}{% insert_handler %}<!DOCTYPE html>
+<html lang="en"><head>
+<title>OneLab - {{ section }}</title>
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<link rel="shortcut icon" href="/static/img/myslice-icon.png">
+{# This is where insert_str will end up #}{% media_container prelude %}
+{% include 'messages-transient-header.html' %}
+<script type="text/javascript"> {# raw js code - use {% insert prelude_js %} ... {% endinsert %} #} {% container prelude_js %}</script>
+<script src="{{ STATIC_URL }}js/jquery.dataTables.min.js"></script>
+<script src="{{ STATIC_URL }}js/bootstrap.datatables.js"></script>
+<script src="{{ STATIC_URL }}js/myslice.js"></script>
+<script src="{{ STATIC_URL }}js/myslice-ui.js"></script>
+<style type="text/css">{# In case we need to add raw css code #}{% container prelude_css %}</style>
+{{ header_prelude }}
+{% block head %} {% endblock head %}
+{# let's add these ones no matter what #}
+{% insert_str prelude "js/jquery.min.js" %}
+{% insert_str prelude "js/angular/angular.min.js" %}
+{% insert_str prelude "js/jquery.html5storage.min.js" %}
+{% insert_str prelude "js/messages-runtime.js" %}
+{% insert_str prelude "js/class.js" %}
+{% insert_str prelude "js/plugin-helper.js" %}
+{% insert_str prelude "js/mustache.js" %}
+{% insert_str prelude "js/hashtable.js" %}
+{% insert_str prelude "js/plugin.js" %}
+{% insert_str prelude "js/manifold.js" %}
+{% insert_str prelude "css/manifold.css" %}
+{% insert_str prelude "css/plugin.css" %}
+{% insert_str prelude "js/bootstrap.js" %}
+{% insert_str prelude "css/bootstrap.css" %}
+{% insert_str prelude "js/bootstrap-datepicker.js" %}
+{% insert_str prelude "css/datepicker.css" %}
+{% insert_str prelude "js/bootstrap-slider.js" %}
+{% insert_str prelude "css/slider.css" %}
+{% insert_str prelude "css/topmenu.css" %}
+{% insert_str prelude "js/logout.js" %}
+<link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}css/{{ theme }}.css">
+</head>
+<body ng-app="ManifoldApp">
+{% block container %}
+ {% block topmenu %}
+ {% include theme|add:"_widget-topmenu.html" %}
+ {% endblock topmenu %}
+ {% include 'messages-transient.html' %}
+ {% block base_content %}
+ {% endblock %}
+{% endblock container %}
+</body>
+</html>
--- /dev/null
+{% extends "layout.html" %}
+
+{% block head %}
+{{ wizard.form.media }}
+{% endblock %}
+
+{% block content %}
+<div class="row">
+ <div class="col-md-12">
+ <div class="breadcrumbs">
+ Support > Contact
+ </div>
+ </div>
+</div>
+<div class="row">
+ <div class="col-md-12">
+ <p>Please check our <a href="/portal/support/">FAQ</a> section. Most of the basic problems are explained there.</p>
+ <p>
+ If you haven't find your answes in the FAQ, please contact us by filling the form below.<br />
+ You can also <a href="mailto:support@myslice.info">e-mail</a> us directly.
+ </p>
+ </div>
+</div>
+
+<div class="row">
+ <div class="col-md-4">
+ <form role="form" method="post">
+ {% csrf_token %}
+ {% for field in form %}
+ <div class="form-group">
+ <label for="{{ field.html_name }}" class="control-label">{{ field.label }}</label>
+ {{ field.errors }} {{ field }}
+ </div>
+ {% endfor %}
+ <button type="submit" class="btn btn-onelab">Create ticket</button>
+ </form>
+ </div>
+</div>
+{% endblock %}
+
--- /dev/null
+{% extends "layout_base.html" %}
+{% load portal_filters %}
+
+{% block content %}
+<!-- <div class="row">
+{% widget '_widget-news.html' %}
+</div> -->
+{% if username %}
+<div class="container dashboard">
+ <div class="row">
+ {%if 'is_pi' in pi %}
+ <div class="col-md-3">
+ <h3>
+ EXPERIMENT
+ </h3>
+ <div>
+ <a href="#"><img src="{{ STATIC_URL }}img/icon_slices.png" alt="" /></a>
+ </div>
+ <div>
+ <button id="slicerequestbtn" type="button" class="btn btn-default"><span class="glyphicon glyphicon-plus"></span> Request Slice</button>
+ </div>
+ <div>
+ <p><strong>Your slices </strong>
+ <span title="A slice is a set of testbed resources on which you can conduct an experiment.
+ Either ask your colleagues to give you access to an existing slice or request a new slice by clicking 'Request Slice'."
+ class="glyphicon glyphicon-info-sign">
+ </span>
+
+ </p>
+ </div>
+ <div>
+ <div id="home-slice-list"><img src="{{ STATIC_URL }}img/loading.gif" alt="Loading Slices" /></div>
+ </div>
+ </div>
+ <div class="col-md-3">
+ <h3>MANAGEMENT</h3>
+ <div>
+ <a href="/portal/institution"><img src="{{ STATIC_URL }}img/icon_authority_color.png" alt="" /></a>
+ </div>
+ <div>
+ <button id="validaterequestbtn" type="button" class="btn btn-default"><span class="glyphicon glyphicon-ok"></span> Validate Requests</button>
+ </div>
+ </div>
+ <div class="col-md-3">
+ <h3>
+ SUPPORT
+ </h3>
+ <div>
+ <a href="/portal/support"><img src="{{ STATIC_URL }}img/icon_support.png" alt="" /></a>
+ </div>
+ <div>
+ <button id="ticketbtn" type="button" class="btn btn-default"><span class="glyphicon glyphicon-envelope"></span> Contact</button>
+ </div>
+ </div>
+
+ <div class="col-md-3">
+ <h3>
+ ACCOUNT
+ </h3>
+ <div>
+ <a href="/portal/account/"><img src="{{ STATIC_URL }}img/icon_user_color.png" alt="" /></a>
+ </div>
+ <div>
+ <button id="logoutbtn" type="button" class="btn btn-default" data-username="{{ username }}"><span class="glyphicon glyphicon-off"></span> Logout</button>
+ </div>
+ <div>
+ {% if person.last_name %}
+ {{person.first_name}} {{person.last_name}}<br />
+ {% endif %}
+ <span class="label">Username:</span> <a href='/portal/account/' title="Click here to see and edit your account details.">{{person.email}}</a>
+ </div>
+ </div>
+ </div>
+ {%else%}
+ <div class="row">
+ <div class="col-md-4">
+ <h3>
+ EXPERIMENT
+ </h3>
+ <div>
+ <a href="#"><img src="{{ STATIC_URL }}img/icon_slices.png" alt="" /></a>
+ </div>
+ <div>
+ <button id="slicerequestbtn" type="button" class="btn btn-default"><span class="glyphicon glyphicon-plus"></span> Request Slice</button>
+ </div>
+ <div>
+ <p><strong>Your slices </strong>
+ <span title="A slice is a set of testbed resources on which you can conduct an experiment.
+ Either ask your colleagues to give you access to an existing slice or request a new slice by clicking 'Request Slice'.
+ However, on the OneLab portal, you will only see slices that you have created through OneLab. If you have created slices elsewhere,
+ such as on the PlanetLab Europe portal, those slices will not appear here."
+ class="glyphicon glyphicon-info-sign">
+ </span>
+ </p>
+ </div>
+ <div>
+ <div id="home-slice-list"><img src="{{ STATIC_URL }}img/loading.gif" alt="Loading Slices" /></div>
+ </div>
+ </div>
+ <div class="col-md-4">
+ <h3>
+ SUPPORT
+ </h3>
+ <div>
+ <a href="/portal/support"><img src="{{ STATIC_URL }}img/icon_support.png" alt="" /></a>
+ </div>
+ <div>
+ <button id="ticketbtn" type="button" class="btn btn-default"><span class="glyphicon glyphicon-envelope"></span> Contact</button>
+ </div>
+ </div>
+
+ <div class="col-md-4">
+ <h3>
+ ACCOUNT
+ </h3>
+ <div>
+ <a href="/portal/account/"><img src="{{ STATIC_URL }}img/icon_user_color.png" alt="" /></a>
+ </div>
+ <div>
+ <button id="logoutbtn" type="button" class="btn btn-default" data-username="{{ username }}"><span class="glyphicon glyphicon-off"></span> Logout</button>
+ </div>
+ <div>
+ {% if person.last_name %}
+ {{person.first_name}} {{person.last_name}}<br />
+ {% endif %}
+ <span class="label">Username:</span> <a href='/portal/account/' title="Click here to see and edit your account details.">{{person.email}}</a>
+ </div>
+ </div>
+ </div>
+ {%endif%}
+
+</div>
+{% else %}
+<div class="container-fluid home">
+ <div class="">
+ <div class="col-sm-1"></div>
+ <div class="col-sm-5 slogan">
+ <h2>
+ FIBRE: Future Internet testbeds experimentation between Brazil and Europe
+ </h2>
+ <h3>
+ Access variety of testbeds through your account
+ </h3>
+ </div>
+ <div class="col-sm-5 col-sm-offset-1">
+ <div class="row">
+ {% include 'fibre__widget-login-fed-manager.html' %}
+ <a href="/cafe" style="margin-left:80px;"><img src="{{ STATIC_URL }}img/fibre/cafe.jpg" alt="CAFe authentication" /></a>
+ </div>
+ </div>
+ <div class="col-sm-1"></div>
+ </div>
+</div>
+{% endif %}
+
+
+<script type="text/javascript">
+ $(document).ready(function() {
+ $('a.home-tab').click(function() {
+ $('ul.nav-tabs li').removeClass('active');
+ $(this).parent().addClass('active');
+ $('div.home-panel').hide();
+ $('div#'+$(this).data('panel')).show();
+ });
+ $('button#validaterequestbtn').click(function() {
+ window.location="/portal/institution#requests";
+ });
+ $('button#ticketbtn').click(function() {
+ window.location="/portal/contact/";
+ });
+ $('button#signupbtn').click(function() {
+ window.location="/portal/register/";
+ });
+ $('button#slicerequestbtn').click(function() {
+ window.location="/portal/slice_request/";
+ });
+/*-------
+List of slices has been moved in
+portal/templates/base.html
+This should go into session
+--------*/
+});
+</script>
+{% endblock %}
--- /dev/null
+{% extends "layout_wide.html" %}
+
+{% block head %}
+<script type="text/javascript" src="{{STATIC_URL}}/js/institution.js"></script>
+{% endblock head %}
+
+{% block content %}
+<div class="container">
+ <div class="row">
+ <div class="col-md-12">
+ <div class="breadcrumbs">
+ Management > Institution: <span id="authority_name"></span>
+ </div>
+ </div>
+ </div>
+</div>
+<div class="container">
+ <div class="row">
+ <div class="col-md-12">
+ <ul class="nav nav-tabs nav-section">
+ <li class="active"><a href="#about">About</a></li>
+ <li><a href="#users">Users</a></li>
+ <li><a href="#slices">Slices</a></li>
+ <li><a href="#requests">Requests</a></li>
+ </ul>
+ </div>
+ </div>
+</div>
+<div class="container tab-content">
+ <div class="tab-pane active row" id="about">
+ <div class="col-md-6">
+ <div>
+ <img src="{{ STATIC_URL|add:'img/institutions/'|add:authority.authority_hrn|add:'.gif'|file_exists }}" alt="{{authority.name}}">
+ </div>
+ <br />
+ <h3><a href="{{authority.url}}">{{authority.name}}</a></h3>
+ <p>
+ {{authority.address}} <br />
+ {{authority.postcode}} {{authority.city}} <br />
+ {{authority.country}}
+ </p>
+ <br />
+ <h4>Onelab membership</h4>
+ <p>
+ {{ authority.onelab_membership }}
+ </p>
+ </div>
+ <div class="col-md-6">
+ <h4>Legal Contact:</h4>
+ <p>
+ {% for c in authority_contacts.legal %}
+ {{ c }} <br />
+ {% endfor %}
+ </p>
+ <br />
+ <h4>Scientific Contact:</h4>
+ <p>
+ {% for c in authority_contacts.scientific %}
+ {{ c }} <br />
+ {% endfor %}
+ </p>
+ <br />
+ <h4>Technical Contact:</h4>
+ <p>
+ {% for c in authority_contacts.technical %}
+ {{ c }} <br />
+ {% endfor %}
+ </p>
+ </div>
+ <script>
+ $(document).ready(function() {
+ $('#authority_name').text("{{ authority.name|default:authority.authority_hrn }}");
+ });
+ </script>
+ </div>
+
+ <div class="tab-pane row" id="users" data-authority="{{user_details.parent_authority}}">
+ <div class="col-md-12 el">
+ <div id="user-tab-loading"><img src="{{ STATIC_URL }}img/loading.gif" alt="Loading Slices" /></div>
+ <div id="user-tab-loaded" style="display:none;">
+ <table id="user-tab" class="table">
+ <tr>
+ <th>+/-</th>
+ <th>Email</th>
+ <th>User hrn</th>
+ <th>First name</th>
+ <th>Last name</th>
+ <th>Enabled</th>
+ </tr>
+ </table>
+
+ </div>
+ {%if 'is_pi' in pi %}
+ <div>
+ <button id="deleteusers" type="button" class="btn btn-danger"><span class="glyphicon glyphicon-remove"></span> Delete selected users</button>
+ </div>
+ {% endif %}
+ </div>
+ </div>
+
+ <div class="tab-pane row" id="slices">
+ <div class="col-md-12 el">
+ <div id="slice-tab-loading"><img src="{{ STATIC_URL }}img/loading.gif" alt="Loading Slices" /></div>
+ <div id="slice-tab-loaded" style="display:none;">
+ <table id="slice-tab" class="table">
+ <tr>
+ <th>+/-</th>
+ <th>Slice hrn</th>
+ <th>Users</th>
+ <th>Url</th>
+ <!-- <th>nodes</th> -->
+ <th>Expiration</th>
+ </tr>
+ </table>
+ </div>
+ {% if 'is_pi' in pi %}
+ <div>
+ {% if 'is_pi' in pi %}
+ <button id="createslice" type="button" class="btn btn-default"><span class="glyphicon glyphicon-plus"></span> Create slice</button>
+ {% else %}
+ <button id="createslice" type="button" class="btn btn-default"><span class="glyphicon glyphicon-plus"></span> Request slice</button>
+ {% endif %}
+ <button id="renewslices" type="button" class="btn btn-primary"><span class="glyphicon glyphicon-refresh"></span> Renew Slices</button>
+ <button id="deleteslices" type="button" class="btn btn-danger"><span class="glyphicon glyphicon-remove"></span> Delete Slices</button>
+ </div>
+ {% endif %}
+ </div>
+ </div>
+ <div class="tab-pane row" id="requests">
+ </div>
+</div>
+<script>
+$(document).ready(function() {
+ {% if person %}
+ {% if user_details.parent_authority %}
+
+ $.post("/rest/slice/",{'filters':{'parent_authority':'{{user_details.parent_authority}}'}}, function( data ) {
+ var list_slices = [];
+ var table_slices = [];
+ /* "slice_hrn", "slice_description", "slice_type", "parent_authority", "created", "nodes", "slice_url", "slice_last_updated", "users", "slice_urn", "slice_expires" */
+ $.each( data, function( key, val ) {
+ list_slices.push( "<li><a href=\"portal/slice/"+val.slice_hrn+"\">" + val.slice_hrn + "</a></li>" );
+ if(val.nodes=="undefined" || val.nodes==null){
+ nodes_length=0;
+ }else{
+ nodes_length=val.nodes.length;
+ }
+ console.log(val);
+ if(val.users=="undefined" || val.users==null){
+ users_length=0;
+ }else{
+ users_length=val.users.length;
+ }
+
+ if(val.slice_url=="undefined" || val.slice_url==null){
+ slice_url="";
+ }else{
+ slice_url="<a href='"+val.slice_url+"' target='_blank'>"+val.slice_url+"</a>";
+ }
+
+ slice_row = "<tr id='"+val.slice_hrn+"'>";
+ slice_row += "<td><input type='checkbox' class='slice' id='"+val.slice_hrn+"'></td>";
+ slice_row += "<td><a href=\"/slice/"+val.slice_hrn+"\">" + val.slice_hrn + "</a></td>";
+ slice_row += "<td>"+users_length+"</td>";
+ slice_row += "<td>"+slice_url+"</td>";
+ //slice_row += "<td>"+nodes_length+"</td>";
+ slice_row += "<td>"+val.slice_expires+"</td>";
+ slice_row += "</tr>";
+ table_slices.push(slice_row);
+
+ });
+
+ /* $("div#slice-list").html($( "<ul/>", { html: list_slices.join( "" ) })); */
+ $("table#slice-tab tr:last").after(table_slices.join( "" ));
+ $("div#slice-tab-loaded").css("display","block");
+ $("div#slice-tab-loading").css("display","none");
+ });
+
+
+ $.post("/rest/user/",{'filters':{'parent_authority':'{{user_details.parent_authority}}'}}, function( data ) {
+ var list_users = [];
+ var table_users = [];
+ /* Available fields
+ user_gid, user_enabled, slices, pi_authorities, keys, parent_authority, user_first_name,
+ user_urn, user_last_name, user_phone, user_hrn, user_email, user_type
+ */
+ $.each( data, function( key, val ) {
+ list_users.push( "<li><a href=\"portal/user/"+val.user_email+"\">" + val.user_email + "</a></li>" );
+ user_row = "<tr id='"+val.user_hrn+"'>";
+ user_row += "<td><input type='checkbox' class='user' id='"+val.user_hrn+"'></td>";
+ user_row += "<td>"+val.user_email+"</td>";
+ user_row += "<td>"+val.user_hrn+"</td>";
+ user_row += "<td>"+val.user_first_name+"</td>";
+ user_row += "<td>"+val.user_last_name+"</td>";
+ user_row += "<td>"+val.user_enabled+"</td>";
+ user_row += "</tr>";
+ table_users.push(user_row);
+ });
+ $("table#user-tab tr:last").after(table_users.join( "" ));
+ $("div#user-tab-loaded").css("display","block");
+ $("div#user-tab-loading").css("display","none");
+ });
+
+ {% endif %}
+ {% endif %}
+
+}); // End document.ready
+/*
+$(document).ready(function() {
+ $('.nav-tabs a').click(function (e) {
+ e.preventDefault();
+ $(this).tab('show');
+ var id = $(this).attr('href').substr(1);
+ if ((id == 'requests') || (id == 'about'))
+ $("#" + id).load('/management/' + id);
+ });
+ var hash = window.location.hash;
+ if (hash) {
+ $('.nav-tabs a[href='+hash+']').click();
+ } else {
+ $('.nav-tabs a[href=#about]').click();
+ }
+});
+*/
+</script>
+{% endblock %}
--- /dev/null
+{% load portal_filters %}
+<div class="col-md-6">
+ <div>
+ <img src="{{ STATIC_URL|add:'img/institutions/'|add:authority.authority_hrn|add:'.gif'|file_exists }}" alt="{{authority.name}}">
+ </div>
+ <br />
+ <h3><a href="{{authority.url}}">{{authority.name}}</a></h3>
+ <p>
+ {{authority.address}} <br />
+ {{authority.postcode}} {{authority.city}} <br />
+ {{authority.country}}
+ </p>
+ <br />
+ <h4>Onelab membership</h4>
+ <p>
+ {{ authority.onelab_membership }}
+ </p>
+</div>
+<div class="col-md-6">
+ <h4>Legal Contact:</h4>
+ <p>
+ {% for c in authority_contacts.legal %}
+ {{ c }} <br />
+ {% endfor %}
+ </p>
+ <br />
+ <h4>Scientific Contact:</h4>
+ <p>
+ {% for c in authority_contacts.scientific %}
+ {{ c }} <br />
+ {% endfor %}
+ </p>
+ <br />
+ <h4>Technical Contact:</h4>
+ <p>
+ {% for c in authority_contacts.technical %}
+ {{ c }} <br />
+ {% endfor %}
+ </p>
+</div>
+<script>
+$(document).ready(function() {
+ $('#authority_name').text("{{ authority.name|default:authority.authority_hrn }}");
+});
+</script>
--- /dev/null
+<script type="text/javascript">
+ $(document).ready(function() {
+ $("li#nav-request").addClass("active");
+ });
+ function on_click_event() {
+ var ids = [];
+ $('.portal__validate__checkbox').each(function(i, el) {
+ if ($(el).prop('checked')) {
+ // portal__validate__checkbox__slice__2
+ var id_array = $(el).attr('id').split('__');
+ // push(slice__2)
+ ids.push(id_array[3] + '__' + id_array[4]);
+ }
+ });
+ if (ids.length > 0) {
+ var id_str = ids.join('/');
+ // XXX spinner
+ $.getJSON('/portal/validate_action/' + id_str,
+ function(status) {
+ $.each(status, function(request_type__id, request_status) {
+ // request_status: NAME -> dict (status, description)
+ var status_str = '';
+ $.each(request_status, function(name, result) {
+ if (status_str != '')
+ status_str += ' -- ';
+
+ if (result.status) {
+ status_str += '<font color="green">OK</font>';
+ $('#portal__validate__checkbox__' + request_type__id).hide();
+ } else {
+ status_str += '<font color="red">ERROR: ' + result.description + '</font>';
+ }
+ });
+ $('#portal__status__' + request_type__id).html(status_str);
+
+
+ });
+ }
+ );
+ }
+ }
+</script>
+
+<div class="col-md-12">
+ <h2>Authorities</h2>
+</div>
+{% if my_authorities %}
+
+ {% for authority, requests in my_authorities.items %}
+
+ <div class="col-md-12">
+ <h2>{{authority}}</h2>
+ </div>
+
+ <table class="table">
+ <th>
+ <td>Type</td>
+ <td>Id</td>
+ <td>Details</td>
+ <td>Timestamp</td>
+ <td>Status</td>
+ </th>
+ {% for request in requests %}
+
+ <tr>
+ <td>
+ {% if request.allowed == 'allowed' %}
+ <input class='portal__validate__checkbox' id='portal__validate__checkbox__{{request.type}}__{{request.id}}' type='checkbox'/>
+ {% else %}
+ {% if request.allowed == 'expired' %}
+ expired
+ {% else %} {# denied #}
+ denied
+ {% endif %}
+ {% endif %}
+ </td>
+ <td>{{ request.type }}</td>
+ <td>{{ request.id }}</td>
+ <td>
+ {% if request.type == 'user' %}
+ Login: {{request.login}} -- First name: {{request.first_name}} -- Last name: {{request.last_name}} -- Email: {{request.email}}
+ {% else %}
+ {% if request.type == 'slice' %}
+ Slice name: {{request.slice_name}} -- Number of nodes: {{request.number_of_nodes}} -- Type of nodes: {{request.type_of_nodes}} -- Purpose: {{request.purpose}}
+ {% else %} {# authority #}
+ Authority name: {{request.site_name}} -- authority_hrn: {{request.site_authority}} -- City: {{request.address_city}} -- Country: {{request.address_country}}
+ {% endif %}
+ {% endif %}
+ </td>
+ <td>{{ request.timestamp }}</td>
+
+ <td><span id='portal__status__{{request.type}}__{{request.id}}'></span></td>
+
+ <!--<div class='portal_validate_request {{request.type}} {% if forloop.counter|divisibleby:2 %}even{% else %}odd{% endif %}'> -->
+ </tr>
+
+ {% endfor %}
+ </table>
+ {% endfor %}
+
+{% else %}
+ <div class="col-md-12">
+ <i>There is no pending request waiting for validation.</i>
+ </div>
+{% endif %}
+<div>nnllknjkn<br /><br /></div>
+<div class="col-md-12">
+ <h2>Sub-Authorities</h2>
+</div>
+{% if sub_authorities %}
+
+ {% for authority, requests in sub_authorities.items %}
+ <div class="col-md-12">
+ <h2>{{authority}}</h2>
+ </div>
+
+ <table class="table">
+ <th>
+ <td>Type</td>
+ <td>Id</td>
+ <td>Details</td>
+ <td>Timestamp</td>
+ <td>Status</td>
+ </th>
+ {% for request in requests %}
+ <tr>
+ <td>
+ {% if request.allowed == 'allowed' %}
+ <input class='portal__validate__checkbox' id='portal__validate__checkbox__{{request.type}}__{{request.id}}' type='checkbox'/>
+ {% else %}
+ {% if request.allowed == 'expired' %}
+ expired
+ {% else %} {# denied #}
+ denied
+ {% endif %}
+ {% endif %}
+ </td>
+ <td>{{ request.type }}</td>
+ <td>{{ request.id }}</td>
+ <td>
+ {% if request.type == 'user' %}
+ Login: {{request.login}} -- First name: {{request.first_name}} -- Last name: {{request.last_name}} -- Email: {{request.email}}
+ {% else %}
+ {% if request.type == 'slice' %}
+ Slice name: {{request.slice_name}} -- Number of nodes: {{request.number_of_nodes}} -- Type of nodes: {{request.type_of_nodes}} -- Purpose: {{request.purpose}}
+ {% else %} {# authority #}
+ Authority name: {{request.site_name}} -- authority_hrn: {{request.site_authority}} -- City: {{request.address_city}} -- Country: {{request.address_country}}
+ {% endif %}
+ {% endif %}
+ </td>
+ <td>{{ request.timestamp }}</td>
+
+ <td><span id='portal__status__{{request.type}}__{{request.id}}'></span></td>
+
+ <!--<div class='portal_validate_request {{request.type}} {% if forloop.counter|divisibleby:2 %}even{% else %}odd{% endif %}'> -->
+ </tr>
+ {% endfor %}
+ </table>
+ {% endfor %}
+{% else %}
+<div class="col-md-12">
+ <i>There is no pending request waiting for validation.</i>
+</div>
+{% endif %}
+
+<div class="col-md-12">
+ <h2>Authorities with delegation</h2>
+</div>
+
+{% if delegation_authorities %}
+
+ {% for authority, requests in delegation_authorities.items %}
+ <div class="col-md-12">
+ <h3>{{authority}}</h3>
+ </div>
+ <table class="table">
+ <th>
+ <td>Type</td>
+ <td>Id</td>
+ <td>Details</td>
+ <td>Timestamp</td>
+ <td>Status</td>
+ </th>
+ {% for request in requests %}
+ <tr>
+ <td>
+ {% if request.allowed == 'allowed' %}
+ <input class='portal__validate__checkbox' id='portal__validate__checkbox__{{request.type}}__{{request.id}}' type='checkbox'/>
+ {% else %}
+ {% if request.allowed == 'expired' %}
+ expired
+ {% else %} {# denied #}
+ denied
+ {% endif %}
+ {% endif %}
+ </td>
+ <td>{{ request.type }}</td>
+ <td>{{ request.id }}</td>
+ <td>
+ {% if request.type == 'user' %}
+ Login: {{request.login}} -- First name: {{request.first_name}} -- Last name: {{request.last_name}} -- Email: {{request.email}}
+ {% else %}
+ {% if request.type == 'slice' %}
+ Slice name: {{request.slice_name}} -- Number of nodes: {{request.number_of_nodes}} -- Type of nodes: {{request.type_of_nodes}} -- Purpose: {{request.purpose}}
+ {% else %} {# authority #}
+ Authority name: {{request.site_name}} -- authority_hrn: {{request.site_authority}} -- City: {{request.address_city}} -- Country: {{request.address_country}}
+ {% endif %}
+ {% endif %}
+ </td>
+ <td>{{ request.timestamp }}</td>
+
+ <td><span id='portal__status__{{request.type}}__{{request.id}}'></span></td>
+
+ <!--<div class='portal_validate_request {{request.type}} {% if forloop.counter|divisibleby:2 %}even{% else %}odd{% endif %}'> -->
+ </tr>
+ {% endfor %}
+ </table>
+ {% endfor %}
+{% else %}
+<div class="col-md-12">
+ <i>There is no pending request waiting for validation.</i>
+</div>
+{% endif %}
+<div class="col-md-12">
+ <button class="btn btn-onelab" type="button" id="portal__validate" onclick="on_click_event();"><span class="glyphicon glyphicon-ok"></span> Validate</button>
+</div>
--- /dev/null
+{% extends "layout_wide.html" %}
+
+{% block content %}
+<div class="container">
+ <div class="row">
+ <div class="col-md-12">
+ <h1><img src="{{ STATIC_URL }}icons/slices-xs.png" alt="News" />News</h1>
+ <br />
+ </div>
+ </div>
+
+ <div class="row">
+ <div class="col-md-12">
+ <b>15 July 2014</b> - The <b>OneLab</b> Portal opens with the <b>PlanetLab Europe</b>, <b>IOTLab</b> and <b>NITOS</b> testbeds!
+ <p>
+ Existing PlanetLab users will be able to open an account with their existing PLE credentials.
+ </p>
+ </div>
+ </div>
+</div>
+{% endblock %}
--- /dev/null
+{% extends "layout.html" %}
+
+{% block content %}
+
+<div class="row">
+ <div class="col-md-12">
+ <h1><img src="{{ STATIC_URL }}icons/user-xs.png" alt="User Registration" />User sign-up</h1>
+ </div>
+</div>
+<div class="row">
+ <div class="col-md-12">
+ <p><strong>Questions? <a href="/portal/contact" >Contact us.</a></strong></p>
+ </div>
+</div>
+{% if errors %}
+<ul>
+ {% for error in errors %}
+ <li>{{ error }}</li>
+ {% endfor %}
+</ul>
+{% endif %}
+
+
+<form action="/register" class="cmxform form-horizontal" method="post" enctype="multipart/form-data">
+<div class="row">
+
+ <div class="col-md-12">
+
+ <div class="form-group">
+ {% csrf_token %}
+ <label for="authority_hrn" class="control-label">Organization</label>
+ <p></p>
+ <input id="authority_hrn" name="org_name" class="form-control" style="width:590px" value="{{ organization }}"
+ title="Choose your organization (company/university) from the list that apears when you click in the field and start to type.
+ Use the arrow keys to scroll through the list; type part of the name to narrow down the list. If it is not in the list,
+ please request its addition by clicking the link below. We will send an email to the managers that we have on record for
+ your organization, asking them to validate your sign-up request." required />
+ <p></p>
+ <p>Organization not listed? <a href="/portal/join">Request its addition now.</a></p>
+ </div>
+ </div>
+</div>
+
+<div class="row">
+ <div class="col-md-6">
+
+ <div class="form-group">
+ <label for="firstname" class="control-label">Personal information</label>
+ <p></p>
+ <input type="text" name="firstname" class="form-control" style="width:350px" minlength="2" value="{{ first_name }}" placeholder="First name" required />
+ </div>
+ <div class="form-group">
+ <input type="text" name="lastname" size="25" class="form-control" style="width:350px" minlength="2" value="{{ last_name }}" placeholder="Last name" required />
+ </div>
+ <div class="form-group">
+ <input type="email" name="email" size="25" class="form-control" style="width:350px" value="{{ email }}"
+ title="Your e-mail address will be your identifier for logging in. We contact you to verify your account and then, occasionally, for important issues."
+ placeholder="Email" required />
+ </div>
+ </div>
+
+ <div class="col-md-6">
+ <div class="form-group">
+ <label for="password" class="control-label">Authentication</label>
+ <p></p>
+ <input type="password" id="password" name="password" class="form-control" style="width:250px" minlength="4" value="{{ password }}"
+ title="Your password allows you to log in to this portal."
+ placeholder="Password" required />
+ </div>
+ <div class="form-group">
+ <input type="password" id="confirmpassword" name="confirmpassword" style="width:250px" minlength="4" class="form-control" value=""
+ placeholder="Confirm password" required />
+ </div>
+ <div class="form-group">
+ <select name="question" class="form-control" style="width:350px" id="key-policy"
+ title="Your public/private key pair allows you to access the testbeds." required >
+ <option value="generate">Generate my keys for me (recommended)</option>
+ <option value="upload">Upload my public key (advanced users only)</option>
+ </select>
+ </div>
+ <div class="form-group" style="display:none;" id="upload_key">
+ <label for="file" class="control-label">Upload public key</label>
+ <input type="file" name="user_public_key" class="form-control" style="width:200px" id="user_public_key" />
+ <br />
+ <div class="alert alert-danger" id="pkey_del_msg">
+ In order for the portal to contact testbeds on your behalf, so as to list and reserve resources, you will need to
+ <a href="http://trac.myslice.info/wiki/InstallSfa" target="_blank">delegate your public key to the portal.</a>
+ </div>
+ </div>
+ </div>
+</div>
+<div class="row">
+ <div class="col-md-12">
+ <div class="form-group">
+ <p></p>
+ <input type="checkbox" name="agreement" value="agreement" required /> I agree to the
+ <a href="#" data-toggle="modal" data-target="#myModal">terms and conditions.</a>
+ </div>
+ </div>
+</div>
+<div class="row">
+ <div class="col-md-12">
+ <div class="form-group" id="register">
+ <p></p>
+ <input class="submit btn btn-onelab" type="submit" value="Sign up" />
+
+ </div>
+ </div>
+</div>
+</form>
+
+ <!-- Modal - columns selector -->
+<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
+ <div class="modal-dialog">
+ <div class="modal-content">
+ <div class="modal-header">
+ <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
+ <h4 class="modal-title" id="myModalLabel">Terms & Conditions</h4>
+ </div>
+ <div class="modal-body">
+ <p align="left">
+ Fibre: Future Internet testbeds experimentation between Brazil and Europe
+ <br/>
+ <a href="/portal/terms" target="_blank">[Printable format]</a>
+ </p>
+ <h1 align="left">1 Context</h1>
+ <p align="left">
+ The main goal of the FIBRE project is the design, implementation and validation of a shared Future Internet research facility, supporting the joint experimentation of European and Brazilian researchers. In order to achieve this goal the project will carry out four main activities:
+ </p>
+ <p align="left">
+ The development and operation of a new experimental facility in Brazil, including the setup of equipment to support experimentation with various technologies (fixed layer 2 and layer 3, wireless, optical) as well as the design and implementation of a control framework to automate the use and operation of the testbed.
+ </p>
+ <p align="left">
+ The development and operation of a Future Internet facility in Europe based on enhancements and the federation of two existing infrastructures: OFELIA and OneLab. Two OFELIA islands (i2CAT and University of Bristol (UNIVBRIS)) and the UTH's NITOS testbed will be enhanced by i) adding more physical resources (servers, OpenFlow-enabled switches and access points) to be able to cope with a bigger number ofusers and different use cases, ii) improving its respective control frameworks (based on the OFELIA control framework and OMF) and iii) adding more manpower to operate the facilities.
+ </p>
+ <p align="left">
+ The federation of the Brazilian and European experimental facilities, both at the physical connectivity and control framework level, to support the provisioning of slices using resources from both testbeds.
+ </p>
+<h2>PROCEDURE OVERVIEW</h2>
+<p>If your institution is willing to join the FIBRE Consortium, you are kindly requested to follow the steps below:<br></p>
+<p>1. <a mce_href="http://www.fibre-ict.eu/images/stories/docs/fibre_mou_v0.3.doc" href="http://www.fibre-ict.eu/images/stories/docs/fibre_mou_v0.3.doc">Download the MoU model</a> to understand the framework of collaboration between your institution and FIBRE project. The content of the MoU shall be discussed in case-by-case basis between the two parties. <span style="line-height: 1.3em;" mce_style="line-height: 1.3em;"> </span></p>
+<p>2. Contact the Project office at <a href="mailto:info@fibre.org.br">info@fibre.org.br</a> to schedule a call to clarify all your questions concerning the duties, responsibilities and advantages of joining the FIBRE project.</p>
+<p>3. If your institution understand and agree on the commitment stated in the MoU, please submit the application by editing the <a href="http://www.fibre-ict.eu/images/fibre_mou_v0.2_ff.doc" mce_href="http://www.fibre-ict.eu/images/fibre_mou_v0.2_ff.doc" style="style" mce_style="style">MoU template</a> and sending it to
+ <a href="mailto:info@fibre.org.br">info@fibre.org.br</a></p>
+<p>4. Application Approval: the FIBRE General Assembly will decide based on the application and information gathered during the call. The approval process will normally take around one month.</p><p>5. By mutual agreement of both parties, MoU will be prepared and signed.</p>
+<p><span style="line-height: 1.3em;" mce_style="line-height: 1.3em;">6. Testbed usage / island installation: FIBRE will provide instructions and support to help your institution to carry out the activities described in the MoU.</span></p>
+<p><br></p>
+<p><span style="line-height: 1.3em;" mce_style="line-height: 1.3em;"><a mce_href="http://webconf2.rnp.br/p27egdf20y7/" href="http://webconf2.rnp.br/p27egdf20y7/">Watch the webconference meeting about the MoU details</a><br> (Held on 5/July 2013, in Portuguese)<br></span></p>
+<p><br></p>
+ </div>
+ <div class="modal-footer">
+ <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
+ </div>
+ </div>
+ </div>
+</div>
+
+
+<script>
+$(document).ready(function(){
+ var availableTags = [
+ {% if authorities %}
+ {% for authority in authorities %}
+ {% if authority.name %}
+ {value:"{{ authority.name }}",label:"{{authority.name}}"},
+ {% else %}
+ {value:"{{ authority.authority_hrn }}",label:"{{authority.authority_hrn}}"},
+ {% endif %}
+ {% endfor %}
+ {% else %}
+ {value:"",label:"No authority found !!!"}
+ {% endif %}
+ ];
+ // sorting the list
+ availableTags.sort(function(a,b){
+ var nameA=a.value.toLowerCase(), nameB=b.value.toLowerCase();
+ if (nameA < nameB) {
+ return -1;
+ }
+ if (nameA > nameB) {
+ return 1;
+ }
+ return 0;
+ });
+ // auto-complete the form
+ $( "#authority_hrn" ).autocomplete({
+ source: availableTags,
+ minLength: 0,
+ change: function (event, ui) {
+ if(!ui.item){
+ //http://api.jqueryui.com/autocomplete/#event-change -
+ // The item selected from the menu, if any. Otherwise the property is null
+ //so clear the item for force selection
+ jQuery("#authority_hrn").val("");
+ }
+ }
+ //select: function( event, ui ) {console.log(jQuery(this))}
+ });
+ // for hover texts
+ $('[title!=""]').qtip();
+ $("form").validate();
+ $("form").submit(function() {
+ if ($('select option:selected').val() == 'upload') {
+ if ($('input[name=user_public_key]').val() == '') {
+ alert('Please specify the key file to upload');
+ return false;
+ }
+ }
+ });
+});
+</script>
+{% endblock %}
+
--- /dev/null
+<script type="text/javascript" src="{{STATIC_URL}}/js/jquery-ui.js"></script>
+<script type="text/javascript" src="{{STATIC_URL}}/js/jquery.qtip.min.js"></script>
+<link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}css/jquery.qtip.min.css">
+<link rel="stylesheet" href="{{ STATIC_URL }}css/jquery-ui.css">
+<script>
+ function get_users_in_slice(authority_hrn){
+ $("table#user-tab").html("<tr><th>+/-</th><th>Email</th><th>User hrn</th></tr>");
+ var slice_users = [];
+ $.post("/rest/user/",{'filters':{'parent_authority': authority_hrn}}, function( data ) {
+ var list_users = [];
+ var table_users = [];
+ /* Available fields
+ user_gid, user_enabled, slices, pi_authorities, keys, parent_authority, user_first_name,
+ user_urn, user_last_name, user_phone, user_hrn, user_email, user_type
+ */
+ $.each( data, function( key, val ) {
+ list_users.push( "<li><a href=\"portal/user/"+val.user_email+"\">" + val.user_email + "</a></li>" );
+ user_row = "<tr>";
+ // checking the box for the users that belong to the selected slice
+ var flag_checkbox = 0;
+ for(var data in val.slices) {
+ var element = val.slices[data];
+ if (element == "{{slice}}"){
+ //console.log("the slice is: "+ element);
+ flag_checkbox = 1;
+ slice_users.push (val.user_hrn)
+ user_row += "<td><input type='checkbox' checked='True' class='user'></td>";
+ }
+ }
+ if(flag_checkbox != 1){
+ user_row += "<td><input type='checkbox' class='user'></td>";
+ }
+ user_row += "<td>"+val.user_email+"</td>";
+ user_row += "<td>"+val.user_hrn+"</td>";
+ //user_row += "<td>"+val.user_enabled+"</td>";
+ user_row += "</tr>";
+ table_users.push(user_row);
+
+ });
+ $("table#user-tab tr:first").after(table_users.join( "" ));
+ $("div#user-tab-loaded").css("display","block");
+ $("div#user-tab-loading").css("display","none");
+ $("input:checkbox.user").click(function() {
+ user_hrn = $(this).closest('tr').find('td:eq(2)').html();
+ if(this.checked){
+ var record_id = this.id;
+ slice_users.push (user_hrn);
+ }else{
+ console.log(slice_users);
+ }
+ });
+ }); // post rest/user
+ }
+
+ $(document).ready(function() {
+ // TODO: Add a filter based on the list of authorities
+ $.post("/rest/authority/",{'fields':['authority_hrn']}, function( data ) {
+ var list_authorities = [];
+ $.each( data, function( key, val ) {
+ auth_hrn = val.authority_hrn;
+ // Keep only the sub authorities, remove root auth
+ //if(auth_hrn.indexOf(".") > -1){
+ list_authorities.push(auth_hrn);
+ list_authorities.sort();
+ if(auth_hrn=="{{user_details.parent_authority}}"){
+ $('#auth_list').val(auth_hrn);
+ }
+ //}
+ });
+ $( "#auth_list" ).autocomplete({
+ source: list_authorities,
+ minLength: 0,
+ select: function (event, ui) {
+ get_users_in_slice(ui.item.value);
+ }
+ //select: function( event, ui ) {console.log(jQuery(this))}
+ });
+ }); // post rest/authority
+
+ get_users_in_slice("{{user_details.parent_authority}}");
+
+ $('button#addusers').click(function() {
+ $.post("/update/slice/",{'filters':{'slice_hrn':'{{slice}}'},'params':{'users':slice_users}}, function(data) {
+ if(data.success){
+ // TODO: highlight row after success
+ //$('tr[id="'+record_id+'"]').highlight();
+ mysliceAlert('Success: slice updated','success', true);
+ }else{
+ mysliceAlert('Rest Error for: '+data.error,'warning', true);
+ }
+ }); // post update slice
+
+ // TODO: refresh table
+ //window.location="/portal/institution#slices";
+
+ }); // button#addusers click
+ $('[title!=""]').qtip();
+ }); // document ready
+</script>
+
+ <div class="col-md-2">
+ <div id="select-platform" class="list-group">
+ </div>
+
+ <ul class="list-group">
+ <li class="list-group-item">Authority</li>
+ <li class="list-group-item" style="padding-left:5px;">
+ <input type="text" id="auth_list" style ="min-width:190px;"
+ title="The default value is the authority that you belong to and the selected users belong to this slice.
+ You can view users of other authorities (organizations) from the list that apears when you click in the field and start to type.
+ Use the arrow keys to scroll through the list; type part of the name to narrow down the list."/>
+ </li>
+ </ul>
+
+ </div>
+ <div class="col-md-10">
+ <div class="row">
+ </div>
+ <div id="user-tab-loading"><img src="{{ STATIC_URL }}img/loading.gif" alt="Loading Useres" /></div>
+ <div id="user-tab-loaded" style="display:none;">
+ <table id="user-tab" class="table">
+ </table>
+
+ <!-- XXX TODO: for the moment only PIs have access to Update but users that have slice credentials should also have access to that -->
+
+ {% if 'is_pi' in pi %}
+ <button id="addusers" type="button" class="btn btn-default"><span class="glyphicon glyphicon-ok"></span> Update users</button>
+ {%endif%}
+ </div>
+
--- /dev/null
+
+<div class="col-md-2">
+ <div id="select-platform" class="list-group">
+ </div>
+
+ <ul class="list-group">
+ <li class="list-group-item">Authority:<b> {{user_details.parent_authority}}</b>
+ <!--<select id="auth_list">
+ <option value="ple.upmc">UPMC</option>
+ <option value="ple.inria">INRIA</option>
+ <option value="ple.nitos">NITOS</option>
+ <option value="ple.iminds">iMinds</option>
+ </select> -->
+ </li>
+ <li class="list-group-item">Filter: slice</li>
+
+ </ul>
+
+</div>
+<div class="col-md-10">
+ <div id="user-tab-loading"><img src="{{ STATIC_URL }}img/loading.gif" alt="Loading Useres" /></div>
+ <div id="user-tab-loaded" style="display:none;">
+ <table id="user-tab" class="table">
+ <tr>
+ <th>+/-</th>
+ <th>Email</th>
+ <th>User hrn</th>
+ <th>Enabled</th>
+ </tr>
+ </table>
+ </div>
+</div>
+<script>
+ $(document).ready(function() {
+ //console.log("the value you selected: " + selectedValue);
+ $.post("/rest/user/",{'filters':{'parent_authority': "{{user_details.parent_authority}}"}}, function( data ) {
+ var list_users = [];
+ var table_users = [];
+ /* Available fields
+ user_gid, user_enabled, slices, pi_authorities, keys, parent_authority, user_first_name,
+ user_urn, user_last_name, user_phone, user_hrn, user_email, user_type
+ */
+ $.each( data, function( key, val ) {
+ //list_users.push( "<li><a href=\"portal/user/"+val.user_email+"\">" + val.user_email + "</a></li>" );
+ user_row = "<tr>";
+ // checking the box for the users that belong to the selected slice
+ var flag_checkbox = 0;
+ for(var data in val.slices) {
+ var element = val.slices[data];
+ if (element == "{{slice}}"){
+ //console.log("the slice is: "+ element);
+ flag_checkbox = 1;
+ user_row += "<td><input type='checkbox' checked='True'></td>";
+ }
+ }
+ if(flag_checkbox != 1){
+ user_row += "<td><input type='checkbox'></td>";
+ }
+ user_row += "<td>"+val.user_email+"</td>";
+ user_row += "<td>"+val.user_hrn+"</td>";
+ user_row += "<td>"+val.user_enabled+"</td>";
+ user_row += "</tr>";
+ table_users.push(user_row);
+
+ });
+ $("table#user-tab tr:last").after(table_users.join( "" ));
+ $("div#user-tab-loaded").css("display","block");
+ $("div#user-tab-loading").css("display","none");
+ });
+ // });
+ });
+</script>
+
--- /dev/null
+{% extends "layout_wide.html" %}
+
+{% block head %}
+
+{% endblock %}
+
+{% block content %}
+
+{% include theme|add:"_widget-slice-sections.html" %}
+
+<div class="container-fluid tab-content container-slice">
+ <div class="tab-pane active row" id="info">...</div>
+ <div class="tab-pane row" id="testbeds">...</div>
+ <div class="tab-pane row" id="resources">...</div>
+ <div class="tab-pane row" id="users">...</div>
+ <!-- <div class="tab-pane row" id="statistics">...</div> -->
+ <!-- <div class="tab-pane row" id="measurements">...</div> -->
+ <div class="tab-pane row" id="experiment">...</div>
+</div>
+{% endblock %}
--- /dev/null
+{% extends "layout.html" %}
+{% load i18n %}
+
+{% block content %}
+ <div class="row">
+ <div class="col-md-12">
+ <div class="breadcrumbs">
+ Experiment > Request a new Slice
+ </div>
+ </div>
+ </div>
+
+ {% if errors %}
+ <div class="row">
+ <div class="col-md-12">
+ <ul>
+ {% for error in errors %}
+ <li>{{ error }}</li>
+ {% endfor %}
+ </ul>
+ </div>
+ </div>
+ {% endif %}
+
+ <div class="row">
+ <div class="col-md-8 el">
+ <form role="form" method="post">
+ {% csrf_token %}
+ <div class="form-group" style="display:none">
+ <input type="email" class="form-control" id="email" style="width:300px" value="{{ email }}" readonly="readonly">
+ </div>
+ <div class="form-group">
+ <input type="text" class="form-control" name="slice_name" id="slice_name" style="width:300px" placeholder="Slice name" value="{{slice_name}}"
+ title="Please enter a name for your slice"required="required">
+ </div>
+ <div class="form-group">
+ {%if 'is_pi' in pi %}
+ <input type="text" class="form-control" id="authority_hrn" name="org_name" style="width:300px" placeholder="Organization"
+ title="An authority responsible for vetting your slice" required="required">
+ {%else%}
+ <input type="text" class="form-control" id="authority_hrn" name="org_name" placeholder="Organization" style="width:300px;"
+ title="An authority responsible for vetting your slice" required="required" readonly>
+ {%endif%}
+ </div>
+ <div class="form-group">
+ <input type="text" class="form-control" name="exp_url" id="exp_url" style="width:300px" placeholder="Experiment URL (if one exists)"
+ title="Please provide the url of your experiment if you have one." value="{{exp_url}}">
+ </div>
+ <div class="form-group">
+ <textarea id="purpose" name="purpose" class="form-control" rows="6" placeholder="Experiment purpose" style="width:300px"
+ title="Purpose of your experiment (informative)" required="required">{{ purpose }}</textarea>
+ </div>
+ <button type="submit" class="btn btn-onelab"><span class="glyphicon glyphicon-plus"></span> Request Slice</button>
+ </form>
+
+ </div>
+ </div>
+
+<script>
+jQuery(document).ready(function(){
+
+ /*$("#authority_hrn").load("/rest/user/", {"fields" : ["parent_authority"], "filters": {"user_hrn": "{{ user_hrn }}"}}, function(data) {
+ var jsonData = JSON.parse(data);
+ $(this).attr("value", jsonData[0]['parent_authority']);
+ });*/
+ console.log("test");
+ test = "{{authority.name}}";
+ if(test){
+ console.log("true");
+ $("#authority_hrn").val("{{authority_name}}");
+ }else{
+ console.log("false");
+ $("#authority_hrn").val("{{authority_hrn}}");
+ }
+
+ var availableTags = [
+ {% if authorities %}
+ {% for authority in authorities %}
+ {% if authority.name %}
+ {value:"{{ authority.name }}",label:"{{authority.name}}"},
+ {% else %}
+ {value:"{{ authority.authority_hrn }}",label:"{{authority.authority_hrn}}"},
+ {% endif %}
+ {% endfor %}
+ {% else %}
+ {value:"",label:"No authority found !!!"}
+ {% endif %}
+ ];
+ // sorting the list
+ availableTags.sort(function(a,b){
+ var nameA=a.value.toLowerCase(), nameB=b.value.toLowerCase();
+ if (nameA < nameB) {
+ return -1;
+ }
+ if (nameA > nameB) {
+ return 1;
+ }
+ return 0;
+ });
+ $( "#authority_hrn" ).autocomplete({
+ source: availableTags,
+ minLength: 0,
+ select: function( event, ui ) {console.log(jQuery(this));}
+ });
+});
+</script>
+{% endblock %}
+
--- /dev/null
+{% extends "layout_wide.html" %}
+
+{% block content %}
+<div class="container">
+ <div class="row">
+ <div class="col-md-12">
+ <div class="breadcrumbs">
+ Support
+ </div>
+ </div>
+ </div>
+</div>
+<div class="container">
+ <div class="row">
+ <div class="col-md-12">
+ <ul class="nav nav-tabs nav-section">
+ <li class="active"><a href="#support">Tickets</a></li>
+ <li><a href="#faq">FAQ</a></li>
+ <li><a href="#contact">Contact</a></li>
+ </ul>
+ </div>
+ </div>
+</div>
+
+<div class="container tab-content">
+ <div class="tab-pane active row" id="support">
+ <div class="col-md-12">
+ <h2>Report a Bug</h2>
+ <p>If you have found a bug or having difficulties accesing some features or found some anomalies, please report it using our ticketing system.</p>
+ <button id="ticketbtn" type="button" class="btn btn-default"><span class="glyphicon glyphicon-plus"></span> Create Ticket</button>
+<!-- <h3>Unresolved Tickets</h3>
+ <table class="mytable table table-bordered table-hover">
+ <tr>
+ <th>Ticket No</th>
+ <th>Reported By</th>
+ <th>Description</th>
+ <th>Status</th>
+ </tr>
+ <tr>
+ <td>1</td>
+ <td>yasin.upmc@gmail.com</td>
+ <td> Slice_request page is not working </td>
+ <td> Unresolved</td>
+ </tr>
+ <tr>
+ <td>2</td>
+ <td>azerty@lip6.fr</td>
+ <td>Unable to Register</td>
+ <td>Unresolved</td>
+ </tr>
+
+ </table> -->
+ </div>
+ </div>
+ <div class="tab-pane row" id="faq">
+ <div class="col-md-12">
+ <h2>Frequently Asked Questions (FAQs)<h2>
+
+ <h3>Users</h3>
+ <ul>
+ <li><h4>Who is a user?</h4></li>
+ <p>A user is an experimenter who registers to the OneLab portal and able to use all the facilites that the portal has to offer. However, a user does not
+ have the right to do any admin operation such as managing slices, users and resources.</p>
+
+
+ <li><h4>How do I register?</h4></li>
+ <p>In order to register you must go to the <a href="/portal/register">Registration</a> page. You have to choose your corresponding institution (authority). After registration you have to wait until the PI validates your account. However upon registration, you will be able login to the portal with a limited access. Do not try to re-register with the same email address.</p>
+
+ <li><h4>Why can't I register with my email?</h4></li>
+ <p>If you have already registered then you won't be able to register again with the same email address. However, if you have never registered and still you are not able to use your email then please
+ <a href="/portal/contact">Contact Support</a> and mention the error message that you are getting while trying to register.</p>
+
+ <li><h4>In registration, in "My keys" option, what should i choose?</h4></li>
+ <p>There are two choices.</p>
+ <p class="text-justify"><b>1. Generate Key Pairs:</b> This option is for users who have no knowledge about SFA and MySlice i.e., new users. We offer convenience to the new users in order to avoid addtional efforts to delegate keys manually. If you choose this option, the portal will automatically handle your credentials and you would be able use the portal as soon as the PI validates your account. However, you can delete your private key from the portal if you are concerned about privacy issues. In that case once your current credentials expire, you have to delegate your credentials manually using <a href="http://trac.myslice.info/wiki/InstallSfa" target="_blank">SFA</a>. As this needs advance knowledge about SFA and Myslice, we highly recommend to the new users to keep both private and public keys in the portal in order to keep the process automatic. </p>
+ <p class="text-justify"><b>2. Upload My Public Key:</b> This option is for users who have experience with MySlice and SFA. If you choose this option, once the PI validates your account, you have to delegate your credentials manually using <a href="http://trac.myslice.info/wiki/InstallSfa" target="_blank">SFA</a>. You have to repeat the same process everytime your credentials expire. Normally, credentials expire every one month. You can see the expiration date in your Account page. </p>
+
+ <li><h4>Who is responsible for validating my account?</h4></li>
+ <p>When you register, you choose an authority fromt he list of authorities. For each authority there is a Principal Investigator (PI). PI of your authority will verify your identity and if he finds that you are from his institution, he will validate your account otherwise he will reject your account.</p>
+
+ <li><h4>How long I have to wait for validation?</h4></li>
+ <p>It depends on the PI of your authority. In general, it should not take more than a week. If you are waiting more than usual, please <a href="/portal/contact">Contact Support</a> and explain your problem.</p>
+ <li><h4>I just registered. Why can't I see any slices and resources?</h4></li>
+ <p>Once you register, you can login to your account with limited access. It means that you can view your account details, modify your name and password. You can also view other pages. However, you will not be able to see any slices as well as resources before your account validation. But you can <a href="/portal/slice_request/">Request Slice</a> before being validated. Therefore, the PI will validate your account as well as your requested slice. Once validated, you will be able to see your slice and if you click on your slice, you will be able to see resources in that slice and you can reserve nodes and start your experiment.</p>
+
+ <li><h4>How can I get access to a slice?</h4></li>
+ <p>If you are a completely new user, you have to <a href="/portal/slice_request/">Request Slice</a>. It is upto the PI of your authority to accept/reject your slice request. </br>On the other hand, if you are a new user to the portal but you already have an account in OneLab SFA registry and you have access to slices, you will be able to see all your slices once your account is validated by the PI.</p>
+
+ <li><h4>I forgot my password, how to recover it?</h4></li>
+ <p>If you have an account in the portal but you forgot the password, you can always <a href="/portal/pass_reset/">Reset your password</a>.</p></ul>
+
+ <h3>Managers</h3>
+ <ul>
+ <li><h4>Who is a manager?</h4></li>
+ <p>A manager is the Principal Investigator (PI) of the institution. Each PI has authority over his own institution. A PI can add, delete, validate users/
+ slices that belong to his institution.</p>
+
+ <li><h4>What is pending users/slices?</h4></li>
+ <p>In <a href="/portal/validate">Requests</a> page you will be able to see all the users that registered under your authority and the slices that users of your authority has requested. Therefore, pending users/slices are those users and slices that are yet to be validated. You can validate/reject these requests based on the policy of your institution.</p>
+
+ <li><h4>How can I manage the users/slices that belong to my institution?</h4></li>
+ <p>In <a href="/portal/institution">Instution</a> page, under "Users" tab, you will be able to see all the users that belong to your authority. You can delete the users that you don't want anymore. Under "Slices" tab, you will be able to see all the slices that belong to your authority. You can renew/delete the slices based on your requirements. As a PI you can also <a href="/portal/slice_request/">Create Slice</a>. Just fill the form of request slice and the slice will be automatically validated if it is requested by a PI. </p>
+
+ </ul>
+ </div>
+ </div>
+
+ <div class="tab-pane row" id="contact">
+ <div class="col-md-12">
+ <h2>Contact Us</h2>
+
+ <h3>Mailing List</h3>
+ <p>You can subscribe to our mailing list by sending a request to: <b>support</b> AT <b>myslice</b> DOT <b>info</b></p>
+ <p>Also you can adress any issues in the same email address.</p>
+
+ <h3>Mailing Address</h3>
+ <address>
+ UPMC - LIP6<br>
+ Boîte courrier 16 <br>
+ Couloir 26-00, Etage 01, Bureau 102<br>
+ 4 place Jussieu<br>
+ 75252 PARIS CEDEX 05<br>
+ France<br>
+ </address>
+ </div>
+ </div>
+</div>
+
+<script>
+$(document).ready(function() {
+ $('button#ticketbtn').click(function() {
+ window.location="/portal/contact/";
+ });
+ $('.nav-tabs a').click(function (e) {
+ e.preventDefault();
+ $(this).tab('show');
+ });
+});
+</script>
+
+
+{% endblock %}
+
--- /dev/null
+{% extends "layout.html" %}
+
+{% block content %}
+<div class="row">
+ <div class="col-md-12">
+ <h1> Terms and conditions</h1>
+ <p align="left">
+ <a name="_Ref238698453"></a>
+ <a name="_Ref238699060"></a>
+ <a name="_Ref249598367"></a>
+ <a name="_Ref254443731"></a>
+ <a name="_Ref254443916"></a>
+ TERMS AND CONDITIONS
+ <br/>
+ Fibre: Future Internet testbeds experimentation between Brazil and Europe
+ <br/>
+</p>
+<h2 align="left">Context</h2>
+ <p align="left">
+ The main goal of the FIBRE project is the design, implementation and validation of a shared Future Internet research facility, supporting the joint experimentation of European and Brazilian researchers. In order to achieve this goal the project will carry out four main activities:
+ </p>
+ <p align="left">
+ The development and operation of a new experimental facility in Brazil, including the setup of equipment to support experimentation with various technologies (fixed layer 2 and layer 3, wireless, optical) as well as the design and implementation of a control framework to automate the use and operation of the testbed.
+ </p>
+ <p align="left">
+ The development and operation of a Future Internet facility in Europe based on enhancements and the federation of two existing infrastructures: OFELIA and OneLab. Two OFELIA islands (i2CAT and University of Bristol (UNIVBRIS)) and the UTH's NITOS testbed will be enhanced by i) adding more physical resources (servers, OpenFlow-enabled switches and access points) to be able to cope with a bigger number ofusers and different use cases, ii) improving its respective control frameworks (based on the OFELIA control framework and OMF) and iii) adding more manpower to operate the facilities.
+ </p>
+ <p align="left">
+ The federation of the Brazilian and European experimental facilities, both at the physical connectivity and control framework level, to support the provisioning of slices using resources from both testbeds.
+ </p>
+<h2>PROCEDURE OVERVIEW</h2>
+<p>If your institution is willing to join the FIBRE Consortium, you are kindly requested to follow the steps below:<br></p>
+<p>1. <a mce_href="http://www.fibre-ict.eu/images/stories/docs/fibre_mou_v0.3.doc" href="http://www.fibre-ict.eu/images/stories/docs/fibre_mou_v0.3.doc">Download the MoU model</a> to understand the framework of collaboration between your institution and FIBRE project. The content of the MoU shall be discussed in case-by-case basis between the two parties. <span style="line-height: 1.3em;" mce_style="line-height: 1.3em;"> </span></p>
+<p>2. Contact the Project office at <a href="mailto:info@fibre.org.br">info@fibre.org.br</a> to schedule a call to clarify all your questions concerning the duties, responsibilities and advantages of joining the FIBRE project.</p>
+<p>3. If your institution understand and agree on the commitment stated in the MoU, please submit the application by editing the <a href="http://www.fibre-ict.eu/images/fibre_mou_v0.2_ff.doc" mce_href="http://www.fibre-ict.eu/images/fibre_mou_v0.2_ff.doc" style="style" mce_style="style">MoU template</a> and sending it to
+ <a href="mailto:info@fibre.org.br">info@fibre.org.br</a></p>
+<p>4. Application Approval: the FIBRE General Assembly will decide based on the application and information gathered during the call. The approval process will normally take around one month.</p><p>5. By mutual agreement of both parties, MoU will be prepared and signed.</p>
+<p><span style="line-height: 1.3em;" mce_style="line-height: 1.3em;">6. Testbed usage / island installation: FIBRE will provide instructions and support to help your institution to carry out the activities described in the MoU.</span></p>
+<p><br></p>
+<p><span style="line-height: 1.3em;" mce_style="line-height: 1.3em;"><a mce_href="http://webconf2.rnp.br/p27egdf20y7/" href="http://webconf2.rnp.br/p27egdf20y7/">Watch the webconference meeting about the MoU details</a><br> (Held on 5/July 2013, in Portuguese)<br></span></p>
+<p><br></p>
+<div>
+ <div>
+ <div id="_com_1">
+ </div>
+ </div>
+</div>
+</div>
+</div>
+<div class="row">
+ <div class="col-md-12">
+
+</div>
+</div>
+{% endblock %}
+
--- /dev/null
+<img src="https://onelab.eu/templates/onelab2/images/logo.png">
+<br>
+<h1>NEW USER REQUEST</h1>
+<br>
+<p>You are receiving this request because we have you listed as a manager at an organization that uses OneLab.</p>
+<p>If you believe that you have received this message in error, or if you have any questions, kindly contact support@onelab.eu.</p>
+<br>
+<b>First name :</b> {{first_name}}<br>
+<b>Last name :</b> {{last_name}}<br>
+<b>Organization :</b> {{organization}}<br>
+<b>Authority hrn:</b> {{authority_hrn}}<br>
+<b>Public key :</b> {{public_key}}<br>
+<b>Email :</b> {{email}}<br>
+<b>User hrn :</b> {{user_hrn}}<br>
+<b>Portal url :</b> {{ current_site }}<br>
+<p></p>
+<p>You can validate the user <a href="http://{{current_site}}/portal/validate">here</a>.<p>
+<p>Please note that the validation request will only become visible to you on the OneLab portal once the user has confirmed his/her email address.</p>
--- /dev/null
+NEW USER REQUEST
+
+You are receiving this request because we have you listed as a manager at an organization that uses OneLab.
+If you believe that you have received this message in error, or if you have any questions, kindly contact support@onelab.eu.
+
+First name : {{first_name}}
+Last name : {{last_name}}
+Organization :{{organization}}
+Authority hrn: {{authority_hrn}}
+Public key : {{public_key}}
+Email : {{email}}
+User hrn : {{user_hrn}}
+Portal url : {{ current_site }}
+
+You can validate the user here: http://{{current_site}}/portal/validate
+
+Please note that the validation request will only become visible to you on the OneLab portal once the user has confirmed his/her email address.
+
+
--- /dev/null
+<div class="login-form">
+ {% if state %}
+ <span class="help-block">{{ state }}</span>
+ {% endif %}
+ <form action="/login/" method="post" role="form">
+ {% csrf_token %}
+ {% if next %}
+ <input type="hidden" name="next" value="{{ next }}" />
+ {% endif %}
+ <div class="form-group">
+ <input type="email" name="username" placeholder="Enter Email / Username">
+ </div>
+ <div class="form-group">
+ <input type="password" name="password" placeholder="Password">
+ </div>
+ <div class="login-submit">
+ <input type="submit" class="btn btn-onelab" value="Sign In" />
+ <span class="lost-password"> | <a href="/portal/pass_reset/">Can't access your account?</a></span>
+ </div>
+ <div class="login-signup">
+ You don't have yet an account?
+
+ <a href="/portal/register">Sign Up!</a>
+ </div>
+ </form>
+</div>
--- /dev/null
+<div class="alert alert-info alert-dismissable">
+<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>
+<span class="glyphicon glyphicon-globe"></span>
+The <b>OneLab</b> Portal opens with the <b>PlanetLab Europe</b>, <b>IOTLab</b> and <b>NITOS</b> testbeds!
+</div>
\ No newline at end of file
--- /dev/null
+<div class="container">
+ <div class="row">
+ <div class="col-md-12">
+ <div class="breadcrumbs">
+ Experiment > {{ slice }}
+ </div>
+ </div>
+ </div>
+</div>
+<div class="container-fluid container-slice">
+<div class="row">
+ <div class="col-md-12">
+{% if section == "resources" %}
+<ul class="nav nav-tabs nav-section">
+ <li><a href="/slice/{{ slice }}#info">Information</a></li>
+ <!-- <li><a href="/slice/{{ slice }}#testbeds">Testbeds</a></li> -->
+ <li class="active"><a class="link" href="/resources/{{ slice }}">Resources</a></li>
+ <li><a href="/slice/{{ slice }}#users">Users</a></li>
+ <!-- <li><a href="/slice/{{ slice }}#experiment">Statistics</a></li> -->
+ <!-- <li><a href="/slice/{{ slice }}#experiment">Measurements</a></li> -->
+ <li><a href="/slice/{{ slice }}#experiment">Tools</a></li>
+</ul>
+{% else %}
+<ul class="nav nav-tabs nav-section">
+ <li class="active"><a href="#info">Information</a></li>
+ <!-- <li class="testbeds"><a href="#testbeds">Testbeds</a></li> -->
+ <li><a class="link" href="/resources/{{ slice }}">Resources</a></li>
+ <li class="users"><a href="#users">Users</a></li>
+ <!-- <li class="statistics"><a href="#experiment">Statistics</a></li> -->
+ <!-- <li class="measurements"><a href="#experiment">Measurements</a></li> -->
+ <li class="experiment"><a href="#experiment">Tools</a></li>
+</ul>
+
+<script>
+$(document).ready(function() {
+ $('.nav-tabs a').click(function (e) {
+ if ($(this).hasClass('link')) return;
+ e.preventDefault();
+ $(this).tab('show');
+ var id = $(this).attr('href').substr(1);
+ $("#" + id).load('/' + id + '/{{ slice }}/');
+ });
+
+ var hash = window.location.hash;
+ if (hash) {
+ $('.nav-tabs a[href='+hash+']').click();
+ } else {
+ $('div#info').load('/info/{{ slice }}/');
+ }
+});
+</script>
+{% endif %}
+</div>
+</div>
+</div>
\ No newline at end of file
<body ng-app="ManifoldApp">
{% block container %}
{% block topmenu %}
- {% include theme|add:"__widget-topmenu.html" %}
+ {% include theme|add:"_widget-topmenu.html" %}
{% endblock topmenu %}
{% include 'messages-transient.html' %}
{% block base_content %}
{% for authority in authorities %}
{% if authority.name %}
{value:"{{ authority.name }}",label:"{{authority.name}}"},
- // to show only full name
- // {% else %}
- // {value:"{{ authority.authority_hrn }}",label:"{{authority.authority_hrn}}"},
+ {% else %}
+ {value:"{{ authority.authority_hrn }}",label:"{{authority.authority_hrn}}"},
{% endif %}
{% endfor %}
{% else %}
{value:"",label:"No authority found !!!"}
{% endif %}
];
+
+ console.log(availableTags);
+
// sorting the list
availableTags.sort(function(a,b){
var nameA=a.value.toLowerCase(), nameB=b.value.toLowerCase();
<ul class="nav nav-tabs">
<li class="active"><a href="#resourcelist" role="tab" data-toggle="tab">Table</a></li>
<li> <a href="#resourcemap" role="tab" data-toggle="tab">Map</a></li>
+ <li> <a href="#resourceflowspace" role="tab" data-toggle="tab">Flowspace</a></li>
<li> <a href="#resourcescheduler" role="tab" data-toggle="tab">Scheduler</a></li>
</ul>
</div>
{{map_resources}}
</div>
<div class="tab-pane" id="resourcescheduler">
- {{scheduler}}
+ {{scheduler}}
+ </div>
+ <div class="tab-pane" id="resourceflowspace">
+ {{resources}}
+ {{flowspaces}}
+ {{flowspaces_form}}
</div>
<!--
<link rel="stylesheet" href="{{ STATIC_URL }}css/jquery-ui.css">
<script>
function get_users_in_slice(authority_hrn){
- console.log(authority_hrn);
$("table#user-tab").html("<tr><th>+/-</th><th>Email</th><th>User hrn</th></tr>");
var slice_users = [];
$.post("/rest/user/",{'filters':{'parent_authority': authority_hrn}}, function( data ) {
$.each( data, function( key, val ) {
auth_hrn = val.authority_hrn;
// Keep only the sub authorities, remove root auth
- if(auth_hrn.indexOf(".") > -1){
+ //if(auth_hrn.indexOf(".") > -1){
list_authorities.push(auth_hrn);
list_authorities.sort();
if(auth_hrn=="{{user_details.parent_authority}}"){
$('#auth_list').val(auth_hrn);
}
- }
+ //}
});
$( "#auth_list" ).autocomplete({
source: list_authorities,
{% block content %}
<div class="row">
- <h1><img src="{{ STATIC_URL }}img/icon_user_small.png" alt="User Registration" /> OneLab Experimenter Registration</h1>
+ <h1><img src="{{ STATIC_URL }}img/icon_user_small.png" alt="User Registration" /> FIBRE Experimenter Registration</h1>
</div>
<div class="row">
--- /dev/null
+{# This is required by insert_above #}{% insert_handler %}<!DOCTYPE html>
+<html lang="en"><head>
+<title>FIBRE - {{ section }}</title>
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<link rel="shortcut icon" href="/static/img/myslice-icon.png">
+{# This is where insert_str will end up #}{% media_container prelude %}
+{% include 'messages-transient-header.html' %}
+<script type="text/javascript"> {# raw js code - use {% insert prelude_js %} ... {% endinsert %} #} {% container prelude_js %}</script>
+<script src="{{ STATIC_URL }}js/jquery.dataTables.min.js"></script>
+<script src="{{ STATIC_URL }}js/bootstrap.datatables.js"></script>
+<script src="{{ STATIC_URL }}js/myslice-ui.js"></script>
+<style type="text/css">{# In case we need to add raw css code #}{% container prelude_css %}</style>
+{{ header_prelude }}
+{% block head %} {% endblock head %}
+{# let's add these ones no matter what #}
+{% insert_str prelude "js/jquery.min.js" %}
+{% insert_str prelude "js/jquery.html5storage.min.js" %}
+{% insert_str prelude "js/messages-runtime.js" %}
+{% insert_str prelude "js/class.js" %}
+{% insert_str prelude "js/plugin-helper.js" %}
+{% insert_str prelude "js/mustache.js" %}
+{% insert_str prelude "js/plugin.js" %}
+{% insert_str prelude "js/manifold.js" %}
+{% insert_str prelude "css/manifold.css" %}
+{% insert_str prelude "css/plugin.css" %}
+<link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}css/{{ theme }}.css">
+</head>
+<body>
+{% block container %}
+ {% block topmenu %}
+ {% include theme|add:"__widget-topmenu.html" %}
+ {% endblock topmenu %}
+ {% include 'messages-transient.html' %}
+ {% block base_content %}
+ {% endblock %}
+{% endblock container %}
+</body>
+</html>