Initial code commit

This commit is contained in:
Ilya Shakhat 2013-06-22 15:38:42 +04:00
parent 5a1376ca06
commit a5f1411218
104 changed files with 19824 additions and 4 deletions

17
.gitignore vendored Normal file
View 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
View File

@ -0,0 +1,4 @@
[gerrit]
host=review.openstack.org
port=29418
project=stackforge/stackalytics.git

4
.testr.conf Normal file
View 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
View 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
View File

@ -0,0 +1,9 @@
include AUTHORS
include README.rst
include ChangeLog
include LICENSE
exclude .gitignore
exclude .gitreview
global-exclude *.pyc

View File

@ -1,4 +0,0 @@
stackalytics
============
OpenStack analytics dashboard

15
README.rst Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View File

987
dashboard/dashboard.py Normal file
View 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')

View 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;
}

View 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;
}

View 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);}

View 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*/

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 220 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 230 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 260 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 342 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 316 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 276 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 275 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 340 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View 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;
}

View 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;
}

View 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;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

12099
dashboard/static/jquery.dataTables.js vendored Normal file

File diff suppressed because it is too large Load Diff

3
dashboard/static/js/excanvas.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View 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);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View 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);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View 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('"',"&quot;"));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);

File diff suppressed because one or more lines are too long

View 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 %}

View 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> &nbsp; <a class="top" href="http://mirantis.com/careers/">Careers</a> &nbsp; <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&ndash;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>

View 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 %}

View 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 %}

View 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 %}

View 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 %}

View 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 %}

View 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&nbsp;</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&nbsp;</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&nbsp;</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 %}

View 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 %}

View File

@ -0,0 +1,3 @@
{% for line in details %}
{{ line.email }} {{ line.name }}
{% endfor %}

10
etc/dashboard.conf Normal file
View 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
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

27
etc/openstack.conf Normal file
View 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
View 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

View 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
View 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
View 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
View 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
View 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
View 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

View 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()

View 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

View 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
View 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
View 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
View 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
View 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
View File

1
tests/unit/__init__.py Normal file
View File

@ -0,0 +1 @@
__author__ = 'ishakhat'

Some files were not shown because too many files have changed in this diff Show More