Initial code commit
17
.gitignore
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
*~
|
||||
*.pyc
|
||||
AUTHORS
|
||||
ChangeLog
|
||||
MANIFEST
|
||||
dist/
|
||||
.venv/
|
||||
build/*
|
||||
build-stamp
|
||||
cover/*
|
||||
doc/build/
|
||||
doc/source/api/
|
||||
stackalytics.egg-info/
|
||||
.autogenerated
|
||||
.coverage
|
||||
.testrepository/
|
||||
.tox/
|
4
.gitreview
Normal file
@ -0,0 +1,4 @@
|
||||
[gerrit]
|
||||
host=review.openstack.org
|
||||
port=29418
|
||||
project=stackforge/stackalytics.git
|
4
.testr.conf
Normal file
@ -0,0 +1,4 @@
|
||||
[DEFAULT]
|
||||
test_command=OS_STDOUT_CAPTURE=1 OS_STDERR_CAPTURE=1 ${PYTHON:-python} -m subunit.run discover -t ./ ./tests $LISTOPT $IDOPTION
|
||||
test_id_option=--load-list $IDFILE
|
||||
test_list_option=--list
|
176
LICENSE
Normal file
@ -0,0 +1,176 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
9
MANIFEST.in
Normal file
@ -0,0 +1,9 @@
|
||||
include AUTHORS
|
||||
include README.rst
|
||||
include ChangeLog
|
||||
include LICENSE
|
||||
|
||||
exclude .gitignore
|
||||
exclude .gitreview
|
||||
|
||||
global-exclude *.pyc
|
15
README.rst
Normal file
@ -0,0 +1,15 @@
|
||||
Stackalytics - OpenStack analytics dashboard
|
||||
============================================
|
||||
|
||||
Application Features
|
||||
--------------------
|
||||
OpenStack Stats is a service that automatically analyzes OpenStack git repos and displays statistics on contribution. The features are:
|
||||
* Extraction of author information from git log, store it in the database;
|
||||
* Calculate metrics on number of lines changed (LOC) and commits;
|
||||
* Mapping authors to companies and launchpad ids;
|
||||
* Filter statistics by time, modules, companies, authors;
|
||||
* Extract blueprint and bug ids from commit messages;
|
||||
* Auto-update of database.
|
||||
|
||||
<todo add instructions>
|
||||
|
31
bin/full-update
Executable file
@ -0,0 +1,31 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [[ -z $STACKALYTICS_HOME ]]; then
|
||||
echo "Variable STACKALYTICS_HOME must be specified"
|
||||
exit
|
||||
fi
|
||||
|
||||
echo "Analytics home is $STACKALYTICS_HOME"
|
||||
|
||||
DASHBOARD_CONF='$STACKALYTICS_HOME/conf/dashboard.conf'
|
||||
|
||||
TOP_DIR=$(cd $(dirname "$0") && pwd)
|
||||
|
||||
DB_FILE=`mktemp -u --tmpdir=$STACKALYTICS_HOME/data stackalytics-XXXXXXXXXXXX.sqlite`
|
||||
TEMP_CONF=`mktemp -u`
|
||||
|
||||
cd $TOP_DIR/../scripts/
|
||||
./pull-repos.sh
|
||||
|
||||
cd $TOP_DIR/../
|
||||
./bin/stackalytics --config-file $STACKALYTICS_HOME/conf/analytics.conf --db-database $DB_FILE --verbose
|
||||
|
||||
DATE=`date -u +'%d-%b-%y %H:%M %Z'`
|
||||
|
||||
echo DATABASE = \'$DB_FILE\' >> $TEMP_CONF
|
||||
echo LAST_UPDATE = \'$DATE\' >> $TEMP_CONF
|
||||
|
||||
#rm $DASHBOARD_CONF
|
||||
#mv $TEMP_CONF $DASHBOARD_CONF
|
||||
|
||||
echo "Data is refreshed, please restart service"
|
5
bin/grab-unmapped
Executable file
@ -0,0 +1,5 @@
|
||||
#!/bin/bash
|
||||
|
||||
TOP_DIR=$(cd $(dirname "$0") && pwd)
|
||||
|
||||
./tools/with_venv.sh python scripts/launchpad/grab-unmapped-launchpad-ids.py
|
11
bin/stackalytics
Executable file
@ -0,0 +1,11 @@
|
||||
#!.venv/bin/python
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
import os
|
||||
import sys
|
||||
sys.path.insert(0, os.getcwd())
|
||||
|
||||
from pycvsanaly2.main import main
|
||||
|
||||
|
||||
main()
|
11
bin/stackalytics-dashboard
Executable file
@ -0,0 +1,11 @@
|
||||
#!.venv/bin/python
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
import os
|
||||
import sys
|
||||
sys.path.insert(0, os.getcwd())
|
||||
|
||||
from dashboard.dashboard import app
|
||||
|
||||
|
||||
app.run()
|
18
bin/update
Executable file
@ -0,0 +1,18 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [[ -z $STACKALYTICS_HOME ]]; then
|
||||
echo "Variable STACKALYTICS_HOME must be specified"
|
||||
exit
|
||||
fi
|
||||
|
||||
echo "Analytics home is $STACKALYTICS_HOME"
|
||||
|
||||
CONF="$STACKALYTICS_HOME/conf/analytics.conf"
|
||||
|
||||
TOP_DIR=$(cd $(dirname "$0") && pwd)
|
||||
cd $TOP_DIR/../scripts/
|
||||
./pull-repos.sh
|
||||
|
||||
echo "Updating data"
|
||||
cd $TOP_DIR/../
|
||||
./bin/stackalytics --config-file $CONF --db-database $STACKALYTICS_HOME/data/stackalyticss.sqlite --verbose
|
0
dashboard/__init__.py
Normal file
987
dashboard/dashboard.py
Normal file
@ -0,0 +1,987 @@
|
||||
# Copyright (C) 2013 Mirantis Inc
|
||||
#
|
||||
# Author: Ilya Shakhat <ishakhat@mirantis.com>
|
||||
|
||||
import cgi
|
||||
|
||||
import datetime as DT
|
||||
import functools
|
||||
import itertools
|
||||
import json
|
||||
import re
|
||||
import sqlite3
|
||||
import time
|
||||
import urllib
|
||||
|
||||
import flask
|
||||
from flask.ext import gravatar as gravatar_ext
|
||||
from werkzeug.contrib import cache as cache_package
|
||||
|
||||
DATABASE = 'stackalytics.sqlite'
|
||||
LAST_UPDATE = None
|
||||
DEBUG = False
|
||||
CACHE_ENABLED = False
|
||||
CACHE_EXPIRATION = 5 * 60
|
||||
CACHE_TYPE = 'simple'
|
||||
|
||||
# create our little application :)
|
||||
app = flask.Flask(__name__)
|
||||
app.config.from_object(__name__)
|
||||
app.config.from_envvar('DASHBOARD_CONF', silent=True)
|
||||
|
||||
if app.config['CACHE_TYPE'] == 'memcached':
|
||||
cache = cache_package.MemcachedCache(['127.0.0.1:11211'])
|
||||
else:
|
||||
cache = cache_package.SimpleCache()
|
||||
|
||||
|
||||
# DB COMMON FUNCS ************************************************************
|
||||
|
||||
|
||||
def get_db():
|
||||
"""Opens a new database connection if there is none yet for the
|
||||
current application context.
|
||||
"""
|
||||
top = flask._app_ctx_stack.top
|
||||
if not hasattr(top, 'sqlite_db'):
|
||||
top.sqlite_db = sqlite3.dbapi2.connect(app.config['DATABASE'])
|
||||
top.sqlite_db.row_factory = sqlite3.dbapi2.Row
|
||||
return top.sqlite_db
|
||||
|
||||
|
||||
@app.teardown_appcontext
|
||||
def close_database(exception):
|
||||
"""Closes the database again at the end of the request."""
|
||||
top = flask._app_ctx_stack.top
|
||||
if hasattr(top, 'sqlite_db'):
|
||||
top.sqlite_db.close()
|
||||
|
||||
|
||||
def query_db(query, args=(), one=False):
|
||||
"""Queries the database and returns a list of dictionaries."""
|
||||
app.logger.debug(query)
|
||||
cur = get_db().execute(query, args)
|
||||
rv = cur.fetchall()
|
||||
return (rv[0] if rv else None) if one else rv
|
||||
|
||||
|
||||
# DECORATORS *****************************************************************
|
||||
|
||||
def cached(timeout=app.config['CACHE_EXPIRATION'], key='view/%s', params=None):
|
||||
def decorator(f):
|
||||
@functools.wraps(f)
|
||||
def decorated_function(*args, **kwargs):
|
||||
if app.config['CACHE_ENABLED']:
|
||||
cache_key = key % flask.request.path
|
||||
if params:
|
||||
cache_key += '/' + '/'.join(
|
||||
[param + '=' + (flask.request.args.get(param) or '')
|
||||
for param in params]
|
||||
)
|
||||
cache_key = cache_key.replace(' ', '+')
|
||||
app.logger.debug('Cache key %s' % cache_key)
|
||||
rv = cache.get(cache_key)
|
||||
app.logger.debug('Got value from the cache \n%s' % rv)
|
||||
if rv is not None:
|
||||
return rv
|
||||
rv = f(*args, **kwargs)
|
||||
cache.set(cache_key, rv, timeout=timeout)
|
||||
app.logger.debug('Set the cache \n%s' % rv)
|
||||
return rv
|
||||
else:
|
||||
return f(*args, **kwargs)
|
||||
return decorated_function
|
||||
return decorator
|
||||
|
||||
|
||||
def templated(template=None):
|
||||
def decorator(f):
|
||||
@functools.wraps(f)
|
||||
def decorated_function(*args, **kwargs):
|
||||
template_name = template
|
||||
if template_name is None:
|
||||
template_name = (flask.request.endpoint.replace('.', '/') +
|
||||
'.html')
|
||||
ctx = f(*args, **kwargs)
|
||||
if ctx is None:
|
||||
ctx = {}
|
||||
elif not isinstance(ctx, dict):
|
||||
return ctx
|
||||
|
||||
# put parameters into template
|
||||
metric = flask.request.args.get('metric')
|
||||
if metric not in METRIC_LABELS:
|
||||
metric = None
|
||||
ctx['metric'] = metric or DEFAULT_METRIC
|
||||
|
||||
period = flask.request.args.get('period')
|
||||
if period not in PERIOD_LABELS:
|
||||
period = None
|
||||
ctx['period'] = period or DEFAULT_PERIOD
|
||||
ctx['metric_label'] = METRIC_LABELS[ctx['metric']]
|
||||
ctx['period_label'] = PERIOD_LABELS[ctx['period']]
|
||||
|
||||
project_type = flask.request.args.get('project_type')
|
||||
if project_type not in PROJECT_TYPES:
|
||||
project_type = None
|
||||
ctx['project_type'] = project_type or DEFAULT_PROJECT_TYPE
|
||||
|
||||
ctx['last_update'] = app.config['LAST_UPDATE']
|
||||
|
||||
return flask.render_template(template_name, **ctx)
|
||||
return decorated_function
|
||||
return decorator
|
||||
|
||||
|
||||
def verified():
|
||||
def decorator(f):
|
||||
@functools.wraps(f)
|
||||
def decorated_function(*args, **kwargs):
|
||||
if 'project_type' in kwargs:
|
||||
if kwargs['project_type'] not in ['CORE', 'INCUBATION', 'ALL']:
|
||||
flask.abort(404)
|
||||
if 'module' in kwargs:
|
||||
res = query_db('select 1 from repositories where name = ?',
|
||||
[kwargs['module'] + '.git'])
|
||||
if not res:
|
||||
flask.abort(404)
|
||||
if 'company' in kwargs:
|
||||
company = urllib.unquote_plus(kwargs['company']).lower()
|
||||
res = query_db('select companies.name from people '
|
||||
'join companies '
|
||||
'on people.company_id = companies.id '
|
||||
'where lower(companies.name) = ?',
|
||||
[company])
|
||||
if not res:
|
||||
flask.abort(404)
|
||||
kwargs['company'] = res[0][0]
|
||||
if 'engineer' in kwargs:
|
||||
res = query_db('select 1 from people where launchpad_id = ?',
|
||||
[kwargs['engineer']])
|
||||
if not res:
|
||||
flask.abort(404)
|
||||
return f(*args, **kwargs)
|
||||
return decorated_function
|
||||
return decorator
|
||||
|
||||
|
||||
# UTIL FUNCS *****************************************************************
|
||||
|
||||
def clear_text(s):
|
||||
a = cgi.escape('\n'.join([a.strip() for a in s.split('\n') if a.strip()]))
|
||||
first, nl, remain = a.partition('\n')
|
||||
return '<b>' + first + '</b>' + nl + nl + remain
|
||||
|
||||
|
||||
def link_blueprint(s, module):
|
||||
return re.sub(r'(blueprint\s+)([\w-]+)',
|
||||
r'\1<a href="https://blueprints.launchpad.net/' +
|
||||
module + r'/+spec/\2">\2</a>',
|
||||
s)
|
||||
|
||||
|
||||
def link_bug(s):
|
||||
return re.sub(r'([B|b]ug\s+)#?([\d]{5,7})',
|
||||
r'\1<a href="https://bugs.launchpad.net/bugs/\2">\2</a>',
|
||||
s)
|
||||
|
||||
|
||||
def link_change_id(s):
|
||||
return re.sub(r'(I[0-9a-f]{40})',
|
||||
r'<a href="https://review.openstack.org/#q,\1,n,z">\1</a>',
|
||||
s)
|
||||
|
||||
|
||||
def filter_over_limit(data, limit):
|
||||
if 1 < limit < len(data):
|
||||
s = 0
|
||||
for rec in data[limit - 1:]:
|
||||
s += rec['rank']
|
||||
data[limit - 1] = data[0].copy()
|
||||
data[limit - 1]['name'] = 'others'
|
||||
data[limit - 1]['rank'] = s
|
||||
data = data[:limit]
|
||||
return data
|
||||
|
||||
|
||||
def paste_links(data, base_uri, metric, period, project_type):
|
||||
for one in data:
|
||||
if one['name']:
|
||||
one['link'] = ('<a href="/' + base_uri +
|
||||
urllib.quote_plus(one['name']) +
|
||||
'?metric=' + metric +
|
||||
'&period=' + period +
|
||||
'&project_type=' + project_type +
|
||||
'">' + (one['name']) + '</a>')
|
||||
else:
|
||||
one['link'] = '<i>Unmapped</i>'
|
||||
return data
|
||||
|
||||
|
||||
def index_column(data):
|
||||
n = 1
|
||||
for one in data:
|
||||
if one['name'] is None or one['name'][0] == '*':
|
||||
one['index'] = ''
|
||||
else:
|
||||
one['index'] = n
|
||||
n += 1
|
||||
return data
|
||||
|
||||
DEFAULT_METRIC = 'loc'
|
||||
DEFAULT_PERIOD = 'havana'
|
||||
DEFAULT_PROJECT_TYPE = 'incubation'
|
||||
|
||||
PERIODS = {
|
||||
'all': (DT.date(2010, 05, 1), DT.date(2013, 10, 1)),
|
||||
'essex': (DT.date(2011, 10, 1), DT.date(2012, 04, 1)),
|
||||
'folsom': (DT.date(2012, 04, 1), DT.date(2012, 10, 1)),
|
||||
'grizzly': (DT.date(2012, 10, 1), DT.date(2013, 04, 1)),
|
||||
'havana': (DT.date(2013, 04, 1), DT.date(2013, 10, 1)),
|
||||
}
|
||||
|
||||
INDEPENDENT = '*independent'
|
||||
|
||||
METRIC_LABELS = {
|
||||
'loc': 'Lines of code',
|
||||
'commits': 'Commits',
|
||||
}
|
||||
|
||||
PERIOD_LABELS = {
|
||||
'all': 'All times',
|
||||
'six_months': 'Last 6 months',
|
||||
'essex': 'Essex',
|
||||
'folsom': 'Folsom',
|
||||
'grizzly': 'Grizzly',
|
||||
'havana': 'Havana',
|
||||
}
|
||||
|
||||
PROJECT_TYPES = {
|
||||
'core': ['core'],
|
||||
'incubation': ['core', 'incubation'],
|
||||
'all': ['core', 'incubation', 'dev'],
|
||||
}
|
||||
|
||||
ISSUE_TYPES = ['bug', 'blueprint']
|
||||
|
||||
|
||||
def extract_time_period(period):
|
||||
begin = DT.date(2010, 2, 1)
|
||||
end = DT.datetime.now().date()
|
||||
|
||||
if not period or period == 'six_months':
|
||||
begin = end - DT.timedelta(days=182)
|
||||
elif period == 'all':
|
||||
begin = PERIODS[period][0]
|
||||
elif period in PERIODS:
|
||||
begin, end = PERIODS[period]
|
||||
|
||||
return begin, end
|
||||
|
||||
|
||||
def parse_time_period(period):
|
||||
begin, end = extract_time_period(period)
|
||||
return DT.date.isoformat(begin), DT.date.isoformat(end)
|
||||
|
||||
|
||||
def parse_date_from_string_to_timestamp(datestring):
|
||||
d = DT.datetime.strptime(datestring, "%Y-%m-%d %H:%M:%S")
|
||||
return time.mktime(d.timetuple())
|
||||
|
||||
|
||||
def get_period_filter(period):
|
||||
return '''
|
||||
and scmlog.date > ? and scmlog.date <= ?
|
||||
'''
|
||||
|
||||
|
||||
def get_metric_filter(metric):
|
||||
if metric == 'loc':
|
||||
metric_filter = 'sum(commits_lines.added) + sum(commits_lines.removed)'
|
||||
else:
|
||||
metric_filter = 'count(*)'
|
||||
return metric_filter
|
||||
|
||||
|
||||
def get_project_type_filter(project_type):
|
||||
if not project_type:
|
||||
project_type = DEFAULT_PROJECT_TYPE
|
||||
types = PROJECT_TYPES[project_type]
|
||||
fts = ["repositories.project_type = '%s'" % t for t in types]
|
||||
return 'and (' + ' or '.join(fts) + ')'
|
||||
|
||||
|
||||
def extract_params():
|
||||
module = flask.request.args.get('module')
|
||||
limit = int(flask.request.args.get('limit') or 0)
|
||||
period = flask.request.args.get('period') or DEFAULT_PERIOD
|
||||
metric = flask.request.args.get('metric') or DEFAULT_METRIC
|
||||
project_type = (flask.request.args.get('project_type')
|
||||
or DEFAULT_PROJECT_TYPE)
|
||||
return module, limit, period, metric, project_type
|
||||
|
||||
|
||||
def row2dict(a):
|
||||
r = {}
|
||||
for key in a.keys():
|
||||
r.update({key: a[key]})
|
||||
return r
|
||||
|
||||
|
||||
# UI HANDLERS ****************************************************************
|
||||
# these handle page rendering
|
||||
|
||||
@app.route('/')
|
||||
@templated('companies.html')
|
||||
def overview():
|
||||
return {}
|
||||
|
||||
|
||||
@app.errorhandler(404)
|
||||
def page_not_found(e):
|
||||
return flask.render_template('404.html'), 404
|
||||
|
||||
|
||||
@app.route('/companies')
|
||||
@app.route('/companies/')
|
||||
@app.route('/modules')
|
||||
@app.route('/modules/')
|
||||
def redirects():
|
||||
return flask.redirect(flask.url_for('overview'))
|
||||
|
||||
|
||||
@app.route('/companies/<company>')
|
||||
@templated()
|
||||
@cached(params=['period', 'project_type'])
|
||||
@verified()
|
||||
def company_details(company):
|
||||
details = contribution_details(flask.request.args.get('period'),
|
||||
flask.request.args.get('project_type'),
|
||||
company=company)
|
||||
details.update({
|
||||
'company': company,
|
||||
})
|
||||
return details
|
||||
|
||||
|
||||
@app.route('/engineers/')
|
||||
@templated()
|
||||
def engineers():
|
||||
return {}
|
||||
|
||||
|
||||
@app.route('/modules/<module>')
|
||||
@templated()
|
||||
@cached()
|
||||
@verified()
|
||||
def module_details(module):
|
||||
commits_res = query_db('''
|
||||
select scmlog.date, scmlog.message, people.launchpad_id, people.name,
|
||||
people.email, companies.name as company from scmlog
|
||||
join people on scmlog.author_id = people.id
|
||||
join companies on people.company_id = companies.id
|
||||
where
|
||||
people.launchpad_id not null
|
||||
and scmlog.id in (
|
||||
select actions.commit_id from actions
|
||||
join branches on branches.id = actions.branch_id
|
||||
where branches.name = 'master'
|
||||
)
|
||||
and scmlog.repository_id in (
|
||||
select repositories.id from repositories
|
||||
where repositories.name = ?
|
||||
)
|
||||
order by scmlog.date desc
|
||||
limit 50
|
||||
''', [module + '.git'])
|
||||
|
||||
commits = []
|
||||
for record in commits_res:
|
||||
message = record['message']
|
||||
|
||||
m = re.search(r'bug\s+(\d{5,7})', message)
|
||||
if m:
|
||||
ref = ('Bug: <a href="https://bugs.launchpad.net/bugs/' +
|
||||
m.group(1) + '">' + m.group(1) + '</a>')
|
||||
else:
|
||||
m = re.search(r'blueprint\s+([\w-]+)', message)
|
||||
if m:
|
||||
ref = ('Blueprint: '
|
||||
'<a href="https://blueprints.launchpad.net/' +
|
||||
module + '/+spec/' + m.group(1) + '">' +
|
||||
m.group(1) + '</a>')
|
||||
else:
|
||||
ref = None
|
||||
|
||||
m = re.search(r'(I[0-9a-f]{40})', message)
|
||||
if m:
|
||||
change_id = m.group(1)
|
||||
else:
|
||||
change_id = None
|
||||
|
||||
company = record['company']
|
||||
if company == INDEPENDENT:
|
||||
company = None
|
||||
|
||||
text = message.split('\n')[0].strip()
|
||||
|
||||
commits.append(
|
||||
{'date': parse_date_from_string_to_timestamp(record['date']),
|
||||
'ref': ref, 'text': text,
|
||||
'change_id': change_id,
|
||||
'launchpad_id': record['launchpad_id'],
|
||||
'name': record['name'], 'email': record['email'],
|
||||
'company': company})
|
||||
|
||||
return {'module': module, 'commits': commits}
|
||||
|
||||
|
||||
def contribution_details(period, project_type, engineer=None, company=None):
|
||||
if engineer:
|
||||
people_filter = 'people.launchpad_id'
|
||||
people_param = engineer
|
||||
elif company:
|
||||
people_filter = 'companies.name'
|
||||
people_param = company
|
||||
else:
|
||||
return None
|
||||
|
||||
time_period = parse_time_period(period)
|
||||
|
||||
commits_res = query_db('''
|
||||
select scmlog.message, scmlog.date, repositories.name as repo,
|
||||
details.change_id, details.issue_type, details.issue_id,
|
||||
details.commit_type, commits_lines.added, commits_lines.removed
|
||||
from scmlog
|
||||
join repositories on scmlog.repository_id = repositories.id
|
||||
join details on scmlog.id = details.commit_id
|
||||
join commits_lines on commits_lines.commit_id = scmlog.id
|
||||
where
|
||||
scmlog.author_id in (
|
||||
select people.id from people
|
||||
join companies on people.company_id = companies.id
|
||||
where ''' + people_filter + ''' = ?
|
||||
)
|
||||
and scmlog.id in (
|
||||
select actions.commit_id from actions
|
||||
join branches on branches.id = actions.branch_id
|
||||
where branches.name = 'master'
|
||||
)
|
||||
''' + get_period_filter(period) +
|
||||
get_project_type_filter(project_type) + '''
|
||||
order by scmlog.date desc
|
||||
''', [people_param, time_period[0], time_period[1]])
|
||||
|
||||
blueprints = set()
|
||||
bugs = set()
|
||||
commits = []
|
||||
code_only_commits = 0
|
||||
test_only_commits = 0
|
||||
code_and_test_commits = 0
|
||||
loc = 0
|
||||
|
||||
for c in commits_res:
|
||||
module = c['repo'].rpartition('.')[0]
|
||||
issue_type = c['issue_type']
|
||||
issue_id = c['issue_id']
|
||||
commit_type = c['commit_type']
|
||||
loc += c['added'] + c['removed']
|
||||
|
||||
is_code = commit_type & 0x1
|
||||
if commit_type == 1:
|
||||
code_only_commits += 1
|
||||
is_test = commit_type & 0x2
|
||||
if commit_type == 2:
|
||||
test_only_commits += 1
|
||||
if commit_type == 3:
|
||||
code_and_test_commits += 1
|
||||
|
||||
if issue_type == 'blueprint':
|
||||
blueprints.add((issue_id, module))
|
||||
elif issue_type == 'bug':
|
||||
bugs.add((issue_id, is_code, is_test))
|
||||
|
||||
commits.append({
|
||||
'message': link_change_id(link_bug(link_blueprint(
|
||||
clear_text(c['message']), module))),
|
||||
'date': parse_date_from_string_to_timestamp(c['date']),
|
||||
'module': module,
|
||||
'is_code': is_code,
|
||||
'is_test': is_test,
|
||||
'added_loc': c['added'],
|
||||
'removed_loc': c['removed'],
|
||||
})
|
||||
|
||||
return {
|
||||
'commits': commits,
|
||||
'blueprints': sorted(blueprints),
|
||||
'bugs': sorted(bugs, key=lambda rec: rec[0]),
|
||||
'code_only_commits': code_only_commits,
|
||||
'test_only_commits': test_only_commits,
|
||||
'code_and_test_commits': code_and_test_commits,
|
||||
'code_commits': (code_only_commits + test_only_commits +
|
||||
code_and_test_commits),
|
||||
'non_code_commits': (len(commits) - code_only_commits -
|
||||
test_only_commits - code_and_test_commits),
|
||||
'loc': loc,
|
||||
}
|
||||
|
||||
|
||||
@app.route('/engineers/<engineer>')
|
||||
@templated()
|
||||
@cached(params=['period', 'project_type'])
|
||||
@verified()
|
||||
def engineer_details(engineer):
|
||||
details_res = query_db('''
|
||||
select people.name, companies.name as company,
|
||||
launchpad_id, email from people
|
||||
join companies on people.company_id = companies.id
|
||||
where people.launchpad_id = ? and end_date is null
|
||||
''', [engineer])
|
||||
|
||||
if not details_res:
|
||||
flask.abort(404)
|
||||
|
||||
details = row2dict(details_res[0])
|
||||
|
||||
commits = contribution_details(flask.request.args.get('period'),
|
||||
flask.request.args.get('project_type'),
|
||||
engineer=engineer)
|
||||
commits.update({
|
||||
'engineer': engineer,
|
||||
'details': details,
|
||||
})
|
||||
|
||||
return commits
|
||||
|
||||
|
||||
@app.route('/commits/')
|
||||
@app.route('/commits/<issue_type>')
|
||||
@templated()
|
||||
@cached(params=['module', 'period', 'project_type'])
|
||||
@verified()
|
||||
def commits(issue_type=None):
|
||||
if issue_type is not None and issue_type not in ISSUE_TYPES:
|
||||
flask.abort(404)
|
||||
|
||||
module, limit, period, metric, project_type = extract_params()
|
||||
time_period = parse_time_period(period)
|
||||
|
||||
res = query_db('''
|
||||
select scmlog.date, scmlog.message, repositories.name as repo,
|
||||
details.issue_id, details.issue_type, details.change_id,
|
||||
people.launchpad_id, people.name as author, companies.name as company,
|
||||
people.email
|
||||
from scmlog
|
||||
join people on people.id = scmlog.author_id
|
||||
join companies on people.company_id = companies.id
|
||||
join repositories on repositories.id = scmlog.repository_id
|
||||
join details on details.commit_id = scmlog.id
|
||||
where
|
||||
1 = 1
|
||||
''' + get_period_filter(period) + get_project_type_filter(project_type) + '''
|
||||
order by scmlog.date desc
|
||||
limit 2000
|
||||
''', [time_period[0], time_period[1]])
|
||||
|
||||
issues = {}
|
||||
for rec in res:
|
||||
#todo make it right (e.g. paging)
|
||||
if len(issues) > 200:
|
||||
break
|
||||
|
||||
if issue_type is not None and issue_type != rec['issue_type']:
|
||||
continue
|
||||
|
||||
module = rec['repo'].rpartition('.')[0]
|
||||
timestamp = parse_date_from_string_to_timestamp(rec['date'])
|
||||
item = {
|
||||
'message': link_change_id(link_bug(link_blueprint(
|
||||
clear_text(rec['message']), module))),
|
||||
'date': timestamp,
|
||||
'change_id': rec['change_id'],
|
||||
'author': rec['author'],
|
||||
'company': rec['company'],
|
||||
'launchpad_id': rec['launchpad_id'],
|
||||
'email': rec['email'],
|
||||
'module': module,
|
||||
}
|
||||
|
||||
if issue_type is None:
|
||||
key = DT.datetime.utcfromtimestamp(timestamp).strftime('%d %b %Y')
|
||||
else:
|
||||
key = rec['issue_id']
|
||||
|
||||
if key in issues:
|
||||
issues[key].append(item)
|
||||
else:
|
||||
issues[key] = [item]
|
||||
|
||||
return {'issue_type': issue_type,
|
||||
'issues': sorted(
|
||||
[{'issue_id': key, 'items': value} for key, value in
|
||||
issues.iteritems()], key=lambda rec: rec['items'][0]['date'],
|
||||
reverse=True)}
|
||||
|
||||
|
||||
@app.route('/unmapped')
|
||||
@templated()
|
||||
def unmapped():
|
||||
res = query_db('''
|
||||
select name, email from people
|
||||
where launchpad_id is null
|
||||
''')
|
||||
|
||||
if not res:
|
||||
flask.abort(404)
|
||||
|
||||
res = [{'name': a['name'], 'email': a['email']} for a in res
|
||||
if (re.match(r'[\w\d._-]+@[\w\d_.-]+$', a['email']) and
|
||||
a['name'] and a['name'] != 'root')]
|
||||
|
||||
return {'details': res}
|
||||
|
||||
|
||||
# AJAX HANDLERS **************************************************************
|
||||
# these handle data retrieval for tables and charts
|
||||
|
||||
|
||||
@app.route('/data/companies')
|
||||
@cached(params=['limit', 'module', 'period', 'metric', 'project_type'])
|
||||
def get_companies():
|
||||
module, limit, period, metric, project_type = extract_params()
|
||||
|
||||
params = []
|
||||
|
||||
if module:
|
||||
module_filter = '''
|
||||
and scmlog.repository_id in (
|
||||
select repositories.id from repositories
|
||||
where repositories.name = ?
|
||||
)
|
||||
'''
|
||||
params.append(module + '.git')
|
||||
else:
|
||||
module_filter = ''
|
||||
|
||||
metric_filter = get_metric_filter(metric)
|
||||
|
||||
time_period = parse_time_period(period)
|
||||
params.append(time_period[0])
|
||||
params.append(time_period[1])
|
||||
|
||||
raw = query_db('''
|
||||
select companies.name as company, ''' + metric_filter + ''' as rank from scmlog
|
||||
join people on scmlog.author_id = people.id
|
||||
join companies on people.company_id = companies.id
|
||||
join commits_lines on commits_lines.commit_id = scmlog.id
|
||||
join repositories on scmlog.repository_id = repositories.id
|
||||
where
|
||||
companies.name != '*robots'
|
||||
and scmlog.id in (
|
||||
select actions.commit_id from actions
|
||||
join branches on branches.id = actions.branch_id
|
||||
where branches.name = 'master'
|
||||
)''' + module_filter + get_period_filter(period) +
|
||||
get_project_type_filter(project_type) + '''
|
||||
group by people.company_id
|
||||
order by rank desc
|
||||
''', params)
|
||||
|
||||
data = [{'name': rec['company'], 'rank': rec['rank']}
|
||||
for rec in raw
|
||||
if rec['company'] is not None]
|
||||
data = index_column(
|
||||
paste_links(filter_over_limit(data, limit), 'companies/', metric,
|
||||
period, project_type))
|
||||
return json.dumps({'aaData': data})
|
||||
|
||||
|
||||
@app.route('/data/companies/<company>')
|
||||
@cached(params=['limit', 'period', 'metric', 'project_type'])
|
||||
@verified()
|
||||
def get_company_details(company):
|
||||
module, limit, period, metric, project_type = extract_params()
|
||||
time_period = parse_time_period(period)
|
||||
|
||||
raw = query_db('''
|
||||
select ''' + get_metric_filter(metric) + ''' as rank, people.name,
|
||||
people.launchpad_id from people
|
||||
left join (
|
||||
select * from scmlog
|
||||
join actions on actions.commit_id = scmlog.id
|
||||
join branches on branches.id = actions.branch_id
|
||||
join repositories on scmlog.repository_id = repositories.id
|
||||
where branches.name = 'master'
|
||||
''' + get_period_filter(period) + get_project_type_filter(project_type) + '''
|
||||
group by scmlog.id
|
||||
) as scm on people.id = scm.author_id
|
||||
join commits_lines on commits_lines.commit_id = scm.id
|
||||
join companies on people.company_id = companies.id
|
||||
where companies.name = ?
|
||||
group by people.name
|
||||
order by rank desc
|
||||
''', [time_period[0], time_period[1], company])
|
||||
|
||||
data = [{'rank': rec[0], 'name': rec[1], 'launchpad_id': rec[2]}
|
||||
for rec in raw]
|
||||
data = index_column(filter_over_limit(data, limit))
|
||||
for one in data:
|
||||
if one['launchpad_id']:
|
||||
one['link'] = ('<a href="/engineers/' + (one['launchpad_id']) +
|
||||
'?metric=' + metric + '&period=' + period +
|
||||
'&project_type=' + project_type + '">' +
|
||||
(one['name']) + '</a>')
|
||||
else:
|
||||
one['link'] = one['name']
|
||||
return json.dumps({'aaData': data})
|
||||
|
||||
|
||||
@app.route('/data/modules')
|
||||
@cached(params=['limit', 'company', 'engineer', 'period', 'metric',
|
||||
'project_type'])
|
||||
def get_modules():
|
||||
module, limit, period, metric, project_type = extract_params()
|
||||
company = flask.request.args.get('company')
|
||||
engineer = flask.request.args.get('engineer')
|
||||
|
||||
params = []
|
||||
|
||||
if engineer:
|
||||
eng_filter = "and people.launchpad_id = ?"
|
||||
params.append(engineer)
|
||||
else:
|
||||
eng_filter = ''
|
||||
if company:
|
||||
company_filter = "and companies.name = ?"
|
||||
params.append(company)
|
||||
else:
|
||||
# if no company filter out all robots
|
||||
company_filter = "and companies.name != '*robots'"
|
||||
|
||||
time_period = parse_time_period(period)
|
||||
params.append(time_period[0])
|
||||
params.append(time_period[1])
|
||||
|
||||
raw = query_db('''
|
||||
select repositories.name as repo, ''' + get_metric_filter(metric) + ''' as rank
|
||||
from scmlog
|
||||
join people on scmlog.author_id = people.id
|
||||
join repositories on scmlog.repository_id = repositories.id
|
||||
join commits_lines on commits_lines.commit_id = scmlog.id
|
||||
join companies on people.company_id = companies.id
|
||||
where
|
||||
scmlog.id in (
|
||||
select actions.commit_id from actions
|
||||
join branches on branches.id = actions.branch_id
|
||||
where branches.name = 'master'
|
||||
)
|
||||
''' + eng_filter + company_filter + get_period_filter(period) +
|
||||
get_project_type_filter(project_type) + '''
|
||||
group by scmlog.repository_id
|
||||
order by rank desc
|
||||
''', params)
|
||||
|
||||
data = [{'name': rec[0].rpartition('.')[0], 'rank': rec[1]} for rec in raw]
|
||||
data = index_column(
|
||||
paste_links(filter_over_limit(data, limit), 'modules/', metric, period,
|
||||
project_type))
|
||||
return json.dumps({'aaData': data})
|
||||
|
||||
|
||||
@app.route('/data/engineers')
|
||||
@cached(params=['limit', 'module', 'period', 'metric', 'project_type'])
|
||||
def get_engineers():
|
||||
module, limit, period, metric, project_type = extract_params()
|
||||
|
||||
params = []
|
||||
|
||||
if module:
|
||||
module_filter = '''
|
||||
and scmlog.repository_id in (
|
||||
select repositories.id from repositories
|
||||
where repositories.name = ?
|
||||
)
|
||||
'''
|
||||
params.append(module + '.git')
|
||||
else:
|
||||
module_filter = ''
|
||||
|
||||
metric_filter = get_metric_filter(metric)
|
||||
|
||||
time_period = parse_time_period(period)
|
||||
params.append(time_period[0])
|
||||
params.append(time_period[1])
|
||||
|
||||
raw = query_db('''
|
||||
select people.name, people.launchpad_id, ''' + metric_filter + ''' as rank
|
||||
from scmlog
|
||||
join people on scmlog.author_id = people.id
|
||||
join commits_lines on commits_lines.commit_id = scmlog.id
|
||||
join repositories on scmlog.repository_id = repositories.id
|
||||
where
|
||||
people.email != 'review@openstack.org'
|
||||
and people.email != 'jenkins@review.openstack.org'
|
||||
and people.email != 'jenkins@openstack.org'
|
||||
and scmlog.id in (
|
||||
select actions.commit_id from actions
|
||||
join branches on branches.id = actions.branch_id
|
||||
where branches.name = 'master'
|
||||
)''' + module_filter + get_period_filter(period) +
|
||||
get_project_type_filter(project_type) +
|
||||
'''
|
||||
group by people.name
|
||||
order by rank desc
|
||||
''', params)
|
||||
|
||||
data = [{'name': rec['name'], 'rank': rec['rank'],
|
||||
'launchpad_id': rec['launchpad_id']} for rec in raw]
|
||||
data = index_column(filter_over_limit(data, limit))
|
||||
for one in data:
|
||||
if one['launchpad_id']:
|
||||
one['link'] = ('<a href="/engineers/' + (one['launchpad_id']) +
|
||||
'?metric=' + metric + '&period=' + period +
|
||||
'&project_type' + project_type + '">' +
|
||||
(one['name']) + '</a>')
|
||||
else:
|
||||
one['link'] = one['name']
|
||||
return json.dumps({'aaData': data})
|
||||
|
||||
|
||||
@app.route('/data/timeline')
|
||||
@cached(params=['company', 'engineer', 'period', 'metric', 'project_type'])
|
||||
def get_timeline():
|
||||
|
||||
company = flask.request.args.get('company')
|
||||
engineer = flask.request.args.get('engineer')
|
||||
module, limit, period, metric, project_type = extract_params()
|
||||
|
||||
params = []
|
||||
if company:
|
||||
company_filter = 'and companies.name = ?'
|
||||
params.append(company)
|
||||
else:
|
||||
company_filter = "and companies.name != '*robots'"
|
||||
|
||||
if engineer:
|
||||
engineer_filter = '''
|
||||
and scmlog.author_id in (
|
||||
select people.id from people
|
||||
where people.launchpad_id = ?
|
||||
)
|
||||
'''
|
||||
params.append(engineer)
|
||||
else:
|
||||
engineer_filter = ''
|
||||
|
||||
if module:
|
||||
module_filter = '''
|
||||
and scmlog.repository_id in (
|
||||
select repositories.id from repositories
|
||||
where repositories.name = ?
|
||||
)
|
||||
'''
|
||||
params.append(module + '.git')
|
||||
else:
|
||||
module_filter = ''
|
||||
|
||||
records = query_db('''
|
||||
select scmlog.date, commits_lines.added + commits_lines.removed as rank
|
||||
from scmlog
|
||||
join commits_lines on commits_lines.commit_id = scmlog.id
|
||||
join people on people.id = scmlog.author_id
|
||||
join repositories on scmlog.repository_id = repositories.id
|
||||
join companies on people.company_id = companies.id
|
||||
where
|
||||
scmlog.id in (
|
||||
select actions.commit_id from actions
|
||||
join branches on branches.id = actions.branch_id
|
||||
where branches.name = 'master'
|
||||
)
|
||||
''' + company_filter + engineer_filter + module_filter +
|
||||
get_project_type_filter(project_type) + '''
|
||||
order by scmlog.date
|
||||
''', params)
|
||||
|
||||
start_date = DT.date(2010, 5, 1)
|
||||
|
||||
def mkdate2(datestring):
|
||||
return DT.datetime.strptime(datestring, "%Y-%m-%d %H:%M:%S").date()
|
||||
|
||||
def week(date):
|
||||
return (date - start_date).days // 7
|
||||
|
||||
def week_rev(n):
|
||||
return start_date + DT.timedelta(days=n * 7)
|
||||
|
||||
dct_rank = {}
|
||||
dct_count = {}
|
||||
t = map(lambda (rec): [mkdate2(str(rec[0])), rec[1]], records)
|
||||
|
||||
for key, grp in itertools.groupby(t, key=lambda (pair): week(pair[0])):
|
||||
grp_as_list = list(grp)
|
||||
dct_rank[key] = sum([x[1] for x in grp_as_list])
|
||||
dct_count[key] = len(grp_as_list)
|
||||
|
||||
last = week(DT.datetime.now().date())
|
||||
res_rank = []
|
||||
res_count = []
|
||||
|
||||
for n in range(1, last + 1):
|
||||
if n not in dct_rank:
|
||||
dct_rank[n] = 0
|
||||
dct_count[n] = 0
|
||||
|
||||
rev = week_rev(n)
|
||||
res_rank.append([str(rev) + ' 0:00AM', dct_rank[n]])
|
||||
res_count.append([str(rev) + ' 0:00AM', dct_count[n]])
|
||||
|
||||
begin, end = extract_time_period(period)
|
||||
begin = week(begin)
|
||||
end = week(end)
|
||||
u_begin = len(res_count) - 52
|
||||
u_end = len(res_count)
|
||||
|
||||
if period == 'all':
|
||||
begin = 0
|
||||
u_begin = 0
|
||||
end = u_end
|
||||
elif period != 'six_months':
|
||||
if u_end > end + 13:
|
||||
u_end = end + 13
|
||||
u_begin = u_end - 52
|
||||
|
||||
return json.dumps([res_count[u_begin:u_end],
|
||||
res_count[begin:end],
|
||||
res_rank[u_begin:u_end]])
|
||||
|
||||
|
||||
# JINJA FILTERS **************************************************************
|
||||
# some useful filters to help with data formatting
|
||||
|
||||
@app.template_filter('datetimeformat')
|
||||
def format_datetime(timestamp):
|
||||
return DT.datetime.utcfromtimestamp(timestamp).strftime('%d %b %Y @ %H:%M')
|
||||
|
||||
|
||||
@app.template_filter('launchpadmodule')
|
||||
def format_launchpad_module_link(module):
|
||||
return '<a href="https://launchpad.net/%s">%s</a>' % (module, module)
|
||||
|
||||
|
||||
@app.template_filter('encode')
|
||||
def safe_encode(s):
|
||||
return urllib.quote_plus(s)
|
||||
|
||||
|
||||
gravatar = gravatar_ext.Gravatar(app,
|
||||
size=100,
|
||||
rating='g',
|
||||
default='wavatar',
|
||||
force_default=False,
|
||||
force_lower=False)
|
||||
|
||||
# APPLICATION LAUNCHER *******************************************************
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run('0.0.0.0')
|
252
dashboard/static/css/jquery.dataTables.css
Normal file
@ -0,0 +1,252 @@
|
||||
|
||||
/*
|
||||
* Table
|
||||
*/
|
||||
table.dataTable {
|
||||
border-spacing:0;
|
||||
margin: 0 auto;
|
||||
clear: both;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
table.dataTable thead th {
|
||||
font-size: 18px;
|
||||
font-weight: normal;
|
||||
border-right: 1px solid #CCC;
|
||||
background-color: #F0F3FA;
|
||||
text-align: left;
|
||||
font-weight: normal;
|
||||
background-image: none;
|
||||
border-bottom: 1px dotted #CECECE;
|
||||
text-shadow: 1px 1px 0px white;
|
||||
padding: 5px 6px;
|
||||
text-align: center;
|
||||
border-top-left-radius: 5px;
|
||||
border-top-right-radius: 5px;
|
||||
cursor: pointer;
|
||||
*cursor: hand;
|
||||
}
|
||||
|
||||
table.dataTable tfoot th {
|
||||
padding: 3px 18px 3px 10px;
|
||||
border-top: 1px solid black;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
table.dataTable td {
|
||||
padding: 3px 10px;
|
||||
}
|
||||
|
||||
table.dataTable td.center,
|
||||
table.dataTable td.dataTables_empty {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
table.dataTable tr.odd { background-color: #fbfafa; }
|
||||
table.dataTable tr.even { background-color: white; }
|
||||
|
||||
table.dataTable tr.odd td.sorting_1 { background-color: #eef1f4; border-right: 1px solid #CCC; }
|
||||
table.dataTable tr.odd td.sorting_2 { background-color: #DADCFF; }
|
||||
table.dataTable tr.odd td.sorting_3 { background-color: #E0E2FF; }
|
||||
table.dataTable tr.even td.sorting_1 { background-color: #f8f9fa; border-right: 1px solid #CCC; }
|
||||
table.dataTable tr.even td.sorting_2 { background-color: #F2F3FF; }
|
||||
table.dataTable tr.even td.sorting_3 { background-color: #F9F9FF; }
|
||||
|
||||
|
||||
/*
|
||||
* Table wrapper
|
||||
*/
|
||||
.dataTables_wrapper {
|
||||
position: relative;
|
||||
clear: both;
|
||||
*zoom: 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Page length menu
|
||||
*/
|
||||
.dataTables_length {
|
||||
float: left;
|
||||
color:#bcc1cb;
|
||||
font-style:italic;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Filter
|
||||
*/
|
||||
.dataTables_filter {
|
||||
float: right;
|
||||
text-align: right;
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
|
||||
.dataTables_filter label {
|
||||
color:#bcc1cb;
|
||||
font-style:italic;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Table information
|
||||
*/
|
||||
.dataTables_info {
|
||||
clear: both;
|
||||
float: left;
|
||||
margin-top: 10px;
|
||||
color:#bcc1cb;
|
||||
font-style:italic;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Pagination
|
||||
*/
|
||||
.dataTables_paginate {
|
||||
float: right;
|
||||
text-align: right;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
/* Two button pagination - previous / next */
|
||||
.paginate_disabled_previous,
|
||||
.paginate_enabled_previous,
|
||||
.paginate_disabled_next,
|
||||
.paginate_enabled_next {
|
||||
height: 19px;
|
||||
float: left;
|
||||
cursor: pointer;
|
||||
*cursor: hand;
|
||||
color: #111 !important;
|
||||
}
|
||||
.paginate_disabled_previous:hover,
|
||||
.paginate_enabled_previous:hover,
|
||||
.paginate_disabled_next:hover,
|
||||
.paginate_enabled_next:hover {
|
||||
text-decoration: none !important;
|
||||
}
|
||||
.paginate_disabled_previous:active,
|
||||
.paginate_enabled_previous:active,
|
||||
.paginate_disabled_next:active,
|
||||
.paginate_enabled_next:active {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.paginate_disabled_previous,
|
||||
.paginate_disabled_next {
|
||||
color: #666 !important;
|
||||
}
|
||||
.paginate_disabled_previous,
|
||||
.paginate_enabled_previous {
|
||||
padding-left: 23px;
|
||||
}
|
||||
.paginate_disabled_next,
|
||||
.paginate_enabled_next {
|
||||
padding-right: 23px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.paginate_enabled_previous { background: url('../images/back_enabled.png') no-repeat top left; }
|
||||
.paginate_enabled_previous:hover { background: url('../images/back_enabled_hover.png') no-repeat top left; }
|
||||
.paginate_disabled_previous { background: url('../images/back_disabled.png') no-repeat top left; }
|
||||
|
||||
.paginate_enabled_next { background: url('../images/forward_enabled.png') no-repeat top right; }
|
||||
.paginate_enabled_next:hover { background: url('../images/forward_enabled_hover.png') no-repeat top right; }
|
||||
.paginate_disabled_next { background: url('../images/forward_disabled.png') no-repeat top right; }
|
||||
|
||||
/* Full number pagination */
|
||||
.paging_full_numbers {
|
||||
height: 22px;
|
||||
line-height: 22px;
|
||||
}
|
||||
.paging_full_numbers a:active {
|
||||
outline: none
|
||||
}
|
||||
.paging_full_numbers a:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.paging_full_numbers a.paginate_active {
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
padding: 0.2em 0.5em;
|
||||
-moz-border-radius: 3px;
|
||||
border-radius: 3px;
|
||||
margin: 4px;
|
||||
font-weight: normal;
|
||||
color: #9f3729;
|
||||
text-shadow: 1px 1px 0px #ff7d6c;
|
||||
background: #d3301a;
|
||||
}
|
||||
|
||||
.paging_full_numbers a.paginate_button {
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
padding: 0.2em 0.5em;
|
||||
background: #edeff1;
|
||||
-moz-border-radius: 3px;
|
||||
border-radius: 3px;
|
||||
text-shadow: 1px 1px 0px white;
|
||||
margin: 4px;
|
||||
border: 1px solid #e0e2e4;
|
||||
}
|
||||
|
||||
.paging_full_numbers a.paginate_button:hover {
|
||||
border-color: #bc2814;
|
||||
background: #d3301a;
|
||||
color: white;
|
||||
text-shadow: -1px -1px 0px #992010;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Processing indicator
|
||||
*/
|
||||
.dataTables_processing {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
width: 250px;
|
||||
height: 30px;
|
||||
margin-left: -125px;
|
||||
margin-top: -15px;
|
||||
padding: 14px 0 2px 0;
|
||||
border: 1px solid #ddd;
|
||||
text-align: center;
|
||||
color: #999;
|
||||
font-size: 14px;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Sorting
|
||||
*/
|
||||
.sorting { background: url('../images/sort_both.png') no-repeat center right; }
|
||||
.sorting_asc { background: url('../images/sort_asc.png') no-repeat center right; }
|
||||
.sorting_desc { background: url('../images/sort_desc.png') no-repeat center right; }
|
||||
|
||||
.sorting_asc_disabled { background: url('../images/sort_asc_disabled.png') no-repeat center right; }
|
||||
.sorting_desc_disabled { background: url('../images/sort_desc_disabled.png') no-repeat center right; }
|
||||
|
||||
table.dataTable thead th:active,
|
||||
table.dataTable thead td:active {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Scrolling
|
||||
*/
|
||||
.dataTables_scroll {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.dataTables_scrollBody {
|
||||
*margin-top: -1px;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
244
dashboard/static/css/jquery.dataTables_themeroller.css
Normal file
@ -0,0 +1,244 @@
|
||||
|
||||
|
||||
/*
|
||||
* Table
|
||||
*/
|
||||
table.dataTable {
|
||||
margin: 0 auto;
|
||||
clear: both;
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
table.dataTable thead th {
|
||||
padding: 3px 0px 3px 10px;
|
||||
cursor: pointer;
|
||||
*cursor: hand;
|
||||
}
|
||||
|
||||
table.dataTable tfoot th {
|
||||
padding: 3px 10px;
|
||||
}
|
||||
|
||||
table.dataTable td {
|
||||
padding: 3px 10px;
|
||||
}
|
||||
|
||||
table.dataTable td.center,
|
||||
table.dataTable td.dataTables_empty {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
table.dataTable tr.odd { background-color: #E2E4FF; }
|
||||
table.dataTable tr.even { background-color: white; }
|
||||
|
||||
table.dataTable tr.odd td.sorting_1 { background-color: #D3D6FF; }
|
||||
table.dataTable tr.odd td.sorting_2 { background-color: #DADCFF; }
|
||||
table.dataTable tr.odd td.sorting_3 { background-color: #E0E2FF; }
|
||||
table.dataTable tr.even td.sorting_1 { background-color: #EAEBFF; }
|
||||
table.dataTable tr.even td.sorting_2 { background-color: #F2F3FF; }
|
||||
table.dataTable tr.even td.sorting_3 { background-color: #F9F9FF; }
|
||||
|
||||
|
||||
/*
|
||||
* Table wrapper
|
||||
*/
|
||||
.dataTables_wrapper {
|
||||
position: relative;
|
||||
clear: both;
|
||||
*zoom: 1;
|
||||
}
|
||||
.dataTables_wrapper .ui-widget-header {
|
||||
font-weight: normal;
|
||||
}
|
||||
.dataTables_wrapper .ui-toolbar {
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Page length menu
|
||||
*/
|
||||
.dataTables_length {
|
||||
float: left;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Filter
|
||||
*/
|
||||
.dataTables_filter {
|
||||
float: right;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Table information
|
||||
*/
|
||||
.dataTables_info {
|
||||
padding-top: 3px;
|
||||
clear: both;
|
||||
float: left;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Pagination
|
||||
*/
|
||||
.dataTables_paginate {
|
||||
float: right;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.dataTables_paginate .ui-button {
|
||||
margin-right: -0.1em !important;
|
||||
}
|
||||
|
||||
.paging_two_button .ui-button {
|
||||
float: left;
|
||||
cursor: pointer;
|
||||
* cursor: hand;
|
||||
}
|
||||
|
||||
.paging_full_numbers .ui-button {
|
||||
padding: 2px 6px;
|
||||
margin: 0;
|
||||
cursor: pointer;
|
||||
* cursor: hand;
|
||||
color: #333 !important;
|
||||
}
|
||||
|
||||
/* Two button pagination - previous / next */
|
||||
.paginate_disabled_previous,
|
||||
.paginate_enabled_previous,
|
||||
.paginate_disabled_next,
|
||||
.paginate_enabled_next {
|
||||
height: 19px;
|
||||
float: left;
|
||||
cursor: pointer;
|
||||
*cursor: hand;
|
||||
color: #111 !important;
|
||||
}
|
||||
.paginate_disabled_previous:hover,
|
||||
.paginate_enabled_previous:hover,
|
||||
.paginate_disabled_next:hover,
|
||||
.paginate_enabled_next:hover {
|
||||
text-decoration: none !important;
|
||||
}
|
||||
.paginate_disabled_previous:active,
|
||||
.paginate_enabled_previous:active,
|
||||
.paginate_disabled_next:active,
|
||||
.paginate_enabled_next:active {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.paginate_disabled_previous,
|
||||
.paginate_disabled_next {
|
||||
color: #666 !important;
|
||||
}
|
||||
.paginate_disabled_previous,
|
||||
.paginate_enabled_previous {
|
||||
padding-left: 23px;
|
||||
}
|
||||
.paginate_disabled_next,
|
||||
.paginate_enabled_next {
|
||||
padding-right: 23px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.paginate_enabled_previous { background: url('../images/back_enabled.png') no-repeat top left; }
|
||||
.paginate_enabled_previous:hover { background: url('../images/back_enabled_hover.png') no-repeat top left; }
|
||||
.paginate_disabled_previous { background: url('../images/back_disabled.png') no-repeat top left; }
|
||||
|
||||
.paginate_enabled_next { background: url('../images/forward_enabled.png') no-repeat top right; }
|
||||
.paginate_enabled_next:hover { background: url('../images/forward_enabled_hover.png') no-repeat top right; }
|
||||
.paginate_disabled_next { background: url('../images/forward_disabled.png') no-repeat top right; }
|
||||
|
||||
/* Full number pagination */
|
||||
.paging_full_numbers a:active {
|
||||
outline: none
|
||||
}
|
||||
.paging_full_numbers a:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.paging_full_numbers a.paginate_button,
|
||||
.paging_full_numbers a.paginate_active {
|
||||
border: 1px solid #aaa;
|
||||
-webkit-border-radius: 5px;
|
||||
-moz-border-radius: 5px;
|
||||
border-radius: 5px;
|
||||
padding: 2px 5px;
|
||||
margin: 0 3px;
|
||||
cursor: pointer;
|
||||
*cursor: hand;
|
||||
color: #333 !important;
|
||||
}
|
||||
|
||||
.paging_full_numbers a.paginate_button {
|
||||
background-color: #ddd;
|
||||
}
|
||||
|
||||
.paging_full_numbers a.paginate_button:hover {
|
||||
background-color: #ccc;
|
||||
text-decoration: none !important;
|
||||
}
|
||||
|
||||
.paging_full_numbers a.paginate_active {
|
||||
background-color: #99B3FF;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Processing indicator
|
||||
*/
|
||||
.dataTables_processing {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
width: 250px;
|
||||
height: 30px;
|
||||
margin-left: -125px;
|
||||
margin-top: -15px;
|
||||
padding: 14px 0 2px 0;
|
||||
border: 1px solid #ddd;
|
||||
text-align: center;
|
||||
color: #999;
|
||||
font-size: 14px;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Sorting
|
||||
*/
|
||||
table.dataTable thead th div.DataTables_sort_wrapper {
|
||||
position: relative;
|
||||
padding-right: 20px;
|
||||
}
|
||||
|
||||
table.dataTable thead th div.DataTables_sort_wrapper span {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
margin-top: -8px;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
table.dataTable th:active {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Scrolling
|
||||
*/
|
||||
.dataTables_scroll {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.dataTables_scrollBody {
|
||||
*margin-top: -1px;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
1
dashboard/static/css/jquery.jqplot.min.css
vendored
Normal file
@ -0,0 +1 @@
|
||||
.jqplot-target{position:relative;color:black;font-family:"PT Sans",Arial,sans-serif;font-size:1em;text-shadow: 1px 1px 0 rgba(255,255,255, 0.5);}.jqplot-axis{font-size:.75em;}.jqplot-xaxis{margin-top:10px;}.jqplot-x2axis{margin-bottom:10px;}.jqplot-yaxis{margin-right:10px;}.jqplot-y2axis,.jqplot-y3axis,.jqplot-y4axis,.jqplot-y5axis,.jqplot-y6axis,.jqplot-y7axis,.jqplot-y8axis,.jqplot-y9axis,.jqplot-yMidAxis{margin-left:10px;margin-right:10px;}.jqplot-axis-tick,.jqplot-xaxis-tick,.jqplot-yaxis-tick,.jqplot-x2axis-tick,.jqplot-y2axis-tick,.jqplot-y3axis-tick,.jqplot-y4axis-tick,.jqplot-y5axis-tick,.jqplot-y6axis-tick,.jqplot-y7axis-tick,.jqplot-y8axis-tick,.jqplot-y9axis-tick,.jqplot-yMidAxis-tick{position:absolute;white-space:pre;}.jqplot-xaxis-tick{top:0;left:15px;vertical-align:top;}.jqplot-x2axis-tick{bottom:0;left:15px;vertical-align:bottom;}.jqplot-yaxis-tick{right:0;top:15px;text-align:right;}.jqplot-yaxis-tick.jqplot-breakTick{right:-20px;margin-right:0;padding:1px 5px 1px 5px;z-index:2;font-size:1.5em;}.jqplot-y2axis-tick,.jqplot-y3axis-tick,.jqplot-y4axis-tick,.jqplot-y5axis-tick,.jqplot-y6axis-tick,.jqplot-y7axis-tick,.jqplot-y8axis-tick,.jqplot-y9axis-tick{left:0;top:15px;text-align:left;}.jqplot-yMidAxis-tick{text-align:center;white-space:nowrap;}.jqplot-xaxis-label{margin-top:10px;font-size:11pt;position:absolute;}.jqplot-x2axis-label{margin-bottom:10px;font-size:11pt;position:absolute;}.jqplot-yaxis-label{margin-right:10px;font-size:11pt;position:absolute;}.jqplot-yMidAxis-label{font-size:11pt;position:absolute;}.jqplot-y2axis-label,.jqplot-y3axis-label,.jqplot-y4axis-label,.jqplot-y5axis-label,.jqplot-y6axis-label,.jqplot-y7axis-label,.jqplot-y8axis-label,.jqplot-y9axis-label{font-size:11pt;margin-left:10px;position:absolute;}.jqplot-meterGauge-tick{font-size:.75em;color:#999;}.jqplot-meterGauge-label{font-size:1em;color:#999;}table.jqplot-table-legend{margin-top:12px;margin-bottom:12px;margin-left:12px;margin-right:12px;}table.jqplot-table-legend,table.jqplot-cursor-legend{background-color:rgba(255,255,255,0.6);border:none;position:absolute;font-size:13px; color:#192233;}td.jqplot-table-legend{vertical-align:middle;}td.jqplot-seriesToggle:hover,td.jqplot-seriesToggle:active{cursor:pointer;}.jqplot-table-legend .jqplot-series-hidden{text-decoration:line-through;}div.jqplot-table-legend-swatch-outline{/*border:1px solid #ccc;padding:1px;*/}div.jqplot-table-legend-swatch{width:0;height:0;border-top-width:5px;border-bottom-width:5px;border-left-width:6px;border-right-width:6px;border-top-style:solid;border-bottom-style:solid;border-left-style:solid;border-right-style:solid;}.jqplot-title{top:0;left:0;padding-bottom:.5em;font-size:1.2em;}table.jqplot-cursor-tooltip{border:1px solid #ccc;font-size:.75em;}.jqplot-cursor-tooltip{border:1px solid #ccc;font-size:.75em;white-space:nowrap;background:rgba(208,208,208,0.5);padding:1px;}.jqplot-highlighter-tooltip,.jqplot-canvasOverlay-tooltip{border:1px solid #ccc;font-size:.75em;white-space:nowrap;background:rgba(208,208,208,0.5);padding:1px;}.jqplot-point-label{font-size:.75em;z-index:2;}td.jqplot-cursor-legend-swatch{vertical-align:middle;text-align:center;}div.jqplot-cursor-legend-swatch{width:1.2em;height:.7em;}.jqplot-error{text-align:center;}.jqplot-error-message{position:relative;top:46%;display:inline-block;}div.jqplot-bubble-label{font-size:.8em;padding-left:2px;padding-right:2px;color:rgb(20%,20%,20%);}div.jqplot-bubble-label.jqplot-bubble-label-highlight{background:rgba(90%,90%,90%,0.7);}div.jqplot-noData-container{text-align:center;background-color:rgba(96%,96%,96%,0.3);}
|
474
dashboard/static/css/style.css
Normal file
@ -0,0 +1,474 @@
|
||||
html, body {
|
||||
font-family: 'PT Sans', arial, sans-serif;
|
||||
font-size: 14px;
|
||||
background: url(../images/osstats_tile.jpg) repeat-x;
|
||||
height: 100%;
|
||||
color: #41454d;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #D32F1A;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: #F00;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 15px;
|
||||
color: #41454D;
|
||||
font-style: normal;
|
||||
margin: 6px 0px 15px 0px;
|
||||
}
|
||||
|
||||
div.Xpage {
|
||||
width: 960px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
div.Xpage h2 {
|
||||
font-family: 'PT Sans Narrow', 'Arial Narrow', arial, sans-serif;
|
||||
font-size: 23px;
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
padding-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
padding-left: 10px;
|
||||
text-shadow: 1px 1px 0 #fff;
|
||||
}
|
||||
|
||||
input[type="text"],
|
||||
input[type="password"] {
|
||||
background: #f8f9f9;
|
||||
padding: 0 5px 0 5px;
|
||||
min-height: 24px;
|
||||
border: none;
|
||||
border-bottom: 1px solid white;
|
||||
border-right: 1px solid white;
|
||||
-moz-border-radius: 3px;
|
||||
border-radius: 3px;
|
||||
text-shadow: 1px 1px 0 white;
|
||||
-moz-box-shadow: inset 2px 2px 7px #D3D8DD;
|
||||
-webkit-box-shadow: inset 2px 2px 7px #D3D8DD;
|
||||
box-shadow: inset 2px 2px 7px #D3D8DD;
|
||||
}
|
||||
|
||||
input[type="submit"] {
|
||||
background: #f8f9f9;
|
||||
padding: 0 5px 0 5px;
|
||||
min-height: 24px;
|
||||
border: none;
|
||||
border-bottom: 1px solid white;
|
||||
border-right: 1px solid white;
|
||||
-moz-border-radius: 2px;
|
||||
border-radius: 2px;
|
||||
text-shadow: 1px 1px 0 white;
|
||||
-moz-box-shadow: inset 2px 2px 7px #D3D8DD;
|
||||
-webkit-box-shadow: inset 2px 2px 7px #D3D8DD;
|
||||
box-shadow: inset 2px 2px 7px #D3D8DD;
|
||||
}
|
||||
|
||||
div.page {
|
||||
background: white;
|
||||
border: 1px solid #e9eaef;
|
||||
width: 90%;
|
||||
margin: 10px auto;
|
||||
}
|
||||
|
||||
div.page h1 {
|
||||
background: white;
|
||||
margin: 0;
|
||||
padding: 0.1em 0.2em;
|
||||
color: black;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
div.drops {
|
||||
font-size: 15px;
|
||||
height: 60px;
|
||||
}
|
||||
|
||||
div.drops label {
|
||||
color: #909cb5;
|
||||
}
|
||||
|
||||
span.drop_period {
|
||||
margin-top: 6px;
|
||||
display: block;
|
||||
height: 30px;
|
||||
float: right;
|
||||
}
|
||||
|
||||
span.drop_metric {
|
||||
margin-top: 6px;
|
||||
margin-right: 1em;
|
||||
display: block;
|
||||
height: 30px;
|
||||
float: right;
|
||||
}
|
||||
|
||||
select {
|
||||
background: #f8f9f9;
|
||||
padding: 0 5px 0 5px;
|
||||
min-height: 24px;
|
||||
border: none;
|
||||
border-bottom: 1px solid white;
|
||||
border-right: 1px solid white;
|
||||
-moz-border-radius: 2px;
|
||||
border-radius: 2px;
|
||||
text-shadow: 1px 1px 0 white;
|
||||
-moz-box-shadow: inset 2px 2px 7px #D3D8DD;
|
||||
-webkit-box-shadow: inset 2px 2px 7px #D3D8DD;
|
||||
box-shadow: inset 2px 2px 7px #D3D8DD;
|
||||
}
|
||||
|
||||
div.aheader {
|
||||
height: 60px;
|
||||
background: #e0e9f2;
|
||||
text-shadow: 1px 1px 0 #fff;
|
||||
}
|
||||
|
||||
div.aheader h1 {
|
||||
font-size: 36px;
|
||||
color: #a8b3bd;
|
||||
text-shadow: 1px 1px 0 #fff;
|
||||
}
|
||||
|
||||
div.aheader h1 a {
|
||||
font-weight: bold;
|
||||
color: #637f99;
|
||||
text-decoration: none;
|
||||
text-shadow: 1px 1px 0 #fff;
|
||||
}
|
||||
|
||||
div.page div.navigation {
|
||||
text-shadow: 1px 1px 0 #fff;
|
||||
background: #fbfafa;
|
||||
padding: 4px 10px;
|
||||
border-top: 1px dashed #e9eaef;
|
||||
border-bottom: 1px dashed #e9eaef;
|
||||
color: #909cb5;
|
||||
font-size: 10pt;
|
||||
}
|
||||
|
||||
div.page div.navigation a {
|
||||
color: #444;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
div.page h2 {
|
||||
margin: 10px 0 0 10px;
|
||||
color: #a41200;
|
||||
}
|
||||
|
||||
div.page div.body {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
div.page div.footer {
|
||||
background: #eee;
|
||||
color: #888;
|
||||
padding: 1em 1em;
|
||||
font-size: 9pt;
|
||||
}
|
||||
|
||||
div.page ul.messages {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
div.page ul.messages li {
|
||||
margin: 10px 0;
|
||||
padding: 5px;
|
||||
background: #F0FAF9;
|
||||
border: 1px solid #DBF3F1;
|
||||
-moz-border-radius: 5px;
|
||||
-webkit-border-radius: 5px;
|
||||
min-height: 48px;
|
||||
}
|
||||
|
||||
div.page ul.messages p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
div.page ul.messages li img {
|
||||
float: left;
|
||||
padding: 0 10px 0 0;
|
||||
}
|
||||
|
||||
div.page ul.messages li small {
|
||||
font-size: 0.9em;
|
||||
color: #888;
|
||||
}
|
||||
|
||||
div.page div.twitbox {
|
||||
margin: 10px 0;
|
||||
padding: 5px;
|
||||
background: #F0FAF9;
|
||||
border: 1px solid #94E2DA;
|
||||
-moz-border-radius: 5px;
|
||||
-webkit-border-radius: 5px;
|
||||
}
|
||||
|
||||
div.page div.twitbox h3 {
|
||||
margin: 0;
|
||||
font-size: 1em;
|
||||
color: #2C7E76;
|
||||
}
|
||||
|
||||
div.page div.twitbox p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
div.page div.twitbox input[type="text"] {
|
||||
width: 585px;
|
||||
}
|
||||
|
||||
div.page div.twitbox input[type="submit"] {
|
||||
width: 70px;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
ul.flashes {
|
||||
list-style: none;
|
||||
margin: 10px 10px 0 10px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
ul.flashes li {
|
||||
background: #B9F3ED;
|
||||
border: 1px solid #81CEC6;
|
||||
-moz-border-radius: 2px;
|
||||
-webkit-border-radius: 2px;
|
||||
padding: 4px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
div.error {
|
||||
margin: 10px 0;
|
||||
background: #FAE4E4;
|
||||
border: 1px solid #DD6F6F;
|
||||
-moz-border-radius: 2px;
|
||||
-webkit-border-radius: 2px;
|
||||
padding: 4px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.spacer {
|
||||
height: 20px;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
table#left_list td {
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
table#right_list td {
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
div#left_list_wrapper {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
div#right_list_wrapper {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.message {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
a[href^="https://blueprints"]:after {
|
||||
content: "↗";
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
a[href^="https://review"]:after {
|
||||
content: "↗";
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
a[href^="https://bugs"]:after {
|
||||
content: "↗";
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
a[href^="https://launchpad"]:after {
|
||||
content: "↗";
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
#analytics_header {
|
||||
height: 25px;
|
||||
width: 960px;
|
||||
margin: 0 auto;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
#analytics_header h3 {
|
||||
font-family: 'PT Sans Narrow', 'Arial Narrow', arial, sans-serif;
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
font-size: 24px;
|
||||
color: black;
|
||||
padding-top: 30px;
|
||||
text-shadow: 1px 1px 0 #fff;
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
#analytics_header p {
|
||||
font-family: georgia, serif;
|
||||
font-weight: normal;
|
||||
font-style: italic;
|
||||
font-size: 16px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
color: #647280;
|
||||
line-height: 1.1em;
|
||||
text-shadow: 1px 1px 0 #fff;
|
||||
}
|
||||
|
||||
.paging_full_numbers {
|
||||
font-size: 9pt;
|
||||
}
|
||||
|
||||
/* MIRANTIS CSS*/
|
||||
|
||||
#miraheader {
|
||||
margin: 0 auto;
|
||||
width: 960px;
|
||||
}
|
||||
|
||||
#top-menu {
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
#ttopmenu {
|
||||
float: right;
|
||||
height: 20px;
|
||||
overflow: hidden;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
#ttopmenu a {
|
||||
font-size: 13px;
|
||||
font-style: italic;
|
||||
color: #A7B6C3;
|
||||
}
|
||||
|
||||
#ttopmenu a:hover {
|
||||
color: #6e8598;
|
||||
}
|
||||
|
||||
#main-menu {
|
||||
height: 47px;
|
||||
margin-top: 30px;
|
||||
text-align: right;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
a.glink {
|
||||
color: black;
|
||||
font-family: 'PT Sans Narrow', 'Arial Narrow', arial, sans-serif;
|
||||
font-size: 19px;
|
||||
padding: 5px 5px 5px 12px;
|
||||
white-space: nowrap;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a.glink:hover {
|
||||
color: #d3301a;
|
||||
}
|
||||
|
||||
.subglobalNav {
|
||||
color: black;
|
||||
position: absolute;
|
||||
font-family: 'PT Sans Narrow', 'Arial Narrow', arial, sans-serif;
|
||||
font-size: 14px;
|
||||
white-space: nowrap;
|
||||
text-decoration: none;
|
||||
right: 0px;
|
||||
padding-top: 10px;
|
||||
}
|
||||
|
||||
.subglobalNav a {
|
||||
color: black;
|
||||
text-decoration: none;
|
||||
padding: 2px 7px 2px 7px;
|
||||
margin-left: 12px;
|
||||
}
|
||||
|
||||
.subglobalNav a:hover {
|
||||
color: #fff;
|
||||
background: #CB2E19;
|
||||
-moz-border-radius: 2px;
|
||||
border-radius: 2px;
|
||||
margin-left: 12px;
|
||||
text-shadow: -1px -1px 0px #7F2114;
|
||||
}
|
||||
|
||||
a.act {
|
||||
color: #d3301a !important;
|
||||
}
|
||||
|
||||
a.act:hover {
|
||||
color: #fff !important;
|
||||
background: #CB2E19;
|
||||
}
|
||||
|
||||
a.active {
|
||||
color: #d3301a;
|
||||
}
|
||||
|
||||
#dummy {
|
||||
height: 115px;
|
||||
margin-top: 20px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#footer {
|
||||
height: 115px;
|
||||
margin-top: -120px;
|
||||
background: url(../images/footer_tile.jpg) repeat-x;
|
||||
font-family: 'PT Sans Narrow', 'Arial Narrow', arial, sans-serif;
|
||||
font-size: 17px;
|
||||
line-height: 21px;
|
||||
text-shadow: 1px 1px 0px white;
|
||||
|
||||
}
|
||||
|
||||
#foottable td {
|
||||
padding-top: 20px;
|
||||
}
|
||||
|
||||
#footer_content {
|
||||
width: 960px;
|
||||
margin: 4px auto auto auto;
|
||||
height: 110px;
|
||||
}
|
||||
|
||||
.fgeneral {
|
||||
color: black;
|
||||
}
|
||||
|
||||
.fgeneralblue {
|
||||
color: #43678a;
|
||||
}
|
||||
|
||||
.fslogan {
|
||||
font-family: 'PT Sans', arial, sans-serif;
|
||||
font-style: italic;
|
||||
color: #43678a;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
#fbox {
|
||||
padding-left: 10px;
|
||||
border-left: 1px solid #d5dbe1;
|
||||
}
|
||||
|
||||
/* MIRANTIS CSS*/
|
BIN
dashboard/static/css/ui-darkness/images/animated-overlay.gif
Normal file
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 220 B |
After Width: | Height: | Size: 230 B |
After Width: | Height: | Size: 260 B |
After Width: | Height: | Size: 342 B |
After Width: | Height: | Size: 316 B |
After Width: | Height: | Size: 3.7 KiB |
After Width: | Height: | Size: 276 B |
After Width: | Height: | Size: 275 B |
After Width: | Height: | Size: 340 B |
After Width: | Height: | Size: 6.8 KiB |
After Width: | Height: | Size: 4.4 KiB |
After Width: | Height: | Size: 4.4 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 12 KiB |
1175
dashboard/static/css/ui-darkness/jquery-ui-1.10.1.custom.css
vendored
Normal file
5
dashboard/static/css/ui-darkness/jquery-ui-1.10.1.custom.min.css
vendored
Normal file
122
dashboard/static/demo_page.css
Normal file
@ -0,0 +1,122 @@
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* General page setup
|
||||
*/
|
||||
#dt_example {
|
||||
font: 80%/1.45em "Lucida Grande", Verdana, Arial, Helvetica, sans-serif;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
color: #333;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
|
||||
#dt_example #container {
|
||||
width: 800px;
|
||||
margin: 30px auto;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
|
||||
#dt_example #footer {
|
||||
margin: 50px auto 0 auto;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#dt_example #demo {
|
||||
margin: 30px auto 0 auto;
|
||||
}
|
||||
|
||||
#dt_example .demo_jui {
|
||||
margin: 30px auto 0 auto;
|
||||
}
|
||||
|
||||
#dt_example .big {
|
||||
font-size: 1.3em;
|
||||
font-weight: bold;
|
||||
line-height: 1.6em;
|
||||
color: #4E6CA3;
|
||||
}
|
||||
|
||||
#dt_example .spacer {
|
||||
height: 20px;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
#dt_example .clear {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
#dt_example pre {
|
||||
padding: 15px;
|
||||
background-color: #F5F5F5;
|
||||
border: 1px solid #CCCCCC;
|
||||
}
|
||||
|
||||
#dt_example h1 {
|
||||
margin-top: 2em;
|
||||
font-size: 1.3em;
|
||||
font-weight: normal;
|
||||
line-height: 1.6em;
|
||||
color: #4E6CA3;
|
||||
border-bottom: 1px solid #B0BED9;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
#dt_example h2 {
|
||||
font-size: 1.2em;
|
||||
font-weight: normal;
|
||||
line-height: 1.6em;
|
||||
color: #4E6CA3;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
#dt_example a {
|
||||
color: #0063DC;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
#dt_example a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
#dt_example ul {
|
||||
color: #4E6CA3;
|
||||
}
|
||||
|
||||
.css_right {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.css_left {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.demo_links {
|
||||
float: left;
|
||||
width: 50%;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
#demo_info {
|
||||
padding: 5px;
|
||||
border: 1px solid #B0BED9;
|
||||
height: 100px;
|
||||
width: 100%;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
#dt_example code {
|
||||
font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
|
||||
padding: 2px 4px !important;
|
||||
white-space: nowrap;
|
||||
font-size: 0.9em;
|
||||
|
||||
color: #D14;
|
||||
background-color: #F7F7F9;
|
||||
|
||||
border: 1px solid #E1E1E8;
|
||||
-webkit-border-radius: 3px;
|
||||
-moz-border-radius: 3px;
|
||||
border-radius: 3px;
|
||||
}
|
577
dashboard/static/demo_table.css
Normal file
@ -0,0 +1,577 @@
|
||||
/*
|
||||
* File: demo_table.css
|
||||
* CVS: $Id$
|
||||
* Description: CSS descriptions for DataTables demo pages
|
||||
* Author: Allan Jardine
|
||||
* Created: Tue May 12 06:47:22 BST 2009
|
||||
* Modified: $Date$ by $Author$
|
||||
* Language: CSS
|
||||
* Project: DataTables
|
||||
*
|
||||
* Copyright 2009 Allan Jardine. All Rights Reserved.
|
||||
*
|
||||
* ***************************************************************************
|
||||
* DESCRIPTION
|
||||
*
|
||||
* The styles given here are suitable for the demos that are used with the standard DataTables
|
||||
* distribution (see www.datatables.net). You will most likely wish to modify these styles to
|
||||
* meet the layout requirements of your site.
|
||||
*
|
||||
* Common issues:
|
||||
* 'full_numbers' pagination - I use an extra selector on the body tag to ensure that there is
|
||||
* no conflict between the two pagination types. If you want to use full_numbers pagination
|
||||
* ensure that you either have "example_alt_pagination" as a body class name, or better yet,
|
||||
* modify that selector.
|
||||
* Note that the path used for Images is relative. All images are by default located in
|
||||
* ../images/ - relative to this CSS file.
|
||||
*/
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* DataTables features
|
||||
*/
|
||||
|
||||
.dataTables_wrapper {
|
||||
position: relative;
|
||||
clear: both;
|
||||
zoom: 1; /* Feeling sorry for IE */
|
||||
}
|
||||
|
||||
.dataTables_processing {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
width: 250px;
|
||||
height: 30px;
|
||||
margin-left: -125px;
|
||||
margin-top: -15px;
|
||||
padding: 14px 0 2px 0;
|
||||
border: 1px solid #ddd;
|
||||
text-align: center;
|
||||
color: #999;
|
||||
font-size: 14px;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.dataTables_length {
|
||||
width: 40%;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.dataTables_filter {
|
||||
width: 50%;
|
||||
float: right;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.dataTables_info {
|
||||
width: 60%;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.dataTables_paginate {
|
||||
float: right;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
/* Pagination nested */
|
||||
.paginate_disabled_previous, .paginate_enabled_previous,
|
||||
.paginate_disabled_next, .paginate_enabled_next {
|
||||
height: 19px;
|
||||
float: left;
|
||||
cursor: pointer;
|
||||
*cursor: hand;
|
||||
color: #111 !important;
|
||||
}
|
||||
.paginate_disabled_previous:hover, .paginate_enabled_previous:hover,
|
||||
.paginate_disabled_next:hover, .paginate_enabled_next:hover {
|
||||
text-decoration: none !important;
|
||||
}
|
||||
.paginate_disabled_previous:active, .paginate_enabled_previous:active,
|
||||
.paginate_disabled_next:active, .paginate_enabled_next:active {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.paginate_disabled_previous,
|
||||
.paginate_disabled_next {
|
||||
color: #666 !important;
|
||||
}
|
||||
.paginate_disabled_previous, .paginate_enabled_previous {
|
||||
padding-left: 23px;
|
||||
}
|
||||
.paginate_disabled_next, .paginate_enabled_next {
|
||||
padding-right: 23px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.paginate_disabled_previous {
|
||||
background: url('../images/back_disabled.png') no-repeat top left;
|
||||
}
|
||||
|
||||
.paginate_enabled_previous {
|
||||
background: url('../images/back_enabled.png') no-repeat top left;
|
||||
}
|
||||
.paginate_enabled_previous:hover {
|
||||
background: url('../images/back_enabled_hover.png') no-repeat top left;
|
||||
}
|
||||
|
||||
.paginate_disabled_next {
|
||||
background: url('../images/forward_disabled.png') no-repeat top right;
|
||||
}
|
||||
|
||||
.paginate_enabled_next {
|
||||
background: url('../images/forward_enabled.png') no-repeat top right;
|
||||
}
|
||||
.paginate_enabled_next:hover {
|
||||
background: url('../images/forward_enabled_hover.png') no-repeat top right;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* DataTables display
|
||||
*/
|
||||
table.display {
|
||||
margin: 0 auto;
|
||||
clear: both;
|
||||
width: 100%;
|
||||
|
||||
/* Note Firefox 3.5 and before have a bug with border-collapse
|
||||
* ( https://bugzilla.mozilla.org/show%5Fbug.cgi?id=155955 )
|
||||
* border-spacing: 0; is one possible option. Conditional-css.com is
|
||||
* useful for this kind of thing
|
||||
*
|
||||
* Further note IE 6/7 has problems when calculating widths with border width.
|
||||
* It subtracts one px relative to the other browsers from the first column, and
|
||||
* adds one to the end...
|
||||
*
|
||||
* If you want that effect I'd suggest setting a border-top/left on th/td's and
|
||||
* then filling in the gaps with other borders.
|
||||
*/
|
||||
}
|
||||
|
||||
table.display thead th {
|
||||
padding: 3px 18px 3px 10px;
|
||||
border-bottom: 1px solid black;
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
* cursor: hand;
|
||||
}
|
||||
|
||||
table.display tfoot th {
|
||||
padding: 3px 18px 3px 10px;
|
||||
border-top: 1px solid black;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
table.display tr.heading2 td {
|
||||
border-bottom: 1px solid #aaa;
|
||||
}
|
||||
|
||||
table.display td {
|
||||
padding: 3px 10px;
|
||||
}
|
||||
|
||||
table.display td.center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* DataTables sorting
|
||||
*/
|
||||
|
||||
.sorting_asc {
|
||||
background: url('../images/sort_asc.png') no-repeat center right;
|
||||
}
|
||||
|
||||
.sorting_desc {
|
||||
background: url('../images/sort_desc.png') no-repeat center right;
|
||||
}
|
||||
|
||||
.sorting {
|
||||
background: url('../images/sort_both.png') no-repeat center right;
|
||||
}
|
||||
|
||||
.sorting_asc_disabled {
|
||||
background: url('../images/sort_asc_disabled.png') no-repeat center right;
|
||||
}
|
||||
|
||||
.sorting_desc_disabled {
|
||||
background: url('../images/sort_desc_disabled.png') no-repeat center right;
|
||||
}
|
||||
|
||||
table.display thead th:active,
|
||||
table.display thead td:active {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* DataTables row classes
|
||||
*/
|
||||
table.display tr.odd.gradeA {
|
||||
background-color: #ddffdd;
|
||||
}
|
||||
|
||||
table.display tr.even.gradeA {
|
||||
background-color: #eeffee;
|
||||
}
|
||||
|
||||
table.display tr.odd.gradeC {
|
||||
background-color: #ddddff;
|
||||
}
|
||||
|
||||
table.display tr.even.gradeC {
|
||||
background-color: #eeeeff;
|
||||
}
|
||||
|
||||
table.display tr.odd.gradeX {
|
||||
background-color: #ffdddd;
|
||||
}
|
||||
|
||||
table.display tr.even.gradeX {
|
||||
background-color: #ffeeee;
|
||||
}
|
||||
|
||||
table.display tr.odd.gradeU {
|
||||
background-color: #ddd;
|
||||
}
|
||||
|
||||
table.display tr.even.gradeU {
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
|
||||
tr.odd {
|
||||
background-color: #E2E4FF;
|
||||
}
|
||||
|
||||
tr.even {
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Misc
|
||||
*/
|
||||
.dataTables_scroll {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.dataTables_scrollBody {
|
||||
*margin-top: -1px;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
.top, .bottom {
|
||||
padding: 15px;
|
||||
background-color: #F5F5F5;
|
||||
border: 1px solid #CCCCCC;
|
||||
}
|
||||
|
||||
.top .dataTables_info {
|
||||
float: none;
|
||||
}
|
||||
|
||||
.clear {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.dataTables_empty {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
tfoot input {
|
||||
margin: 0.5em 0;
|
||||
width: 100%;
|
||||
color: #444;
|
||||
}
|
||||
|
||||
tfoot input.search_init {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
td.group {
|
||||
background-color: #d1cfd0;
|
||||
border-bottom: 2px solid #A19B9E;
|
||||
border-top: 2px solid #A19B9E;
|
||||
}
|
||||
|
||||
td.details {
|
||||
background-color: #d1cfd0;
|
||||
border: 2px solid #A19B9E;
|
||||
}
|
||||
|
||||
|
||||
.example_alt_pagination div.dataTables_info {
|
||||
width: 40%;
|
||||
}
|
||||
|
||||
.paging_full_numbers {
|
||||
width: 400px;
|
||||
height: 22px;
|
||||
line-height: 22px;
|
||||
}
|
||||
|
||||
.paging_full_numbers a:active {
|
||||
outline: none
|
||||
}
|
||||
|
||||
.paging_full_numbers a:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.paging_full_numbers a.paginate_button,
|
||||
.paging_full_numbers a.paginate_active {
|
||||
border: 1px solid #aaa;
|
||||
-webkit-border-radius: 5px;
|
||||
-moz-border-radius: 5px;
|
||||
padding: 2px 5px;
|
||||
margin: 0 3px;
|
||||
cursor: pointer;
|
||||
*cursor: hand;
|
||||
color: #333 !important;
|
||||
}
|
||||
|
||||
.paging_full_numbers a.paginate_button {
|
||||
background-color: #ddd;
|
||||
}
|
||||
|
||||
.paging_full_numbers a.paginate_button:hover {
|
||||
background-color: #ccc;
|
||||
text-decoration: none !important;
|
||||
}
|
||||
|
||||
.paging_full_numbers a.paginate_active {
|
||||
background-color: #99B3FF;
|
||||
}
|
||||
|
||||
table.display tr.even.row_selected td {
|
||||
background-color: #B0BED9;
|
||||
}
|
||||
|
||||
table.display tr.odd.row_selected td {
|
||||
background-color: #9FAFD1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Sorting classes for columns
|
||||
*/
|
||||
/* For the standard odd/even */
|
||||
tr.odd td.sorting_1 {
|
||||
background-color: #D3D6FF;
|
||||
}
|
||||
|
||||
tr.odd td.sorting_2 {
|
||||
background-color: #DADCFF;
|
||||
}
|
||||
|
||||
tr.odd td.sorting_3 {
|
||||
background-color: #E0E2FF;
|
||||
}
|
||||
|
||||
tr.even td.sorting_1 {
|
||||
background-color: #EAEBFF;
|
||||
}
|
||||
|
||||
tr.even td.sorting_2 {
|
||||
background-color: #F2F3FF;
|
||||
}
|
||||
|
||||
tr.even td.sorting_3 {
|
||||
background-color: #F9F9FF;
|
||||
}
|
||||
|
||||
|
||||
/* For the Conditional-CSS grading rows */
|
||||
/*
|
||||
Colour calculations (based off the main row colours)
|
||||
Level 1:
|
||||
dd > c4
|
||||
ee > d5
|
||||
Level 2:
|
||||
dd > d1
|
||||
ee > e2
|
||||
*/
|
||||
tr.odd.gradeA td.sorting_1 {
|
||||
background-color: #c4ffc4;
|
||||
}
|
||||
|
||||
tr.odd.gradeA td.sorting_2 {
|
||||
background-color: #d1ffd1;
|
||||
}
|
||||
|
||||
tr.odd.gradeA td.sorting_3 {
|
||||
background-color: #d1ffd1;
|
||||
}
|
||||
|
||||
tr.even.gradeA td.sorting_1 {
|
||||
background-color: #d5ffd5;
|
||||
}
|
||||
|
||||
tr.even.gradeA td.sorting_2 {
|
||||
background-color: #e2ffe2;
|
||||
}
|
||||
|
||||
tr.even.gradeA td.sorting_3 {
|
||||
background-color: #e2ffe2;
|
||||
}
|
||||
|
||||
tr.odd.gradeC td.sorting_1 {
|
||||
background-color: #c4c4ff;
|
||||
}
|
||||
|
||||
tr.odd.gradeC td.sorting_2 {
|
||||
background-color: #d1d1ff;
|
||||
}
|
||||
|
||||
tr.odd.gradeC td.sorting_3 {
|
||||
background-color: #d1d1ff;
|
||||
}
|
||||
|
||||
tr.even.gradeC td.sorting_1 {
|
||||
background-color: #d5d5ff;
|
||||
}
|
||||
|
||||
tr.even.gradeC td.sorting_2 {
|
||||
background-color: #e2e2ff;
|
||||
}
|
||||
|
||||
tr.even.gradeC td.sorting_3 {
|
||||
background-color: #e2e2ff;
|
||||
}
|
||||
|
||||
tr.odd.gradeX td.sorting_1 {
|
||||
background-color: #ffc4c4;
|
||||
}
|
||||
|
||||
tr.odd.gradeX td.sorting_2 {
|
||||
background-color: #ffd1d1;
|
||||
}
|
||||
|
||||
tr.odd.gradeX td.sorting_3 {
|
||||
background-color: #ffd1d1;
|
||||
}
|
||||
|
||||
tr.even.gradeX td.sorting_1 {
|
||||
background-color: #ffd5d5;
|
||||
}
|
||||
|
||||
tr.even.gradeX td.sorting_2 {
|
||||
background-color: #ffe2e2;
|
||||
}
|
||||
|
||||
tr.even.gradeX td.sorting_3 {
|
||||
background-color: #ffe2e2;
|
||||
}
|
||||
|
||||
tr.odd.gradeU td.sorting_1 {
|
||||
background-color: #c4c4c4;
|
||||
}
|
||||
|
||||
tr.odd.gradeU td.sorting_2 {
|
||||
background-color: #d1d1d1;
|
||||
}
|
||||
|
||||
tr.odd.gradeU td.sorting_3 {
|
||||
background-color: #d1d1d1;
|
||||
}
|
||||
|
||||
tr.even.gradeU td.sorting_1 {
|
||||
background-color: #d5d5d5;
|
||||
}
|
||||
|
||||
tr.even.gradeU td.sorting_2 {
|
||||
background-color: #e2e2e2;
|
||||
}
|
||||
|
||||
tr.even.gradeU td.sorting_3 {
|
||||
background-color: #e2e2e2;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Row highlighting example
|
||||
*/
|
||||
.ex_highlight #example tbody tr.even:hover, #example tbody tr.even td.highlighted {
|
||||
background-color: #ECFFB3;
|
||||
}
|
||||
|
||||
.ex_highlight #example tbody tr.odd:hover, #example tbody tr.odd td.highlighted {
|
||||
background-color: #E6FF99;
|
||||
}
|
||||
|
||||
.ex_highlight_row #example tr.even:hover {
|
||||
background-color: #ECFFB3;
|
||||
}
|
||||
|
||||
.ex_highlight_row #example tr.even:hover td.sorting_1 {
|
||||
background-color: #DDFF75;
|
||||
}
|
||||
|
||||
.ex_highlight_row #example tr.even:hover td.sorting_2 {
|
||||
background-color: #E7FF9E;
|
||||
}
|
||||
|
||||
.ex_highlight_row #example tr.even:hover td.sorting_3 {
|
||||
background-color: #E2FF89;
|
||||
}
|
||||
|
||||
.ex_highlight_row #example tr.odd:hover {
|
||||
background-color: #E6FF99;
|
||||
}
|
||||
|
||||
.ex_highlight_row #example tr.odd:hover td.sorting_1 {
|
||||
background-color: #D6FF5C;
|
||||
}
|
||||
|
||||
.ex_highlight_row #example tr.odd:hover td.sorting_2 {
|
||||
background-color: #E0FF84;
|
||||
}
|
||||
|
||||
.ex_highlight_row #example tr.odd:hover td.sorting_3 {
|
||||
background-color: #DBFF70;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* KeyTable
|
||||
*/
|
||||
table.KeyTable td {
|
||||
border: 3px solid transparent;
|
||||
}
|
||||
|
||||
table.KeyTable td.focus {
|
||||
border: 3px solid #3366FF;
|
||||
}
|
||||
|
||||
table.display tr.gradeA {
|
||||
background-color: #eeffee;
|
||||
}
|
||||
|
||||
table.display tr.gradeC {
|
||||
background-color: #ddddff;
|
||||
}
|
||||
|
||||
table.display tr.gradeX {
|
||||
background-color: #ffdddd;
|
||||
}
|
||||
|
||||
table.display tr.gradeU {
|
||||
background-color: #ddd;
|
||||
}
|
||||
|
||||
div.box {
|
||||
height: 100px;
|
||||
padding: 10px;
|
||||
overflow: auto;
|
||||
border: 1px solid #8080FF;
|
||||
background-color: #E5E5FF;
|
||||
}
|
501
dashboard/static/demo_table_jui.css
Normal file
@ -0,0 +1,501 @@
|
||||
/*
|
||||
* File: demo_table_jui.css
|
||||
* CVS: $Id$
|
||||
* Description: CSS descriptions for DataTables demo pages
|
||||
* Author: Allan Jardine
|
||||
* Created: Tue May 12 06:47:22 BST 2009
|
||||
* Modified: $Date$ by $Author$
|
||||
* Language: CSS
|
||||
* Project: DataTables
|
||||
*
|
||||
* Copyright 2009 Allan Jardine. All Rights Reserved.
|
||||
*
|
||||
* ***************************************************************************
|
||||
* DESCRIPTION
|
||||
*
|
||||
* The styles given here are suitable for the demos that are used with the standard DataTables
|
||||
* distribution (see www.datatables.net). You will most likely wish to modify these styles to
|
||||
* meet the layout requirements of your site.
|
||||
*
|
||||
* Common issues:
|
||||
* 'full_numbers' pagination - I use an extra selector on the body tag to ensure that there is
|
||||
* no conflict between the two pagination types. If you want to use full_numbers pagination
|
||||
* ensure that you either have "example_alt_pagination" as a body class name, or better yet,
|
||||
* modify that selector.
|
||||
* Note that the path used for Images is relative. All images are by default located in
|
||||
* ../images/ - relative to this CSS file.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* jQuery UI specific styling
|
||||
*/
|
||||
|
||||
.paging_two_button .ui-button {
|
||||
float: left;
|
||||
cursor: pointer;
|
||||
* cursor: hand;
|
||||
}
|
||||
|
||||
.paging_full_numbers .ui-button {
|
||||
padding: 2px 6px;
|
||||
margin: 0;
|
||||
cursor: pointer;
|
||||
* cursor: hand;
|
||||
color: #333 !important;
|
||||
}
|
||||
|
||||
.dataTables_paginate .ui-button {
|
||||
margin-right: -0.1em !important;
|
||||
}
|
||||
|
||||
.paging_full_numbers {
|
||||
width: 350px !important;
|
||||
}
|
||||
|
||||
.dataTables_wrapper .ui-toolbar {
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.dataTables_paginate {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.dataTables_info {
|
||||
padding-top: 3px;
|
||||
}
|
||||
|
||||
table.display thead th {
|
||||
padding: 3px 0px 3px 10px;
|
||||
cursor: pointer;
|
||||
* cursor: hand;
|
||||
}
|
||||
|
||||
div.dataTables_wrapper .ui-widget-header {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Sort arrow icon positioning
|
||||
*/
|
||||
table.display thead th div.DataTables_sort_wrapper {
|
||||
position: relative;
|
||||
padding-right: 20px;
|
||||
}
|
||||
|
||||
table.display thead th div.DataTables_sort_wrapper span {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
margin-top: -8px;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Everything below this line is the same as demo_table.css. This file is
|
||||
* required for 'cleanliness' of the markup
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* DataTables features
|
||||
*/
|
||||
|
||||
.dataTables_wrapper {
|
||||
position: relative;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.dataTables_processing {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 50%;
|
||||
width: 250px;
|
||||
margin-left: -125px;
|
||||
border: 1px solid #ddd;
|
||||
text-align: center;
|
||||
color: #999;
|
||||
font-size: 11px;
|
||||
padding: 2px 0;
|
||||
}
|
||||
|
||||
.dataTables_length {
|
||||
width: 40%;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.dataTables_filter {
|
||||
width: 50%;
|
||||
float: right;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.dataTables_info {
|
||||
width: 50%;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.dataTables_paginate {
|
||||
float: right;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* DataTables display
|
||||
*/
|
||||
table.display {
|
||||
margin: 0 auto;
|
||||
width: 100%;
|
||||
clear: both;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
table.display tfoot th {
|
||||
padding: 3px 0px 3px 10px;
|
||||
font-weight: bold;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
table.display tr.heading2 td {
|
||||
border-bottom: 1px solid #aaa;
|
||||
}
|
||||
|
||||
table.display td {
|
||||
padding: 3px 10px;
|
||||
}
|
||||
|
||||
table.display td.center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* DataTables sorting
|
||||
*/
|
||||
|
||||
.sorting_asc {
|
||||
background: url('../images/sort_asc.png') no-repeat center right;
|
||||
}
|
||||
|
||||
.sorting_desc {
|
||||
background: url('../images/sort_desc.png') no-repeat center right;
|
||||
}
|
||||
|
||||
.sorting {
|
||||
background: url('../images/sort_both.png') no-repeat center right;
|
||||
}
|
||||
|
||||
.sorting_asc_disabled {
|
||||
background: url('../images/sort_asc_disabled.png') no-repeat center right;
|
||||
}
|
||||
|
||||
.sorting_desc_disabled {
|
||||
background: url('../images/sort_desc_disabled.png') no-repeat center right;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* DataTables row classes
|
||||
*/
|
||||
table.display tr.odd.gradeA {
|
||||
background-color: #ddffdd;
|
||||
}
|
||||
|
||||
table.display tr.even.gradeA {
|
||||
background-color: #eeffee;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
table.display tr.odd.gradeA {
|
||||
background-color: #ddffdd;
|
||||
}
|
||||
|
||||
table.display tr.even.gradeA {
|
||||
background-color: #eeffee;
|
||||
}
|
||||
|
||||
table.display tr.odd.gradeC {
|
||||
background-color: #ddddff;
|
||||
}
|
||||
|
||||
table.display tr.even.gradeC {
|
||||
background-color: #eeeeff;
|
||||
}
|
||||
|
||||
table.display tr.odd.gradeX {
|
||||
background-color: #ffdddd;
|
||||
}
|
||||
|
||||
table.display tr.even.gradeX {
|
||||
background-color: #ffeeee;
|
||||
}
|
||||
|
||||
table.display tr.odd.gradeU {
|
||||
background-color: #ddd;
|
||||
}
|
||||
|
||||
table.display tr.even.gradeU {
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
|
||||
tr.odd {
|
||||
background-color: #E2E4FF;
|
||||
}
|
||||
|
||||
tr.even {
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Misc
|
||||
*/
|
||||
.dataTables_scroll {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.dataTables_scrollBody {
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
.top, .bottom {
|
||||
padding: 15px;
|
||||
background-color: #F5F5F5;
|
||||
border: 1px solid #CCCCCC;
|
||||
}
|
||||
|
||||
.top .dataTables_info {
|
||||
float: none;
|
||||
}
|
||||
|
||||
.clear {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.dataTables_empty {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
tfoot input {
|
||||
margin: 0.5em 0;
|
||||
width: 100%;
|
||||
color: #444;
|
||||
}
|
||||
|
||||
tfoot input.search_init {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
td.group {
|
||||
background-color: #d1cfd0;
|
||||
border-bottom: 2px solid #A19B9E;
|
||||
border-top: 2px solid #A19B9E;
|
||||
}
|
||||
|
||||
td.details {
|
||||
background-color: #d1cfd0;
|
||||
border: 2px solid #A19B9E;
|
||||
}
|
||||
|
||||
|
||||
.example_alt_pagination div.dataTables_info {
|
||||
width: 40%;
|
||||
}
|
||||
|
||||
.paging_full_numbers a.paginate_button,
|
||||
.paging_full_numbers a.paginate_active {
|
||||
border: 1px solid #aaa;
|
||||
-webkit-border-radius: 5px;
|
||||
-moz-border-radius: 5px;
|
||||
padding: 2px 5px;
|
||||
margin: 0 3px;
|
||||
cursor: pointer;
|
||||
*cursor: hand;
|
||||
color: #333 !important;
|
||||
}
|
||||
|
||||
.paging_full_numbers a.paginate_button {
|
||||
background-color: #ddd;
|
||||
}
|
||||
|
||||
.paging_full_numbers a.paginate_button:hover {
|
||||
background-color: #ccc;
|
||||
text-decoration: none !important;
|
||||
}
|
||||
|
||||
.paging_full_numbers a.paginate_active {
|
||||
background-color: #99B3FF;
|
||||
}
|
||||
|
||||
table.display tr.even.row_selected td {
|
||||
background-color: #B0BED9;
|
||||
}
|
||||
|
||||
table.display tr.odd.row_selected td {
|
||||
background-color: #9FAFD1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Sorting classes for columns
|
||||
*/
|
||||
/* For the standard odd/even */
|
||||
tr.odd td.sorting_1 {
|
||||
background-color: #D3D6FF;
|
||||
}
|
||||
|
||||
tr.odd td.sorting_2 {
|
||||
background-color: #DADCFF;
|
||||
}
|
||||
|
||||
tr.odd td.sorting_3 {
|
||||
background-color: #E0E2FF;
|
||||
}
|
||||
|
||||
tr.even td.sorting_1 {
|
||||
background-color: #EAEBFF;
|
||||
}
|
||||
|
||||
tr.even td.sorting_2 {
|
||||
background-color: #F2F3FF;
|
||||
}
|
||||
|
||||
tr.even td.sorting_3 {
|
||||
background-color: #F9F9FF;
|
||||
}
|
||||
|
||||
|
||||
/* For the Conditional-CSS grading rows */
|
||||
/*
|
||||
Colour calculations (based off the main row colours)
|
||||
Level 1:
|
||||
dd > c4
|
||||
ee > d5
|
||||
Level 2:
|
||||
dd > d1
|
||||
ee > e2
|
||||
*/
|
||||
tr.odd.gradeA td.sorting_1 {
|
||||
background-color: #c4ffc4;
|
||||
}
|
||||
|
||||
tr.odd.gradeA td.sorting_2 {
|
||||
background-color: #d1ffd1;
|
||||
}
|
||||
|
||||
tr.odd.gradeA td.sorting_3 {
|
||||
background-color: #d1ffd1;
|
||||
}
|
||||
|
||||
tr.even.gradeA td.sorting_1 {
|
||||
background-color: #d5ffd5;
|
||||
}
|
||||
|
||||
tr.even.gradeA td.sorting_2 {
|
||||
background-color: #e2ffe2;
|
||||
}
|
||||
|
||||
tr.even.gradeA td.sorting_3 {
|
||||
background-color: #e2ffe2;
|
||||
}
|
||||
|
||||
tr.odd.gradeC td.sorting_1 {
|
||||
background-color: #c4c4ff;
|
||||
}
|
||||
|
||||
tr.odd.gradeC td.sorting_2 {
|
||||
background-color: #d1d1ff;
|
||||
}
|
||||
|
||||
tr.odd.gradeC td.sorting_3 {
|
||||
background-color: #d1d1ff;
|
||||
}
|
||||
|
||||
tr.even.gradeC td.sorting_1 {
|
||||
background-color: #d5d5ff;
|
||||
}
|
||||
|
||||
tr.even.gradeC td.sorting_2 {
|
||||
background-color: #e2e2ff;
|
||||
}
|
||||
|
||||
tr.even.gradeC td.sorting_3 {
|
||||
background-color: #e2e2ff;
|
||||
}
|
||||
|
||||
tr.odd.gradeX td.sorting_1 {
|
||||
background-color: #ffc4c4;
|
||||
}
|
||||
|
||||
tr.odd.gradeX td.sorting_2 {
|
||||
background-color: #ffd1d1;
|
||||
}
|
||||
|
||||
tr.odd.gradeX td.sorting_3 {
|
||||
background-color: #ffd1d1;
|
||||
}
|
||||
|
||||
tr.even.gradeX td.sorting_1 {
|
||||
background-color: #ffd5d5;
|
||||
}
|
||||
|
||||
tr.even.gradeX td.sorting_2 {
|
||||
background-color: #ffe2e2;
|
||||
}
|
||||
|
||||
tr.even.gradeX td.sorting_3 {
|
||||
background-color: #ffe2e2;
|
||||
}
|
||||
|
||||
tr.odd.gradeU td.sorting_1 {
|
||||
background-color: #c4c4c4;
|
||||
}
|
||||
|
||||
tr.odd.gradeU td.sorting_2 {
|
||||
background-color: #d1d1d1;
|
||||
}
|
||||
|
||||
tr.odd.gradeU td.sorting_3 {
|
||||
background-color: #d1d1d1;
|
||||
}
|
||||
|
||||
tr.even.gradeU td.sorting_1 {
|
||||
background-color: #d5d5d5;
|
||||
}
|
||||
|
||||
tr.even.gradeU td.sorting_2 {
|
||||
background-color: #e2e2e2;
|
||||
}
|
||||
|
||||
tr.even.gradeU td.sorting_3 {
|
||||
background-color: #e2e2e2;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Row highlighting example
|
||||
*/
|
||||
.ex_highlight #example tbody tr.even:hover, #example tbody tr.even td.highlighted {
|
||||
background-color: #ECFFB3;
|
||||
}
|
||||
|
||||
.ex_highlight #example tbody tr.odd:hover, #example tbody tr.odd td.highlighted {
|
||||
background-color: #E6FF99;
|
||||
}
|
BIN
dashboard/static/images/back_disabled.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
dashboard/static/images/back_enabled.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
dashboard/static/images/back_enabled_hover.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
dashboard/static/images/footer_tile.jpg
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
dashboard/static/images/forward_disabled.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
dashboard/static/images/forward_enabled.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
dashboard/static/images/forward_enabled_hover.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
dashboard/static/images/mirantis_logo.gif
Normal file
After Width: | Height: | Size: 3.3 KiB |
BIN
dashboard/static/images/noise_lightblue.jpg
Normal file
After Width: | Height: | Size: 3.0 KiB |
BIN
dashboard/static/images/noise_lightgray.jpg
Normal file
After Width: | Height: | Size: 2.0 KiB |
BIN
dashboard/static/images/osstats_tile.jpg
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
dashboard/static/images/sort_asc.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
dashboard/static/images/sort_asc_disabled.png
Normal file
After Width: | Height: | Size: 1.0 KiB |
BIN
dashboard/static/images/sort_both.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
dashboard/static/images/sort_desc.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
dashboard/static/images/sort_desc_disabled.png
Normal file
After Width: | Height: | Size: 1.0 KiB |
12099
dashboard/static/jquery.dataTables.js
vendored
Normal file
3
dashboard/static/js/excanvas.min.js
vendored
Normal file
3
dashboard/static/js/jqplot.canvasAxisTickRenderer.min.js
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
/* jqPlot 1.0.7r1224 | (c) 2009-2013 Chris Leonello | jplot.com
|
||||
jsDate | (c) 2010-2013 Chris Leonello
|
||||
*/(function(a){a.jqplot.CanvasAxisTickRenderer=function(b){this.mark="outside";this.showMark=true;this.showGridline=true;this.isMinorTick=false;this.angle=0;this.markSize=4;this.show=true;this.showLabel=true;this.labelPosition="auto";this.label="";this.value=null;this._styles={};this.formatter=a.jqplot.DefaultTickFormatter;this.formatString="";this.prefix="";this.fontFamily='"Trebuchet MS", Arial, Helvetica, sans-serif';this.fontSize="10pt";this.fontWeight="normal";this.fontStretch=1;this.textColor="#666666";this.enableFontSupport=true;this.pt2px=null;this._elem;this._ctx;this._plotWidth;this._plotHeight;this._plotDimensions={height:null,width:null};a.extend(true,this,b);var c={fontSize:this.fontSize,fontWeight:this.fontWeight,fontStretch:this.fontStretch,fillStyle:this.textColor,angle:this.getAngleRad(),fontFamily:this.fontFamily};if(this.pt2px){c.pt2px=this.pt2px}if(this.enableFontSupport){if(a.jqplot.support_canvas_text()){this._textRenderer=new a.jqplot.CanvasFontRenderer(c)}else{this._textRenderer=new a.jqplot.CanvasTextRenderer(c)}}else{this._textRenderer=new a.jqplot.CanvasTextRenderer(c)}};a.jqplot.CanvasAxisTickRenderer.prototype.init=function(b){a.extend(true,this,b);this._textRenderer.init({fontSize:this.fontSize,fontWeight:this.fontWeight,fontStretch:this.fontStretch,fillStyle:this.textColor,angle:this.getAngleRad(),fontFamily:this.fontFamily})};a.jqplot.CanvasAxisTickRenderer.prototype.getWidth=function(d){if(this._elem){return this._elem.outerWidth(true)}else{var f=this._textRenderer;var c=f.getWidth(d);var e=f.getHeight(d);var b=Math.abs(Math.sin(f.angle)*e)+Math.abs(Math.cos(f.angle)*c);return b}};a.jqplot.CanvasAxisTickRenderer.prototype.getHeight=function(d){if(this._elem){return this._elem.outerHeight(true)}else{var f=this._textRenderer;var c=f.getWidth(d);var e=f.getHeight(d);var b=Math.abs(Math.cos(f.angle)*e)+Math.abs(Math.sin(f.angle)*c);return b}};a.jqplot.CanvasAxisTickRenderer.prototype.getTop=function(b){if(this._elem){return this._elem.position().top}else{return null}};a.jqplot.CanvasAxisTickRenderer.prototype.getAngleRad=function(){var b=this.angle*Math.PI/180;return b};a.jqplot.CanvasAxisTickRenderer.prototype.setTick=function(b,d,c){this.value=b;if(c){this.isMinorTick=true}return this};a.jqplot.CanvasAxisTickRenderer.prototype.draw=function(c,f){if(!this.label){this.label=this.prefix+this.formatter(this.formatString,this.value)}if(this._elem){if(a.jqplot.use_excanvas&&window.G_vmlCanvasManager.uninitElement!==undefined){window.G_vmlCanvasManager.uninitElement(this._elem.get(0))}this._elem.emptyForce();this._elem=null}var e=f.canvasManager.getCanvas();this._textRenderer.setText(this.label,c);var b=this.getWidth(c);var d=this.getHeight(c);e.width=b;e.height=d;e.style.width=b;e.style.height=d;e.style.textAlign="left";e.style.position="absolute";e=f.canvasManager.initCanvas(e);this._elem=a(e);this._elem.css(this._styles);this._elem.addClass("jqplot-"+this.axis+"-tick");e=null;return this._elem};a.jqplot.CanvasAxisTickRenderer.prototype.pack=function(){this._textRenderer.draw(this._elem.get(0).getContext("2d"),this.label)}})(jQuery);
|
3
dashboard/static/js/jqplot.canvasTextRenderer.min.js
vendored
Normal file
3
dashboard/static/js/jqplot.cursor.min.js
vendored
Normal file
3
dashboard/static/js/jqplot.dateAxisRenderer.min.js
vendored
Normal file
3
dashboard/static/js/jqplot.highlighter.min.js
vendored
Normal file
3
dashboard/static/js/jqplot.json2.min.js
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
/* jqPlot 1.0.7r1224 | (c) 2009-2013 Chris Leonello | jplot.com
|
||||
jsDate | (c) 2010-2013 Chris Leonello
|
||||
*/(function($){$.jqplot.JSON=window.JSON;if(!window.JSON){$.jqplot.JSON={}}function f(n){return n<10?"0"+n:n}if(typeof Date.prototype.toJSON!=="function"){Date.prototype.toJSON=function(key){return isFinite(this.valueOf())?this.getUTCFullYear()+"-"+f(this.getUTCMonth()+1)+"-"+f(this.getUTCDate())+"T"+f(this.getUTCHours())+":"+f(this.getUTCMinutes())+":"+f(this.getUTCSeconds())+"Z":null};String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(key){return this.valueOf()}}var cx=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,escapable=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,gap,indent,meta={"\b":"\\b","\t":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"},rep;function quote(string){escapable.lastIndex=0;return escapable.test(string)?'"'+string.replace(escapable,function(a){var c=meta[a];return typeof c==="string"?c:"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+string+'"'}function str(key,holder){var i,k,v,length,mind=gap,partial,value=holder[key];if(value&&typeof value==="object"&&typeof value.toJSON==="function"){value=value.toJSON(key)}if(typeof rep==="function"){value=rep.call(holder,key,value)}switch(typeof value){case"string":return quote(value);case"number":return isFinite(value)?String(value):"null";case"boolean":case"null":return String(value);case"object":if(!value){return"null"}gap+=indent;partial=[];if(Object.prototype.toString.apply(value)==="[object Array]"){length=value.length;for(i=0;i<length;i+=1){partial[i]=str(i,value)||"null"}v=partial.length===0?"[]":gap?"[\n"+gap+partial.join(",\n"+gap)+"\n"+mind+"]":"["+partial.join(",")+"]";gap=mind;return v}if(rep&&typeof rep==="object"){length=rep.length;for(i=0;i<length;i+=1){k=rep[i];if(typeof k==="string"){v=str(k,value);if(v){partial.push(quote(k)+(gap?": ":":")+v)}}}}else{for(k in value){if(Object.hasOwnProperty.call(value,k)){v=str(k,value);if(v){partial.push(quote(k)+(gap?": ":":")+v)}}}}v=partial.length===0?"{}":gap?"{\n"+gap+partial.join(",\n"+gap)+"\n"+mind+"}":"{"+partial.join(",")+"}";gap=mind;return v}}if(typeof $.jqplot.JSON.stringify!=="function"){$.jqplot.JSON.stringify=function(value,replacer,space){var i;gap="";indent="";if(typeof space==="number"){for(i=0;i<space;i+=1){indent+=" "}}else{if(typeof space==="string"){indent=space}}rep=replacer;if(replacer&&typeof replacer!=="function"&&(typeof replacer!=="object"||typeof replacer.length!=="number")){throw new Error("$.jqplot.JSON.stringify")}return str("",{"":value})}}if(typeof $.jqplot.JSON.parse!=="function"){$.jqplot.JSON.parse=function(text,reviver){var j;function walk(holder,key){var k,v,value=holder[key];if(value&&typeof value==="object"){for(k in value){if(Object.hasOwnProperty.call(value,k)){v=walk(value,k);if(v!==undefined){value[k]=v}else{delete value[k]}}}}return reviver.call(holder,key,value)}text=String(text);cx.lastIndex=0;if(cx.test(text)){text=text.replace(cx,function(a){return"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)})}if(/^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,""))){j=eval("("+text+")");return typeof reviver==="function"?walk({"":j},""):j}throw new SyntaxError("$.jqplot.JSON.parse")}}})(jQuery);
|
3
dashboard/static/js/jqplot.pieRenderer.min.js
vendored
Normal file
5
dashboard/static/js/jquery-1.9.1.min.js
vendored
Normal file
6
dashboard/static/js/jquery-ui-1.10.1.custom.min.js
vendored
Normal file
155
dashboard/static/js/jquery.dataTables.min.js
vendored
Normal file
@ -0,0 +1,155 @@
|
||||
/*
|
||||
* File: jquery.dataTables.min.js
|
||||
* Version: 1.9.4
|
||||
* Author: Allan Jardine (www.sprymedia.co.uk)
|
||||
* Info: www.datatables.net
|
||||
*
|
||||
* Copyright 2008-2012 Allan Jardine, all rights reserved.
|
||||
*
|
||||
* This source file is free software, under either the GPL v2 license or a
|
||||
* BSD style license, available at:
|
||||
* http://datatables.net/license_gpl2
|
||||
* http://datatables.net/license_bsd
|
||||
*
|
||||
* This source file is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
|
||||
*/
|
||||
(function(X,l,n){var L=function(h){var j=function(e){function o(a,b){var c=j.defaults.columns,d=a.aoColumns.length,c=h.extend({},j.models.oColumn,c,{sSortingClass:a.oClasses.sSortable,sSortingClassJUI:a.oClasses.sSortJUI,nTh:b?b:l.createElement("th"),sTitle:c.sTitle?c.sTitle:b?b.innerHTML:"",aDataSort:c.aDataSort?c.aDataSort:[d],mData:c.mData?c.oDefaults:d});a.aoColumns.push(c);if(a.aoPreSearchCols[d]===n||null===a.aoPreSearchCols[d])a.aoPreSearchCols[d]=h.extend({},j.models.oSearch);else if(c=a.aoPreSearchCols[d],
|
||||
c.bRegex===n&&(c.bRegex=!0),c.bSmart===n&&(c.bSmart=!0),c.bCaseInsensitive===n)c.bCaseInsensitive=!0;m(a,d,null)}function m(a,b,c){var d=a.aoColumns[b];c!==n&&null!==c&&(c.mDataProp&&!c.mData&&(c.mData=c.mDataProp),c.sType!==n&&(d.sType=c.sType,d._bAutoType=!1),h.extend(d,c),p(d,c,"sWidth","sWidthOrig"),c.iDataSort!==n&&(d.aDataSort=[c.iDataSort]),p(d,c,"aDataSort"));var i=d.mRender?Q(d.mRender):null,f=Q(d.mData);d.fnGetData=function(a,b){var c=f(a,b);return d.mRender&&b&&""!==b?i(c,b,a):c};d.fnSetData=
|
||||
L(d.mData);a.oFeatures.bSort||(d.bSortable=!1);!d.bSortable||-1==h.inArray("asc",d.asSorting)&&-1==h.inArray("desc",d.asSorting)?(d.sSortingClass=a.oClasses.sSortableNone,d.sSortingClassJUI=""):-1==h.inArray("asc",d.asSorting)&&-1==h.inArray("desc",d.asSorting)?(d.sSortingClass=a.oClasses.sSortable,d.sSortingClassJUI=a.oClasses.sSortJUI):-1!=h.inArray("asc",d.asSorting)&&-1==h.inArray("desc",d.asSorting)?(d.sSortingClass=a.oClasses.sSortableAsc,d.sSortingClassJUI=a.oClasses.sSortJUIAscAllowed):-1==
|
||||
h.inArray("asc",d.asSorting)&&-1!=h.inArray("desc",d.asSorting)&&(d.sSortingClass=a.oClasses.sSortableDesc,d.sSortingClassJUI=a.oClasses.sSortJUIDescAllowed)}function k(a){if(!1===a.oFeatures.bAutoWidth)return!1;da(a);for(var b=0,c=a.aoColumns.length;b<c;b++)a.aoColumns[b].nTh.style.width=a.aoColumns[b].sWidth}function G(a,b){var c=r(a,"bVisible");return"number"===typeof c[b]?c[b]:null}function R(a,b){var c=r(a,"bVisible"),c=h.inArray(b,c);return-1!==c?c:null}function t(a){return r(a,"bVisible").length}
|
||||
function r(a,b){var c=[];h.map(a.aoColumns,function(a,i){a[b]&&c.push(i)});return c}function B(a){for(var b=j.ext.aTypes,c=b.length,d=0;d<c;d++){var i=b[d](a);if(null!==i)return i}return"string"}function u(a,b){for(var c=b.split(","),d=[],i=0,f=a.aoColumns.length;i<f;i++)for(var g=0;g<f;g++)if(a.aoColumns[i].sName==c[g]){d.push(g);break}return d}function M(a){for(var b="",c=0,d=a.aoColumns.length;c<d;c++)b+=a.aoColumns[c].sName+",";return b.length==d?"":b.slice(0,-1)}function ta(a,b,c,d){var i,f,
|
||||
g,e,w;if(b)for(i=b.length-1;0<=i;i--){var j=b[i].aTargets;h.isArray(j)||D(a,1,"aTargets must be an array of targets, not a "+typeof j);f=0;for(g=j.length;f<g;f++)if("number"===typeof j[f]&&0<=j[f]){for(;a.aoColumns.length<=j[f];)o(a);d(j[f],b[i])}else if("number"===typeof j[f]&&0>j[f])d(a.aoColumns.length+j[f],b[i]);else if("string"===typeof j[f]){e=0;for(w=a.aoColumns.length;e<w;e++)("_all"==j[f]||h(a.aoColumns[e].nTh).hasClass(j[f]))&&d(e,b[i])}}if(c){i=0;for(a=c.length;i<a;i++)d(i,c[i])}}function H(a,
|
||||
b){var c;c=h.isArray(b)?b.slice():h.extend(!0,{},b);var d=a.aoData.length,i=h.extend(!0,{},j.models.oRow);i._aData=c;a.aoData.push(i);for(var f,i=0,g=a.aoColumns.length;i<g;i++)c=a.aoColumns[i],"function"===typeof c.fnRender&&c.bUseRendered&&null!==c.mData?F(a,d,i,S(a,d,i)):F(a,d,i,v(a,d,i)),c._bAutoType&&"string"!=c.sType&&(f=v(a,d,i,"type"),null!==f&&""!==f&&(f=B(f),null===c.sType?c.sType=f:c.sType!=f&&"html"!=c.sType&&(c.sType="string")));a.aiDisplayMaster.push(d);a.oFeatures.bDeferRender||ea(a,
|
||||
d);return d}function ua(a){var b,c,d,i,f,g,e;if(a.bDeferLoading||null===a.sAjaxSource)for(b=a.nTBody.firstChild;b;){if("TR"==b.nodeName.toUpperCase()){c=a.aoData.length;b._DT_RowIndex=c;a.aoData.push(h.extend(!0,{},j.models.oRow,{nTr:b}));a.aiDisplayMaster.push(c);f=b.firstChild;for(d=0;f;){g=f.nodeName.toUpperCase();if("TD"==g||"TH"==g)F(a,c,d,h.trim(f.innerHTML)),d++;f=f.nextSibling}}b=b.nextSibling}i=T(a);d=[];b=0;for(c=i.length;b<c;b++)for(f=i[b].firstChild;f;)g=f.nodeName.toUpperCase(),("TD"==
|
||||
g||"TH"==g)&&d.push(f),f=f.nextSibling;c=0;for(i=a.aoColumns.length;c<i;c++){e=a.aoColumns[c];null===e.sTitle&&(e.sTitle=e.nTh.innerHTML);var w=e._bAutoType,o="function"===typeof e.fnRender,k=null!==e.sClass,n=e.bVisible,m,p;if(w||o||k||!n){g=0;for(b=a.aoData.length;g<b;g++)f=a.aoData[g],m=d[g*i+c],w&&"string"!=e.sType&&(p=v(a,g,c,"type"),""!==p&&(p=B(p),null===e.sType?e.sType=p:e.sType!=p&&"html"!=e.sType&&(e.sType="string"))),e.mRender?m.innerHTML=v(a,g,c,"display"):e.mData!==c&&(m.innerHTML=v(a,
|
||||
g,c,"display")),o&&(p=S(a,g,c),m.innerHTML=p,e.bUseRendered&&F(a,g,c,p)),k&&(m.className+=" "+e.sClass),n?f._anHidden[c]=null:(f._anHidden[c]=m,m.parentNode.removeChild(m)),e.fnCreatedCell&&e.fnCreatedCell.call(a.oInstance,m,v(a,g,c,"display"),f._aData,g,c)}}if(0!==a.aoRowCreatedCallback.length){b=0;for(c=a.aoData.length;b<c;b++)f=a.aoData[b],A(a,"aoRowCreatedCallback",null,[f.nTr,f._aData,b])}}function I(a,b){return b._DT_RowIndex!==n?b._DT_RowIndex:null}function fa(a,b,c){for(var b=J(a,b),d=0,a=
|
||||
a.aoColumns.length;d<a;d++)if(b[d]===c)return d;return-1}function Y(a,b,c,d){for(var i=[],f=0,g=d.length;f<g;f++)i.push(v(a,b,d[f],c));return i}function v(a,b,c,d){var i=a.aoColumns[c];if((c=i.fnGetData(a.aoData[b]._aData,d))===n)return a.iDrawError!=a.iDraw&&null===i.sDefaultContent&&(D(a,0,"Requested unknown parameter "+("function"==typeof i.mData?"{mData function}":"'"+i.mData+"'")+" from the data source for row "+b),a.iDrawError=a.iDraw),i.sDefaultContent;if(null===c&&null!==i.sDefaultContent)c=
|
||||
i.sDefaultContent;else if("function"===typeof c)return c();return"display"==d&&null===c?"":c}function F(a,b,c,d){a.aoColumns[c].fnSetData(a.aoData[b]._aData,d)}function Q(a){if(null===a)return function(){return null};if("function"===typeof a)return function(b,d,i){return a(b,d,i)};if("string"===typeof a&&(-1!==a.indexOf(".")||-1!==a.indexOf("["))){var b=function(a,d,i){var f=i.split("."),g;if(""!==i){var e=0;for(g=f.length;e<g;e++){if(i=f[e].match(U)){f[e]=f[e].replace(U,"");""!==f[e]&&(a=a[f[e]]);
|
||||
g=[];f.splice(0,e+1);for(var f=f.join("."),e=0,h=a.length;e<h;e++)g.push(b(a[e],d,f));a=i[0].substring(1,i[0].length-1);a=""===a?g:g.join(a);break}if(null===a||a[f[e]]===n)return n;a=a[f[e]]}}return a};return function(c,d){return b(c,d,a)}}return function(b){return b[a]}}function L(a){if(null===a)return function(){};if("function"===typeof a)return function(b,d){a(b,"set",d)};if("string"===typeof a&&(-1!==a.indexOf(".")||-1!==a.indexOf("["))){var b=function(a,d,i){var i=i.split("."),f,g,e=0;for(g=
|
||||
i.length-1;e<g;e++){if(f=i[e].match(U)){i[e]=i[e].replace(U,"");a[i[e]]=[];f=i.slice();f.splice(0,e+1);g=f.join(".");for(var h=0,j=d.length;h<j;h++)f={},b(f,d[h],g),a[i[e]].push(f);return}if(null===a[i[e]]||a[i[e]]===n)a[i[e]]={};a=a[i[e]]}a[i[i.length-1].replace(U,"")]=d};return function(c,d){return b(c,d,a)}}return function(b,d){b[a]=d}}function Z(a){for(var b=[],c=a.aoData.length,d=0;d<c;d++)b.push(a.aoData[d]._aData);return b}function ga(a){a.aoData.splice(0,a.aoData.length);a.aiDisplayMaster.splice(0,
|
||||
a.aiDisplayMaster.length);a.aiDisplay.splice(0,a.aiDisplay.length);y(a)}function ha(a,b){for(var c=-1,d=0,i=a.length;d<i;d++)a[d]==b?c=d:a[d]>b&&a[d]--; -1!=c&&a.splice(c,1)}function S(a,b,c){var d=a.aoColumns[c];return d.fnRender({iDataRow:b,iDataColumn:c,oSettings:a,aData:a.aoData[b]._aData,mDataProp:d.mData},v(a,b,c,"display"))}function ea(a,b){var c=a.aoData[b],d;if(null===c.nTr){c.nTr=l.createElement("tr");c.nTr._DT_RowIndex=b;c._aData.DT_RowId&&(c.nTr.id=c._aData.DT_RowId);c._aData.DT_RowClass&&
|
||||
(c.nTr.className=c._aData.DT_RowClass);for(var i=0,f=a.aoColumns.length;i<f;i++){var g=a.aoColumns[i];d=l.createElement(g.sCellType);d.innerHTML="function"===typeof g.fnRender&&(!g.bUseRendered||null===g.mData)?S(a,b,i):v(a,b,i,"display");null!==g.sClass&&(d.className=g.sClass);g.bVisible?(c.nTr.appendChild(d),c._anHidden[i]=null):c._anHidden[i]=d;g.fnCreatedCell&&g.fnCreatedCell.call(a.oInstance,d,v(a,b,i,"display"),c._aData,b,i)}A(a,"aoRowCreatedCallback",null,[c.nTr,c._aData,b])}}function va(a){var b,
|
||||
c,d;if(0!==h("th, td",a.nTHead).length){b=0;for(d=a.aoColumns.length;b<d;b++)if(c=a.aoColumns[b].nTh,c.setAttribute("role","columnheader"),a.aoColumns[b].bSortable&&(c.setAttribute("tabindex",a.iTabIndex),c.setAttribute("aria-controls",a.sTableId)),null!==a.aoColumns[b].sClass&&h(c).addClass(a.aoColumns[b].sClass),a.aoColumns[b].sTitle!=c.innerHTML)c.innerHTML=a.aoColumns[b].sTitle}else{var i=l.createElement("tr");b=0;for(d=a.aoColumns.length;b<d;b++)c=a.aoColumns[b].nTh,c.innerHTML=a.aoColumns[b].sTitle,
|
||||
c.setAttribute("tabindex","0"),null!==a.aoColumns[b].sClass&&h(c).addClass(a.aoColumns[b].sClass),i.appendChild(c);h(a.nTHead).html("")[0].appendChild(i);V(a.aoHeader,a.nTHead)}h(a.nTHead).children("tr").attr("role","row");if(a.bJUI){b=0;for(d=a.aoColumns.length;b<d;b++){c=a.aoColumns[b].nTh;i=l.createElement("div");i.className=a.oClasses.sSortJUIWrapper;h(c).contents().appendTo(i);var f=l.createElement("span");f.className=a.oClasses.sSortIcon;i.appendChild(f);c.appendChild(i)}}if(a.oFeatures.bSort)for(b=
|
||||
0;b<a.aoColumns.length;b++)!1!==a.aoColumns[b].bSortable?ia(a,a.aoColumns[b].nTh,b):h(a.aoColumns[b].nTh).addClass(a.oClasses.sSortableNone);""!==a.oClasses.sFooterTH&&h(a.nTFoot).children("tr").children("th").addClass(a.oClasses.sFooterTH);if(null!==a.nTFoot){c=N(a,null,a.aoFooter);b=0;for(d=a.aoColumns.length;b<d;b++)c[b]&&(a.aoColumns[b].nTf=c[b],a.aoColumns[b].sClass&&h(c[b]).addClass(a.aoColumns[b].sClass))}}function W(a,b,c){var d,i,f,g=[],e=[],h=a.aoColumns.length,j;c===n&&(c=!1);d=0;for(i=
|
||||
b.length;d<i;d++){g[d]=b[d].slice();g[d].nTr=b[d].nTr;for(f=h-1;0<=f;f--)!a.aoColumns[f].bVisible&&!c&&g[d].splice(f,1);e.push([])}d=0;for(i=g.length;d<i;d++){if(a=g[d].nTr)for(;f=a.firstChild;)a.removeChild(f);f=0;for(b=g[d].length;f<b;f++)if(j=h=1,e[d][f]===n){a.appendChild(g[d][f].cell);for(e[d][f]=1;g[d+h]!==n&&g[d][f].cell==g[d+h][f].cell;)e[d+h][f]=1,h++;for(;g[d][f+j]!==n&&g[d][f].cell==g[d][f+j].cell;){for(c=0;c<h;c++)e[d+c][f+j]=1;j++}g[d][f].cell.rowSpan=h;g[d][f].cell.colSpan=j}}}function x(a){var b=
|
||||
A(a,"aoPreDrawCallback","preDraw",[a]);if(-1!==h.inArray(!1,b))E(a,!1);else{var c,d,b=[],i=0,f=a.asStripeClasses.length;c=a.aoOpenRows.length;a.bDrawing=!0;a.iInitDisplayStart!==n&&-1!=a.iInitDisplayStart&&(a._iDisplayStart=a.oFeatures.bServerSide?a.iInitDisplayStart:a.iInitDisplayStart>=a.fnRecordsDisplay()?0:a.iInitDisplayStart,a.iInitDisplayStart=-1,y(a));if(a.bDeferLoading)a.bDeferLoading=!1,a.iDraw++;else if(a.oFeatures.bServerSide){if(!a.bDestroying&&!wa(a))return}else a.iDraw++;if(0!==a.aiDisplay.length){var g=
|
||||
a._iDisplayStart;d=a._iDisplayEnd;a.oFeatures.bServerSide&&(g=0,d=a.aoData.length);for(;g<d;g++){var e=a.aoData[a.aiDisplay[g]];null===e.nTr&&ea(a,a.aiDisplay[g]);var j=e.nTr;if(0!==f){var o=a.asStripeClasses[i%f];e._sRowStripe!=o&&(h(j).removeClass(e._sRowStripe).addClass(o),e._sRowStripe=o)}A(a,"aoRowCallback",null,[j,a.aoData[a.aiDisplay[g]]._aData,i,g]);b.push(j);i++;if(0!==c)for(e=0;e<c;e++)if(j==a.aoOpenRows[e].nParent){b.push(a.aoOpenRows[e].nTr);break}}}else b[0]=l.createElement("tr"),a.asStripeClasses[0]&&
|
||||
(b[0].className=a.asStripeClasses[0]),c=a.oLanguage,f=c.sZeroRecords,1==a.iDraw&&null!==a.sAjaxSource&&!a.oFeatures.bServerSide?f=c.sLoadingRecords:c.sEmptyTable&&0===a.fnRecordsTotal()&&(f=c.sEmptyTable),c=l.createElement("td"),c.setAttribute("valign","top"),c.colSpan=t(a),c.className=a.oClasses.sRowEmpty,c.innerHTML=ja(a,f),b[i].appendChild(c);A(a,"aoHeaderCallback","header",[h(a.nTHead).children("tr")[0],Z(a),a._iDisplayStart,a.fnDisplayEnd(),a.aiDisplay]);A(a,"aoFooterCallback","footer",[h(a.nTFoot).children("tr")[0],
|
||||
Z(a),a._iDisplayStart,a.fnDisplayEnd(),a.aiDisplay]);i=l.createDocumentFragment();c=l.createDocumentFragment();if(a.nTBody){f=a.nTBody.parentNode;c.appendChild(a.nTBody);if(!a.oScroll.bInfinite||!a._bInitComplete||a.bSorted||a.bFiltered)for(;c=a.nTBody.firstChild;)a.nTBody.removeChild(c);c=0;for(d=b.length;c<d;c++)i.appendChild(b[c]);a.nTBody.appendChild(i);null!==f&&f.appendChild(a.nTBody)}A(a,"aoDrawCallback","draw",[a]);a.bSorted=!1;a.bFiltered=!1;a.bDrawing=!1;a.oFeatures.bServerSide&&(E(a,!1),
|
||||
a._bInitComplete||$(a))}}function aa(a){a.oFeatures.bSort?O(a,a.oPreviousSearch):a.oFeatures.bFilter?K(a,a.oPreviousSearch):(y(a),x(a))}function xa(a){var b=h("<div></div>")[0];a.nTable.parentNode.insertBefore(b,a.nTable);a.nTableWrapper=h('<div id="'+a.sTableId+'_wrapper" class="'+a.oClasses.sWrapper+'" role="grid"></div>')[0];a.nTableReinsertBefore=a.nTable.nextSibling;for(var c=a.nTableWrapper,d=a.sDom.split(""),i,f,g,e,w,o,k,m=0;m<d.length;m++){f=0;g=d[m];if("<"==g){e=h("<div></div>")[0];w=d[m+
|
||||
1];if("'"==w||'"'==w){o="";for(k=2;d[m+k]!=w;)o+=d[m+k],k++;"H"==o?o=a.oClasses.sJUIHeader:"F"==o&&(o=a.oClasses.sJUIFooter);-1!=o.indexOf(".")?(w=o.split("."),e.id=w[0].substr(1,w[0].length-1),e.className=w[1]):"#"==o.charAt(0)?e.id=o.substr(1,o.length-1):e.className=o;m+=k}c.appendChild(e);c=e}else if(">"==g)c=c.parentNode;else if("l"==g&&a.oFeatures.bPaginate&&a.oFeatures.bLengthChange)i=ya(a),f=1;else if("f"==g&&a.oFeatures.bFilter)i=za(a),f=1;else if("r"==g&&a.oFeatures.bProcessing)i=Aa(a),f=
|
||||
1;else if("t"==g)i=Ba(a),f=1;else if("i"==g&&a.oFeatures.bInfo)i=Ca(a),f=1;else if("p"==g&&a.oFeatures.bPaginate)i=Da(a),f=1;else if(0!==j.ext.aoFeatures.length){e=j.ext.aoFeatures;k=0;for(w=e.length;k<w;k++)if(g==e[k].cFeature){(i=e[k].fnInit(a))&&(f=1);break}}1==f&&null!==i&&("object"!==typeof a.aanFeatures[g]&&(a.aanFeatures[g]=[]),a.aanFeatures[g].push(i),c.appendChild(i))}b.parentNode.replaceChild(a.nTableWrapper,b)}function V(a,b){var c=h(b).children("tr"),d,i,f,g,e,j,o,k,m,p;a.splice(0,a.length);
|
||||
f=0;for(j=c.length;f<j;f++)a.push([]);f=0;for(j=c.length;f<j;f++){d=c[f];for(i=d.firstChild;i;){if("TD"==i.nodeName.toUpperCase()||"TH"==i.nodeName.toUpperCase()){k=1*i.getAttribute("colspan");m=1*i.getAttribute("rowspan");k=!k||0===k||1===k?1:k;m=!m||0===m||1===m?1:m;g=0;for(e=a[f];e[g];)g++;o=g;p=1===k?!0:!1;for(e=0;e<k;e++)for(g=0;g<m;g++)a[f+g][o+e]={cell:i,unique:p},a[f+g].nTr=d}i=i.nextSibling}}}function N(a,b,c){var d=[];c||(c=a.aoHeader,b&&(c=[],V(c,b)));for(var b=0,i=c.length;b<i;b++)for(var f=
|
||||
0,g=c[b].length;f<g;f++)if(c[b][f].unique&&(!d[f]||!a.bSortCellsTop))d[f]=c[b][f].cell;return d}function wa(a){if(a.bAjaxDataGet){a.iDraw++;E(a,!0);var b=Ea(a);ka(a,b);a.fnServerData.call(a.oInstance,a.sAjaxSource,b,function(b){Fa(a,b)},a);return!1}return!0}function Ea(a){var b=a.aoColumns.length,c=[],d,i,f,g;c.push({name:"sEcho",value:a.iDraw});c.push({name:"iColumns",value:b});c.push({name:"sColumns",value:M(a)});c.push({name:"iDisplayStart",value:a._iDisplayStart});c.push({name:"iDisplayLength",
|
||||
value:!1!==a.oFeatures.bPaginate?a._iDisplayLength:-1});for(f=0;f<b;f++)d=a.aoColumns[f].mData,c.push({name:"mDataProp_"+f,value:"function"===typeof d?"function":d});if(!1!==a.oFeatures.bFilter){c.push({name:"sSearch",value:a.oPreviousSearch.sSearch});c.push({name:"bRegex",value:a.oPreviousSearch.bRegex});for(f=0;f<b;f++)c.push({name:"sSearch_"+f,value:a.aoPreSearchCols[f].sSearch}),c.push({name:"bRegex_"+f,value:a.aoPreSearchCols[f].bRegex}),c.push({name:"bSearchable_"+f,value:a.aoColumns[f].bSearchable})}if(!1!==
|
||||
a.oFeatures.bSort){var e=0;d=null!==a.aaSortingFixed?a.aaSortingFixed.concat(a.aaSorting):a.aaSorting.slice();for(f=0;f<d.length;f++){i=a.aoColumns[d[f][0]].aDataSort;for(g=0;g<i.length;g++)c.push({name:"iSortCol_"+e,value:i[g]}),c.push({name:"sSortDir_"+e,value:d[f][1]}),e++}c.push({name:"iSortingCols",value:e});for(f=0;f<b;f++)c.push({name:"bSortable_"+f,value:a.aoColumns[f].bSortable})}return c}function ka(a,b){A(a,"aoServerParams","serverParams",[b])}function Fa(a,b){if(b.sEcho!==n){if(1*b.sEcho<
|
||||
a.iDraw)return;a.iDraw=1*b.sEcho}(!a.oScroll.bInfinite||a.oScroll.bInfinite&&(a.bSorted||a.bFiltered))&&ga(a);a._iRecordsTotal=parseInt(b.iTotalRecords,10);a._iRecordsDisplay=parseInt(b.iTotalDisplayRecords,10);var c=M(a),c=b.sColumns!==n&&""!==c&&b.sColumns!=c,d;c&&(d=u(a,b.sColumns));for(var i=Q(a.sAjaxDataProp)(b),f=0,g=i.length;f<g;f++)if(c){for(var e=[],h=0,j=a.aoColumns.length;h<j;h++)e.push(i[f][d[h]]);H(a,e)}else H(a,i[f]);a.aiDisplay=a.aiDisplayMaster.slice();a.bAjaxDataGet=!1;x(a);a.bAjaxDataGet=
|
||||
!0;E(a,!1)}function za(a){var b=a.oPreviousSearch,c=a.oLanguage.sSearch,c=-1!==c.indexOf("_INPUT_")?c.replace("_INPUT_",'<input type="text" />'):""===c?'<input type="text" />':c+' <input type="text" />',d=l.createElement("div");d.className=a.oClasses.sFilter;d.innerHTML="<label>"+c+"</label>";a.aanFeatures.f||(d.id=a.sTableId+"_filter");c=h('input[type="text"]',d);d._DT_Input=c[0];c.val(b.sSearch.replace('"',"""));c.bind("keyup.DT",function(){for(var c=a.aanFeatures.f,d=this.value===""?"":this.value,
|
||||
g=0,e=c.length;g<e;g++)c[g]!=h(this).parents("div.dataTables_filter")[0]&&h(c[g]._DT_Input).val(d);d!=b.sSearch&&K(a,{sSearch:d,bRegex:b.bRegex,bSmart:b.bSmart,bCaseInsensitive:b.bCaseInsensitive})});c.attr("aria-controls",a.sTableId).bind("keypress.DT",function(a){if(a.keyCode==13)return false});return d}function K(a,b,c){var d=a.oPreviousSearch,i=a.aoPreSearchCols,f=function(a){d.sSearch=a.sSearch;d.bRegex=a.bRegex;d.bSmart=a.bSmart;d.bCaseInsensitive=a.bCaseInsensitive};if(a.oFeatures.bServerSide)f(b);
|
||||
else{Ga(a,b.sSearch,c,b.bRegex,b.bSmart,b.bCaseInsensitive);f(b);for(b=0;b<a.aoPreSearchCols.length;b++)Ha(a,i[b].sSearch,b,i[b].bRegex,i[b].bSmart,i[b].bCaseInsensitive);Ia(a)}a.bFiltered=!0;h(a.oInstance).trigger("filter",a);a._iDisplayStart=0;y(a);x(a);la(a,0)}function Ia(a){for(var b=j.ext.afnFiltering,c=r(a,"bSearchable"),d=0,i=b.length;d<i;d++)for(var f=0,g=0,e=a.aiDisplay.length;g<e;g++){var h=a.aiDisplay[g-f];b[d](a,Y(a,h,"filter",c),h)||(a.aiDisplay.splice(g-f,1),f++)}}function Ha(a,b,c,
|
||||
d,i,f){if(""!==b)for(var g=0,b=ma(b,d,i,f),d=a.aiDisplay.length-1;0<=d;d--)i=Ja(v(a,a.aiDisplay[d],c,"filter"),a.aoColumns[c].sType),b.test(i)||(a.aiDisplay.splice(d,1),g++)}function Ga(a,b,c,d,i,f){d=ma(b,d,i,f);i=a.oPreviousSearch;c||(c=0);0!==j.ext.afnFiltering.length&&(c=1);if(0>=b.length)a.aiDisplay.splice(0,a.aiDisplay.length),a.aiDisplay=a.aiDisplayMaster.slice();else if(a.aiDisplay.length==a.aiDisplayMaster.length||i.sSearch.length>b.length||1==c||0!==b.indexOf(i.sSearch)){a.aiDisplay.splice(0,
|
||||
a.aiDisplay.length);la(a,1);for(b=0;b<a.aiDisplayMaster.length;b++)d.test(a.asDataSearch[b])&&a.aiDisplay.push(a.aiDisplayMaster[b])}else for(b=c=0;b<a.asDataSearch.length;b++)d.test(a.asDataSearch[b])||(a.aiDisplay.splice(b-c,1),c++)}function la(a,b){if(!a.oFeatures.bServerSide){a.asDataSearch=[];for(var c=r(a,"bSearchable"),d=1===b?a.aiDisplayMaster:a.aiDisplay,i=0,f=d.length;i<f;i++)a.asDataSearch[i]=na(a,Y(a,d[i],"filter",c))}}function na(a,b){var c=b.join(" ");-1!==c.indexOf("&")&&(c=h("<div>").html(c).text());
|
||||
return c.replace(/[\n\r]/g," ")}function ma(a,b,c,d){if(c)return a=b?a.split(" "):oa(a).split(" "),a="^(?=.*?"+a.join(")(?=.*?")+").*$",RegExp(a,d?"i":"");a=b?a:oa(a);return RegExp(a,d?"i":"")}function Ja(a,b){return"function"===typeof j.ext.ofnSearch[b]?j.ext.ofnSearch[b](a):null===a?"":"html"==b?a.replace(/[\r\n]/g," ").replace(/<.*?>/g,""):"string"===typeof a?a.replace(/[\r\n]/g," "):a}function oa(a){return a.replace(RegExp("(\\/|\\.|\\*|\\+|\\?|\\||\\(|\\)|\\[|\\]|\\{|\\}|\\\\|\\$|\\^|\\-)","g"),
|
||||
"\\$1")}function Ca(a){var b=l.createElement("div");b.className=a.oClasses.sInfo;a.aanFeatures.i||(a.aoDrawCallback.push({fn:Ka,sName:"information"}),b.id=a.sTableId+"_info");a.nTable.setAttribute("aria-describedby",a.sTableId+"_info");return b}function Ka(a){if(a.oFeatures.bInfo&&0!==a.aanFeatures.i.length){var b=a.oLanguage,c=a._iDisplayStart+1,d=a.fnDisplayEnd(),i=a.fnRecordsTotal(),f=a.fnRecordsDisplay(),g;g=0===f?b.sInfoEmpty:b.sInfo;f!=i&&(g+=" "+b.sInfoFiltered);g+=b.sInfoPostFix;g=ja(a,g);
|
||||
null!==b.fnInfoCallback&&(g=b.fnInfoCallback.call(a.oInstance,a,c,d,i,f,g));a=a.aanFeatures.i;b=0;for(c=a.length;b<c;b++)h(a[b]).html(g)}}function ja(a,b){var c=a.fnFormatNumber(a._iDisplayStart+1),d=a.fnDisplayEnd(),d=a.fnFormatNumber(d),i=a.fnRecordsDisplay(),i=a.fnFormatNumber(i),f=a.fnRecordsTotal(),f=a.fnFormatNumber(f);a.oScroll.bInfinite&&(c=a.fnFormatNumber(1));return b.replace(/_START_/g,c).replace(/_END_/g,d).replace(/_TOTAL_/g,i).replace(/_MAX_/g,f)}function ba(a){var b,c,d=a.iInitDisplayStart;
|
||||
if(!1===a.bInitialised)setTimeout(function(){ba(a)},200);else{xa(a);va(a);W(a,a.aoHeader);a.nTFoot&&W(a,a.aoFooter);E(a,!0);a.oFeatures.bAutoWidth&&da(a);b=0;for(c=a.aoColumns.length;b<c;b++)null!==a.aoColumns[b].sWidth&&(a.aoColumns[b].nTh.style.width=q(a.aoColumns[b].sWidth));a.oFeatures.bSort?O(a):a.oFeatures.bFilter?K(a,a.oPreviousSearch):(a.aiDisplay=a.aiDisplayMaster.slice(),y(a),x(a));null!==a.sAjaxSource&&!a.oFeatures.bServerSide?(c=[],ka(a,c),a.fnServerData.call(a.oInstance,a.sAjaxSource,
|
||||
c,function(c){var f=a.sAjaxDataProp!==""?Q(a.sAjaxDataProp)(c):c;for(b=0;b<f.length;b++)H(a,f[b]);a.iInitDisplayStart=d;if(a.oFeatures.bSort)O(a);else{a.aiDisplay=a.aiDisplayMaster.slice();y(a);x(a)}E(a,false);$(a,c)},a)):a.oFeatures.bServerSide||(E(a,!1),$(a))}}function $(a,b){a._bInitComplete=!0;A(a,"aoInitComplete","init",[a,b])}function pa(a){var b=j.defaults.oLanguage;!a.sEmptyTable&&(a.sZeroRecords&&"No data available in table"===b.sEmptyTable)&&p(a,a,"sZeroRecords","sEmptyTable");!a.sLoadingRecords&&
|
||||
(a.sZeroRecords&&"Loading..."===b.sLoadingRecords)&&p(a,a,"sZeroRecords","sLoadingRecords")}function ya(a){if(a.oScroll.bInfinite)return null;var b='<select size="1" '+('name="'+a.sTableId+'_length"')+">",c,d,i=a.aLengthMenu;if(2==i.length&&"object"===typeof i[0]&&"object"===typeof i[1]){c=0;for(d=i[0].length;c<d;c++)b+='<option value="'+i[0][c]+'">'+i[1][c]+"</option>"}else{c=0;for(d=i.length;c<d;c++)b+='<option value="'+i[c]+'">'+i[c]+"</option>"}b+="</select>";i=l.createElement("div");a.aanFeatures.l||
|
||||
(i.id=a.sTableId+"_length");i.className=a.oClasses.sLength;i.innerHTML="<label>"+a.oLanguage.sLengthMenu.replace("_MENU_",b)+"</label>";h('select option[value="'+a._iDisplayLength+'"]',i).attr("selected",!0);h("select",i).bind("change.DT",function(){var b=h(this).val(),i=a.aanFeatures.l;c=0;for(d=i.length;c<d;c++)i[c]!=this.parentNode&&h("select",i[c]).val(b);a._iDisplayLength=parseInt(b,10);y(a);if(a.fnDisplayEnd()==a.fnRecordsDisplay()){a._iDisplayStart=a.fnDisplayEnd()-a._iDisplayLength;if(a._iDisplayStart<
|
||||
0)a._iDisplayStart=0}if(a._iDisplayLength==-1)a._iDisplayStart=0;x(a)});h("select",i).attr("aria-controls",a.sTableId);return i}function y(a){a._iDisplayEnd=!1===a.oFeatures.bPaginate?a.aiDisplay.length:a._iDisplayStart+a._iDisplayLength>a.aiDisplay.length||-1==a._iDisplayLength?a.aiDisplay.length:a._iDisplayStart+a._iDisplayLength}function Da(a){if(a.oScroll.bInfinite)return null;var b=l.createElement("div");b.className=a.oClasses.sPaging+a.sPaginationType;j.ext.oPagination[a.sPaginationType].fnInit(a,
|
||||
b,function(a){y(a);x(a)});a.aanFeatures.p||a.aoDrawCallback.push({fn:function(a){j.ext.oPagination[a.sPaginationType].fnUpdate(a,function(a){y(a);x(a)})},sName:"pagination"});return b}function qa(a,b){var c=a._iDisplayStart;if("number"===typeof b)a._iDisplayStart=b*a._iDisplayLength,a._iDisplayStart>a.fnRecordsDisplay()&&(a._iDisplayStart=0);else if("first"==b)a._iDisplayStart=0;else if("previous"==b)a._iDisplayStart=0<=a._iDisplayLength?a._iDisplayStart-a._iDisplayLength:0,0>a._iDisplayStart&&(a._iDisplayStart=
|
||||
0);else if("next"==b)0<=a._iDisplayLength?a._iDisplayStart+a._iDisplayLength<a.fnRecordsDisplay()&&(a._iDisplayStart+=a._iDisplayLength):a._iDisplayStart=0;else if("last"==b)if(0<=a._iDisplayLength){var d=parseInt((a.fnRecordsDisplay()-1)/a._iDisplayLength,10)+1;a._iDisplayStart=(d-1)*a._iDisplayLength}else a._iDisplayStart=0;else D(a,0,"Unknown paging action: "+b);h(a.oInstance).trigger("page",a);return c!=a._iDisplayStart}function Aa(a){var b=l.createElement("div");a.aanFeatures.r||(b.id=a.sTableId+
|
||||
"_processing");b.innerHTML=a.oLanguage.sProcessing;b.className=a.oClasses.sProcessing;a.nTable.parentNode.insertBefore(b,a.nTable);return b}function E(a,b){if(a.oFeatures.bProcessing)for(var c=a.aanFeatures.r,d=0,i=c.length;d<i;d++)c[d].style.visibility=b?"visible":"hidden";h(a.oInstance).trigger("processing",[a,b])}function Ba(a){if(""===a.oScroll.sX&&""===a.oScroll.sY)return a.nTable;var b=l.createElement("div"),c=l.createElement("div"),d=l.createElement("div"),i=l.createElement("div"),f=l.createElement("div"),
|
||||
g=l.createElement("div"),e=a.nTable.cloneNode(!1),j=a.nTable.cloneNode(!1),o=a.nTable.getElementsByTagName("thead")[0],k=0===a.nTable.getElementsByTagName("tfoot").length?null:a.nTable.getElementsByTagName("tfoot")[0],m=a.oClasses;c.appendChild(d);f.appendChild(g);i.appendChild(a.nTable);b.appendChild(c);b.appendChild(i);d.appendChild(e);e.appendChild(o);null!==k&&(b.appendChild(f),g.appendChild(j),j.appendChild(k));b.className=m.sScrollWrapper;c.className=m.sScrollHead;d.className=m.sScrollHeadInner;
|
||||
i.className=m.sScrollBody;f.className=m.sScrollFoot;g.className=m.sScrollFootInner;a.oScroll.bAutoCss&&(c.style.overflow="hidden",c.style.position="relative",f.style.overflow="hidden",i.style.overflow="auto");c.style.border="0";c.style.width="100%";f.style.border="0";d.style.width=""!==a.oScroll.sXInner?a.oScroll.sXInner:"100%";e.removeAttribute("id");e.style.marginLeft="0";a.nTable.style.marginLeft="0";null!==k&&(j.removeAttribute("id"),j.style.marginLeft="0");d=h(a.nTable).children("caption");0<
|
||||
d.length&&(d=d[0],"top"===d._captionSide?e.appendChild(d):"bottom"===d._captionSide&&k&&j.appendChild(d));""!==a.oScroll.sX&&(c.style.width=q(a.oScroll.sX),i.style.width=q(a.oScroll.sX),null!==k&&(f.style.width=q(a.oScroll.sX)),h(i).scroll(function(){c.scrollLeft=this.scrollLeft;if(k!==null)f.scrollLeft=this.scrollLeft}));""!==a.oScroll.sY&&(i.style.height=q(a.oScroll.sY));a.aoDrawCallback.push({fn:La,sName:"scrolling"});a.oScroll.bInfinite&&h(i).scroll(function(){if(!a.bDrawing&&h(this).scrollTop()!==
|
||||
0&&h(this).scrollTop()+h(this).height()>h(a.nTable).height()-a.oScroll.iLoadGap&&a.fnDisplayEnd()<a.fnRecordsDisplay()){qa(a,"next");y(a);x(a)}});a.nScrollHead=c;a.nScrollFoot=f;return b}function La(a){var b=a.nScrollHead.getElementsByTagName("div")[0],c=b.getElementsByTagName("table")[0],d=a.nTable.parentNode,i,f,g,e,j,o,k,m,p=[],n=[],l=null!==a.nTFoot?a.nScrollFoot.getElementsByTagName("div")[0]:null,R=null!==a.nTFoot?l.getElementsByTagName("table")[0]:null,r=a.oBrowser.bScrollOversize,s=function(a){k=
|
||||
a.style;k.paddingTop="0";k.paddingBottom="0";k.borderTopWidth="0";k.borderBottomWidth="0";k.height=0};h(a.nTable).children("thead, tfoot").remove();i=h(a.nTHead).clone()[0];a.nTable.insertBefore(i,a.nTable.childNodes[0]);g=a.nTHead.getElementsByTagName("tr");e=i.getElementsByTagName("tr");null!==a.nTFoot&&(j=h(a.nTFoot).clone()[0],a.nTable.insertBefore(j,a.nTable.childNodes[1]),o=a.nTFoot.getElementsByTagName("tr"),j=j.getElementsByTagName("tr"));""===a.oScroll.sX&&(d.style.width="100%",b.parentNode.style.width=
|
||||
"100%");var t=N(a,i);i=0;for(f=t.length;i<f;i++)m=G(a,i),t[i].style.width=a.aoColumns[m].sWidth;null!==a.nTFoot&&C(function(a){a.style.width=""},j);a.oScroll.bCollapse&&""!==a.oScroll.sY&&(d.style.height=d.offsetHeight+a.nTHead.offsetHeight+"px");i=h(a.nTable).outerWidth();if(""===a.oScroll.sX){if(a.nTable.style.width="100%",r&&(h("tbody",d).height()>d.offsetHeight||"scroll"==h(d).css("overflow-y")))a.nTable.style.width=q(h(a.nTable).outerWidth()-a.oScroll.iBarWidth)}else""!==a.oScroll.sXInner?a.nTable.style.width=
|
||||
q(a.oScroll.sXInner):i==h(d).width()&&h(d).height()<h(a.nTable).height()?(a.nTable.style.width=q(i-a.oScroll.iBarWidth),h(a.nTable).outerWidth()>i-a.oScroll.iBarWidth&&(a.nTable.style.width=q(i))):a.nTable.style.width=q(i);i=h(a.nTable).outerWidth();C(s,e);C(function(a){p.push(q(h(a).width()))},e);C(function(a,b){a.style.width=p[b]},g);h(e).height(0);null!==a.nTFoot&&(C(s,j),C(function(a){n.push(q(h(a).width()))},j),C(function(a,b){a.style.width=n[b]},o),h(j).height(0));C(function(a,b){a.innerHTML=
|
||||
"";a.style.width=p[b]},e);null!==a.nTFoot&&C(function(a,b){a.innerHTML="";a.style.width=n[b]},j);if(h(a.nTable).outerWidth()<i){g=d.scrollHeight>d.offsetHeight||"scroll"==h(d).css("overflow-y")?i+a.oScroll.iBarWidth:i;if(r&&(d.scrollHeight>d.offsetHeight||"scroll"==h(d).css("overflow-y")))a.nTable.style.width=q(g-a.oScroll.iBarWidth);d.style.width=q(g);a.nScrollHead.style.width=q(g);null!==a.nTFoot&&(a.nScrollFoot.style.width=q(g));""===a.oScroll.sX?D(a,1,"The table cannot fit into the current element which will cause column misalignment. The table has been drawn at its minimum possible width."):
|
||||
""!==a.oScroll.sXInner&&D(a,1,"The table cannot fit into the current element which will cause column misalignment. Increase the sScrollXInner value or remove it to allow automatic calculation")}else d.style.width=q("100%"),a.nScrollHead.style.width=q("100%"),null!==a.nTFoot&&(a.nScrollFoot.style.width=q("100%"));""===a.oScroll.sY&&r&&(d.style.height=q(a.nTable.offsetHeight+a.oScroll.iBarWidth));""!==a.oScroll.sY&&a.oScroll.bCollapse&&(d.style.height=q(a.oScroll.sY),r=""!==a.oScroll.sX&&a.nTable.offsetWidth>
|
||||
d.offsetWidth?a.oScroll.iBarWidth:0,a.nTable.offsetHeight<d.offsetHeight&&(d.style.height=q(a.nTable.offsetHeight+r)));r=h(a.nTable).outerWidth();c.style.width=q(r);b.style.width=q(r);c=h(a.nTable).height()>d.clientHeight||"scroll"==h(d).css("overflow-y");b.style.paddingRight=c?a.oScroll.iBarWidth+"px":"0px";null!==a.nTFoot&&(R.style.width=q(r),l.style.width=q(r),l.style.paddingRight=c?a.oScroll.iBarWidth+"px":"0px");h(d).scroll();if(a.bSorted||a.bFiltered)d.scrollTop=0}function C(a,b,c){for(var d=
|
||||
0,i=0,f=b.length,g,e;i<f;){g=b[i].firstChild;for(e=c?c[i].firstChild:null;g;)1===g.nodeType&&(c?a(g,e,d):a(g,d),d++),g=g.nextSibling,e=c?e.nextSibling:null;i++}}function Ma(a,b){if(!a||null===a||""===a)return 0;b||(b=l.body);var c,d=l.createElement("div");d.style.width=q(a);b.appendChild(d);c=d.offsetWidth;b.removeChild(d);return c}function da(a){var b=0,c,d=0,i=a.aoColumns.length,f,e,j=h("th",a.nTHead),o=a.nTable.getAttribute("width");e=a.nTable.parentNode;for(f=0;f<i;f++)a.aoColumns[f].bVisible&&
|
||||
(d++,null!==a.aoColumns[f].sWidth&&(c=Ma(a.aoColumns[f].sWidthOrig,e),null!==c&&(a.aoColumns[f].sWidth=q(c)),b++));if(i==j.length&&0===b&&d==i&&""===a.oScroll.sX&&""===a.oScroll.sY)for(f=0;f<a.aoColumns.length;f++)c=h(j[f]).width(),null!==c&&(a.aoColumns[f].sWidth=q(c));else{b=a.nTable.cloneNode(!1);f=a.nTHead.cloneNode(!0);d=l.createElement("tbody");c=l.createElement("tr");b.removeAttribute("id");b.appendChild(f);null!==a.nTFoot&&(b.appendChild(a.nTFoot.cloneNode(!0)),C(function(a){a.style.width=
|
||||
""},b.getElementsByTagName("tr")));b.appendChild(d);d.appendChild(c);d=h("thead th",b);0===d.length&&(d=h("tbody tr:eq(0)>td",b));j=N(a,f);for(f=d=0;f<i;f++){var k=a.aoColumns[f];k.bVisible&&null!==k.sWidthOrig&&""!==k.sWidthOrig?j[f-d].style.width=q(k.sWidthOrig):k.bVisible?j[f-d].style.width="":d++}for(f=0;f<i;f++)a.aoColumns[f].bVisible&&(d=Na(a,f),null!==d&&(d=d.cloneNode(!0),""!==a.aoColumns[f].sContentPadding&&(d.innerHTML+=a.aoColumns[f].sContentPadding),c.appendChild(d)));e.appendChild(b);
|
||||
""!==a.oScroll.sX&&""!==a.oScroll.sXInner?b.style.width=q(a.oScroll.sXInner):""!==a.oScroll.sX?(b.style.width="",h(b).width()<e.offsetWidth&&(b.style.width=q(e.offsetWidth))):""!==a.oScroll.sY?b.style.width=q(e.offsetWidth):o&&(b.style.width=q(o));b.style.visibility="hidden";Oa(a,b);i=h("tbody tr:eq(0)",b).children();0===i.length&&(i=N(a,h("thead",b)[0]));if(""!==a.oScroll.sX){for(f=d=e=0;f<a.aoColumns.length;f++)a.aoColumns[f].bVisible&&(e=null===a.aoColumns[f].sWidthOrig?e+h(i[d]).outerWidth():
|
||||
e+(parseInt(a.aoColumns[f].sWidth.replace("px",""),10)+(h(i[d]).outerWidth()-h(i[d]).width())),d++);b.style.width=q(e);a.nTable.style.width=q(e)}for(f=d=0;f<a.aoColumns.length;f++)a.aoColumns[f].bVisible&&(e=h(i[d]).width(),null!==e&&0<e&&(a.aoColumns[f].sWidth=q(e)),d++);i=h(b).css("width");a.nTable.style.width=-1!==i.indexOf("%")?i:q(h(b).outerWidth());b.parentNode.removeChild(b)}o&&(a.nTable.style.width=q(o))}function Oa(a,b){""===a.oScroll.sX&&""!==a.oScroll.sY?(h(b).width(),b.style.width=q(h(b).outerWidth()-
|
||||
a.oScroll.iBarWidth)):""!==a.oScroll.sX&&(b.style.width=q(h(b).outerWidth()))}function Na(a,b){var c=Pa(a,b);if(0>c)return null;if(null===a.aoData[c].nTr){var d=l.createElement("td");d.innerHTML=v(a,c,b,"");return d}return J(a,c)[b]}function Pa(a,b){for(var c=-1,d=-1,i=0;i<a.aoData.length;i++){var e=v(a,i,b,"display")+"",e=e.replace(/<.*?>/g,"");e.length>c&&(c=e.length,d=i)}return d}function q(a){if(null===a)return"0px";if("number"==typeof a)return 0>a?"0px":a+"px";var b=a.charCodeAt(a.length-1);
|
||||
return 48>b||57<b?a:a+"px"}function Qa(){var a=l.createElement("p"),b=a.style;b.width="100%";b.height="200px";b.padding="0px";var c=l.createElement("div"),b=c.style;b.position="absolute";b.top="0px";b.left="0px";b.visibility="hidden";b.width="200px";b.height="150px";b.padding="0px";b.overflow="hidden";c.appendChild(a);l.body.appendChild(c);b=a.offsetWidth;c.style.overflow="scroll";a=a.offsetWidth;b==a&&(a=c.clientWidth);l.body.removeChild(c);return b-a}function O(a,b){var c,d,i,e,g,k,o=[],m=[],p=
|
||||
j.ext.oSort,l=a.aoData,q=a.aoColumns,G=a.oLanguage.oAria;if(!a.oFeatures.bServerSide&&(0!==a.aaSorting.length||null!==a.aaSortingFixed)){o=null!==a.aaSortingFixed?a.aaSortingFixed.concat(a.aaSorting):a.aaSorting.slice();for(c=0;c<o.length;c++)if(d=o[c][0],i=R(a,d),e=a.aoColumns[d].sSortDataType,j.ext.afnSortData[e])if(g=j.ext.afnSortData[e].call(a.oInstance,a,d,i),g.length===l.length){i=0;for(e=l.length;i<e;i++)F(a,i,d,g[i])}else D(a,0,"Returned data sort array (col "+d+") is the wrong length");c=
|
||||
0;for(d=a.aiDisplayMaster.length;c<d;c++)m[a.aiDisplayMaster[c]]=c;var r=o.length,s;c=0;for(d=l.length;c<d;c++)for(i=0;i<r;i++){s=q[o[i][0]].aDataSort;g=0;for(k=s.length;g<k;g++)e=q[s[g]].sType,e=p[(e?e:"string")+"-pre"],l[c]._aSortData[s[g]]=e?e(v(a,c,s[g],"sort")):v(a,c,s[g],"sort")}a.aiDisplayMaster.sort(function(a,b){var c,d,e,i,f;for(c=0;c<r;c++){f=q[o[c][0]].aDataSort;d=0;for(e=f.length;d<e;d++)if(i=q[f[d]].sType,i=p[(i?i:"string")+"-"+o[c][1]](l[a]._aSortData[f[d]],l[b]._aSortData[f[d]]),0!==
|
||||
i)return i}return p["numeric-asc"](m[a],m[b])})}(b===n||b)&&!a.oFeatures.bDeferRender&&P(a);c=0;for(d=a.aoColumns.length;c<d;c++)e=q[c].sTitle.replace(/<.*?>/g,""),i=q[c].nTh,i.removeAttribute("aria-sort"),i.removeAttribute("aria-label"),q[c].bSortable?0<o.length&&o[0][0]==c?(i.setAttribute("aria-sort","asc"==o[0][1]?"ascending":"descending"),i.setAttribute("aria-label",e+("asc"==(q[c].asSorting[o[0][2]+1]?q[c].asSorting[o[0][2]+1]:q[c].asSorting[0])?G.sSortAscending:G.sSortDescending))):i.setAttribute("aria-label",
|
||||
e+("asc"==q[c].asSorting[0]?G.sSortAscending:G.sSortDescending)):i.setAttribute("aria-label",e);a.bSorted=!0;h(a.oInstance).trigger("sort",a);a.oFeatures.bFilter?K(a,a.oPreviousSearch,1):(a.aiDisplay=a.aiDisplayMaster.slice(),a._iDisplayStart=0,y(a),x(a))}function ia(a,b,c,d){Ra(b,{},function(b){if(!1!==a.aoColumns[c].bSortable){var e=function(){var d,e;if(b.shiftKey){for(var f=!1,h=0;h<a.aaSorting.length;h++)if(a.aaSorting[h][0]==c){f=!0;d=a.aaSorting[h][0];e=a.aaSorting[h][2]+1;a.aoColumns[d].asSorting[e]?
|
||||
(a.aaSorting[h][1]=a.aoColumns[d].asSorting[e],a.aaSorting[h][2]=e):a.aaSorting.splice(h,1);break}!1===f&&a.aaSorting.push([c,a.aoColumns[c].asSorting[0],0])}else 1==a.aaSorting.length&&a.aaSorting[0][0]==c?(d=a.aaSorting[0][0],e=a.aaSorting[0][2]+1,a.aoColumns[d].asSorting[e]||(e=0),a.aaSorting[0][1]=a.aoColumns[d].asSorting[e],a.aaSorting[0][2]=e):(a.aaSorting.splice(0,a.aaSorting.length),a.aaSorting.push([c,a.aoColumns[c].asSorting[0],0]));O(a)};a.oFeatures.bProcessing?(E(a,!0),setTimeout(function(){e();
|
||||
a.oFeatures.bServerSide||E(a,!1)},0)):e();"function"==typeof d&&d(a)}})}function P(a){var b,c,d,e,f,g=a.aoColumns.length,j=a.oClasses;for(b=0;b<g;b++)a.aoColumns[b].bSortable&&h(a.aoColumns[b].nTh).removeClass(j.sSortAsc+" "+j.sSortDesc+" "+a.aoColumns[b].sSortingClass);c=null!==a.aaSortingFixed?a.aaSortingFixed.concat(a.aaSorting):a.aaSorting.slice();for(b=0;b<a.aoColumns.length;b++)if(a.aoColumns[b].bSortable){f=a.aoColumns[b].sSortingClass;e=-1;for(d=0;d<c.length;d++)if(c[d][0]==b){f="asc"==c[d][1]?
|
||||
j.sSortAsc:j.sSortDesc;e=d;break}h(a.aoColumns[b].nTh).addClass(f);a.bJUI&&(f=h("span."+j.sSortIcon,a.aoColumns[b].nTh),f.removeClass(j.sSortJUIAsc+" "+j.sSortJUIDesc+" "+j.sSortJUI+" "+j.sSortJUIAscAllowed+" "+j.sSortJUIDescAllowed),f.addClass(-1==e?a.aoColumns[b].sSortingClassJUI:"asc"==c[e][1]?j.sSortJUIAsc:j.sSortJUIDesc))}else h(a.aoColumns[b].nTh).addClass(a.aoColumns[b].sSortingClass);f=j.sSortColumn;if(a.oFeatures.bSort&&a.oFeatures.bSortClasses){a=J(a);e=[];for(b=0;b<g;b++)e.push("");b=0;
|
||||
for(d=1;b<c.length;b++)j=parseInt(c[b][0],10),e[j]=f+d,3>d&&d++;f=RegExp(f+"[123]");var o;b=0;for(c=a.length;b<c;b++)j=b%g,d=a[b].className,o=e[j],j=d.replace(f,o),j!=d?a[b].className=h.trim(j):0<o.length&&-1==d.indexOf(o)&&(a[b].className=d+" "+o)}}function ra(a){if(a.oFeatures.bStateSave&&!a.bDestroying){var b,c;b=a.oScroll.bInfinite;var d={iCreate:(new Date).getTime(),iStart:b?0:a._iDisplayStart,iEnd:b?a._iDisplayLength:a._iDisplayEnd,iLength:a._iDisplayLength,aaSorting:h.extend(!0,[],a.aaSorting),
|
||||
oSearch:h.extend(!0,{},a.oPreviousSearch),aoSearchCols:h.extend(!0,[],a.aoPreSearchCols),abVisCols:[]};b=0;for(c=a.aoColumns.length;b<c;b++)d.abVisCols.push(a.aoColumns[b].bVisible);A(a,"aoStateSaveParams","stateSaveParams",[a,d]);a.fnStateSave.call(a.oInstance,a,d)}}function Sa(a,b){if(a.oFeatures.bStateSave){var c=a.fnStateLoad.call(a.oInstance,a);if(c){var d=A(a,"aoStateLoadParams","stateLoadParams",[a,c]);if(-1===h.inArray(!1,d)){a.oLoadedState=h.extend(!0,{},c);a._iDisplayStart=c.iStart;a.iInitDisplayStart=
|
||||
c.iStart;a._iDisplayEnd=c.iEnd;a._iDisplayLength=c.iLength;a.aaSorting=c.aaSorting.slice();a.saved_aaSorting=c.aaSorting.slice();h.extend(a.oPreviousSearch,c.oSearch);h.extend(!0,a.aoPreSearchCols,c.aoSearchCols);b.saved_aoColumns=[];for(d=0;d<c.abVisCols.length;d++)b.saved_aoColumns[d]={},b.saved_aoColumns[d].bVisible=c.abVisCols[d];A(a,"aoStateLoaded","stateLoaded",[a,c])}}}}function s(a){for(var b=0;b<j.settings.length;b++)if(j.settings[b].nTable===a)return j.settings[b];return null}function T(a){for(var b=
|
||||
[],a=a.aoData,c=0,d=a.length;c<d;c++)null!==a[c].nTr&&b.push(a[c].nTr);return b}function J(a,b){var c=[],d,e,f,g,h,j;e=0;var o=a.aoData.length;b!==n&&(e=b,o=b+1);for(f=e;f<o;f++)if(j=a.aoData[f],null!==j.nTr){e=[];for(d=j.nTr.firstChild;d;)g=d.nodeName.toLowerCase(),("td"==g||"th"==g)&&e.push(d),d=d.nextSibling;g=d=0;for(h=a.aoColumns.length;g<h;g++)a.aoColumns[g].bVisible?c.push(e[g-d]):(c.push(j._anHidden[g]),d++)}return c}function D(a,b,c){a=null===a?"DataTables warning: "+c:"DataTables warning (table id = '"+
|
||||
a.sTableId+"'): "+c;if(0===b)if("alert"==j.ext.sErrMode)alert(a);else throw Error(a);else X.console&&console.log&&console.log(a)}function p(a,b,c,d){d===n&&(d=c);b[c]!==n&&(a[d]=b[c])}function Ta(a,b){var c,d;for(d in b)b.hasOwnProperty(d)&&(c=b[d],"object"===typeof e[d]&&null!==c&&!1===h.isArray(c)?h.extend(!0,a[d],c):a[d]=c);return a}function Ra(a,b,c){h(a).bind("click.DT",b,function(b){a.blur();c(b)}).bind("keypress.DT",b,function(a){13===a.which&&c(a)}).bind("selectstart.DT",function(){return!1})}
|
||||
function z(a,b,c,d){c&&a[b].push({fn:c,sName:d})}function A(a,b,c,d){for(var b=a[b],e=[],f=b.length-1;0<=f;f--)e.push(b[f].fn.apply(a.oInstance,d));null!==c&&h(a.oInstance).trigger(c,d);return e}function Ua(a){var b=h('<div style="position:absolute; top:0; left:0; height:1px; width:1px; overflow:hidden"><div style="position:absolute; top:1px; left:1px; width:100px; overflow:scroll;"><div id="DT_BrowserTest" style="width:100%; height:10px;"></div></div></div>')[0];l.body.appendChild(b);a.oBrowser.bScrollOversize=
|
||||
100===h("#DT_BrowserTest",b)[0].offsetWidth?!0:!1;l.body.removeChild(b)}function Va(a){return function(){var b=[s(this[j.ext.iApiIndex])].concat(Array.prototype.slice.call(arguments));return j.ext.oApi[a].apply(this,b)}}var U=/\[.*?\]$/,Wa=X.JSON?JSON.stringify:function(a){var b=typeof a;if("object"!==b||null===a)return"string"===b&&(a='"'+a+'"'),a+"";var c,d,e=[],f=h.isArray(a);for(c in a)d=a[c],b=typeof d,"string"===b?d='"'+d+'"':"object"===b&&null!==d&&(d=Wa(d)),e.push((f?"":'"'+c+'":')+d);return(f?
|
||||
"[":"{")+e+(f?"]":"}")};this.$=function(a,b){var c,d,e=[],f;d=s(this[j.ext.iApiIndex]);var g=d.aoData,o=d.aiDisplay,k=d.aiDisplayMaster;b||(b={});b=h.extend({},{filter:"none",order:"current",page:"all"},b);if("current"==b.page){c=d._iDisplayStart;for(d=d.fnDisplayEnd();c<d;c++)(f=g[o[c]].nTr)&&e.push(f)}else if("current"==b.order&&"none"==b.filter){c=0;for(d=k.length;c<d;c++)(f=g[k[c]].nTr)&&e.push(f)}else if("current"==b.order&&"applied"==b.filter){c=0;for(d=o.length;c<d;c++)(f=g[o[c]].nTr)&&e.push(f)}else if("original"==
|
||||
b.order&&"none"==b.filter){c=0;for(d=g.length;c<d;c++)(f=g[c].nTr)&&e.push(f)}else if("original"==b.order&&"applied"==b.filter){c=0;for(d=g.length;c<d;c++)f=g[c].nTr,-1!==h.inArray(c,o)&&f&&e.push(f)}else D(d,1,"Unknown selection options");e=h(e);c=e.filter(a);e=e.find(a);return h([].concat(h.makeArray(c),h.makeArray(e)))};this._=function(a,b){var c=[],d,e,f=this.$(a,b);d=0;for(e=f.length;d<e;d++)c.push(this.fnGetData(f[d]));return c};this.fnAddData=function(a,b){if(0===a.length)return[];var c=[],
|
||||
d,e=s(this[j.ext.iApiIndex]);if("object"===typeof a[0]&&null!==a[0])for(var f=0;f<a.length;f++){d=H(e,a[f]);if(-1==d)return c;c.push(d)}else{d=H(e,a);if(-1==d)return c;c.push(d)}e.aiDisplay=e.aiDisplayMaster.slice();(b===n||b)&&aa(e);return c};this.fnAdjustColumnSizing=function(a){var b=s(this[j.ext.iApiIndex]);k(b);a===n||a?this.fnDraw(!1):(""!==b.oScroll.sX||""!==b.oScroll.sY)&&this.oApi._fnScrollDraw(b)};this.fnClearTable=function(a){var b=s(this[j.ext.iApiIndex]);ga(b);(a===n||a)&&x(b)};this.fnClose=
|
||||
function(a){for(var b=s(this[j.ext.iApiIndex]),c=0;c<b.aoOpenRows.length;c++)if(b.aoOpenRows[c].nParent==a)return(a=b.aoOpenRows[c].nTr.parentNode)&&a.removeChild(b.aoOpenRows[c].nTr),b.aoOpenRows.splice(c,1),0;return 1};this.fnDeleteRow=function(a,b,c){var d=s(this[j.ext.iApiIndex]),e,f,a="object"===typeof a?I(d,a):a,g=d.aoData.splice(a,1);e=0;for(f=d.aoData.length;e<f;e++)null!==d.aoData[e].nTr&&(d.aoData[e].nTr._DT_RowIndex=e);e=h.inArray(a,d.aiDisplay);d.asDataSearch.splice(e,1);ha(d.aiDisplayMaster,
|
||||
a);ha(d.aiDisplay,a);"function"===typeof b&&b.call(this,d,g);d._iDisplayStart>=d.fnRecordsDisplay()&&(d._iDisplayStart-=d._iDisplayLength,0>d._iDisplayStart&&(d._iDisplayStart=0));if(c===n||c)y(d),x(d);return g};this.fnDestroy=function(a){var b=s(this[j.ext.iApiIndex]),c=b.nTableWrapper.parentNode,d=b.nTBody,i,f,a=a===n?!1:a;b.bDestroying=!0;A(b,"aoDestroyCallback","destroy",[b]);if(!a){i=0;for(f=b.aoColumns.length;i<f;i++)!1===b.aoColumns[i].bVisible&&this.fnSetColumnVis(i,!0)}h(b.nTableWrapper).find("*").andSelf().unbind(".DT");
|
||||
h("tbody>tr>td."+b.oClasses.sRowEmpty,b.nTable).parent().remove();b.nTable!=b.nTHead.parentNode&&(h(b.nTable).children("thead").remove(),b.nTable.appendChild(b.nTHead));b.nTFoot&&b.nTable!=b.nTFoot.parentNode&&(h(b.nTable).children("tfoot").remove(),b.nTable.appendChild(b.nTFoot));b.nTable.parentNode.removeChild(b.nTable);h(b.nTableWrapper).remove();b.aaSorting=[];b.aaSortingFixed=[];P(b);h(T(b)).removeClass(b.asStripeClasses.join(" "));h("th, td",b.nTHead).removeClass([b.oClasses.sSortable,b.oClasses.sSortableAsc,
|
||||
b.oClasses.sSortableDesc,b.oClasses.sSortableNone].join(" "));b.bJUI&&(h("th span."+b.oClasses.sSortIcon+", td span."+b.oClasses.sSortIcon,b.nTHead).remove(),h("th, td",b.nTHead).each(function(){var a=h("div."+b.oClasses.sSortJUIWrapper,this),c=a.contents();h(this).append(c);a.remove()}));!a&&b.nTableReinsertBefore?c.insertBefore(b.nTable,b.nTableReinsertBefore):a||c.appendChild(b.nTable);i=0;for(f=b.aoData.length;i<f;i++)null!==b.aoData[i].nTr&&d.appendChild(b.aoData[i].nTr);!0===b.oFeatures.bAutoWidth&&
|
||||
(b.nTable.style.width=q(b.sDestroyWidth));if(f=b.asDestroyStripes.length){a=h(d).children("tr");for(i=0;i<f;i++)a.filter(":nth-child("+f+"n + "+i+")").addClass(b.asDestroyStripes[i])}i=0;for(f=j.settings.length;i<f;i++)j.settings[i]==b&&j.settings.splice(i,1);e=b=null};this.fnDraw=function(a){var b=s(this[j.ext.iApiIndex]);!1===a?(y(b),x(b)):aa(b)};this.fnFilter=function(a,b,c,d,e,f){var g=s(this[j.ext.iApiIndex]);if(g.oFeatures.bFilter){if(c===n||null===c)c=!1;if(d===n||null===d)d=!0;if(e===n||null===
|
||||
e)e=!0;if(f===n||null===f)f=!0;if(b===n||null===b){if(K(g,{sSearch:a+"",bRegex:c,bSmart:d,bCaseInsensitive:f},1),e&&g.aanFeatures.f){b=g.aanFeatures.f;c=0;for(d=b.length;c<d;c++)try{b[c]._DT_Input!=l.activeElement&&h(b[c]._DT_Input).val(a)}catch(o){h(b[c]._DT_Input).val(a)}}}else h.extend(g.aoPreSearchCols[b],{sSearch:a+"",bRegex:c,bSmart:d,bCaseInsensitive:f}),K(g,g.oPreviousSearch,1)}};this.fnGetData=function(a,b){var c=s(this[j.ext.iApiIndex]);if(a!==n){var d=a;if("object"===typeof a){var e=a.nodeName.toLowerCase();
|
||||
"tr"===e?d=I(c,a):"td"===e&&(d=I(c,a.parentNode),b=fa(c,d,a))}return b!==n?v(c,d,b,""):c.aoData[d]!==n?c.aoData[d]._aData:null}return Z(c)};this.fnGetNodes=function(a){var b=s(this[j.ext.iApiIndex]);return a!==n?b.aoData[a]!==n?b.aoData[a].nTr:null:T(b)};this.fnGetPosition=function(a){var b=s(this[j.ext.iApiIndex]),c=a.nodeName.toUpperCase();return"TR"==c?I(b,a):"TD"==c||"TH"==c?(c=I(b,a.parentNode),a=fa(b,c,a),[c,R(b,a),a]):null};this.fnIsOpen=function(a){for(var b=s(this[j.ext.iApiIndex]),c=0;c<
|
||||
b.aoOpenRows.length;c++)if(b.aoOpenRows[c].nParent==a)return!0;return!1};this.fnOpen=function(a,b,c){var d=s(this[j.ext.iApiIndex]),e=T(d);if(-1!==h.inArray(a,e)){this.fnClose(a);var e=l.createElement("tr"),f=l.createElement("td");e.appendChild(f);f.className=c;f.colSpan=t(d);"string"===typeof b?f.innerHTML=b:h(f).html(b);b=h("tr",d.nTBody);-1!=h.inArray(a,b)&&h(e).insertAfter(a);d.aoOpenRows.push({nTr:e,nParent:a});return e}};this.fnPageChange=function(a,b){var c=s(this[j.ext.iApiIndex]);qa(c,a);
|
||||
y(c);(b===n||b)&&x(c)};this.fnSetColumnVis=function(a,b,c){var d=s(this[j.ext.iApiIndex]),e,f,g=d.aoColumns,h=d.aoData,o,m;if(g[a].bVisible!=b){if(b){for(e=f=0;e<a;e++)g[e].bVisible&&f++;m=f>=t(d);if(!m)for(e=a;e<g.length;e++)if(g[e].bVisible){o=e;break}e=0;for(f=h.length;e<f;e++)null!==h[e].nTr&&(m?h[e].nTr.appendChild(h[e]._anHidden[a]):h[e].nTr.insertBefore(h[e]._anHidden[a],J(d,e)[o]))}else{e=0;for(f=h.length;e<f;e++)null!==h[e].nTr&&(o=J(d,e)[a],h[e]._anHidden[a]=o,o.parentNode.removeChild(o))}g[a].bVisible=
|
||||
b;W(d,d.aoHeader);d.nTFoot&&W(d,d.aoFooter);e=0;for(f=d.aoOpenRows.length;e<f;e++)d.aoOpenRows[e].nTr.colSpan=t(d);if(c===n||c)k(d),x(d);ra(d)}};this.fnSettings=function(){return s(this[j.ext.iApiIndex])};this.fnSort=function(a){var b=s(this[j.ext.iApiIndex]);b.aaSorting=a;O(b)};this.fnSortListener=function(a,b,c){ia(s(this[j.ext.iApiIndex]),a,b,c)};this.fnUpdate=function(a,b,c,d,e){var f=s(this[j.ext.iApiIndex]),b="object"===typeof b?I(f,b):b;if(h.isArray(a)&&c===n){f.aoData[b]._aData=a.slice();
|
||||
for(c=0;c<f.aoColumns.length;c++)this.fnUpdate(v(f,b,c),b,c,!1,!1)}else if(h.isPlainObject(a)&&c===n){f.aoData[b]._aData=h.extend(!0,{},a);for(c=0;c<f.aoColumns.length;c++)this.fnUpdate(v(f,b,c),b,c,!1,!1)}else{F(f,b,c,a);var a=v(f,b,c,"display"),g=f.aoColumns[c];null!==g.fnRender&&(a=S(f,b,c),g.bUseRendered&&F(f,b,c,a));null!==f.aoData[b].nTr&&(J(f,b)[c].innerHTML=a)}c=h.inArray(b,f.aiDisplay);f.asDataSearch[c]=na(f,Y(f,b,"filter",r(f,"bSearchable")));(e===n||e)&&k(f);(d===n||d)&&aa(f);return 0};
|
||||
this.fnVersionCheck=j.ext.fnVersionCheck;this.oApi={_fnExternApiFunc:Va,_fnInitialise:ba,_fnInitComplete:$,_fnLanguageCompat:pa,_fnAddColumn:o,_fnColumnOptions:m,_fnAddData:H,_fnCreateTr:ea,_fnGatherData:ua,_fnBuildHead:va,_fnDrawHead:W,_fnDraw:x,_fnReDraw:aa,_fnAjaxUpdate:wa,_fnAjaxParameters:Ea,_fnAjaxUpdateDraw:Fa,_fnServerParams:ka,_fnAddOptionsHtml:xa,_fnFeatureHtmlTable:Ba,_fnScrollDraw:La,_fnAdjustColumnSizing:k,_fnFeatureHtmlFilter:za,_fnFilterComplete:K,_fnFilterCustom:Ia,_fnFilterColumn:Ha,
|
||||
_fnFilter:Ga,_fnBuildSearchArray:la,_fnBuildSearchRow:na,_fnFilterCreateSearch:ma,_fnDataToSearch:Ja,_fnSort:O,_fnSortAttachListener:ia,_fnSortingClasses:P,_fnFeatureHtmlPaginate:Da,_fnPageChange:qa,_fnFeatureHtmlInfo:Ca,_fnUpdateInfo:Ka,_fnFeatureHtmlLength:ya,_fnFeatureHtmlProcessing:Aa,_fnProcessingDisplay:E,_fnVisibleToColumnIndex:G,_fnColumnIndexToVisible:R,_fnNodeToDataIndex:I,_fnVisbleColumns:t,_fnCalculateEnd:y,_fnConvertToWidth:Ma,_fnCalculateColumnWidths:da,_fnScrollingWidthAdjust:Oa,_fnGetWidestNode:Na,
|
||||
_fnGetMaxLenString:Pa,_fnStringToCss:q,_fnDetectType:B,_fnSettingsFromNode:s,_fnGetDataMaster:Z,_fnGetTrNodes:T,_fnGetTdNodes:J,_fnEscapeRegex:oa,_fnDeleteIndex:ha,_fnReOrderIndex:u,_fnColumnOrdering:M,_fnLog:D,_fnClearTable:ga,_fnSaveState:ra,_fnLoadState:Sa,_fnCreateCookie:function(a,b,c,d,e){var f=new Date;f.setTime(f.getTime()+1E3*c);var c=X.location.pathname.split("/"),a=a+"_"+c.pop().replace(/[\/:]/g,"").toLowerCase(),g;null!==e?(g="function"===typeof h.parseJSON?h.parseJSON(b):eval("("+b+")"),
|
||||
b=e(a,g,f.toGMTString(),c.join("/")+"/")):b=a+"="+encodeURIComponent(b)+"; expires="+f.toGMTString()+"; path="+c.join("/")+"/";a=l.cookie.split(";");e=b.split(";")[0].length;f=[];if(4096<e+l.cookie.length+10){for(var j=0,o=a.length;j<o;j++)if(-1!=a[j].indexOf(d)){var k=a[j].split("=");try{(g=eval("("+decodeURIComponent(k[1])+")"))&&g.iCreate&&f.push({name:k[0],time:g.iCreate})}catch(m){}}for(f.sort(function(a,b){return b.time-a.time});4096<e+l.cookie.length+10;){if(0===f.length)return;d=f.pop();l.cookie=
|
||||
d.name+"=; expires=Thu, 01-Jan-1970 00:00:01 GMT; path="+c.join("/")+"/"}}l.cookie=b},_fnReadCookie:function(a){for(var b=X.location.pathname.split("/"),a=a+"_"+b[b.length-1].replace(/[\/:]/g,"").toLowerCase()+"=",b=l.cookie.split(";"),c=0;c<b.length;c++){for(var d=b[c];" "==d.charAt(0);)d=d.substring(1,d.length);if(0===d.indexOf(a))return decodeURIComponent(d.substring(a.length,d.length))}return null},_fnDetectHeader:V,_fnGetUniqueThs:N,_fnScrollBarWidth:Qa,_fnApplyToChildren:C,_fnMap:p,_fnGetRowData:Y,
|
||||
_fnGetCellData:v,_fnSetCellData:F,_fnGetObjectDataFn:Q,_fnSetObjectDataFn:L,_fnApplyColumnDefs:ta,_fnBindAction:Ra,_fnExtend:Ta,_fnCallbackReg:z,_fnCallbackFire:A,_fnJsonString:Wa,_fnRender:S,_fnNodeToColumnIndex:fa,_fnInfoMacros:ja,_fnBrowserDetect:Ua,_fnGetColumns:r};h.extend(j.ext.oApi,this.oApi);for(var sa in j.ext.oApi)sa&&(this[sa]=Va(sa));var ca=this;this.each(function(){var a=0,b,c,d;c=this.getAttribute("id");var i=!1,f=!1;if("table"!=this.nodeName.toLowerCase())D(null,0,"Attempted to initialise DataTables on a node which is not a table: "+
|
||||
this.nodeName);else{a=0;for(b=j.settings.length;a<b;a++){if(j.settings[a].nTable==this){if(e===n||e.bRetrieve)return j.settings[a].oInstance;if(e.bDestroy){j.settings[a].oInstance.fnDestroy();break}else{D(j.settings[a],0,"Cannot reinitialise DataTable.\n\nTo retrieve the DataTables object for this table, pass no arguments or see the docs for bRetrieve and bDestroy");return}}if(j.settings[a].sTableId==this.id){j.settings.splice(a,1);break}}if(null===c||""===c)this.id=c="DataTables_Table_"+j.ext._oExternConfig.iNextUnique++;
|
||||
var g=h.extend(!0,{},j.models.oSettings,{nTable:this,oApi:ca.oApi,oInit:e,sDestroyWidth:h(this).width(),sInstance:c,sTableId:c});j.settings.push(g);g.oInstance=1===ca.length?ca:h(this).dataTable();e||(e={});e.oLanguage&&pa(e.oLanguage);e=Ta(h.extend(!0,{},j.defaults),e);p(g.oFeatures,e,"bPaginate");p(g.oFeatures,e,"bLengthChange");p(g.oFeatures,e,"bFilter");p(g.oFeatures,e,"bSort");p(g.oFeatures,e,"bInfo");p(g.oFeatures,e,"bProcessing");p(g.oFeatures,e,"bAutoWidth");p(g.oFeatures,e,"bSortClasses");
|
||||
p(g.oFeatures,e,"bServerSide");p(g.oFeatures,e,"bDeferRender");p(g.oScroll,e,"sScrollX","sX");p(g.oScroll,e,"sScrollXInner","sXInner");p(g.oScroll,e,"sScrollY","sY");p(g.oScroll,e,"bScrollCollapse","bCollapse");p(g.oScroll,e,"bScrollInfinite","bInfinite");p(g.oScroll,e,"iScrollLoadGap","iLoadGap");p(g.oScroll,e,"bScrollAutoCss","bAutoCss");p(g,e,"asStripeClasses");p(g,e,"asStripClasses","asStripeClasses");p(g,e,"fnServerData");p(g,e,"fnFormatNumber");p(g,e,"sServerMethod");p(g,e,"aaSorting");p(g,
|
||||
e,"aaSortingFixed");p(g,e,"aLengthMenu");p(g,e,"sPaginationType");p(g,e,"sAjaxSource");p(g,e,"sAjaxDataProp");p(g,e,"iCookieDuration");p(g,e,"sCookiePrefix");p(g,e,"sDom");p(g,e,"bSortCellsTop");p(g,e,"iTabIndex");p(g,e,"oSearch","oPreviousSearch");p(g,e,"aoSearchCols","aoPreSearchCols");p(g,e,"iDisplayLength","_iDisplayLength");p(g,e,"bJQueryUI","bJUI");p(g,e,"fnCookieCallback");p(g,e,"fnStateLoad");p(g,e,"fnStateSave");p(g.oLanguage,e,"fnInfoCallback");z(g,"aoDrawCallback",e.fnDrawCallback,"user");
|
||||
z(g,"aoServerParams",e.fnServerParams,"user");z(g,"aoStateSaveParams",e.fnStateSaveParams,"user");z(g,"aoStateLoadParams",e.fnStateLoadParams,"user");z(g,"aoStateLoaded",e.fnStateLoaded,"user");z(g,"aoRowCallback",e.fnRowCallback,"user");z(g,"aoRowCreatedCallback",e.fnCreatedRow,"user");z(g,"aoHeaderCallback",e.fnHeaderCallback,"user");z(g,"aoFooterCallback",e.fnFooterCallback,"user");z(g,"aoInitComplete",e.fnInitComplete,"user");z(g,"aoPreDrawCallback",e.fnPreDrawCallback,"user");g.oFeatures.bServerSide&&
|
||||
g.oFeatures.bSort&&g.oFeatures.bSortClasses?z(g,"aoDrawCallback",P,"server_side_sort_classes"):g.oFeatures.bDeferRender&&z(g,"aoDrawCallback",P,"defer_sort_classes");e.bJQueryUI?(h.extend(g.oClasses,j.ext.oJUIClasses),e.sDom===j.defaults.sDom&&"lfrtip"===j.defaults.sDom&&(g.sDom='<"H"lfr>t<"F"ip>')):h.extend(g.oClasses,j.ext.oStdClasses);h(this).addClass(g.oClasses.sTable);if(""!==g.oScroll.sX||""!==g.oScroll.sY)g.oScroll.iBarWidth=Qa();g.iInitDisplayStart===n&&(g.iInitDisplayStart=e.iDisplayStart,
|
||||
g._iDisplayStart=e.iDisplayStart);e.bStateSave&&(g.oFeatures.bStateSave=!0,Sa(g,e),z(g,"aoDrawCallback",ra,"state_save"));null!==e.iDeferLoading&&(g.bDeferLoading=!0,a=h.isArray(e.iDeferLoading),g._iRecordsDisplay=a?e.iDeferLoading[0]:e.iDeferLoading,g._iRecordsTotal=a?e.iDeferLoading[1]:e.iDeferLoading);null!==e.aaData&&(f=!0);""!==e.oLanguage.sUrl?(g.oLanguage.sUrl=e.oLanguage.sUrl,h.getJSON(g.oLanguage.sUrl,null,function(a){pa(a);h.extend(true,g.oLanguage,e.oLanguage,a);ba(g)}),i=!0):h.extend(!0,
|
||||
g.oLanguage,e.oLanguage);null===e.asStripeClasses&&(g.asStripeClasses=[g.oClasses.sStripeOdd,g.oClasses.sStripeEven]);b=g.asStripeClasses.length;g.asDestroyStripes=[];if(b){c=!1;d=h(this).children("tbody").children("tr:lt("+b+")");for(a=0;a<b;a++)d.hasClass(g.asStripeClasses[a])&&(c=!0,g.asDestroyStripes.push(g.asStripeClasses[a]));c&&d.removeClass(g.asStripeClasses.join(" "))}c=[];a=this.getElementsByTagName("thead");0!==a.length&&(V(g.aoHeader,a[0]),c=N(g));if(null===e.aoColumns){d=[];a=0;for(b=
|
||||
c.length;a<b;a++)d.push(null)}else d=e.aoColumns;a=0;for(b=d.length;a<b;a++)e.saved_aoColumns!==n&&e.saved_aoColumns.length==b&&(null===d[a]&&(d[a]={}),d[a].bVisible=e.saved_aoColumns[a].bVisible),o(g,c?c[a]:null);ta(g,e.aoColumnDefs,d,function(a,b){m(g,a,b)});a=0;for(b=g.aaSorting.length;a<b;a++){g.aaSorting[a][0]>=g.aoColumns.length&&(g.aaSorting[a][0]=0);var k=g.aoColumns[g.aaSorting[a][0]];g.aaSorting[a][2]===n&&(g.aaSorting[a][2]=0);e.aaSorting===n&&g.saved_aaSorting===n&&(g.aaSorting[a][1]=
|
||||
k.asSorting[0]);c=0;for(d=k.asSorting.length;c<d;c++)if(g.aaSorting[a][1]==k.asSorting[c]){g.aaSorting[a][2]=c;break}}P(g);Ua(g);a=h(this).children("caption").each(function(){this._captionSide=h(this).css("caption-side")});b=h(this).children("thead");0===b.length&&(b=[l.createElement("thead")],this.appendChild(b[0]));g.nTHead=b[0];b=h(this).children("tbody");0===b.length&&(b=[l.createElement("tbody")],this.appendChild(b[0]));g.nTBody=b[0];g.nTBody.setAttribute("role","alert");g.nTBody.setAttribute("aria-live",
|
||||
"polite");g.nTBody.setAttribute("aria-relevant","all");b=h(this).children("tfoot");if(0===b.length&&0<a.length&&(""!==g.oScroll.sX||""!==g.oScroll.sY))b=[l.createElement("tfoot")],this.appendChild(b[0]);0<b.length&&(g.nTFoot=b[0],V(g.aoFooter,g.nTFoot));if(f)for(a=0;a<e.aaData.length;a++)H(g,e.aaData[a]);else ua(g);g.aiDisplay=g.aiDisplayMaster.slice();g.bInitialised=!0;!1===i&&ba(g)}});ca=null;return this};j.fnVersionCheck=function(e){for(var h=function(e,h){for(;e.length<h;)e+="0";return e},m=j.ext.sVersion.split("."),
|
||||
e=e.split("."),k="",n="",l=0,t=e.length;l<t;l++)k+=h(m[l],3),n+=h(e[l],3);return parseInt(k,10)>=parseInt(n,10)};j.fnIsDataTable=function(e){for(var h=j.settings,m=0;m<h.length;m++)if(h[m].nTable===e||h[m].nScrollHead===e||h[m].nScrollFoot===e)return!0;return!1};j.fnTables=function(e){var o=[];jQuery.each(j.settings,function(j,k){(!e||!0===e&&h(k.nTable).is(":visible"))&&o.push(k.nTable)});return o};j.version="1.9.4";j.settings=[];j.models={};j.models.ext={afnFiltering:[],afnSortData:[],aoFeatures:[],
|
||||
aTypes:[],fnVersionCheck:j.fnVersionCheck,iApiIndex:0,ofnSearch:{},oApi:{},oStdClasses:{},oJUIClasses:{},oPagination:{},oSort:{},sVersion:j.version,sErrMode:"alert",_oExternConfig:{iNextUnique:0}};j.models.oSearch={bCaseInsensitive:!0,sSearch:"",bRegex:!1,bSmart:!0};j.models.oRow={nTr:null,_aData:[],_aSortData:[],_anHidden:[],_sRowStripe:""};j.models.oColumn={aDataSort:null,asSorting:null,bSearchable:null,bSortable:null,bUseRendered:null,bVisible:null,_bAutoType:!0,fnCreatedCell:null,fnGetData:null,
|
||||
fnRender:null,fnSetData:null,mData:null,mRender:null,nTh:null,nTf:null,sClass:null,sContentPadding:null,sDefaultContent:null,sName:null,sSortDataType:"std",sSortingClass:null,sSortingClassJUI:null,sTitle:null,sType:null,sWidth:null,sWidthOrig:null};j.defaults={aaData:null,aaSorting:[[0,"asc"]],aaSortingFixed:null,aLengthMenu:[10,25,50,100],aoColumns:null,aoColumnDefs:null,aoSearchCols:[],asStripeClasses:null,bAutoWidth:!0,bDeferRender:!1,bDestroy:!1,bFilter:!0,bInfo:!0,bJQueryUI:!1,bLengthChange:!0,
|
||||
bPaginate:!0,bProcessing:!1,bRetrieve:!1,bScrollAutoCss:!0,bScrollCollapse:!1,bScrollInfinite:!1,bServerSide:!1,bSort:!0,bSortCellsTop:!1,bSortClasses:!0,bStateSave:!1,fnCookieCallback:null,fnCreatedRow:null,fnDrawCallback:null,fnFooterCallback:null,fnFormatNumber:function(e){if(1E3>e)return e;for(var h=e+"",e=h.split(""),j="",h=h.length,k=0;k<h;k++)0===k%3&&0!==k&&(j=this.oLanguage.sInfoThousands+j),j=e[h-k-1]+j;return j},fnHeaderCallback:null,fnInfoCallback:null,fnInitComplete:null,fnPreDrawCallback:null,
|
||||
fnRowCallback:null,fnServerData:function(e,j,m,k){k.jqXHR=h.ajax({url:e,data:j,success:function(e){e.sError&&k.oApi._fnLog(k,0,e.sError);h(k.oInstance).trigger("xhr",[k,e]);m(e)},dataType:"json",cache:!1,type:k.sServerMethod,error:function(e,h){"parsererror"==h&&k.oApi._fnLog(k,0,"DataTables warning: JSON data from server could not be parsed. This is caused by a JSON formatting error.")}})},fnServerParams:null,fnStateLoad:function(e){var e=this.oApi._fnReadCookie(e.sCookiePrefix+e.sInstance),j;try{j=
|
||||
"function"===typeof h.parseJSON?h.parseJSON(e):eval("("+e+")")}catch(m){j=null}return j},fnStateLoadParams:null,fnStateLoaded:null,fnStateSave:function(e,h){this.oApi._fnCreateCookie(e.sCookiePrefix+e.sInstance,this.oApi._fnJsonString(h),e.iCookieDuration,e.sCookiePrefix,e.fnCookieCallback)},fnStateSaveParams:null,iCookieDuration:7200,iDeferLoading:null,iDisplayLength:10,iDisplayStart:0,iScrollLoadGap:100,iTabIndex:0,oLanguage:{oAria:{sSortAscending:": activate to sort column ascending",sSortDescending:": activate to sort column descending"},
|
||||
oPaginate:{sFirst:"First",sLast:"Last",sNext:"Next",sPrevious:"Previous"},sEmptyTable:"No data available in table",sInfo:"Showing _START_ to _END_ of _TOTAL_ entries",sInfoEmpty:"Showing 0 to 0 of 0 entries",sInfoFiltered:"(filtered from _MAX_ total entries)",sInfoPostFix:"",sInfoThousands:",",sLengthMenu:"Show _MENU_ entries",sLoadingRecords:"Loading...",sProcessing:"Processing...",sSearch:"Search:",sUrl:"",sZeroRecords:"No matching records found"},oSearch:h.extend({},j.models.oSearch),sAjaxDataProp:"aaData",
|
||||
sAjaxSource:null,sCookiePrefix:"SpryMedia_DataTables_",sDom:"lfrtip",sPaginationType:"two_button",sScrollX:"",sScrollXInner:"",sScrollY:"",sServerMethod:"GET"};j.defaults.columns={aDataSort:null,asSorting:["asc","desc"],bSearchable:!0,bSortable:!0,bUseRendered:!0,bVisible:!0,fnCreatedCell:null,fnRender:null,iDataSort:-1,mData:null,mRender:null,sCellType:"td",sClass:"",sContentPadding:"",sDefaultContent:null,sName:"",sSortDataType:"std",sTitle:null,sType:null,sWidth:null};j.models.oSettings={oFeatures:{bAutoWidth:null,
|
||||
bDeferRender:null,bFilter:null,bInfo:null,bLengthChange:null,bPaginate:null,bProcessing:null,bServerSide:null,bSort:null,bSortClasses:null,bStateSave:null},oScroll:{bAutoCss:null,bCollapse:null,bInfinite:null,iBarWidth:0,iLoadGap:null,sX:null,sXInner:null,sY:null},oLanguage:{fnInfoCallback:null},oBrowser:{bScrollOversize:!1},aanFeatures:[],aoData:[],aiDisplay:[],aiDisplayMaster:[],aoColumns:[],aoHeader:[],aoFooter:[],asDataSearch:[],oPreviousSearch:{},aoPreSearchCols:[],aaSorting:null,aaSortingFixed:null,
|
||||
asStripeClasses:null,asDestroyStripes:[],sDestroyWidth:0,aoRowCallback:[],aoHeaderCallback:[],aoFooterCallback:[],aoDrawCallback:[],aoRowCreatedCallback:[],aoPreDrawCallback:[],aoInitComplete:[],aoStateSaveParams:[],aoStateLoadParams:[],aoStateLoaded:[],sTableId:"",nTable:null,nTHead:null,nTFoot:null,nTBody:null,nTableWrapper:null,bDeferLoading:!1,bInitialised:!1,aoOpenRows:[],sDom:null,sPaginationType:"two_button",iCookieDuration:0,sCookiePrefix:"",fnCookieCallback:null,aoStateSave:[],aoStateLoad:[],
|
||||
oLoadedState:null,sAjaxSource:null,sAjaxDataProp:null,bAjaxDataGet:!0,jqXHR:null,fnServerData:null,aoServerParams:[],sServerMethod:null,fnFormatNumber:null,aLengthMenu:null,iDraw:0,bDrawing:!1,iDrawError:-1,_iDisplayLength:10,_iDisplayStart:0,_iDisplayEnd:10,_iRecordsTotal:0,_iRecordsDisplay:0,bJUI:null,oClasses:{},bFiltered:!1,bSorted:!1,bSortCellsTop:null,oInit:null,aoDestroyCallback:[],fnRecordsTotal:function(){return this.oFeatures.bServerSide?parseInt(this._iRecordsTotal,10):this.aiDisplayMaster.length},
|
||||
fnRecordsDisplay:function(){return this.oFeatures.bServerSide?parseInt(this._iRecordsDisplay,10):this.aiDisplay.length},fnDisplayEnd:function(){return this.oFeatures.bServerSide?!1===this.oFeatures.bPaginate||-1==this._iDisplayLength?this._iDisplayStart+this.aiDisplay.length:Math.min(this._iDisplayStart+this._iDisplayLength,this._iRecordsDisplay):this._iDisplayEnd},oInstance:null,sInstance:null,iTabIndex:0,nScrollHead:null,nScrollFoot:null};j.ext=h.extend(!0,{},j.models.ext);h.extend(j.ext.oStdClasses,
|
||||
{sTable:"dataTable",sPagePrevEnabled:"paginate_enabled_previous",sPagePrevDisabled:"paginate_disabled_previous",sPageNextEnabled:"paginate_enabled_next",sPageNextDisabled:"paginate_disabled_next",sPageJUINext:"",sPageJUIPrev:"",sPageButton:"paginate_button",sPageButtonActive:"paginate_active",sPageButtonStaticDisabled:"paginate_button paginate_button_disabled",sPageFirst:"first",sPagePrevious:"previous",sPageNext:"next",sPageLast:"last",sStripeOdd:"odd",sStripeEven:"even",sRowEmpty:"dataTables_empty",
|
||||
sWrapper:"dataTables_wrapper",sFilter:"dataTables_filter",sInfo:"dataTables_info",sPaging:"dataTables_paginate paging_",sLength:"dataTables_length",sProcessing:"dataTables_processing",sSortAsc:"sorting_asc",sSortDesc:"sorting_desc",sSortable:"sorting",sSortableAsc:"sorting_asc_disabled",sSortableDesc:"sorting_desc_disabled",sSortableNone:"sorting_disabled",sSortColumn:"sorting_",sSortJUIAsc:"",sSortJUIDesc:"",sSortJUI:"",sSortJUIAscAllowed:"",sSortJUIDescAllowed:"",sSortJUIWrapper:"",sSortIcon:"",
|
||||
sScrollWrapper:"dataTables_scroll",sScrollHead:"dataTables_scrollHead",sScrollHeadInner:"dataTables_scrollHeadInner",sScrollBody:"dataTables_scrollBody",sScrollFoot:"dataTables_scrollFoot",sScrollFootInner:"dataTables_scrollFootInner",sFooterTH:"",sJUIHeader:"",sJUIFooter:""});h.extend(j.ext.oJUIClasses,j.ext.oStdClasses,{sPagePrevEnabled:"fg-button ui-button ui-state-default ui-corner-left",sPagePrevDisabled:"fg-button ui-button ui-state-default ui-corner-left ui-state-disabled",sPageNextEnabled:"fg-button ui-button ui-state-default ui-corner-right",
|
||||
sPageNextDisabled:"fg-button ui-button ui-state-default ui-corner-right ui-state-disabled",sPageJUINext:"ui-icon ui-icon-circle-arrow-e",sPageJUIPrev:"ui-icon ui-icon-circle-arrow-w",sPageButton:"fg-button ui-button ui-state-default",sPageButtonActive:"fg-button ui-button ui-state-default ui-state-disabled",sPageButtonStaticDisabled:"fg-button ui-button ui-state-default ui-state-disabled",sPageFirst:"first ui-corner-tl ui-corner-bl",sPageLast:"last ui-corner-tr ui-corner-br",sPaging:"dataTables_paginate fg-buttonset ui-buttonset fg-buttonset-multi ui-buttonset-multi paging_",
|
||||
sSortAsc:"ui-state-default",sSortDesc:"ui-state-default",sSortable:"ui-state-default",sSortableAsc:"ui-state-default",sSortableDesc:"ui-state-default",sSortableNone:"ui-state-default",sSortJUIAsc:"css_right ui-icon ui-icon-triangle-1-n",sSortJUIDesc:"css_right ui-icon ui-icon-triangle-1-s",sSortJUI:"css_right ui-icon ui-icon-carat-2-n-s",sSortJUIAscAllowed:"css_right ui-icon ui-icon-carat-1-n",sSortJUIDescAllowed:"css_right ui-icon ui-icon-carat-1-s",sSortJUIWrapper:"DataTables_sort_wrapper",sSortIcon:"DataTables_sort_icon",
|
||||
sScrollHead:"dataTables_scrollHead ui-state-default",sScrollFoot:"dataTables_scrollFoot ui-state-default",sFooterTH:"ui-state-default",sJUIHeader:"fg-toolbar ui-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix",sJUIFooter:"fg-toolbar ui-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix"});h.extend(j.ext.oPagination,{two_button:{fnInit:function(e,j,m){var k=e.oLanguage.oPaginate,n=function(h){e.oApi._fnPageChange(e,h.data.action)&&m(e)},k=!e.bJUI?'<a class="'+
|
||||
e.oClasses.sPagePrevDisabled+'" tabindex="'+e.iTabIndex+'" role="button">'+k.sPrevious+'</a><a class="'+e.oClasses.sPageNextDisabled+'" tabindex="'+e.iTabIndex+'" role="button">'+k.sNext+"</a>":'<a class="'+e.oClasses.sPagePrevDisabled+'" tabindex="'+e.iTabIndex+'" role="button"><span class="'+e.oClasses.sPageJUIPrev+'"></span></a><a class="'+e.oClasses.sPageNextDisabled+'" tabindex="'+e.iTabIndex+'" role="button"><span class="'+e.oClasses.sPageJUINext+'"></span></a>';h(j).append(k);var l=h("a",j),
|
||||
k=l[0],l=l[1];e.oApi._fnBindAction(k,{action:"previous"},n);e.oApi._fnBindAction(l,{action:"next"},n);e.aanFeatures.p||(j.id=e.sTableId+"_paginate",k.id=e.sTableId+"_previous",l.id=e.sTableId+"_next",k.setAttribute("aria-controls",e.sTableId),l.setAttribute("aria-controls",e.sTableId))},fnUpdate:function(e){if(e.aanFeatures.p)for(var h=e.oClasses,j=e.aanFeatures.p,k,l=0,n=j.length;l<n;l++)if(k=j[l].firstChild)k.className=0===e._iDisplayStart?h.sPagePrevDisabled:h.sPagePrevEnabled,k=k.nextSibling,
|
||||
k.className=e.fnDisplayEnd()==e.fnRecordsDisplay()?h.sPageNextDisabled:h.sPageNextEnabled}},iFullNumbersShowPages:5,full_numbers:{fnInit:function(e,j,m){var k=e.oLanguage.oPaginate,l=e.oClasses,n=function(h){e.oApi._fnPageChange(e,h.data.action)&&m(e)};h(j).append('<a tabindex="'+e.iTabIndex+'" class="'+l.sPageButton+" "+l.sPageFirst+'">'+k.sFirst+'</a><a tabindex="'+e.iTabIndex+'" class="'+l.sPageButton+" "+l.sPagePrevious+'">'+k.sPrevious+'</a><span></span><a tabindex="'+e.iTabIndex+'" class="'+
|
||||
l.sPageButton+" "+l.sPageNext+'">'+k.sNext+'</a><a tabindex="'+e.iTabIndex+'" class="'+l.sPageButton+" "+l.sPageLast+'">'+k.sLast+"</a>");var t=h("a",j),k=t[0],l=t[1],r=t[2],t=t[3];e.oApi._fnBindAction(k,{action:"first"},n);e.oApi._fnBindAction(l,{action:"previous"},n);e.oApi._fnBindAction(r,{action:"next"},n);e.oApi._fnBindAction(t,{action:"last"},n);e.aanFeatures.p||(j.id=e.sTableId+"_paginate",k.id=e.sTableId+"_first",l.id=e.sTableId+"_previous",r.id=e.sTableId+"_next",t.id=e.sTableId+"_last")},
|
||||
fnUpdate:function(e,o){if(e.aanFeatures.p){var m=j.ext.oPagination.iFullNumbersShowPages,k=Math.floor(m/2),l=Math.ceil(e.fnRecordsDisplay()/e._iDisplayLength),n=Math.ceil(e._iDisplayStart/e._iDisplayLength)+1,t="",r,B=e.oClasses,u,M=e.aanFeatures.p,L=function(h){e.oApi._fnBindAction(this,{page:h+r-1},function(h){e.oApi._fnPageChange(e,h.data.page);o(e);h.preventDefault()})};-1===e._iDisplayLength?n=k=r=1:l<m?(r=1,k=l):n<=k?(r=1,k=m):n>=l-k?(r=l-m+1,k=l):(r=n-Math.ceil(m/2)+1,k=r+m-1);for(m=r;m<=k;m++)t+=
|
||||
n!==m?'<a tabindex="'+e.iTabIndex+'" class="'+B.sPageButton+'">'+e.fnFormatNumber(m)+"</a>":'<a tabindex="'+e.iTabIndex+'" class="'+B.sPageButtonActive+'">'+e.fnFormatNumber(m)+"</a>";m=0;for(k=M.length;m<k;m++)u=M[m],u.hasChildNodes()&&(h("span:eq(0)",u).html(t).children("a").each(L),u=u.getElementsByTagName("a"),u=[u[0],u[1],u[u.length-2],u[u.length-1]],h(u).removeClass(B.sPageButton+" "+B.sPageButtonActive+" "+B.sPageButtonStaticDisabled),h([u[0],u[1]]).addClass(1==n?B.sPageButtonStaticDisabled:
|
||||
B.sPageButton),h([u[2],u[3]]).addClass(0===l||n===l||-1===e._iDisplayLength?B.sPageButtonStaticDisabled:B.sPageButton))}}}});h.extend(j.ext.oSort,{"string-pre":function(e){"string"!=typeof e&&(e=null!==e&&e.toString?e.toString():"");return e.toLowerCase()},"string-asc":function(e,h){return e<h?-1:e>h?1:0},"string-desc":function(e,h){return e<h?1:e>h?-1:0},"html-pre":function(e){return e.replace(/<.*?>/g,"").toLowerCase()},"html-asc":function(e,h){return e<h?-1:e>h?1:0},"html-desc":function(e,h){return e<
|
||||
h?1:e>h?-1:0},"date-pre":function(e){e=Date.parse(e);if(isNaN(e)||""===e)e=Date.parse("01/01/1970 00:00:00");return e},"date-asc":function(e,h){return e-h},"date-desc":function(e,h){return h-e},"numeric-pre":function(e){return"-"==e||""===e?0:1*e},"numeric-asc":function(e,h){return e-h},"numeric-desc":function(e,h){return h-e}});h.extend(j.ext.aTypes,[function(e){if("number"===typeof e)return"numeric";if("string"!==typeof e)return null;var h,j=!1;h=e.charAt(0);if(-1=="0123456789-".indexOf(h))return null;
|
||||
for(var k=1;k<e.length;k++){h=e.charAt(k);if(-1=="0123456789.".indexOf(h))return null;if("."==h){if(j)return null;j=!0}}return"numeric"},function(e){var h=Date.parse(e);return null!==h&&!isNaN(h)||"string"===typeof e&&0===e.length?"date":null},function(e){return"string"===typeof e&&-1!=e.indexOf("<")&&-1!=e.indexOf(">")?"html":null}]);h.fn.DataTable=j;h.fn.dataTable=j;h.fn.dataTableSettings=j.settings;h.fn.dataTableExt=j.ext};"function"===typeof define&&define.amd?define(["jquery"],L):jQuery&&!jQuery.fn.dataTable&&
|
||||
L(jQuery)})(window,document);
|
3
dashboard/static/js/jquery.jqplot.min.js
vendored
Normal file
19
dashboard/templates/404.html
Normal file
@ -0,0 +1,19 @@
|
||||
{% extends "layout.html" %}
|
||||
|
||||
{% block title %}
|
||||
404
|
||||
{% endblock %}
|
||||
|
||||
{% block left_frame %}
|
||||
|
||||
<h2>404 Not Found</h2>
|
||||
|
||||
<div>The requested page is not found. Return to <a href="/">Overview</a>
|
||||
</div>
|
||||
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block right_frame %}
|
||||
|
||||
{% endblock %}
|
183
dashboard/templates/base.html
Normal file
@ -0,0 +1,183 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" dir="ltr" lang="en-US">
|
||||
<head profile="http://gmpg.org/xfn/11">
|
||||
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
|
||||
|
||||
<title>{% block title %}Welcome{% endblock %} | Stackalytics - OpenStack Analytics Dashboard</title>
|
||||
|
||||
<link rel="alternate" type="application/rss+xml" href="http://www.mirantis.com/feed/" title="Mirantis latest posts" />
|
||||
<link rel="alternate" type="application/rss+xml" href="http://www.mirantis.com/comments/feed/" title="Mirantis latest comments" />
|
||||
<link rel="pingback" href="http://www.mirantis.com/xmlrpc.php" />
|
||||
<link rel='archives' title='June 2013' href='http://www.mirantis.com/2013/06/' />
|
||||
<link rel='archives' title='May 2013' href='http://www.mirantis.com/2013/05/' />
|
||||
<link rel='archives' title='April 2013' href='http://www.mirantis.com/2013/04/' />
|
||||
<link rel='archives' title='March 2013' href='http://www.mirantis.com/2013/03/' />
|
||||
<link rel='archives' title='February 2013' href='http://www.mirantis.com/2013/02/' />
|
||||
<link rel='archives' title='January 2013' href='http://www.mirantis.com/2013/01/' />
|
||||
<link rel='archives' title='December 2012' href='http://www.mirantis.com/2012/12/' />
|
||||
<link rel='archives' title='November 2012' href='http://www.mirantis.com/2012/11/' />
|
||||
<link rel='archives' title='October 2012' href='http://www.mirantis.com/2012/10/' />
|
||||
<link rel='archives' title='September 2012' href='http://www.mirantis.com/2012/09/' />
|
||||
<link rel='archives' title='August 2012' href='http://www.mirantis.com/2012/08/' />
|
||||
<link rel='archives' title='July 2012' href='http://www.mirantis.com/2012/07/' />
|
||||
<link rel='archives' title='June 2012' href='http://www.mirantis.com/2012/06/' />
|
||||
<link rel='archives' title='May 2012' href='http://www.mirantis.com/2012/05/' />
|
||||
<link rel='archives' title='April 2012' href='http://www.mirantis.com/2012/04/' />
|
||||
<link rel='archives' title='March 2012' href='http://www.mirantis.com/2012/03/' />
|
||||
<link rel='archives' title='February 2012' href='http://www.mirantis.com/2012/02/' />
|
||||
<link rel='archives' title='January 2012' href='http://www.mirantis.com/2012/01/' />
|
||||
<link rel='archives' title='December 2011' href='http://www.mirantis.com/2011/12/' />
|
||||
<link rel='archives' title='November 2011' href='http://www.mirantis.com/2011/11/' />
|
||||
<link rel='archives' title='October 2011' href='http://www.mirantis.com/2011/10/' />
|
||||
<link rel='archives' title='September 2011' href='http://www.mirantis.com/2011/09/' />
|
||||
<link rel='archives' title='August 2011' href='http://www.mirantis.com/2011/08/' />
|
||||
<link rel='archives' title='July 2011' href='http://www.mirantis.com/2011/07/' />
|
||||
<link rel='archives' title='June 2011' href='http://www.mirantis.com/2011/06/' />
|
||||
<link rel='archives' title='May 2011' href='http://www.mirantis.com/2011/05/' />
|
||||
<link href='http://fonts.googleapis.com/css?family=PT+Sans:400,700,400italic&subset=latin,cyrillic' rel='stylesheet' type='text/css'>
|
||||
<link href='http://fonts.googleapis.com/css?family=PT+Sans+Caption&subset=latin,cyrillic' rel='stylesheet' type='text/css'>
|
||||
<link href='http://fonts.googleapis.com/css?family=PT+Sans+Narrow:400,700&subset=latin,cyrillic' rel='stylesheet' type='text/css'>
|
||||
|
||||
|
||||
{# <script type="text/javascript" src="{{ url_for('static', filename='js/jquery-1.9.1.min.js') }}"></script>#}
|
||||
{##}
|
||||
{# <script type='text/javascript' src='http://www.mirantis.com/wp-content/themes/carrington-jam-1.4/js/menu.js'></script>#}
|
||||
|
||||
|
||||
<a rel="author" href="https://plus.google.com/105615415033737866019" target="blank" rel="nofollow"></a>
|
||||
|
||||
{% block head %}{% endblock %}
|
||||
|
||||
<!-- Google Analytics -->
|
||||
<script type="text/javascript">
|
||||
var _gaq = _gaq || [];
|
||||
_gaq.push(['_setAccount', 'UA-8933515-2']);
|
||||
_gaq.push(['_setDomainName', 'stackalytics.com']);
|
||||
_gaq.push(['_setAllowLinker', true]);
|
||||
_gaq.push(['_trackPageview']);
|
||||
(function () {
|
||||
var ga = document.createElement('script');
|
||||
ga.type = 'text/javascript';
|
||||
ga.async = true;
|
||||
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
||||
var s = document.getElementsByTagName('script')[0];
|
||||
s.parentNode.insertBefore(ga, s);
|
||||
})();
|
||||
</script>
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="content">
|
||||
<table cellpadding="0" cellspacing="0" id="miraheader">
|
||||
<tr>
|
||||
<td width="167px" height="107px"><a href="http://www.mirantis.com/" title="Home" rel="home"><img src="{{ url_for('static', filename='images/mirantis_logo.gif') }}" alt="Mirantis" border="0"/></a></td>
|
||||
<td>
|
||||
<div id="top-menu">
|
||||
<div class="textwidget"><table align="right">
|
||||
<tr><td>
|
||||
<div style="margin-top:5px; margin-right:10px;">
|
||||
{#<a href="https://twitter.com/MirantisIT" class="twitter-follow-button" data-show-count="false" data-show-screen-name="false">Follow @twitter</a>#}
|
||||
{#<script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src="//platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");</script>#}
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div id="ttopmenu"><a class="top" href="http://mirantis.com/blog/">Blog</a> <a class="top" href="http://mirantis.com/careers/">Careers</a> <a class="top" href="http://mirantis.com/contact/">Contact Us</a></div>
|
||||
</td>
|
||||
</tr>
|
||||
</table></div>
|
||||
</div>
|
||||
<!--#top-menu-->
|
||||
<div id="main-menu">
|
||||
<div id="text-89" class="widget widget_text">
|
||||
<div id="masthead">
|
||||
<div id="globalNav">
|
||||
<div id="globalLink">
|
||||
<a href="http://mirantis.com/openstack-services/" id="gl1" class="glink" name="gl1">OpenStack Services</a>
|
||||
<a href="http://mirantis.com/openstack-training/" id="gl2" class="glink" name="gl2">Training</a>
|
||||
<a href="http://fuel.mirantis.com" id="gl3" class="glink" name="gl3">Fuel for OpenStack</a>
|
||||
<a href="http://mirantis.com/openstack-use-cases/" id="gl4" class="glink" name="gl4">Use Cases </a>
|
||||
<a href="http://mirantis.com/why-mirantis/" id="gl5" class="glink" name="gl5">Why Mirantis</a>
|
||||
<a href="http://mirantis.com/company/" id="gl6" class="glink" name="gl6">Company</a>
|
||||
</div>
|
||||
</div>
|
||||
<div id="subglobal1" class="subglobalNav" style="visibility: hidden;">
|
||||
<a href="http://mirantis.com/openstack-services/do-it-yourself-assist/">Do-It-Yourself Assist</a>
|
||||
<a href="http://mirantis.com/openstack-services/deployment-integration/">Deployment & Integration</a>
|
||||
<a href="http://mirantis.com/openstack-services/support/">Support</a>
|
||||
</div>
|
||||
<div id="subglobal4" class="subglobalNav" style="visibility: hidden;">
|
||||
<a href="http://mirantis.com/openstack-use-cases/saas-web/">SaaS/Web Vendors</a>
|
||||
<a href="http://mirantis.com/openstack-use-cases/service-providers/">Service Providers</a>
|
||||
<a href="http://mirantis.com/openstack-use-cases/enterprise-cloud/">Enterprise Cloud</a>
|
||||
<a href="http://mirantis.com/openstack-use-cases/infrastructure-technology/">Infrastructure Vendors</a>
|
||||
</div>
|
||||
<div id="subglobal5" class="subglobalNav" style="visibility: hidden;">
|
||||
<a href="http://mirantis.com/why-mirantis/mirantis-approach/">The Mirantis Approach</a>
|
||||
<a href="http://mirantis.com/why-mirantis/openstack-technology/">OpenStack Technology</a>
|
||||
<a href="http://mirantis.com/why-mirantis/success-stories/">Success Stories</a>
|
||||
</div>
|
||||
<div id="subglobal6" class="subglobalNav" style="visibility: hidden;">
|
||||
<a href="http://mirantis.com/company/about/">About</a>
|
||||
<a href="http://mirantis.com/company/leadership/">Leadership</a>
|
||||
<a href="http://mirantis.com/company/news/">In the Media</a>
|
||||
<a href="http://mirantis.com/company/press-release/">Company News</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="clear"></div>
|
||||
</div>
|
||||
</div>
|
||||
<!--#main-menu-->
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<div id="analytics_header">
|
||||
<h3><a href="/?metric={{ metric }}&period={{ period }}&project_type={{ project_type }}">Stackalytics</a> | {{ self.title() }}</h3>
|
||||
<p>Community heartbeat</p>
|
||||
</div>
|
||||
<!--#topdynamicinner-->
|
||||
|
||||
{% block body %}{% endblock %}
|
||||
|
||||
|
||||
|
||||
<div id="dummy">
|
||||
</div>
|
||||
</div>
|
||||
<div id="footer">
|
||||
<div id="footer_content">
|
||||
<div id="text-5" class="widget widget_text"><!--Footer-->
|
||||
<table width="100%" border="0" cellpadding="0" cellspacing="0"
|
||||
id="foottable">
|
||||
<tr>
|
||||
<td valign="top">
|
||||
<span class="fgeneral">Mirantis Inc.<br>
|
||||
<span class="fslogan">OpenStack Clouds. Delivered.</span></span>
|
||||
</td>
|
||||
<td valign="top">
|
||||
<span class="fgeneral">© 2005–2013</span>
|
||||
<span class="fgeneralblue">All Rights Reserved</span>
|
||||
</td>
|
||||
<td valign="top">
|
||||
<div id="fbox">
|
||||
<span class="fgeneral">615 National Avenue, Suite 100<br>
|
||||
Mountain View, CA 94043</span></div>
|
||||
</td>
|
||||
<td valign="top">
|
||||
<div id="fbox">
|
||||
<span class="fgeneralblue">Phone</span> <span
|
||||
class="fgeneral">650-963-9828</span>
|
||||
<br>
|
||||
<span class="fgeneralblue">Fax</span> <span
|
||||
class="fgeneral">650-963-9723</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<div class="clear"></div></div><div id="DNSindicator"></div>
|
||||
</div>
|
||||
</div><!--#footer-->
|
||||
|
||||
</body>
|
||||
</html>
|
60
dashboard/templates/commits.html
Normal file
@ -0,0 +1,60 @@
|
||||
{% extends "layout.html" %}
|
||||
|
||||
{% block title %}
|
||||
{% if issue_type %}
|
||||
{{ issue_type }}s
|
||||
{% else %}
|
||||
Commits
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block left_frame %}
|
||||
|
||||
<script type="text/javascript">
|
||||
loadTimeline()
|
||||
</script>
|
||||
|
||||
{% for rec in issues %}
|
||||
|
||||
{% set issue = rec['issue_id'] %}
|
||||
{% set items = rec['items'] %}
|
||||
|
||||
<h3>{{ issue }}
|
||||
{% if issue_type %}
|
||||
({{ link('/modules/' + items[0].module, items[0].module) }})
|
||||
{% endif %}
|
||||
</h3>
|
||||
|
||||
{% for rec in items %}
|
||||
|
||||
<div style="padding-bottom: 1em;">
|
||||
<div style='float: left; '>
|
||||
<img src="{{ rec.email|gravatar(size=32) }}">
|
||||
</div>
|
||||
<div style="margin-left: 4em;">
|
||||
<div>
|
||||
{% if rec.launchpad_id %}
|
||||
{{ link('/engineers/' + rec.launchpad_id, rec.author) }}
|
||||
{% else %}
|
||||
{{ rec.author }}
|
||||
{% endif %}
|
||||
{% if rec.company %}
|
||||
(
|
||||
{{ link('/companies/' + rec.company, rec.company) }}
|
||||
)
|
||||
{% endif %}
|
||||
<em>{{ rec.date|datetimeformat }}</em>
|
||||
({{ link('/modules/' + rec.module, rec.module) }})
|
||||
</div>
|
||||
|
||||
<div class="message">{{ rec.message|safe }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block right_frame %}
|
||||
{% endblock %}
|
58
dashboard/templates/companies.html
Normal file
@ -0,0 +1,58 @@
|
||||
{% extends "layout.html" %}
|
||||
|
||||
{% block title %}
|
||||
Overview
|
||||
{% endblock %}
|
||||
|
||||
{% block left_frame %}
|
||||
|
||||
<h2>Contribution by companies</h2>
|
||||
|
||||
<script type="text/javascript">
|
||||
loadTable("left_list", "/data/companies");
|
||||
loadChart("left_chart", "/data/companies", {limit: 10});
|
||||
loadTimeline('')
|
||||
</script>
|
||||
|
||||
<div id="left_chart" style="width: 100%; height: 350px;"></div>
|
||||
|
||||
<table id="left_list" class="display">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>Company</th>
|
||||
<th>{{ metric_label }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="spacer"></div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block right_frame %}
|
||||
|
||||
<h2>Contribution by modules</h2>
|
||||
|
||||
<script type="text/javascript">
|
||||
loadTable("right_list", "/data/modules");
|
||||
loadChart("right_chart", "/data/modules", {limit: 10});
|
||||
</script>
|
||||
|
||||
<div id="right_chart" style="width: 100%; height: 350px;"></div>
|
||||
|
||||
<table id="right_list" class="display">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>Module</th>
|
||||
<th>{{ metric_label }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="spacer"></div>
|
||||
|
||||
{% endblock %}
|
81
dashboard/templates/company_details.html
Normal file
@ -0,0 +1,81 @@
|
||||
{% extends "layout.html" %}
|
||||
|
||||
{% block title %}
|
||||
{{ company }}
|
||||
{% endblock %}
|
||||
|
||||
{% block left_frame %}
|
||||
|
||||
<h2>Contribution by engineers</h2>
|
||||
|
||||
<script type="text/javascript">
|
||||
loadTable("left_list", "/data/companies/{{ company|encode }}");
|
||||
loadChart("left_chart", "/data/companies/{{ company|encode }}", {limit: 10});
|
||||
loadTimeline({company: '{{ company }}'})
|
||||
</script>
|
||||
|
||||
<div id="left_chart" style="width: 100%; height: 350px;"></div>
|
||||
|
||||
<table id="left_list" class="display">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>Engineer</th>
|
||||
<th>{{ metric_label }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="spacer"></div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block right_frame %}
|
||||
|
||||
<h2>Contribution by modules</h2>
|
||||
|
||||
<script type="text/javascript">
|
||||
loadTable("right_list", "/data/modules", {company: "{{ company|encode }}" });
|
||||
loadChart("right_chart", "/data/modules", {limit: 10, company: "{{ company|encode }}" });
|
||||
</script>
|
||||
|
||||
<div id="right_chart" style="width: 100%; height: 350px;"></div>
|
||||
|
||||
<table id="right_list" class="display">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>Module</th>
|
||||
<th>{{ metric_label }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="spacer"></div>
|
||||
|
||||
<h3>Commit overview</h3>
|
||||
{% if blueprints %}
|
||||
<div>Blueprints:
|
||||
<ol>
|
||||
{% for one in blueprints %}
|
||||
<li>
|
||||
<a href="https://blueprints.launchpad.net/{{ one[1] }}/+spec/{{ one[0] }}">{{ one[0] }}</a>
|
||||
<small>{{ one[1] }}</small>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ol>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if bugs %}
|
||||
<div>Bug fixes: <b>{{ bugs|length }}</b>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div>Total commits: <b>{{ commits|length }}</b>, among them <b>{{ code_commits }}</b> commits in code,
|
||||
among them <b>{{ test_only_commits }}</b> test only commits</div>
|
||||
<div>Total LOC: <b>{{ loc }}</b></div>
|
||||
|
||||
{% endblock %}
|
105
dashboard/templates/engineer_details.html
Normal file
@ -0,0 +1,105 @@
|
||||
{% extends "layout.html" %}
|
||||
|
||||
{% block title %}
|
||||
{{ details.name }}
|
||||
{% endblock %}
|
||||
|
||||
{% block left_frame %}
|
||||
|
||||
<script type="text/javascript">
|
||||
loadTimeline({engineer: '{{engineer}}'})
|
||||
</script>
|
||||
|
||||
<div style='float: left;'>
|
||||
<img src="{{ details.email|gravatar(size=64) }}">
|
||||
</div>
|
||||
<div style='margin-left: 90px;'>
|
||||
<h2 style='margin-bottom: 0.5em;'>{{ details.name }}</h2>
|
||||
{% if details.company %}
|
||||
<div>Company: {{ link('/companies/' + details.company, details.company) }}</div>
|
||||
{% endif %}
|
||||
<div>Launchpad: <a href="https://launchpad.net/~{{ details.launchpad_id }}">{{ details.launchpad_id }}</a></div>
|
||||
{# <div>Email: {{ details.email }}</div>#}
|
||||
</div>
|
||||
|
||||
<h3>Commits history</h3>
|
||||
|
||||
{% if not commits %}
|
||||
<div>There are no commits for selected period or project type.</div>
|
||||
{% endif %}
|
||||
|
||||
{% for message in commits %}
|
||||
<div>
|
||||
<h4>{{ message.date|datetimeformat }} to <a href="https://launchpad.net/{{ message.module }}">{{ message.module }}</a>
|
||||
{% if message.is_code %} <span style="color: royalblue">code</span> {% endif %}
|
||||
{% if message.is_test %} <span style="color: magenta">test</span> {% endif %}
|
||||
</h4>
|
||||
<div style='white-space: pre-wrap; padding-left: 2em;'>{{ message.message|safe }}</div>
|
||||
<div style="padding-left: 2em;"><span style="color: green">+ {{ message.added_loc }}</span>
|
||||
<span style="color: red">- {{ message.removed_loc }}</span></div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block right_frame %}
|
||||
|
||||
{% if commits %}
|
||||
<h2>Contribution by modules</h2>
|
||||
|
||||
<script type="text/javascript">
|
||||
loadTable("right_list", "/data/modules", {engineer: "{{ engineer }}" });
|
||||
loadChart("right_chart", "/data/modules", {limit: 10, engineer: "{{ engineer }}" });
|
||||
</script>
|
||||
|
||||
<div id="right_chart" style="width: 100%; height: 350px;"></div>
|
||||
|
||||
<table id="right_list" class="display">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>Module</th>
|
||||
<th>{{ metric_label }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="spacer"></div>
|
||||
|
||||
<h3>Commit overview</h3>
|
||||
{% if blueprints %}
|
||||
<div>Blueprints:
|
||||
<ol>
|
||||
{% for one in blueprints %}
|
||||
<li>
|
||||
<a href="https://blueprints.launchpad.net/{{ one[1] }}/+spec/{{ one[0] }}">{{ one[0] }}</a>
|
||||
<small>{{ one[1] }}</small>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ol>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if bugs %}
|
||||
<div>Bug fixes:
|
||||
<ol>
|
||||
{% for one in bugs %}
|
||||
<li>
|
||||
<a href="https://bugs.launchpad.net/bugs/{{ one[0] }}">{{ one[0] }}</a>
|
||||
<small>
|
||||
{% if one[1] %} <span style="color: royalblue">C</span> {% endif %}
|
||||
{% if one[2] %} <span style="color: magenta">T</span> {% endif %}
|
||||
</small>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ol>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div>Total commits: <b>{{ commits|length }}</b>, among them <b>{{ code_commits }}</b> commits in code,
|
||||
among them <b>{{ test_only_commits }}</b> test only commits</div>
|
||||
<div>Total LOC: <b>{{ loc }}</b></div>
|
||||
{% endif %}
|
||||
|
||||
{% endblock %}
|
58
dashboard/templates/engineers.html
Normal file
@ -0,0 +1,58 @@
|
||||
{% extends "layout.html" %}
|
||||
|
||||
{% block title %}
|
||||
engineers
|
||||
{% endblock %}
|
||||
|
||||
{% block left_frame %}
|
||||
|
||||
<h2>Contribution by engineers</h2>
|
||||
|
||||
<script type="text/javascript">
|
||||
loadTable("left_list", "/data/engineers");
|
||||
loadChart("left_chart", "/data/engineers", {limit:10});
|
||||
loadTimeline('')
|
||||
</script>
|
||||
|
||||
<div id="left_chart" style="width: 100%; height: 350px;"></div>
|
||||
|
||||
<table id="left_list" class="display">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>Engineer</th>
|
||||
<th>{{ metric_label }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="spacer"></div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block right_frame %}
|
||||
|
||||
<h2>Contribution by modules</h2>
|
||||
|
||||
<script type="text/javascript">
|
||||
loadTable("right_list", "/data/modules");
|
||||
loadChart("right_chart", "/data/modules", {limit:10});
|
||||
</script>
|
||||
|
||||
<div id="right_chart" style="width: 100%; height: 350px;"></div>
|
||||
|
||||
<table id="right_list" class="display">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>Module</th>
|
||||
<th>{{ metric_label }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="spacer"></div>
|
||||
|
||||
{% endblock %}
|
284
dashboard/templates/layout.html
Normal file
@ -0,0 +1,284 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block head %}
|
||||
<link rel=stylesheet type=text/css href="{{ url_for('static', filename='css/style.css') }}">
|
||||
<link rel=stylesheet type=text/css href="{{ url_for('static', filename='css/jquery.jqplot.min.css') }}">
|
||||
<link rel=stylesheet type=text/css href="{{ url_for('static', filename='css/jquery.dataTables.css') }}">
|
||||
|
||||
<script type="text/javascript" src="{{ url_for('static', filename='js/jquery-1.9.1.min.js') }}"></script>
|
||||
<script type="text/javascript" src="{{ url_for('static', filename='js/jquery.dataTables.min.js') }}"></script>
|
||||
<script type="text/javascript" src="{{ url_for('static', filename='js/jquery.jqplot.min.js') }}"></script>
|
||||
<!--[if lt IE 9]><script type="text/javascript" src="{{ url_for('static', filename='js/excanvas.min.js') }}"></script><![endif]-->
|
||||
<script type="text/javascript" src="{{ url_for('static', filename='js/jqplot.json2.min.js') }}"></script>
|
||||
<script type="text/javascript" src="{{ url_for('static', filename='js/jqplot.pieRenderer.min.js') }}"></script>
|
||||
<script type="text/javascript" src="{{ url_for('static', filename='js/jqplot.dateAxisRenderer.min.js') }}"></script>
|
||||
<script type="text/javascript" src="{{ url_for('static', filename='js/jqplot.canvasTextRenderer.min.js') }}"></script>
|
||||
<script type="text/javascript" src="{{ url_for('static', filename='js/jqplot.canvasAxisTickRenderer.min.js') }}"></script>
|
||||
<script type="text/javascript" src="{{ url_for('static', filename='js/jqplot.cursor.min.js') }}"></script>
|
||||
<script type="text/javascript" src="{{ url_for('static', filename='js/jqplot.highlighter.min.js') }}"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
// load table data
|
||||
function loadTable(table_id, source, options) {
|
||||
$(document).ready(function () {
|
||||
$("#"+table_id).dataTable({
|
||||
"aLengthMenu": [[25, 50, -1], [25, 50, "All"]],
|
||||
"aaSorting": [[ 2, "desc" ]],
|
||||
"bProcessing": true,
|
||||
"sAjaxSource": make_uri(source, options),
|
||||
"sPaginationType": "full_numbers",
|
||||
"iDisplayLength": 25,
|
||||
"aoColumns": [
|
||||
{ "mData": "index" },
|
||||
{ "mData": "link" },
|
||||
{ "mData": "rank" }
|
||||
]
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// load chart
|
||||
function loadChart(chart_id, source, options) {
|
||||
$(document).ready(function () {
|
||||
// Our ajax data renderer which here retrieves a text file.
|
||||
// it could contact any source and pull data, however.
|
||||
// The options argument isn't used in this renderer.
|
||||
var ajaxDataRenderer = function (url, plot, options) {
|
||||
var ret = null;
|
||||
$.ajax({
|
||||
// have to use synchronous here, else the function
|
||||
// will return before the data is fetched
|
||||
async: false,
|
||||
url: url,
|
||||
dataType: "json",
|
||||
success: function (data) {
|
||||
var array = [];
|
||||
for(i = 0; i < data['aaData'].length; i++) {
|
||||
array.push([data['aaData'][i].name, data['aaData'][i].rank]);
|
||||
}
|
||||
ret = [array]
|
||||
}
|
||||
});
|
||||
return ret;
|
||||
};
|
||||
|
||||
// passing in the url string as the jqPlot data argument is a handy
|
||||
// shortcut for our renderer. You could also have used the
|
||||
// "dataRendererOptions" option to pass in the url.
|
||||
var plot = $.jqplot(chart_id, make_uri(source, options), {
|
||||
dataRenderer: ajaxDataRenderer,
|
||||
seriesDefaults: {
|
||||
// Make this a pie chart.
|
||||
renderer: jQuery.jqplot.PieRenderer,
|
||||
rendererOptions: {
|
||||
// Put data labels on the pie slices.
|
||||
// By default, labels show the percentage of the slice.
|
||||
showDataLabels: true
|
||||
}
|
||||
},
|
||||
legend: { show: true, location: 'e' }
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// load timeline
|
||||
function loadTimeline(options) {
|
||||
$(document).ready(function () {
|
||||
var ajaxDataRenderer = function (url, plot, options) {
|
||||
var ret = null;
|
||||
$.ajax({
|
||||
// have to use synchronous here, else the function
|
||||
// will return before the data is fetched
|
||||
async: false,
|
||||
url: url,
|
||||
dataType: "json",
|
||||
success: function (data) {
|
||||
ret = data;
|
||||
}
|
||||
});
|
||||
return ret;
|
||||
};
|
||||
|
||||
var jsonurl = make_uri("/data/timeline", options);
|
||||
|
||||
var plot = $.jqplot('timeline', jsonurl, {
|
||||
dataRenderer: ajaxDataRenderer,
|
||||
dataRendererOptions: {
|
||||
unusedOptionalUrl: jsonurl
|
||||
},
|
||||
gridPadding: {right: 35},
|
||||
cursor: {
|
||||
show: false
|
||||
},
|
||||
highlighter: {
|
||||
show: true,
|
||||
sizeAdjust: 6
|
||||
},
|
||||
axes: {
|
||||
xaxis: {
|
||||
tickRenderer: $.jqplot.CanvasAxisTickRenderer,
|
||||
tickOptions: {
|
||||
fontSize: '8pt',
|
||||
angle: -90,
|
||||
formatString: '%b \'%y'
|
||||
},
|
||||
renderer: $.jqplot.DateAxisRenderer,
|
||||
tickInterval: '1 month'
|
||||
},
|
||||
yaxis: {
|
||||
min: 0,
|
||||
label: ''
|
||||
},
|
||||
y2axis: {
|
||||
min: 0,
|
||||
label: ''
|
||||
}
|
||||
},
|
||||
series: [
|
||||
{
|
||||
shadow: false,
|
||||
fill: true,
|
||||
fillColor: '#4bb2c5',
|
||||
fillAlpha: 0.3
|
||||
},
|
||||
{
|
||||
shadow: false,
|
||||
fill: true,
|
||||
color: '#4bb2c5',
|
||||
fillColor: '#4bb2c5'
|
||||
},
|
||||
{
|
||||
shadow: false,
|
||||
lineWidth: 1.5,
|
||||
showMarker: true,
|
||||
markerOptions: { size: 5 },
|
||||
yaxis: 'y2axis'
|
||||
}
|
||||
]
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
$(document).ready(function () {
|
||||
$('#metric').val('{{ metric }}');
|
||||
$('#period').val('{{ period }}');
|
||||
$('#project_type').val('{{ project_type }}');
|
||||
});
|
||||
|
||||
function make_uri(uri, options) {
|
||||
var ops = {};
|
||||
if (options != null) {
|
||||
$.extend(ops, options);
|
||||
}
|
||||
$.extend(ops, make_std_options());
|
||||
var str = $.map(ops,function (val, index) {
|
||||
return index + "=" + val;
|
||||
}).join("&");
|
||||
|
||||
return uri + "?" + str;
|
||||
}
|
||||
|
||||
function make_std_options() {
|
||||
var options = {};
|
||||
if (getPeriod() != 'havana') {
|
||||
options['period'] = getPeriod();
|
||||
}
|
||||
if (getMetric() != 'loc') {
|
||||
options['metric'] = getMetric();
|
||||
}
|
||||
if (getProjectType() != 'incubation') {
|
||||
options['project_type'] = getProjectType();
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
function reload() {
|
||||
window.location.search = $.map(make_std_options(),function (val, index) {
|
||||
return index + "=" + val;
|
||||
}).join("&")
|
||||
}
|
||||
|
||||
$(document).on('change', '#metric', function (evt) {
|
||||
reload();
|
||||
});
|
||||
|
||||
$(document).on('change', '#period', function (evt) {
|
||||
reload();
|
||||
});
|
||||
|
||||
$(document).on('change', '#project_type', function (evt) {
|
||||
reload();
|
||||
});
|
||||
|
||||
function getPeriod() {
|
||||
return $('#period').val()
|
||||
}
|
||||
|
||||
function getMetric() {
|
||||
return $('#metric').val()
|
||||
}
|
||||
|
||||
function getProjectType() {
|
||||
return $('#project_type').val()
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<div class="Xpage">
|
||||
<div class="Xaheader">
|
||||
<div class="drops" style='margin: 0.8em; height: 2em;'>
|
||||
<span class="drop_metric" style="float: right;">
|
||||
<label for="project_type">Projects </label><select id="project_type" name="project_type">
|
||||
<option value="core">Core</option>
|
||||
<option value="incubation">Core+Incubation</option>
|
||||
<option value="all">All</option>
|
||||
</select>
|
||||
</span>
|
||||
<span class="drop_metric" style="float: right;">
|
||||
<label for="metric">Metric </label><select id="metric" name="metric">
|
||||
<option value="commits">Commits</option>
|
||||
<option value="loc">Lines of code</option>
|
||||
</select>
|
||||
</span>
|
||||
<span class="drop_period" style="float: right;">
|
||||
<label for="period">Period </label><select id="period" name="period">
|
||||
<option value="all">All times</option>
|
||||
<option value="six_months">Last 6 months</option>
|
||||
<option value="havana">Havana</option>
|
||||
<option value="grizzly">Grizzly</option>
|
||||
<option value="folsom">Folsom</option>
|
||||
<option value="essex">Essex</option>
|
||||
</select>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="navigation">
|
||||
<div id="timeline" style="width: 100%; height: 120px; margin-top: 15px;"></div>
|
||||
</div>
|
||||
|
||||
<table style="width: 100%" cellspacing="0">
|
||||
<tr>
|
||||
<td style="width: 50%; vertical-align: top;">
|
||||
<div class="body" style="margin-right: 2em;">
|
||||
{% block left_frame %}{% endblock %}
|
||||
</div>
|
||||
</td>
|
||||
<td style="width: 50%; vertical-align: top;">
|
||||
<div class="body" style="margin-left: 2em;">
|
||||
{% block right_frame %}{% endblock %}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% macro link(base, title) -%}
|
||||
<a href="{{ base }}?metric={{ metric }}&period={{ period }}&project_type={{ project_type }}">{{ title }}</a>
|
||||
{%- endmacro %}
|
69
dashboard/templates/module_details.html
Normal file
@ -0,0 +1,69 @@
|
||||
{% extends "layout.html" %}
|
||||
|
||||
{% block title %}
|
||||
{{ module }}
|
||||
{% endblock %}
|
||||
|
||||
{% block left_frame %}
|
||||
|
||||
<h2>Contribution by companies</h2>
|
||||
|
||||
<script type="text/javascript">
|
||||
loadTable("left_list", "/data/companies", { module: "{{ module }}" });
|
||||
loadChart("left_chart", "/data/companies", { module: "{{ module }}", limit: 10 });
|
||||
loadTimeline({module: '{{ module }}'})
|
||||
</script>
|
||||
|
||||
<div id="left_chart" style="width: 100%; height: 350px;"></div>
|
||||
|
||||
<table id="left_list" class="display">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>Company</th>
|
||||
<th>{{ metric_label }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="spacer"></div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block right_frame %}
|
||||
|
||||
<h2>Recent commits</h2>
|
||||
|
||||
{% for rec in commits %}
|
||||
<div style="padding-bottom: 1em;">
|
||||
<div style='float: left; '>
|
||||
<img src="{{ rec.email|gravatar(size=32) }}">
|
||||
</div>
|
||||
<div style="margin-left: 4em;">
|
||||
<div>
|
||||
{{ link('/engineers/' + rec.launchpad_id, rec.name) }}
|
||||
{# <a href="/engineers/{{ rec.launchpad_id }}?metric={{ metric }}&period={{ period }}&project_type={{ project_type }}">{{ rec.name }}</a>#}
|
||||
{% if rec.company %}
|
||||
(
|
||||
{{ link('/companies/' + rec.company, rec.company) }}
|
||||
{# <a href="/companies/{{ rec.company }}?metric={{ metric }}&period={{ period }}&project_type={{ project_type }}">{{ rec.company }}</a>#}
|
||||
)
|
||||
{% endif %}
|
||||
<em>{{ rec.date|datetimeformat }}</em>
|
||||
</div>
|
||||
|
||||
{% if rec.ref %}
|
||||
<div>{{ rec.ref|safe }}</div>
|
||||
{% endif %}
|
||||
<div>{{ rec.text }}</div>
|
||||
{% if rec.change_id %}
|
||||
<div>Change-Id: <a
|
||||
href="https://review.openstack.org/#q,{{ rec.change_id }},n,z">{{ rec.change_id }}</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
{% endblock %}
|
3
dashboard/templates/unmapped.html
Normal file
@ -0,0 +1,3 @@
|
||||
{% for line in details %}
|
||||
{{ line.email }} {{ line.name }}
|
||||
{% endfor %}
|
10
etc/dashboard.conf
Normal file
@ -0,0 +1,10 @@
|
||||
#
|
||||
# Configuration of stackalytics dashboard
|
||||
#
|
||||
|
||||
# Database
|
||||
DATABASE = 'stackalytics.sqlite'
|
||||
|
||||
LAST_UPDATE = '2013-06-04'
|
||||
|
||||
DEBUG = True
|
94
etc/domain-company
Normal file
@ -0,0 +1,94 @@
|
||||
# domain employer [< yyyy-mm-dd]
|
||||
3ds.com Dassault Systèmes
|
||||
99cloud.net 99cloud
|
||||
alyseo.com Alyseo
|
||||
ansolabs.com Rackspace < 2012-07-20
|
||||
ansolabs.com Nebula
|
||||
atomia.com Atomia
|
||||
att.com AT&T
|
||||
attinteractive.com AT&T
|
||||
bigswitch.com Big Switch Networks
|
||||
b1-systems.de BL Systems
|
||||
brocade.com Brocade
|
||||
bull.net Bull
|
||||
canonical.com Canonical
|
||||
cern.ch CERN
|
||||
cisco.com Cisco Systems
|
||||
citrix.com Citrix
|
||||
cloud.com Citrix Systems
|
||||
cloudbau.de Cloudbau
|
||||
cloudscaling.com Cloudscaling
|
||||
dell.com Dell
|
||||
Dell.com Dell
|
||||
denali-systems.com Denali Systems
|
||||
dreamhost.com DreamHost
|
||||
emc.com EMC
|
||||
enovance.com eNovance
|
||||
fathomdb.com FathomDB
|
||||
gluster.com Red Hat
|
||||
griddynamics.com Grid Dynamics
|
||||
guardian.co.uk The Guardian
|
||||
hds.com Hitachi
|
||||
hp.com HP
|
||||
huawei.com Huawei
|
||||
ibm.com IBM
|
||||
inktank.com Inktank
|
||||
intel.com Intel
|
||||
internap.com Internap
|
||||
isi.edu University of Southern Carolina
|
||||
ispras.ru ISP RAS
|
||||
kt.com KT Corporation
|
||||
kth.se Kungliga Tekniska högskolan
|
||||
linux.vnet.ibm.com IBM
|
||||
locaweb.com.br Locaweb
|
||||
lahondaresearch.org La Honda Research
|
||||
managedit.ie Managed IT
|
||||
mellanox.com Mellanox
|
||||
memset.com Memset
|
||||
metacloud.com Metacloud
|
||||
midokura.com Midokura
|
||||
midokura.jp Midokura
|
||||
mirantis.com Mirantis
|
||||
mirantis.ru Mirantis
|
||||
nasa.gov NASA
|
||||
nebula.com Nebula
|
||||
nexenta.com Nexenta
|
||||
nec.co.jp NEC
|
||||
cq.jp.nec.com NEC
|
||||
da.jp.nec.com NEC
|
||||
mxw.nes.nec.co.jp NEC
|
||||
mxd.nes.nec.co.jp NEC
|
||||
netapp.com NetApp
|
||||
nicira.com Nicira
|
||||
nimbisservices.com Nimbis Services
|
||||
ntt.co.jp NTT
|
||||
ntt.com NTT
|
||||
nttdata.com NTT
|
||||
nttdata.co.jp NTT
|
||||
nttmcl.com NTT
|
||||
vertex.co.in NTT
|
||||
pednape StackOps
|
||||
pistoncloud.com Piston Cloud
|
||||
rackspace.co.uk Rackspace
|
||||
rackspace.com Rackspace
|
||||
radware.com Radware
|
||||
redhat.com Red Hat
|
||||
scality.com Scality
|
||||
sdsc.edu San Diego Supercomputer Center
|
||||
sina.com SINA
|
||||
software.dell.com Dell
|
||||
solidfire.com SolidFire
|
||||
suse.de SUSE
|
||||
suse.com SUSE
|
||||
suse.cz SUSE
|
||||
swiftstack.com SwiftStack
|
||||
thoughtworks.com ThoughtWorks
|
||||
umd.edu University of Maryland
|
||||
unimelb.edu.au University of Melbourne
|
||||
valinux.co.jp VA Linux
|
||||
vexxhost.com VexxHost
|
||||
virtualtech.jp Virtualtech
|
||||
vmware.com VMware
|
||||
wikimedia.org Wikimedia Foundation
|
||||
yahoo-inc.com Yahoo!
|
||||
zadarastorage.com Zadara Storage
|
257
etc/email-aliases
Normal file
@ -0,0 +1,257 @@
|
||||
armamig@gmail.com Armando.Migliaccio@eu.citrix.com
|
||||
yogesh.srikrishnan@rackspace.com yogesh.srikrishnan@rackspace.com
|
||||
emagana@gmail.com eperdomo@cisco.com eperdomo@dhcp-171-71-119-164.cisco.com
|
||||
jeblair@hp.com jeblair@openstack.org
|
||||
rohitgarwalla@gmail.com roagarwa@cisco.com
|
||||
shweta.ap05@gmail.com shpadubi@cisco.com
|
||||
e0ne@e0ne.info ikolodyazhny@mirantis.com
|
||||
santhosh.m@thoughtworks.com santhom@thoughtworks.com
|
||||
john.garbutt@citrix.com john.garbutt@rackspace.com
|
||||
thingee@gmail.com mike.perez@dreamhost.com
|
||||
duncan.thomas@gmail.com duncan.thomas@hp.com
|
||||
adamg@canonical.com adam.gandelman@canonical.com
|
||||
admin@jakedahn.com jake@ansolabs.com
|
||||
amesserl@rackspace.com ant@openstack.org
|
||||
amigliaccio@internap.com Armando.Migliaccio@eu.citrix.com
|
||||
andrew@cloudscaling.com acs@parvuscaptus.com
|
||||
anne.gentle@rackspace.com anne@openstack.org
|
||||
anne@openstack.org anne@openstack.org
|
||||
armando.migliaccio@citrix.com Armando.Migliaccio@eu.citrix.com
|
||||
asomya@cisco.com asomya@cisco.com
|
||||
bcwaldon@gmail.com brian.waldon@rackspace.com
|
||||
bfschott@gmail.com bschott@isi.edu
|
||||
Bogott abogott@wikimedia.org
|
||||
brian.lamar@gmail.com brian.lamar@rackspace.com
|
||||
brian.lamar@rackspace.com brian.lamar@rackspace.com
|
||||
cbehrens@codestud.com cbehrens+github@codestud.com
|
||||
cbehrens+github@codestud.com cbehrens+github@codestud.com
|
||||
chiradeep@chiradeep-lt2 chiradeep@cloud.com
|
||||
chmouel@chmouel.com chmouel.boudjnah@rackspace.co.uk
|
||||
chmouel@enovance.com chmouel@chmouel.com
|
||||
chris.behrens@rackspace.com cbehrens@codestud.com
|
||||
chris@slicehost.com chris@pistoncloud.com
|
||||
chuck.short@canonical.com zulcss@ubuntu.com
|
||||
clayg@clayg-desktop clay.gerrard@gmail.com
|
||||
clay.gerrard@gmail.com clay.gerrard@gmail.com
|
||||
clay.gerrard@rackspace.com clay.gerrard@gmail.com
|
||||
code@term.ie code@term.ie
|
||||
corvus@gnu.org jeblair@hp.com
|
||||
corvus@inaugust.com jeblair@hp.com
|
||||
corywright@gmail.com cory.wright@rackspace.com
|
||||
cory.wright@rackspace.com corywright@gmail.com
|
||||
dan@nicira.com dan@nicira.com
|
||||
dan.prince@rackspace.com dprince@redhat.com
|
||||
danwent@dan-xs3-cs dan@nicira.com
|
||||
danwent@gmail.com dan@nicira.com
|
||||
Dave.Walker@Canonical.com dave.walker@canonical.com
|
||||
DaveWalker@ubuntu.com dave.walker@canonical.com
|
||||
DaveWalker@ubuntu.com Dave.Walker@canonical.com
|
||||
david.goetz@gmail.com david.goetz@rackspace.com
|
||||
david.hadas@gmail.com davidh@il.ibm.com
|
||||
devcamcar@illian.local devin.carlen@gmail.com
|
||||
devnull@brim.net gholt@rackspace.com
|
||||
Dietz matt.dietz@rackspace.com
|
||||
dolph.mathews@gmail.com dolph.mathews@rackspace.com
|
||||
doug.hellmann@gmail.com doug.hellmann@dreamhost.com
|
||||
dougw@sdsc.edu dweimer@gmail.com
|
||||
dpgoetz@gmail.com david.goetz@rackspace.com
|
||||
dt-github@xr7.org dtroyer@gmail.com
|
||||
Édouard edouard.thuleau@orange.com
|
||||
emellor@silver ewan.mellor@citrix.com
|
||||
enugaev@griddynamics.com reldan@oscloud.ru
|
||||
florian.hines@gmail.com syn@ronin.io
|
||||
gaurav@gluster.com gaurav@gluster.com
|
||||
ghe.rivero@gmail.com ghe@debian.org
|
||||
ghe.rivero@stackops.com ghe@debian.org
|
||||
gholt@brim.net gholt@rackspace.com
|
||||
gihub@highbridgellc.com github@highbridgellc.com
|
||||
github@anarkystic.com code@term.ie
|
||||
github@anarkystic.com github@anarkystic.com
|
||||
glange@rackspace.com greglange@gmail.com
|
||||
greglange+launchpad@gmail.com greglange@gmail.com
|
||||
heut2008@gmail.com yaguang.tang@canonical.com
|
||||
higginsd@gmail.com derekh@redhat.com
|
||||
ialekseev@griddynamics.com ilyaalekseyev@acm.org
|
||||
ilya@oscloud.ru ilyaalekseyev@acm.org
|
||||
itoumsn@shayol itoumsn@nttdata.co.jp
|
||||
jake@ansolabs.com jake@ansolabs.com
|
||||
jake@markupisart.com jake@ansolabs.com
|
||||
james.blair@rackspace.com jeblair@hp.com
|
||||
jaypipes@gmail.com jaypipes@gmail.com
|
||||
jesse@aire.local anotherjesse@gmail.com
|
||||
jesse@dancelamb anotherjesse@gmail.com
|
||||
jesse@gigantor.local anotherjesse@gmail.com
|
||||
jesse@ubuntu anotherjesse@gmail.com
|
||||
jian.wen@ubuntu.com jian.wen@canonical.com
|
||||
jkearney@nova.(none) josh@jk0.org
|
||||
jkearney@nova.(none) josh.kearney@pistoncloud.com
|
||||
jmckenty@joshua-mckentys-macbook-pro.local jmckenty@gmail.com
|
||||
jmckenty@yyj-dhcp171.corp.flock.com jmckenty@gmail.com
|
||||
joe@cloudscaling.com joe@swiftstack.com
|
||||
johannes@compute3.221.st johannes.erdfelt@rackspace.com
|
||||
johannes@erdfelt.com johannes.erdfelt@rackspace.com
|
||||
john.dickinson@rackspace.com me@not.mn
|
||||
john.eo@gmail.com john.eo@rackspace.com
|
||||
john.griffith8@gmail.com john.griffith@solidfire.com
|
||||
john.griffith@solidfire.com john.griffith@solidfire.com
|
||||
josh@jk0.org josh.kearney@pistoncloud.com
|
||||
josh.kearney@rackspace.com josh@jk0.org
|
||||
josh.kearney@rackspace.com josh.kearney@pistoncloud.com
|
||||
joshua.mckenty@nasa.gov jmckenty@gmail.com
|
||||
jpipes@serialcoder jaypipes@gmail.com
|
||||
jpipes@uberbox.gateway.2wire.net jaypipes@gmail.com
|
||||
jsuh@bespin jsuh@isi.edu
|
||||
jtran@attinteractive.com jhtran@att.com
|
||||
julien.danjou@enovance.com julien@danjou.info
|
||||
justin@fathomdb.com justin@fathomdb.com
|
||||
justinsb@justinsb-desktop justin@fathomdb.com
|
||||
kapil.foss@gmail.com kapil.foss@gmail.com
|
||||
ken.pepple@rabbityard.com ken.pepple@gmail.com
|
||||
ke.wu@nebula.com ke.wu@ibeca.me
|
||||
khaled.hussein@gmail.com khaled.hussein@rackspace.com
|
||||
Knouff philip.knouff@mailtrust.com
|
||||
Kölker jason@koelker.net
|
||||
kshileev@griddynamics.com kshileev@gmail.com
|
||||
laner@controller rlane@wikimedia.org
|
||||
letterj@racklabs.com letterj@gmail.com
|
||||
liem.m.nguyen@gmail.com liem_m_nguyen@hp.com
|
||||
liem.m.nguyen@hp.com liem_m_nguyen@hp.com
|
||||
Lopez aloga@ifca.unican.es
|
||||
lorin@isi.edu lorin@nimbisservices.com
|
||||
lrqrun@gmail.com lrqrun@gmail.com
|
||||
lzyeval@gmail.com zhongyue.nah@intel.com
|
||||
marcelo.martins@rackspace.com btorch@gmail.com
|
||||
masumotok@nttdata.co.jp masumotok@nttdata.co.jp
|
||||
masumoto masumotok@nttdata.co.jp
|
||||
matt.dietz@rackspace.com matt.dietz@rackspace.com
|
||||
matthew.dietz@gmail.com matt.dietz@rackspace.com
|
||||
matthewdietz@Matthew-Dietzs-MacBook-Pro.local matt.dietz@rackspace.com
|
||||
McConnell bmcconne@rackspace.com
|
||||
mdietz@openstack matt.dietz@rackspace.com
|
||||
mgius7096@gmail.com launchpad@markgius.com
|
||||
michael.barton@rackspace.com mike@weirdlooking.com
|
||||
michael.still@canonical.com mikal@stillhq.com
|
||||
mike-launchpad@weirdlooking.com mike@weirdlooking.com
|
||||
Moore joelbm24@gmail.com
|
||||
mordred@hudson mordred@inaugust.com
|
||||
nati.ueno@gmail.com ueno.nachi@lab.ntt.co.jp
|
||||
naveed.massjouni@rackspace.com naveedm9@gmail.com
|
||||
nelson@nelson-laptop russ@crynwr.com
|
||||
nirmal.ranganathan@rackspace.com rnirmal@gmail.com
|
||||
nirmal.ranganathan@rackspace.coom rnirmal@gmail.com
|
||||
nova@u4 ueno.nachi@lab.ntt.co.jp
|
||||
nsokolov@griddynamics.net nsokolov@griddynamics.com
|
||||
openstack@lab.ntt.co.jp ueno.nachi@lab.ntt.co.jp
|
||||
paul@openstack.org paul@openstack.org
|
||||
paul@substation9.com paul@openstack.org
|
||||
paul.voccio@rackspace.com paul@openstack.org
|
||||
pvoccio@castor.local paul@openstack.org
|
||||
ramana@venus.lekha.org rjuvvadi@hcl.com
|
||||
rclark@chat-blanc rick@openstack.org
|
||||
renuka.apte@citrix.com renuka.apte@citrix.com
|
||||
rick.harris@rackspace.com rconradharris@gmail.com
|
||||
rick@quasar.racklabs.com rconradharris@gmail.com
|
||||
root@bsirish.(none) sirish.bitra@gmail.com
|
||||
root@debian.ohthree.com amesserl@rackspace.com
|
||||
root@mirror.nasanebula.net vishvananda@gmail.com
|
||||
root@openstack2-api masumotok@nttdata.co.jp
|
||||
root@tonbuntu sleepsonthefloor@gmail.com
|
||||
root@ubuntu vishvananda@gmail.com
|
||||
rrjuvvadi@gmail.com rjuvvadi@hcl.com
|
||||
salv.orlando@gmail.com salvatore.orlando@eu.citrix.com
|
||||
sandy@sandywalsh.com sandy@darksecretsoftware.com
|
||||
sandy@sandywalsh.com sandy.walsh@rackspace.com
|
||||
sandy.walsh@rackspace.com sandy@darksecretsoftware.com
|
||||
sandy.walsh@rackspace.com sandy.walsh@rackspace.com
|
||||
sateesh.chodapuneedi@citrix.com sateesh.chodapuneedi@citrix.com
|
||||
SB justin@fathomdb.com
|
||||
sirish.bitra@gmail.com sirish.bitra@gmail.com
|
||||
sleepsonthefloor@gmail.com sleepsonthefloor@gmail.com
|
||||
Smith code@term.ie
|
||||
Sokolov nsokolov@griddynamics.com
|
||||
Somya asomya@cisco.com
|
||||
soren.hansen@rackspace.com soren@linux2go.dk
|
||||
soren@linux2go.dk soren.hansen@rackspace.com
|
||||
soren@openstack.org soren.hansen@rackspace.com
|
||||
sorhanse@cisco.com sorenhansen@rackspace.com
|
||||
sorlando@nicira.com salvatore.orlando@eu.citrix.com
|
||||
spam@andcheese.org sam@swiftstack.com
|
||||
superstack@superstack.org justin@fathomdb.com
|
||||
termie@preciousroy.local code@term.ie
|
||||
thuleau@gmail.com edouard1.thuleau@orange.com
|
||||
thuleau@gmail.com edouard.thuleau@orange.com
|
||||
tim.simpson4@gmail.com tim.simpson@rackspace.com
|
||||
todd@lapex todd@ansolabs.com
|
||||
todd@rubidine.com todd@ansolabs.com
|
||||
todd@rubidine.com xtoddx@gmail.com
|
||||
tpatil@vertex.co.in tushar.vitthal.patil@gmail.com
|
||||
Tran jtran@attinteractive.com
|
||||
treyemorris@gmail.com trey.morris@rackspace.com
|
||||
ttcl@mac.com troy.toman@rackspace.com
|
||||
Ueno ueno.nachi@lab.ntt.co.jp
|
||||
vishvananda@yahoo.com vishvananda@gmail.com
|
||||
vito.ordaz@gmail.com victor.rodionov@nexenta.com
|
||||
wenjianhn@gmail.com jian.wen@canonical.com
|
||||
will.wolf@rackspace.com throughnothing@gmail.com
|
||||
wwkeyboard@gmail.com aaron.lee@rackspace.com
|
||||
xchu@redhat.com xychu2008@gmail.com
|
||||
xtoddx@gmail.com todd@ansolabs.com
|
||||
xyj.asmy@gmail.com xyj.asmy@gmail.com
|
||||
yorik@ytaraday yorik.sar@gmail.com
|
||||
YS vivek.ys@gmail.com
|
||||
z-github@brim.net gholt@rackspace.com
|
||||
ziad.sawalha@rackspace.com github@highbridgellc.com
|
||||
z-launchpad@brim.net gholt@rackspace.com
|
||||
derek.morton25@gmail.com derek@networkwhisperer.com
|
||||
bartosz.gorski@ntti3.com bartosz.gorski@nttmcl.com
|
||||
launchpad@chmouel.com chmouel@chmouel.com
|
||||
launchpad@chmouel.com chmouel@enovance.com
|
||||
launchpad@chmouel.com chmouel@openstack.org
|
||||
imsplitbit@gmail.com dsalinas@rackspace.com
|
||||
clint@fewbar.com clint.byrum@hp.com
|
||||
clint@fewbar.com clint@ubuntu.com
|
||||
sbaker@redhat.com steve@stevebaker.org
|
||||
asalkeld@redhat.com angus@salkeld.id.au
|
||||
evgeniy@afonichev.com eafonichev@mirantis.com
|
||||
smoser@ubuntu.com scott.moser@canonical.com
|
||||
smoser@ubuntu.com smoser@brickies.net
|
||||
smoser@ubuntu.com smoser@canonical.com
|
||||
smoser@ubuntu.com ssmoser2@gmail.com
|
||||
jason@koelker.net jkoelker@rackspace.com
|
||||
john.garbutt@rackspace.com john@johngarbutt.com
|
||||
zhongyue.nah@intel.com lzyeval@gmail.com
|
||||
jiajun@unitedstack.com iamljj@gmail.com
|
||||
christophe.sauthier@ubuntu.com christophe.sauthier@gmail.com
|
||||
christophe.sauthier@ubuntu.com christophe@sauthier.com
|
||||
christophe.sauthier@objectif-libre.com christophe@sauthier.com
|
||||
aababilov@griddynamics.com ilovegnulinux@gmail.com
|
||||
yportnova@griddynamics.com yportnov@yahoo-inc.com
|
||||
mkislins@yahoo-inc.com mkislinska@griddynamics.com
|
||||
ryan.moore@hp.com rmoore08@gmail.com
|
||||
starodubcevna@gmail.com nstarodubtsev@mirantis.com
|
||||
lakhinder.walia@hds.com lakhindr@hotmail.com
|
||||
kanzhe@gmail.com kanzhe.jiang@bigswitch.com
|
||||
anita.kuno@enovance.com akuno@lavabit.com
|
||||
me@frostman.ru slukjanov@mirantis.com
|
||||
alexei.kornienko@gmail.com akornienko@mirantis.com
|
||||
nicolas@barcet.com nick.barcet@canonical.com
|
||||
nicolas@barcet.com nick@enovance.com
|
||||
nicolas@barcet.com nijaba@ubuntu.com
|
||||
graham.binns@canonical.com gmb@canonical.com
|
||||
graham.binns@canonical.com gmb@grahambinns.com
|
||||
graham.binns@canonical.com graham.binns@gmail.com
|
||||
graham.binns@canonical.com graham@canonical.com
|
||||
graham.binns@canonical.com graham@grahambinns.com
|
||||
emilien.macchi@stackops.com emilien.macchi@enovance.com
|
||||
emilien.macchi@stackops.com emilien@enovance.com
|
||||
swann.croiset@bull.net swann@oopss.org
|
||||
soulascedric@gmail.com cedric.soulas@cloudwatt.com
|
||||
simon.pasquier@bull.net pasquier.simon+launchpad@gmail.com
|
||||
simon.pasquier@bull.net pasquier.simon@gmail.com
|
||||
bogorodskiy@gmail.com novel@FreeBSD.org
|
||||
bogorodskiy@gmail.com rbogorodskiy@mirantis.com
|
||||
svilgelm@mirantis.com sergey.vilgelm@gmail.com
|
||||
robert.myers@rackspace.com robert_myers@earthlink.net
|
||||
raymond_pekowski@dell.com pekowski@gmail.com
|
||||
agorodnev@mirantis.com a.gorodnev@gmail.com
|
||||
rprikhodchenko@mirantis.com me@romcheg.me
|
17
etc/email-company
Normal file
@ -0,0 +1,17 @@
|
||||
# user@domain employer
|
||||
anotherjesse@gmail.com Nebula
|
||||
bcwaldon@gmail.com Nebula
|
||||
code@term.ie Nebula
|
||||
dprince@redhat.com Red Hat
|
||||
github@anarkystic.com Nebula
|
||||
jake@ansolabs.com Nebula
|
||||
jaypipes@gmail.com AT&T
|
||||
jeblair@hp.com HP
|
||||
lzyeval@gmail.com Intel
|
||||
me@not.mn SwiftStack
|
||||
mordred@inaugust.com HP
|
||||
sleepsonthefloor@gmail.com Nebula
|
||||
soren@linux2go.dk Cisco
|
||||
vishvananda@gmail.com Nebula
|
||||
dtroyer@gmail.com Nebula
|
||||
|
36
etc/launchpad-company
Normal file
@ -0,0 +1,36 @@
|
||||
tatyana-leontovich Grid Dynamics
|
||||
vkhomenko Grid Dynamics
|
||||
cthiel-suse DE Telekom
|
||||
yorik-sar Mirantis
|
||||
gelbuhos Mirantis
|
||||
aababilov Grid Dynamics
|
||||
alexpilotti Cloudbase Solutions
|
||||
devananda HP
|
||||
heckj Nebula
|
||||
matt-sherborne Rackspace
|
||||
michael-ogorman Cisco Systems
|
||||
boris-42 Mirantis
|
||||
boris-42 *independent < 2013-04-10
|
||||
victor-r-howard Comcast
|
||||
amitry Comcast
|
||||
scollins Comcast
|
||||
w-emailme Comcast
|
||||
jasondunsmore Rackspace
|
||||
kannan Rightscale
|
||||
bob-melander Cisco Systems
|
||||
gabriel-hurley Nebula
|
||||
mathrock National Security Agency
|
||||
yosshy NEC
|
||||
johngarbutt Rackspace
|
||||
johngarbutt Citrix < 2013-02-01
|
||||
jean-baptiste-ransy Alyseo
|
||||
darren-birkett Rackspace
|
||||
lucasagomes Red Hat
|
||||
nobodycam HP
|
||||
cboylan HP
|
||||
dmllr SUSE
|
||||
therve HP
|
||||
hughsaunders Rackspace
|
||||
bruno-semperlotti Dassault Systèmes
|
||||
james-slagle Red Hat
|
||||
openstack *robots
|
1128
etc/launchpad-ids
Normal file
27
etc/openstack.conf
Normal file
@ -0,0 +1,27 @@
|
||||
[DEFAULT]
|
||||
# Run in debug mode?
|
||||
# debug = False
|
||||
|
||||
# Database parameters
|
||||
# db_driver = sqlite
|
||||
# db_user = operator
|
||||
# db_password = None
|
||||
# db_database = /opt/stack/data/stackalytics.sqlite
|
||||
# db_hostname = localhost
|
||||
|
||||
# Extensions
|
||||
# extensions = CommitsLOC,MessageDetails
|
||||
|
||||
# Root for all project sources. The tool will iterate over its contents
|
||||
# sources_root = /opt/stack/repos
|
||||
|
||||
# email mappings (e.g. collected from .mailmap files)
|
||||
# email_aliases = etc/email-aliases
|
||||
# mappings from domains to company names
|
||||
# domain2company = etc/domain-company
|
||||
# mappings from emails to company names
|
||||
# email2company = etc/email-company
|
||||
# mappings from launchpad ids to emails and user names
|
||||
# launchpad2email = etc/launchpad-ids
|
||||
# mappings from launchpad id to company name
|
||||
# launchpad2company = etc/launchpad-company
|
11
requirements.txt
Normal file
@ -0,0 +1,11 @@
|
||||
d2to1>=0.2.10,<0.3
|
||||
pbr>=0.5.16,<0.6
|
||||
#MySQL-python
|
||||
#pysqlite
|
||||
#git+git://github.com/MetricsGrimoire/RepositoryHandler.git#egg=repositoryhandler-0.5
|
||||
#git+git://github.com/SoftwareIntrospectionLab/guilty.git#egg=guilty-2.1
|
||||
launchpadlib
|
||||
Flask>=0.9
|
||||
Flask-Gravatar
|
||||
oslo.config
|
||||
pylibmc
|
110
scripts/gerrit/parse-reviews.py
Normal file
@ -0,0 +1,110 @@
|
||||
import argparse
|
||||
import json
|
||||
import sys
|
||||
import time
|
||||
|
||||
#
|
||||
# List reviewers for a set of git commits
|
||||
#
|
||||
# python buglist.py essex-commits.txt openstack-config/launchpad-ids.txt
|
||||
# < gerrit.json
|
||||
#
|
||||
|
||||
parser = argparse.ArgumentParser(description='List reviewers in gerrit')
|
||||
|
||||
parser.add_argument('commits', help='path to list of commits to consider')
|
||||
parser.add_argument('usermap', help='path to username to email map')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
username_to_email_map = {}
|
||||
for l in open(args.usermap, 'r'):
|
||||
(username, email) = l.split()
|
||||
username_to_email_map.setdefault(username, email)
|
||||
|
||||
commits = [l.strip() for l in open(args.commits, 'r')]
|
||||
|
||||
|
||||
class Reviewer:
|
||||
def __init__(self, username, name, email):
|
||||
self.username = username
|
||||
self.name = name
|
||||
self.email = (email if email
|
||||
else username_to_email_map.get(self.username))
|
||||
|
||||
@classmethod
|
||||
def parse(cls, r):
|
||||
return cls(r.get('username'), r.get('name'), r.get('email'))
|
||||
|
||||
|
||||
class Approval:
|
||||
CodeReviewed, Approved, Submitted, Verified = range(4)
|
||||
|
||||
type_map = {
|
||||
'CRVW': CodeReviewed,
|
||||
'APRV': Approved,
|
||||
'SUBM': Submitted,
|
||||
'VRIF': Verified,
|
||||
}
|
||||
|
||||
def __init__(self, type, value, date, by):
|
||||
self.type = type
|
||||
self.value = value
|
||||
self.date = date
|
||||
self.by = by
|
||||
|
||||
@classmethod
|
||||
def parse(cls, a):
|
||||
return cls(cls.type_map[a['type']],
|
||||
int(a['value']),
|
||||
time.gmtime(int(a['grantedOn'])),
|
||||
Reviewer.parse(a['by']))
|
||||
|
||||
|
||||
class PatchSet:
|
||||
def __init__(self, revision, approvals):
|
||||
self.revision = revision
|
||||
self.approvals = approvals
|
||||
|
||||
@classmethod
|
||||
def parse(cls, ps):
|
||||
return cls(ps['revision'],
|
||||
[Approval.parse(a) for a in ps.get('approvals', [])])
|
||||
|
||||
|
||||
class Review:
|
||||
def __init__(self, id, patchsets):
|
||||
self.id = id
|
||||
self.patchsets = patchsets
|
||||
|
||||
@classmethod
|
||||
def parse(cls, r):
|
||||
return cls(r['id'],
|
||||
[PatchSet.parse(ps) for ps in r['patchSets']])
|
||||
|
||||
reviews = [Review.parse(json.loads(l)) for l in sys.stdin
|
||||
if not 'runTimeMilliseconds' in l]
|
||||
|
||||
|
||||
def reviewers(review):
|
||||
ret = {}
|
||||
for ps in r.patchsets:
|
||||
for a in ps.approvals:
|
||||
if a.type == Approval.CodeReviewed and a.value:
|
||||
ret.setdefault(a.by.username, (a.by, a.date))
|
||||
return ret.values()
|
||||
|
||||
|
||||
def interesting(review):
|
||||
for ps in r.patchsets:
|
||||
if ps.revision in commits:
|
||||
return True
|
||||
return False
|
||||
|
||||
for r in reviews:
|
||||
if not interesting(r):
|
||||
continue
|
||||
for reviewer, date in reviewers(r):
|
||||
if reviewer.email:
|
||||
print (time.strftime('%Y-%m-%d', date),
|
||||
reviewer.username, reviewer.email)
|
11
scripts/grab-all-emails.sh
Executable file
@ -0,0 +1,11 @@
|
||||
#!/bin/bash
|
||||
|
||||
grep -v '^#' grizzly-with-libs | \
|
||||
while read project; do \
|
||||
cd ~/Work/metric-root/$project; \
|
||||
git log | awk -F '[<>]' '/^Author:/ {print $2}'; \
|
||||
done | sort | uniq | grep -v '\((none)\|\.local\)$' > tmp
|
||||
sed 's/ /\n/' < aliases >> tmp
|
||||
sed 's/ /\n/' < other-aliases >> tmp
|
||||
(sort | uniq | grep -v '\((none)\|\.local\)$') < tmp > emails.txt
|
||||
rm tmp
|
6
scripts/grab-buglist.sh
Executable file
@ -0,0 +1,6 @@
|
||||
#!/bin/bash
|
||||
|
||||
grep -v '^#' grizzly-with-libs | \
|
||||
while read project; do \
|
||||
.././tools/with_venv.sh python ./launchpad/buglist.py $project grizzly; \
|
||||
done > buglist.txt
|
4
scripts/grab-launchpad-ids.sh
Executable file
@ -0,0 +1,4 @@
|
||||
#!/bin/bash
|
||||
|
||||
.././tools/with_venv.sh python launchpad/map-email-to-lp-name.py \
|
||||
$(cat emails.txt) > launchpad-ids.txt
|
8
scripts/grab-mailmap.sh
Executable file
@ -0,0 +1,8 @@
|
||||
#!/bin/bash
|
||||
|
||||
grep -v '^#' grizzly-with-libs | \
|
||||
while read project; do cat ~/Work/metric-root/$project/.mailmap; done | \
|
||||
grep -v '^#' | sed 's/^[^<]*<\([^>]*\)>/\1/' | \
|
||||
grep '<.*>' | sed -e 's/[<>]/ /g' | \
|
||||
awk '{if ($3 != "") { print $3" "$1 } else {print $2" "$1}}' | \
|
||||
sort | uniq > aliases
|
35
scripts/grab-unmatched.sh
Executable file
@ -0,0 +1,35 @@
|
||||
#!/bin/bash
|
||||
|
||||
grep -v '^#' unmatched-names | \
|
||||
while read line; do \
|
||||
|
||||
echo
|
||||
echo "LINE: $line"
|
||||
|
||||
EMAIL=$(echo "$line" | awk -F" " '{print $1}')
|
||||
NAME=$(echo "$line" | cut -d ' ' -f2-)
|
||||
# echo $EMAIL
|
||||
# echo $NAME
|
||||
|
||||
LAUNCHPAD=$(links -dump -codepage UTF-8 -http.extra-header "Cookie: PREF=ID=532e2937af64f34a:FF=0:NW=1:TM=1363615469:LM=1363615469:S=RQ32u6mIZ60kEpWC; NID=67=oaBHx3gZQzXJUBSwHhFGDPEnD9G_kGy-3MedWLoLiG-qPmMRIgDqehVG0epg-SzYAvqR4KMWNTzE2JLt-Cp03mdh1iAnHI5JMKp3mDYO32JySQMC_e5x1zLOxpE_YuEH" "http://google.com/search?ie=windows-1251&hl=ru&source=hp&q=$NAME+site%3Alaunchpad.net&btnG=%CF%EE%E8%F1%EA+%E2+Google&gbv=1" | grep launchpad.net/~ | \
|
||||
sed -r 's/.*launchpad.net\/~([a-z0-9\.-]+).*/\1/' | uniq | sort)
|
||||
|
||||
echo "LAUNCHPAD: $LAUNCHPAD"
|
||||
|
||||
if [ $LAUNCHPAD ]; then
|
||||
|
||||
RES=$(links -dump https://launchpad.net/~$LAUNCHPAD | grep "$NAME")
|
||||
|
||||
if [ -n "$RES" ]; then
|
||||
echo "$LAUNCHPAD $EMAIL $NAME ---- $RES"
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
if [ -z $LAUNCHPAD ]; then
|
||||
echo "********** $EMAIL $NAME"
|
||||
fi
|
||||
|
||||
sleep 1
|
||||
|
||||
done
|
27
scripts/launchpad/buglist.py
Normal file
@ -0,0 +1,27 @@
|
||||
|
||||
#
|
||||
# List all bugs marked as 'Fix Released' on a given series
|
||||
#
|
||||
# python buglist.py glance essex
|
||||
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser(description='List fixed bugs for a series')
|
||||
|
||||
parser.add_argument('project', help='the project to act on')
|
||||
parser.add_argument('series', help='the series to list fixed bugs for')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
from launchpadlib import launchpad
|
||||
|
||||
lp = launchpad.Launchpad.login_with('openstack-dm', 'production')
|
||||
|
||||
project = lp.projects[args.project]
|
||||
series = project.getSeries(name=args.series)
|
||||
|
||||
for milestone in series.all_milestones:
|
||||
for task in milestone.searchTasks(status='Fix Released'):
|
||||
assignee = task.assignee.name if task.assignee else '<unknown>'
|
||||
date = task.date_fix_committed or task.date_fix_released
|
||||
print task.bug.id, assignee, date.date()
|
35
scripts/launchpad/grab-unmapped-launchpad-ids.py
Normal file
@ -0,0 +1,35 @@
|
||||
#
|
||||
# fetch launchpad ids for unknown persons
|
||||
#
|
||||
|
||||
import httplib
|
||||
|
||||
from launchpadlib import launchpad
|
||||
|
||||
try:
|
||||
conn = httplib.HTTPConnection("analytics.vm.mirantis.net")
|
||||
conn.request("GET", "/unmapped")
|
||||
r1 = conn.getresponse()
|
||||
data = r1.read()
|
||||
except Exception as e:
|
||||
print ('Error while retrieving mapping report. Check that the server '
|
||||
'is up and running. \nDetails: %s' % e)
|
||||
exit(1)
|
||||
|
||||
lp = launchpad.Launchpad.login_with('openstack-dm', 'production')
|
||||
|
||||
for line in data.split('\n'):
|
||||
line = line.strip()
|
||||
if not line:
|
||||
continue
|
||||
|
||||
(email, sep, name) = line.partition(' ')
|
||||
try:
|
||||
person = lp.people.getByEmail(email=email)
|
||||
if person:
|
||||
if name == person.display_name:
|
||||
print person.name, email, person.display_name
|
||||
else:
|
||||
print person.name, email, person.display_name, '*', name
|
||||
except Exception:
|
||||
continue
|
26
scripts/launchpad/map-email-to-lp-name.py
Normal file
@ -0,0 +1,26 @@
|
||||
|
||||
#
|
||||
# Attempt to find a launchpad name for every email address supplied:
|
||||
#
|
||||
# python map-email-to-lp-name.py foo@bar.com blaa@foo.com
|
||||
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser(description='List fixed bugs for a series')
|
||||
|
||||
parser.add_argument('emails', metavar='EMAIL', nargs='+',
|
||||
help='An email address to query')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
from launchpadlib import launchpad
|
||||
|
||||
lp = launchpad.Launchpad.login_with('openstack-dm', 'production')
|
||||
|
||||
for email in args.emails:
|
||||
try:
|
||||
person = lp.people.getByEmail(email=email)
|
||||
if person:
|
||||
print person.name, email, person.display_name
|
||||
except Exception:
|
||||
continue
|
18
scripts/pull-repos.sh
Executable file
@ -0,0 +1,18 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [[ -z $STACKALYTICS_HOME ]]; then
|
||||
CONF='../etc/analytics.conf.local'
|
||||
else
|
||||
CONF="$STACKALYTICS_HOME/conf/analytics.conf"
|
||||
fi
|
||||
|
||||
TOP_DIR=$(cd $(dirname "$0") && pwd)
|
||||
|
||||
cd `cat $CONF | grep sources_root | awk -F"=" '{print $2}'`
|
||||
|
||||
for a in `dir`; do
|
||||
echo "Pulling $a"
|
||||
cd $a
|
||||
git pull
|
||||
cd ../
|
||||
done
|
30
setup.cfg
Normal file
@ -0,0 +1,30 @@
|
||||
[metadata]
|
||||
name = stackalytics
|
||||
version = 0.1
|
||||
summary = OpenStack analytics dashboard
|
||||
description-file =
|
||||
README.rst
|
||||
author = OpenStack Stackalytics Project
|
||||
author-email = openstack-dev@lists.openstack.org
|
||||
home-page = http://www.openstack.org/
|
||||
classifier =
|
||||
Environment :: OpenStack
|
||||
Intended Audience :: Developers
|
||||
Intended Audience :: Information Technology
|
||||
License :: OSI Approved :: Apache Software License
|
||||
Operating System :: POSIX :: Linux
|
||||
Programming Language :: Python
|
||||
Programming Language :: Python :: 2
|
||||
Programming Language :: Python :: 2.7
|
||||
|
||||
[files]
|
||||
packages =
|
||||
dashboard
|
||||
|
||||
[global]
|
||||
setup-hooks =
|
||||
pbr.hooks.setup_hook
|
||||
|
||||
[entry_points]
|
||||
console_scripts =
|
||||
stackalytics-dashboard = dashboard.dashboard:main
|
7
setup.py
Normal file
@ -0,0 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import setuptools
|
||||
|
||||
setuptools.setup(
|
||||
setup_requires=['d2to1>=0.2.10,<0.3', 'pbr>=0.5.10,<0.6'],
|
||||
d2to1=True)
|
13
test-requirements.txt
Normal file
@ -0,0 +1,13 @@
|
||||
# Install bounded pep8/pyflakes first, then let flake8 install
|
||||
pep8==1.4.5
|
||||
pyflakes==0.7.2
|
||||
flake8==2.0
|
||||
hacking>=0.5.3,<0.6
|
||||
|
||||
coverage
|
||||
discover
|
||||
fixtures>=0.3.12
|
||||
mox
|
||||
python-subunit
|
||||
testrepository>=0.0.13
|
||||
testtools>=0.9.22
|
0
tests/__init__.py
Normal file
1
tests/unit/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
__author__ = 'ishakhat'
|