diff --git a/LICENSE b/LICENSE
index 261eeb9..37935c2 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,3 +1,4 @@
+
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
@@ -186,7 +187,7 @@
same "printed page" as the copyright notice for easier
identification within third-party archives.
- Copyright [yyyy] [name of copyright owner]
+ Copyright 2018 Lancaster University, Queen’s University Belfast, Crown Copyright 2018 GCHQ
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
diff --git a/README.md b/README.md
index 13f56d2..8705369 100644
--- a/README.md
+++ b/README.md
@@ -1,8 +1,66 @@
-# TENNISON
-TENNISON is an SDN security framework which is soon to appear in JSAC SI on SDN Scalabiltiy Issues.
-The TENNISON source code is currently undergoing licensing and is expected to be released to the public in the 15th of October 2018 .
-This repository will include TENNISON's source code, user applications, graphical interface, and the developer's guide for working with the system.
+![Tennison Logo](imgs/tennison_logo.png)
+
+TENNISON is a network security framework that harnesses Software Defined Networks.
Please contact Lyndon at l.fawcett1@lancaster.ac.uk about any questions on TENNISON.
+
+
+TENNISON's KSPs:
+* Extensibility
+* Holistic view
+* Rapid reaction
+* Transparency and interoperability
+* Kill chain detection support
+* Legacy network support
+
+TENNISON requires multiple components to function correctly. Below shows an
+overview of the system architecture.
+
+![Tennison Logo](imgs/tennison_overview.png)
+
+Please contact Lyndon at l.fawcett1@lancaster.ac.uk about any questions on TENNISON.
+
+# License
+Gaffer is licensed under the Apache 2 license and is covered by [Crown Copyright](https://www.nationalarchives.gov.uk/information-management/re-using-public-sector-information/copyright-and-re-use/crown-copyright/).
+
+
+# Getting started
+**Details on getting started with TENNISON are available in docs/developer_guide.pdf**
+
+---------------
+This repository is laid out as follows:
+
+#### _coordinator/_
+This is the primary component of TENNISON and is where the policy engine is
+located and is what decides what should happen to traffic. For extensibility it
+has southbound and northbound interfaces.
+The *southbound interfaces* are responsible for collecting a range of information
+from networks and hosts. The *northbound interface* provides users/developers
+with the ability to create their own security applications, providing TENNISON
+with rapid reaction capability.
+
+
+#### _onos-tennison-apps/_
+These applications interface with ONOS. They assist in montiroing and
+remediation, providing the primitives to interface with the network.
+
+#### _pig-relay/_
+This is a wrapper for snort that manages it, providing the coordinator with an
+ability to update rules and also a method of alerting the coordinator on attack
+detection.
+
+
+#### _onos-security-pipeline/_
+This is the lowest level component of the system and sits at ONOS's driver layer
+and is what realises the OpenFlow pipeline.
+It has been created so that security and monitoring rules can be injected before
+any forwarding is applied. This makes the system transparent at the control
+plane meaning that it can work with any routing implementation.
+
+#### _tools/_
+This directory provides scripts to automate the testing and deployment of
+TENNISON, reducing the learning curve to working with TENNISON. Most of these
+are wrapped in the *"tennison_experimenter"*
+application.
diff --git a/coordinator/.gitignore b/coordinator/.gitignore
new file mode 100644
index 0000000..b93ed67
--- /dev/null
+++ b/coordinator/.gitignore
@@ -0,0 +1,4 @@
+*__pycache__
+*.log
+*.pyc
+*.out
diff --git a/coordinator/ChangeLog b/coordinator/ChangeLog
new file mode 100644
index 0000000..9af8899
--- /dev/null
+++ b/coordinator/ChangeLog
@@ -0,0 +1,68 @@
+483bd7c was Jamie Bird, 22 hours ago, message: Merged latest GUI
+a97f85f was Jamie Bird, 23 hours ago, message: Fixes to ipfix-portscan and ipfix-ddos
+3e586ec was Jamie Bird, 2 days ago, message: Added DDoS snort threshold
+d655e49 was Jamie Bird, 3 days ago, message: Variable/selective treatment fields.
+15e3427 was Jamie Bird, 3 days ago, message: Logging and config added to NBI
+cf6608b was Jamie Bird, 3 days ago, message: Add pkt field back to snort alerts
+2d694c7 was Jamie Bird, 7 days ago, message: Merge branch 'master' of d31-git.lancaster.ac.uk:mervyn/mervyn
+2ab9f00 was Jamie Bird, 7 days ago, message: 'Resolved' GUI permisson issue.
+b14aa56 was Lyndon, 8 days ago, message: Added IPFIX threshold for 20 -> 5 which mirrors to snort. Snort treatment will then block the flow if intrusion detected
+e889c6e was Jamie Bird, 8 days ago, message: Added gui src
+989f640 was Jamie Bird, 8 days ago, message: Merge branch 'master' of d31-git.lancaster.ac.uk:mervyn/mervyn
+b340990 was Jamie Bird, 8 days ago, message: Gracefull exiting of apps.
+7d137d6 was Lyndon, 8 days ago, message: Removed old TODO messages
+312f882 was Jamie Bird, 9 days ago, message: Added pip requirements.
+d4544b6 was Jamie Bird, 9 days ago, message: Integration of northbound apps. Including the GUI which is hosted.
+bc99918 was Jamie Bird, 10 days ago, message: Refactored snort thresholds to match on alertmsg not the rule. Coord no longer in charge of installing rules.
+7d442d7 was Jamie Bird, 11 days ago, message: Removed excessive printing
+c5c87a4 was Jamie Bird, 11 days ago, message: Extract pkt info from snort alerts to be used as treatment fields. Optional treatment_fields now specified in thresholds.
+b9f38fd was Jamie Bird, 2 weeks ago, message: Default applications loaded and started with mervyn.
+aad4d56 was Jamie Bird, 2 weeks ago, message: Started work on application management in the NBI
+cb1f32e was Jamie Bird, 2 weeks ago, message: Added Access-Control-Allow-Origin for gui
+8fa3dfc was Jamie Bird, 3 weeks ago, message: Fixed protocolIdentifier for sflow
+7448b57 was Jamie Bird, 3 weeks ago, message: Added snort/query to NBI for RT alerts
+c7e8495 was Jamie Bird, 3 weeks ago, message: Implemented avg_bps and avg_pps ipfix metrics
+9995083 was Jamie Bird, 3 weeks ago, message: yaml syntax fix
+73a3fa2 was Jamie Bird, 3 weeks ago, message: Save working version of thresholds to yaml to be reloaded in on restart
+1e6d658 was Jamie Bird, 3 weeks ago, message: Thresholds allow IP ranges for easier white/black list definitinos.
+e51ef4d was Jamie Bird, 4 weeks ago, message: Alternative fix for uint64 issue
+c51a2eb was Andrew Wright, 4 weeks ago, message: MongoDB 8-Byte issue
+7826062 was Andrew Wright, 4 weeks ago, message: Merge branch 'master' of d31-git.lancaster.ac.uk:mervyn/mervyn
+4927b52 was Andrew Wright, 4 weeks ago, message: Update for sFlow message handling format
+7bb7ca9 was Jamie Bird, 4 weeks ago, message: Removed sflow TODOs
+c659100 was Jamie Bird, 4 weeks ago, message: Merge branch 'master' of d31-git.lancaster.ac.uk:mervyn/mervyn
+a41d337 was Jamie Bird, 4 weeks ago, message: ipfix now a treatment. Fix ipfix to onos url protocolIdentifier translation
+a31be1d was Andrew Wright, 4 weeks ago, message: Updates for sFlow alert handling
+67e5ee9 was Andrew Wright, 4 weeks ago, message: Updates for sFlow alert handling
+ebe5439 was Jamie Bird, 4 weeks ago, message: IPFIX times now in ISO 8601
+a9de72f was Jamie Bird, 5 weeks ago, message: IPFIX thresholds complete
+29f1082 was Jamie Bird, 5 weeks ago, message: IPFIX(interfix) now periodic
+3e5590b was Jamie Bird, 6 weeks ago, message: Get switch dpid from ipfix messages
+2d4ce3d was Jamie Bird, 6 weeks ago, message: Coord NBI version 1 tested
+a76ac42 was Jamie Bird, 6 weeks ago, message: Update thresholds done. Remove thresholds done. Better return codes.
+29c72a8 was Jamie Bird, 6 weeks ago, message: IPFIX and snort thresholds now fully dynamic via NBI with required values check
+3b1b3f4 was Jamie Bird, 6 weeks ago, message: Snort query done. Threshold query done. Started work on threshold modification.
+5b3085b was Jamie Bird, 7 weeks ago, message: IPFIX query now timely on a per app basis
+b9e0159 was Jamie Bird, 7 weeks ago, message: Fixed Mac address serialisation in collectors
+e41c3dd was Jamie Bird, 7 weeks ago, message: NBI basics for IPFIX
+e730a74 was Andrew Wright, 7 weeks ago, message: Indentation fixes
+612bde3 was Jamie Bird, 7 weeks ago, message: Started coord NBI outline
+29af1b8 was Jamie Bird, 7 weeks ago, message: Timeouts and connection refused catches added to REST calls to avoid full coord crash.
+f33a8ce was Jamie Bird, 7 weeks ago, message: Alert path fix (temp)
+d69f3ea was Jamie Bird, 8 weeks ago, message: Merge
+ac9a6e8 was Jamie Bird, 8 weeks ago, message: Coord now report to multiple snort instances. Defined in config.yaml
+8e65cb1 was Jamie Bird, 8 weeks ago, message: Started work on snort management
+f55be78 was Jamie Bird, 8 weeks ago, message: Clear existing snort instances from onos on start up. TODO: Configure multiple snort instances in onos from config file
+6f2d439 was Jamie Bird, 9 weeks ago, message: Further TODOs
+5a9ce1a was Lyndon, 4 months ago, message: Added todo notes for integrating sFlowRT into decision making
+88ced10 was Lyndon, 4 months ago, message: Updated readme with collector changes
+3c9aa3c was Lyndon, 4 months ago, message: sFlowRT messages now pushed to ZeroMQ
+2a10ac3 was Lyndon, 4 months ago, message: Created new collector for sFlowRT alerts.
+f63653f was Lyndon John Fawcett, 9 weeks ago, message: Updated todo list
+1775a82 was Bryce Anderson-Cooper, 8 months ago, message: Updated README
+f7c9241 was Bryce Anderson-Cooper, 9 months ago, message: Fixed truffle HTTP POST message
+d6896b3 was Bryce Anderson-Cooper, 9 months ago, message: Fixed dictionary and string comparison
+2630e2f was Bryce Anderson-Cooper, 9 months ago, message: Fixed pyobj parsing and changed listening IP
+785f201 was Bryce Anderson-Cooper, 9 months ago, message: Fixed Snort Rule parsing
+21c0e37 was Bryce Anderson-Cooper, 9 months ago, message: Updated config and thresholds
+dd730f7 was Bryce Anderson-Cooper, 9 months ago, message: Updated Readme
diff --git a/coordinator/README.md b/coordinator/README.md
new file mode 100644
index 0000000..4940db2
--- /dev/null
+++ b/coordinator/README.md
@@ -0,0 +1,34 @@
+# Coordinator
+
+The TENNISON Coordinator is responsible for receiving messages from potentially multiple IPFIX and Snort exporters. It will collect then parse these messages, and determine appropriate courses of action. The action will be determined by the highest matching threshold in the thresholds.yaml file. This may include upgrading monitoring from lightweight-detection (IPFIX) to heavyweight-detection (Snort).
+
+## Architecture
+
+When initialised, tennison.py reads all the thresholds and asks rpc.py to send a list of all the Snort rules to add to pigrelay. tennison.py then starts up multiple collectors (collector.py) as daemons, with each collector only collecting one type of event (prefix, ipfix, interfix, snort, sFlowRT). These parse collected packets and place them into a distributed messaging queue (ZeroMQ). These messages are collected by tennison.py, to be passed on to messagehandler.py. At the same time a copy of the packet is sent to MongoDB. The message handler finds the highest matching threshold and sends the packet to treatment.py where the appropriate treatment from the threshold is picked. rpc.py sends a message on to the TENNISONAPI app with a request that matches the treatment.
+
+## Dependencies
+
+TENNISON Coordinator is built using Python 3.x. It uses a MongoDB database to store messages received from the collectors. This can be located remotely if necessary. Please see the sample configuration file (examples/config.yaml) for details on how to connect to a remote database.
+
+## Installation
+
+To run the coordinator, you will first need to install the necessary Python dependencies. These can be installed with:
+
+```pip3 install -r pip3.3requirements.txt```
+
+```pip install -r pip2.7requirements.txt```
+
+
+TODO add requirements for applications and bower.
+
+Install python3 python python3-pip python-pip npm bower
+
+## Running
+
+Once the dependencies are installed, run the coordinator with:
+
+```sudo python3 tennison.py```
+
+Alternatively, the coordinator can also be run with a different configuration file:
+
+```sudo python3 tennison.py --config=other_configuration_file.yaml```
diff --git a/coordinator/TODO.md b/coordinator/TODO.md
new file mode 100644
index 0000000..0c3770d
--- /dev/null
+++ b/coordinator/TODO.md
@@ -0,0 +1,5 @@
+– Implement the InterFIX periodic polling.
+
+- Add collector (and everything associated with that in coordinator) for sFlow.
+
+Also see FIXME and TODO comments in-line.
diff --git a/coordinator/app-requirements.txt b/coordinator/app-requirements.txt
new file mode 100644
index 0000000..93a9189
--- /dev/null
+++ b/coordinator/app-requirements.txt
@@ -0,0 +1,2 @@
+numpy==1.12.1
+pyflux==0.4.14
diff --git a/coordinator/apps/gui-legacy/README.md b/coordinator/apps/gui-legacy/README.md
new file mode 100644
index 0000000..a6dacbf
--- /dev/null
+++ b/coordinator/apps/gui-legacy/README.md
@@ -0,0 +1,40 @@
+
+# IPFix Monitor Interface
+
+### Main files
+###### Javascript polling & chart file : js/pollingbck.js
+###### Configuration file : js/ipfixConfig.js (contains app-name, ports..etc. Can be utilised more)
+###### Home Page : ipfix-flows.html
+
+
+Go to http://127.0.0.1:8080/ to see the GUI
+
+
+
+Use the disable graphs flag to stop graphs from loading (currently this is required as a bug in the graphs halts the system).
+`http://127.0.0.1:8080/?disable_graphs=true`
+
+#### Configuration:
+
+Go to ipfixConfig.json to configure the ip address of the machine running TENNISON before starting the GUI.
+
+
+#### Procedure:
+
+1. The system registers the APP name, and makes the first call for the existing thresholds to render the chart and information DIV elements.
+2. Once the DIV elements scaffolding is in place, the system polls for
+Threshold information from the NBI
+IPFix information from the NBI
+3. Once the information has arrived the system loops through the IPFix records to check if the record matches ALL fields of any thresholds in the threshold information given
+For each FULL fields match ascertained there is a further check to see if the IPfix record has been plotted already, and to ascertain a consistent source of information (ONLY accept IPFix records from one switch)
+4. The system then takes the most recent stored information from the last plot to calculate the period's throughput (currentOctetCount-previousOctetCount)/(currentRecordTime-previousRecordTime)
+5. Once this has been ascertained the flow information is stored in an array which keeps historical ipfix octetCount and flowEndMilliSecond time (or another timeframe depending on the ipfix subtype).
+6. Depending on what record subtype it is (ipfix,prefix,interfix) the system will put the data needed in the array for plotting data.
+- For a prefix record, the system plots 2 points : the flowStart time with 0 throughput as the first record, and the flowEnd time with the calculated throughput. This is so that the chart is seen staring from zero on the chart at the time of the flow starting.
+- For an interfix record it plots just one point, which has the current flowEnd time with the calculated throughput.
+- For an ipfix record, it plots 2 points : The current flowEnd time with the calculated throughput, and the CURRENT TIME with 0 throughput. This shows as the end of the flow on the chart.
+7. At the same time the current threshold value is collected and put into a array which will be fed to the same chart for the corresponding ipfix records to be plotted.
+8. The chart for the threshold being looped is then plotted and the the process (from point 3. ) is repeated until all records have been checked.
+
+The colours are selected randomly using a random colour generator, but the colour for a flow after generated is kept throughout the lifetime of a flow, even if it's started and stopped, unless the page is refreshed.
+
diff --git a/coordinator/apps/gui-legacy/app-management.html b/coordinator/apps/gui-legacy/app-management.html
new file mode 100644
index 0000000..82bd03e
--- /dev/null
+++ b/coordinator/apps/gui-legacy/app-management.html
@@ -0,0 +1,110 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ IPFIX Monitor
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/coordinator/apps/gui-legacy/config.json b/coordinator/apps/gui-legacy/config.json
new file mode 100644
index 0000000..a6fe7dc
--- /dev/null
+++ b/coordinator/apps/gui-legacy/config.json
@@ -0,0 +1,3 @@
+{
+ "default_app" : false
+}
diff --git a/coordinator/apps/gui-legacy/dist/css/sb-admin-2.css b/coordinator/apps/gui-legacy/dist/css/sb-admin-2.css
new file mode 100644
index 0000000..b8e1bdf
--- /dev/null
+++ b/coordinator/apps/gui-legacy/dist/css/sb-admin-2.css
@@ -0,0 +1,434 @@
+/*!
+ * Start Bootstrap - SB Admin 2 v3.3.7+1 (http://startbootstrap.com/template-overviews/sb-admin-2)
+ * Copyright 2013-2016 Start Bootstrap
+ * Licensed under MIT (https://github.com/BlackrockDigital/startbootstrap/blob/gh-pages/LICENSE)
+ */
+body {
+ background-color: #f8f8f8;
+}
+#wrapper {
+ width: 100%;
+}
+#page-wrapper {
+ padding: 0 15px;
+ min-height: 568px;
+ background-color: white;
+}
+@media (min-width: 768px) {
+ #page-wrapper {
+ position: inherit;
+ margin: 0 0 0 0px;
+ padding: 0 30px;
+ border-left: 1px solid #e7e7e7;
+ }
+}
+.navbar-top-links {
+ margin-right: 0;
+}
+.navbar-top-links li {
+ display: inline-block;
+}
+.navbar-top-links li:last-child {
+ margin-right: 15px;
+}
+.navbar-top-links li a {
+ padding: 15px;
+ min-height: 50px;
+}
+.navbar-top-links .dropdown-menu li {
+ display: block;
+}
+.navbar-top-links .dropdown-menu li:last-child {
+ margin-right: 0;
+}
+.navbar-top-links .dropdown-menu li a {
+ padding: 3px 20px;
+ min-height: 0;
+}
+.navbar-top-links .dropdown-menu li a div {
+ white-space: normal;
+}
+.navbar-top-links .dropdown-messages,
+.navbar-top-links .dropdown-tasks,
+.navbar-top-links .dropdown-alerts {
+ width: 310px;
+ min-width: 0;
+}
+.navbar-top-links .dropdown-messages {
+ margin-left: 5px;
+}
+.navbar-top-links .dropdown-tasks {
+ margin-left: -59px;
+}
+.navbar-top-links .dropdown-alerts {
+ margin-left: -123px;
+}
+.navbar-top-links .dropdown-user {
+ right: 0;
+ left: auto;
+}
+.sidebar .sidebar-nav.navbar-collapse {
+ padding-left: 0;
+ padding-right: 0;
+}
+.sidebar .sidebar-search {
+ padding: 15px;
+}
+.sidebar ul li {
+ border-bottom: 1px solid #e7e7e7;
+}
+.sidebar ul li a.active {
+ background-color: #eeeeee;
+}
+.sidebar .arrow {
+ float: right;
+}
+.sidebar .fa.arrow:before {
+ content: "\f104";
+}
+.sidebar .active > a > .fa.arrow:before {
+ content: "\f107";
+}
+.sidebar .nav-second-level li,
+.sidebar .nav-third-level li {
+ border-bottom: none !important;
+}
+.sidebar .nav-second-level li a {
+ padding-left: 37px;
+}
+.sidebar .nav-third-level li a {
+ padding-left: 52px;
+}
+@media (min-width: 768px) {
+ .sidebar {
+ z-index: 1;
+ position: absolute;
+ width: 250px;
+ margin-top: 51px;
+ }
+ .navbar-top-links .dropdown-messages,
+ .navbar-top-links .dropdown-tasks,
+ .navbar-top-links .dropdown-alerts {
+ margin-left: auto;
+ }
+}
+.btn-outline {
+ color: inherit;
+ background-color: transparent;
+ transition: all .5s;
+}
+.btn-primary.btn-outline {
+ color: #428bca;
+}
+.btn-success.btn-outline {
+ color: #5cb85c;
+}
+.btn-info.btn-outline {
+ color: #5bc0de;
+}
+.btn-warning.btn-outline {
+ color: #f0ad4e;
+}
+.btn-danger.btn-outline {
+ color: #d9534f;
+}
+.btn-primary.btn-outline:hover,
+.btn-success.btn-outline:hover,
+.btn-info.btn-outline:hover,
+.btn-warning.btn-outline:hover,
+.btn-danger.btn-outline:hover {
+ color: white;
+}
+.chat {
+ margin: 0;
+ padding: 0;
+ list-style: none;
+}
+.chat li {
+ margin-bottom: 10px;
+ padding-bottom: 5px;
+ border-bottom: 1px dotted #999999;
+}
+.chat li.left .chat-body {
+ margin-left: 60px;
+}
+.chat li.right .chat-body {
+ margin-right: 60px;
+}
+.chat li .chat-body p {
+ margin: 0;
+}
+.panel .slidedown .glyphicon,
+.chat .glyphicon {
+ margin-right: 5px;
+}
+.chat-panel .panel-body {
+ height: 350px;
+ overflow-y: scroll;
+}
+.login-panel {
+ margin-top: 25%;
+}
+.flot-chart {
+ display: block;
+ height: 400px;
+}
+.flot-chart-content {
+ width: 100%;
+ height: 100%;
+}
+table.dataTable thead .sorting,
+table.dataTable thead .sorting_asc,
+table.dataTable thead .sorting_desc,
+table.dataTable thead .sorting_asc_disabled,
+table.dataTable thead .sorting_desc_disabled {
+ background: transparent;
+}
+table.dataTable thead .sorting_asc:after {
+ content: "\f0de";
+ float: right;
+ font-family: fontawesome;
+}
+table.dataTable thead .sorting_desc:after {
+ content: "\f0dd";
+ float: right;
+ font-family: fontawesome;
+}
+table.dataTable thead .sorting:after {
+ content: "\f0dc";
+ float: right;
+ font-family: fontawesome;
+ color: rgba(50, 50, 50, 0.5);
+}
+.btn-circle {
+ width: 30px;
+ height: 30px;
+ padding: 6px 0;
+ border-radius: 15px;
+ text-align: center;
+ font-size: 12px;
+ line-height: 1.428571429;
+}
+.btn-circle.btn-lg {
+ width: 50px;
+ height: 50px;
+ padding: 10px 16px;
+ border-radius: 25px;
+ font-size: 18px;
+ line-height: 1.33;
+}
+.btn-circle.btn-xl {
+ width: 70px;
+ height: 70px;
+ padding: 10px 16px;
+ border-radius: 35px;
+ font-size: 24px;
+ line-height: 1.33;
+}
+.show-grid [class^="col-"] {
+ padding-top: 10px;
+ padding-bottom: 10px;
+ border: 1px solid #ddd;
+ background-color: #eee !important;
+}
+.show-grid {
+ margin: 15px 0;
+}
+.huge {
+ font-size: 40px;
+}
+.panel-green {
+ border-color: #5cb85c;
+}
+.panel-green > .panel-heading {
+ border-color: #5cb85c;
+ color: white;
+ background-color: #5cb85c;
+}
+.panel-green > a {
+ color: #5cb85c;
+}
+.panel-green > a:hover {
+ color: #3d8b3d;
+}
+.panel-red {
+ border-color: #d9534f;
+}
+.panel-red > .panel-heading {
+ border-color: #d9534f;
+ color: white;
+ background-color: #d9534f;
+}
+.panel-red > a {
+ color: #d9534f;
+}
+.panel-red > a:hover {
+ color: #b52b27;
+}
+.panel-yellow {
+ border-color: #f0ad4e;
+}
+.panel-yellow > .panel-heading {
+ border-color: #f0ad4e;
+ color: white;
+ background-color: #f0ad4e;
+}
+.panel-yellow > a {
+ color: #f0ad4e;
+}
+.panel-yellow > a:hover {
+ color: #df8a13;
+}
+.timeline {
+ position: relative;
+ padding: 20px 0 20px;
+ list-style: none;
+}
+.timeline:before {
+ content: " ";
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ left: 50%;
+ width: 3px;
+ margin-left: -1.5px;
+ background-color: #eeeeee;
+}
+.timeline > li {
+ position: relative;
+ margin-bottom: 20px;
+}
+.timeline > li:before,
+.timeline > li:after {
+ content: " ";
+ display: table;
+}
+.timeline > li:after {
+ clear: both;
+}
+.timeline > li:before,
+.timeline > li:after {
+ content: " ";
+ display: table;
+}
+.timeline > li:after {
+ clear: both;
+}
+.timeline > li > .timeline-panel {
+ float: left;
+ position: relative;
+ width: 46%;
+ padding: 20px;
+ border: 1px solid #d4d4d4;
+ border-radius: 2px;
+ -webkit-box-shadow: 0 1px 6px rgba(0, 0, 0, 0.175);
+ box-shadow: 0 1px 6px rgba(0, 0, 0, 0.175);
+}
+.timeline > li > .timeline-panel:before {
+ content: " ";
+ display: inline-block;
+ position: absolute;
+ top: 26px;
+ right: -15px;
+ border-top: 15px solid transparent;
+ border-right: 0 solid #ccc;
+ border-bottom: 15px solid transparent;
+ border-left: 15px solid #ccc;
+}
+.timeline > li > .timeline-panel:after {
+ content: " ";
+ display: inline-block;
+ position: absolute;
+ top: 27px;
+ right: -14px;
+ border-top: 14px solid transparent;
+ border-right: 0 solid #fff;
+ border-bottom: 14px solid transparent;
+ border-left: 14px solid #fff;
+}
+.timeline > li > .timeline-badge {
+ z-index: 100;
+ position: absolute;
+ top: 16px;
+ left: 50%;
+ width: 50px;
+ height: 50px;
+ margin-left: -25px;
+ border-radius: 50% 50% 50% 50%;
+ text-align: center;
+ font-size: 1.4em;
+ line-height: 50px;
+ color: #fff;
+ background-color: #999999;
+}
+.timeline > li.timeline-inverted > .timeline-panel {
+ float: right;
+}
+.timeline > li.timeline-inverted > .timeline-panel:before {
+ right: auto;
+ left: -15px;
+ border-right-width: 15px;
+ border-left-width: 0;
+}
+.timeline > li.timeline-inverted > .timeline-panel:after {
+ right: auto;
+ left: -14px;
+ border-right-width: 14px;
+ border-left-width: 0;
+}
+.timeline-badge.primary {
+ background-color: #2e6da4 !important;
+}
+.timeline-badge.success {
+ background-color: #3f903f !important;
+}
+.timeline-badge.warning {
+ background-color: #f0ad4e !important;
+}
+.timeline-badge.danger {
+ background-color: #d9534f !important;
+}
+.timeline-badge.info {
+ background-color: #5bc0de !important;
+}
+.timeline-title {
+ margin-top: 0;
+ color: inherit;
+}
+.timeline-body > p,
+.timeline-body > ul {
+ margin-bottom: 0;
+}
+.timeline-body > p + p {
+ margin-top: 5px;
+}
+@media (max-width: 767px) {
+ ul.timeline:before {
+ left: 40px;
+ }
+ ul.timeline > li > .timeline-panel {
+ width: calc(10%);
+ width: -moz-calc(10%);
+ width: -webkit-calc(10%);
+ }
+ ul.timeline > li > .timeline-badge {
+ top: 16px;
+ left: 15px;
+ margin-left: 0;
+ }
+ ul.timeline > li > .timeline-panel {
+ float: right;
+ }
+ ul.timeline > li > .timeline-panel:before {
+ right: auto;
+ left: -15px;
+ border-right-width: 15px;
+ border-left-width: 0;
+ }
+ ul.timeline > li > .timeline-panel:after {
+ right: auto;
+ left: -14px;
+ border-right-width: 14px;
+ border-left-width: 0;
+ }
+}
diff --git a/coordinator/apps/gui-legacy/dist/css/sb-admin-2.min.css b/coordinator/apps/gui-legacy/dist/css/sb-admin-2.min.css
new file mode 100644
index 0000000..a685970
--- /dev/null
+++ b/coordinator/apps/gui-legacy/dist/css/sb-admin-2.min.css
@@ -0,0 +1,5 @@
+/*!
+ * Start Bootstrap - SB Admin 2 v3.3.7+1 (http://startbootstrap.com/template-overviews/sb-admin-2)
+ * Copyright 2013-2016 Start Bootstrap
+ * Licensed under MIT (https://github.com/BlackrockDigital/startbootstrap/blob/gh-pages/LICENSE)
+ */.chat,.timeline{list-style:none}body{background-color:#f8f8f8}#wrapper{width:100%}#page-wrapper{padding:0 15px;min-height:568px;background-color:#fff}@media (min-width:768px){#page-wrapper{position:inherit;margin:0 0 0 250px;padding:0 30px;border-left:1px solid #e7e7e7}}.navbar-top-links{margin-right:0}.navbar-top-links li{display:inline-block}.flot-chart,.navbar-top-links .dropdown-menu li{display:block}.navbar-top-links li:last-child{margin-right:15px}.navbar-top-links li a{padding:15px;min-height:50px}.navbar-top-links .dropdown-menu li:last-child{margin-right:0}.navbar-top-links .dropdown-menu li a{padding:3px 20px;min-height:0}.navbar-top-links .dropdown-menu li a div{white-space:normal}.navbar-top-links .dropdown-alerts,.navbar-top-links .dropdown-messages,.navbar-top-links .dropdown-tasks{width:310px;min-width:0}.navbar-top-links .dropdown-messages{margin-left:5px}.navbar-top-links .dropdown-tasks{margin-left:-59px}.navbar-top-links .dropdown-alerts{margin-left:-123px}.navbar-top-links .dropdown-user{right:0;left:auto}.sidebar .sidebar-nav.navbar-collapse{padding-left:0;padding-right:0}.sidebar .sidebar-search{padding:15px}.sidebar ul li{border-bottom:1px solid #e7e7e7}.sidebar ul li a.active{background-color:#eee}.sidebar .arrow{float:right}.sidebar .fa.arrow:before{content:"\f104"}.sidebar .active>a>.fa.arrow:before{content:"\f107"}.sidebar .nav-second-level li,.sidebar .nav-third-level li{border-bottom:none!important}.sidebar .nav-second-level li a{padding-left:37px}.sidebar .nav-third-level li a{padding-left:52px}@media (min-width:768px){.sidebar{z-index:1;position:absolute;width:250px;margin-top:51px}.navbar-top-links .dropdown-alerts,.navbar-top-links .dropdown-messages,.navbar-top-links .dropdown-tasks{margin-left:auto}}.btn-outline{color:inherit;background-color:transparent;transition:all .5s}.btn-primary.btn-outline{color:#428bca}.btn-success.btn-outline{color:#5cb85c}.btn-info.btn-outline{color:#5bc0de}.btn-warning.btn-outline{color:#f0ad4e}.btn-danger.btn-outline{color:#d9534f}.btn-danger.btn-outline:hover,.btn-info.btn-outline:hover,.btn-primary.btn-outline:hover,.btn-success.btn-outline:hover,.btn-warning.btn-outline:hover{color:#fff}.chat{margin:0;padding:0}.chat li{margin-bottom:10px;padding-bottom:5px;border-bottom:1px dotted #999}.chat li.left .chat-body{margin-left:60px}.chat li.right .chat-body{margin-right:60px}.chat li .chat-body p{margin:0}.chat .glyphicon,.panel .slidedown .glyphicon{margin-right:5px}.chat-panel .panel-body{height:350px;overflow-y:scroll}.login-panel{margin-top:25%}.flot-chart{height:400px}.flot-chart-content{width:100%;height:100%}table.dataTable thead .sorting,table.dataTable thead .sorting_asc,table.dataTable thead .sorting_asc_disabled,table.dataTable thead .sorting_desc,table.dataTable thead .sorting_desc_disabled{background:0 0}table.dataTable thead .sorting_asc:after{content:"\f0de";float:right;font-family:fontawesome}table.dataTable thead .sorting_desc:after{content:"\f0dd";float:right;font-family:fontawesome}table.dataTable thead .sorting:after{content:"\f0dc";float:right;font-family:fontawesome;color:rgba(50,50,50,.5)}.btn-circle{width:30px;height:30px;padding:6px 0;border-radius:15px;text-align:center;font-size:12px;line-height:1.428571429}.btn-circle.btn-lg{width:50px;height:50px;padding:10px 16px;border-radius:25px;font-size:18px;line-height:1.33}.btn-circle.btn-xl{width:70px;height:70px;padding:10px 16px;border-radius:35px;font-size:24px;line-height:1.33}.show-grid [class^=col-]{padding-top:10px;padding-bottom:10px;border:1px solid #ddd;background-color:#eee!important}.show-grid{margin:15px 0}.huge{font-size:40px}.panel-green{border-color:#5cb85c}.panel-green>.panel-heading{border-color:#5cb85c;color:#fff;background-color:#5cb85c}.panel-green>a{color:#5cb85c}.panel-green>a:hover{color:#3d8b3d}.panel-red{border-color:#d9534f}.panel-red>.panel-heading{border-color:#d9534f;color:#fff;background-color:#d9534f}.panel-red>a{color:#d9534f}.panel-red>a:hover{color:#b52b27}.panel-yellow{border-color:#f0ad4e}.panel-yellow>.panel-heading{border-color:#f0ad4e;color:#fff;background-color:#f0ad4e}.panel-yellow>a{color:#f0ad4e}.panel-yellow>a:hover{color:#df8a13}.timeline{position:relative;padding:20px 0}.timeline:before{content:" ";position:absolute;top:0;bottom:0;left:50%;width:3px;margin-left:-1.5px;background-color:#eee}.timeline>li{position:relative;margin-bottom:20px}.timeline>li:after,.timeline>li:before{content:" ";display:table}.timeline>li:after{clear:both}.timeline>li>.timeline-panel{float:left;position:relative;width:46%;padding:20px;border:1px solid #d4d4d4;border-radius:2px;-webkit-box-shadow:0 1px 6px rgba(0,0,0,.175);box-shadow:0 1px 6px rgba(0,0,0,.175)}.timeline>li>.timeline-panel:before{content:" ";display:inline-block;position:absolute;top:26px;right:-15px;border-top:15px solid transparent;border-right:0 solid #ccc;border-bottom:15px solid transparent;border-left:15px solid #ccc}.timeline>li>.timeline-panel:after{content:" ";display:inline-block;position:absolute;top:27px;right:-14px;border-top:14px solid transparent;border-right:0 solid #fff;border-bottom:14px solid transparent;border-left:14px solid #fff}.timeline>li>.timeline-badge{z-index:100;position:absolute;top:16px;left:50%;width:50px;height:50px;margin-left:-25px;border-radius:50%;text-align:center;font-size:1.4em;line-height:50px;color:#fff;background-color:#999}.timeline>li.timeline-inverted>.timeline-panel{float:right}.timeline>li.timeline-inverted>.timeline-panel:before{right:auto;left:-15px;border-right-width:15px;border-left-width:0}.timeline>li.timeline-inverted>.timeline-panel:after{right:auto;left:-14px;border-right-width:14px;border-left-width:0}.timeline-badge.primary{background-color:#2e6da4!important}.timeline-badge.success{background-color:#3f903f!important}.timeline-badge.warning{background-color:#f0ad4e!important}.timeline-badge.danger{background-color:#d9534f!important}.timeline-badge.info{background-color:#5bc0de!important}.timeline-title{margin-top:0;color:inherit}.timeline-body>p,.timeline-body>ul{margin-bottom:0}.timeline-body>p+p{margin-top:5px}@media (max-width:767px){ul.timeline:before{left:40px}ul.timeline>li>.timeline-panel{width:calc(10%);width:-moz-calc(10%);width:-webkit-calc(10%);float:right}ul.timeline>li>.timeline-badge{top:16px;left:15px;margin-left:0}ul.timeline>li>.timeline-panel:before{right:auto;left:-15px;border-right-width:15px;border-left-width:0}ul.timeline>li>.timeline-panel:after{right:auto;left:-14px;border-right-width:14px;border-left-width:0}}
\ No newline at end of file
diff --git a/coordinator/apps/gui-legacy/dist/js/sb-admin-2.js b/coordinator/apps/gui-legacy/dist/js/sb-admin-2.js
new file mode 100644
index 0000000..24b26ce
--- /dev/null
+++ b/coordinator/apps/gui-legacy/dist/js/sb-admin-2.js
@@ -0,0 +1,47 @@
+/*!
+ * Start Bootstrap - SB Admin 2 v3.3.7+1 (http://startbootstrap.com/template-overviews/sb-admin-2)
+ * Copyright 2013-2016 Start Bootstrap
+ * Licensed under MIT (https://github.com/BlackrockDigital/startbootstrap/blob/gh-pages/LICENSE)
+ */
+$(function() {
+ $('#side-menu').metisMenu();
+});
+
+//Loads the correct sidebar on window load,
+//collapses the sidebar on window resize.
+// Sets the min-height of #page-wrapper to window size
+$(function() {
+ $(window).bind("load resize", function() {
+ var topOffset = 50;
+ var width = (this.window.innerWidth > 0) ? this.window.innerWidth : this.screen.width;
+ if (width < 768) {
+ $('div.navbar-collapse').addClass('collapse');
+ topOffset = 100; // 2-row-menu
+ } else {
+ $('div.navbar-collapse').removeClass('collapse');
+ }
+
+ var height = ((this.window.innerHeight > 0) ? this.window.innerHeight : this.screen.height) - 1;
+ height = height - topOffset;
+ if (height < 1) height = 1;
+ if (height > topOffset) {
+ $("#page-wrapper").css("min-height", (height) + "px");
+ }
+ });
+
+ var url = window.location;
+ // var element = $('ul.nav a').filter(function() {
+ // return this.href == url;
+ // }).addClass('active').parent().parent().addClass('in').parent();
+ var element = $('ul.nav a').filter(function() {
+ return this.href == url;
+ }).addClass('active').parent();
+
+ while (true) {
+ if (element.is('li')) {
+ element = element.parent().addClass('in').parent();
+ } else {
+ break;
+ }
+ }
+});
diff --git a/coordinator/apps/gui-legacy/dist/js/sb-admin-2.min.js b/coordinator/apps/gui-legacy/dist/js/sb-admin-2.min.js
new file mode 100644
index 0000000..892ea1e
--- /dev/null
+++ b/coordinator/apps/gui-legacy/dist/js/sb-admin-2.min.js
@@ -0,0 +1,6 @@
+/*!
+ * Start Bootstrap - SB Admin 2 v3.3.7+1 (http://startbootstrap.com/template-overviews/sb-admin-2)
+ * Copyright 2013-2016 Start Bootstrap
+ * Licensed under MIT (https://github.com/BlackrockDigital/startbootstrap/blob/gh-pages/LICENSE)
+ */
+$(function(){$("#side-menu").metisMenu()}),$(function(){$(window).bind("load resize",function(){var i=50,n=this.window.innerWidth>0?this.window.innerWidth:this.screen.width;n<768?($("div.navbar-collapse").addClass("collapse"),i=100):$("div.navbar-collapse").removeClass("collapse");var e=(this.window.innerHeight>0?this.window.innerHeight:this.screen.height)-1;e-=i,e<1&&(e=1),e>i&&$("#page-wrapper").css("min-height",e+"px")});for(var i=window.location,n=$("ul.nav a").filter(function(){return this.href==i}).addClass("active").parent();;){if(!n.is("li"))break;n=n.parent().addClass("in").parent()}});
\ No newline at end of file
diff --git a/coordinator/apps/gui-legacy/httpd.py b/coordinator/apps/gui-legacy/httpd.py
new file mode 100644
index 0000000..0aac014
--- /dev/null
+++ b/coordinator/apps/gui-legacy/httpd.py
@@ -0,0 +1,28 @@
+import SimpleHTTPServer
+import SocketServer
+import os
+import signal
+import sys
+import socket
+import time
+
+PORT = 80
+
+os.chdir(os.path.dirname(os.path.realpath(__file__)))
+
+Handler = SimpleHTTPServer.SimpleHTTPRequestHandler
+
+SocketServer.TCPServer.allow_reuse_address = True
+httpd = SocketServer.TCPServer(("", PORT), Handler)
+
+def close(signum, frame):
+ print("Stopping httpd")
+ httpd.server_close()
+ sys.exit(0)
+
+signal.signal(signal.SIGINT, close)
+signal.signal(signal.SIGTERM, close)
+
+print("Starting httpd")
+
+httpd.serve_forever()
diff --git a/coordinator/apps/gui-legacy/index.html b/coordinator/apps/gui-legacy/index.html
new file mode 100644
index 0000000..e12dc08
--- /dev/null
+++ b/coordinator/apps/gui-legacy/index.html
@@ -0,0 +1,212 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ TENNISON Coordinator
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/coordinator/apps/gui-legacy/ipfix-flows.html b/coordinator/apps/gui-legacy/ipfix-flows.html
new file mode 100644
index 0000000..a5796b2
--- /dev/null
+++ b/coordinator/apps/gui-legacy/ipfix-flows.html
@@ -0,0 +1,134 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ IPFIX Monitor
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ IPFIX Charts
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Charts
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/coordinator/apps/gui-legacy/js/apps.js b/coordinator/apps/gui-legacy/js/apps.js
new file mode 100644
index 0000000..71c6ae0
--- /dev/null
+++ b/coordinator/apps/gui-legacy/js/apps.js
@@ -0,0 +1,117 @@
+ //port used on which either the app is found OR on which the port forwarding is done
+ var port = ipfixConfig.port;
+ var addr = ipfixConfig.addr;
+
+ $(function() {
+ getApps();
+ });
+
+ function getApps(){
+ $.getJSON("http://"+ addr +":" + port + "/tennison/app/query", function(data){
+
+ $("#app_panel").html('');
+ Object.keys(data).forEach(function(key) {
+ $("#app_panel").append(appDiv(key, data[key]))
+
+ if (data[key]['status'] != 'not_installed') {
+ getAppConfig(key);
+ getAppLog(key);
+ }
+ });
+
+ });
+ }
+
+ function updateApps(){
+ $.getJSON("http://"+ addr +":" + port + "/tennison/app/query", function(data){
+
+ Object.keys(data).forEach(function(key) {
+ updateAppView(key, data[key])
+
+ if (data[key]['status'] != 'not_installed') {
+ getAppConfig(key);
+ getAppLog(key);
+ }
+ });
+
+ });
+ }
+
+ function appDiv(key, data){
+
+ var btn = "";
+ if (data['status'] == 'active') {
+ btn = "Deactivate ";
+ } else if (data['status'] == 'not_active') {
+ btn = "Activate ";
+ } else {
+ btn = "Not installed ";
+ }
+
+ var div =
+ ""+
+ "
"+
+ "
"+
+ "
Status "+
+ JSON.stringify(data, null, 2)+
+ " "+
+ "
"+
+ "
"+
+ "
"+
+ "
";
+ return div;
+ }
+
+ function activateApp(app){
+ console.log("Starting app " + app);
+ $.post("http://" +addr+":" + port + "/tennison/app/start/" + app, function(data){
+ console.log(data);
+ updateApps();
+ });
+ }
+
+ function deactivateApp(app){
+ console.log("Stopping app " + app);
+ $.post("http://"+addr+":" + port + "/tennison/app/stop/" + app, function(data){
+ console.log(data);
+ updateApps();
+ });
+ }
+
+ function updateAppView(app, data){
+
+ // Update JSON
+ $('#status-'+app).html(JSON.stringify(data, null, 2));
+
+ // Update button
+ if (data['status'] == 'active') {
+ $('#activate-'+app).html('Deactivate');
+ $('#activate-'+app).removeClass('btn-success');
+ $('#activate-'+app).addClass('btn-danger');
+ $('#activate-'+app).attr('onclick', 'deactivateApp("'+app+'")');
+ } else if (data['status'] == 'not_active') {
+ $('#activate-'+app).html('Activate');
+ $('#activate-'+app).removeClass('btn-danger');
+ $('#activate-'+app).addClass('btn-success');
+ $('#activate-'+app).attr('onclick', 'activateApp("'+app+'")');
+ }
+ }
+
+ function getAppConfig(app){
+ $.getJSON("http://"+addr+":" + port + "/tennison/app/query/" + app + "/config", function(data){
+ $('#config-'+app).html(JSON.stringify(data, null, 2));
+ });
+ }
+
+ function getAppLog(app){
+ $.getJSON("http://"+addr+":" + port + "/tennison/app/query/" + app + "/log", function(data){
+ $('#log-'+app).html(data['log']);
+ });
+ }
diff --git a/coordinator/apps/gui-legacy/js/flot/jquery.flot.axislabels.js b/coordinator/apps/gui-legacy/js/flot/jquery.flot.axislabels.js
new file mode 100644
index 0000000..76ddb98
--- /dev/null
+++ b/coordinator/apps/gui-legacy/js/flot/jquery.flot.axislabels.js
@@ -0,0 +1,411 @@
+/*
+Axis Labels Plugin for flot.
+http://github.com/markrcote/flot-axislabels
+
+Original code is Copyright (c) 2010 Xuan Luo.
+Original code was released under the GPLv3 license by Xuan Luo, September 2010.
+Original code was rereleased under the MIT license by Xuan Luo, April 2012.
+
+Improvements by Mark Cote.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+*/
+(function ($) {
+ var options = {};
+
+ function canvasSupported() {
+ return !!document.createElement('canvas').getContext;
+ }
+
+ function canvasTextSupported() {
+ if (!canvasSupported()) {
+ return false;
+ }
+ var dummy_canvas = document.createElement('canvas');
+ var context = dummy_canvas.getContext('2d');
+ return typeof context.fillText == 'function';
+ }
+
+ function css3TransitionSupported() {
+ var div = document.createElement('div');
+ return typeof div.style.MozTransition != 'undefined' // Gecko
+ || typeof div.style.OTransition != 'undefined' // Opera
+ || typeof div.style.webkitTransition != 'undefined' // WebKit
+ || typeof div.style.transition != 'undefined';
+ }
+
+
+ function AxisLabel(axisName, position, padding, plot, opts) {
+ this.axisName = axisName;
+ this.position = position;
+ this.padding = padding;
+ this.plot = plot;
+ this.opts = opts;
+ this.width = 0;
+ this.height = 0;
+ }
+
+
+ CanvasAxisLabel.prototype = new AxisLabel();
+ CanvasAxisLabel.prototype.constructor = CanvasAxisLabel;
+ function CanvasAxisLabel(axisName, position, padding, plot, opts) {
+ AxisLabel.prototype.constructor.call(this, axisName, position, padding,
+ plot, opts);
+ }
+
+ CanvasAxisLabel.prototype.calculateSize = function () {
+ if (!this.opts.axisLabelFontSizePixels)
+ this.opts.axisLabelFontSizePixels = 14;
+ if (!this.opts.axisLabelFontFamily)
+ this.opts.axisLabelFontFamily = 'sans-serif';
+
+ var textWidth = this.opts.axisLabelFontSizePixels + this.padding;
+ var textHeight = this.opts.axisLabelFontSizePixels + this.padding;
+ if (this.position == 'left' || this.position == 'right') {
+ this.width = this.opts.axisLabelFontSizePixels + this.padding;
+ this.height = 0;
+ } else {
+ this.width = 0;
+ this.height = this.opts.axisLabelFontSizePixels + this.padding;
+ }
+ };
+
+ CanvasAxisLabel.prototype.draw = function (box) {
+ var ctx = this.plot.getCanvas().getContext('2d');
+ ctx.save();
+ ctx.font = this.opts.axisLabelFontSizePixels + 'px ' +
+ this.opts.axisLabelFontFamily;
+ var width = ctx.measureText(this.opts.axisLabel).width;
+ var height = this.opts.axisLabelFontSizePixels;
+ var x, y, angle = 0;
+ if (this.position == 'top') {
+ x = box.left + box.width / 2 - width / 2;
+ y = box.top + height * 0.72;
+ } else if (this.position == 'bottom') {
+ x = box.left + box.width / 2 - width / 2;
+ y = box.top + box.height - height * 0.72;
+ } else if (this.position == 'left') {
+ x = box.left + height * 0.72;
+ y = box.height / 2 + box.top + width / 2;
+ angle = -Math.PI / 2;
+ } else if (this.position == 'right') {
+ x = box.left + box.width - height * 0.72;
+ y = box.height / 2 + box.top - width / 2;
+ angle = Math.PI / 2;
+ }
+ ctx.translate(x, y);
+ ctx.rotate(angle);
+ ctx.fillText(this.opts.axisLabel, 0, 0);
+ ctx.restore();
+ };
+
+
+ HtmlAxisLabel.prototype = new AxisLabel();
+ HtmlAxisLabel.prototype.constructor = HtmlAxisLabel;
+ function HtmlAxisLabel(axisName, position, padding, plot, opts) {
+ AxisLabel.prototype.constructor.call(this, axisName, position,
+ padding, plot, opts);
+ }
+
+ HtmlAxisLabel.prototype.calculateSize = function () {
+ var elem = $('' +
+ this.opts.axisLabel + '
');
+ this.plot.getPlaceholder().append(elem);
+ // store height and width of label itself, for use in draw()
+ this.labelWidth = elem.outerWidth(true);
+ this.labelHeight = elem.outerHeight(true);
+ elem.remove();
+
+ this.width = this.height = 0;
+ if (this.position == 'left' || this.position == 'right') {
+ this.width = this.labelWidth + this.padding;
+ } else {
+ this.height = this.labelHeight + this.padding;
+ }
+ };
+
+ HtmlAxisLabel.prototype.draw = function (box) {
+ this.plot.getPlaceholder().find('#' + this.axisName + 'Label').remove();
+ var elem = $(''
+ + this.opts.axisLabel + '
');
+ this.plot.getPlaceholder().append(elem);
+ if (this.position == 'top') {
+ elem.css('left', box.left + box.width / 2 - this.labelWidth / 2 + 'px');
+ elem.css('top', box.top + 'px');
+ } else if (this.position == 'bottom') {
+ elem.css('left', box.left + box.width / 2 - this.labelWidth / 2 + 'px');
+ elem.css('top', box.top + box.height - this.labelHeight + 'px');
+ } else if (this.position == 'left') {
+ elem.css('top', box.top + box.height / 2 - this.labelHeight / 2 + 'px');
+ elem.css('left', box.left + 'px');
+ } else if (this.position == 'right') {
+ elem.css('top', box.top + box.height / 2 - this.labelHeight / 2 + 'px');
+ elem.css('left', box.left + box.width - this.labelWidth + 'px');
+ }
+ };
+
+
+ CssTransformAxisLabel.prototype = new HtmlAxisLabel();
+ CssTransformAxisLabel.prototype.constructor = CssTransformAxisLabel;
+ function CssTransformAxisLabel(axisName, position, padding, plot, opts) {
+ HtmlAxisLabel.prototype.constructor.call(this, axisName, position,
+ padding, plot, opts);
+ }
+
+ CssTransformAxisLabel.prototype.calculateSize = function () {
+ HtmlAxisLabel.prototype.calculateSize.call(this);
+ this.width = this.height = 0;
+ if (this.position == 'left' || this.position == 'right') {
+ this.width = this.labelHeight + this.padding;
+ } else {
+ this.height = this.labelHeight + this.padding;
+ }
+ };
+
+ CssTransformAxisLabel.prototype.transforms = function (degrees, x, y) {
+ var stransforms = {
+ '-moz-transform': '',
+ '-webkit-transform': '',
+ '-o-transform': '',
+ '-ms-transform': ''
+ };
+ if (x != 0 || y != 0) {
+ var stdTranslate = ' translate(' + x + 'px, ' + y + 'px)';
+ stransforms['-moz-transform'] += stdTranslate;
+ stransforms['-webkit-transform'] += stdTranslate;
+ stransforms['-o-transform'] += stdTranslate;
+ stransforms['-ms-transform'] += stdTranslate;
+ }
+ if (degrees != 0) {
+ var rotation = degrees / 90;
+ var stdRotate = ' rotate(' + degrees + 'deg)';
+ stransforms['-moz-transform'] += stdRotate;
+ stransforms['-webkit-transform'] += stdRotate;
+ stransforms['-o-transform'] += stdRotate;
+ stransforms['-ms-transform'] += stdRotate;
+ }
+ var s = 'top: 0; left: 0; ';
+ for (var prop in stransforms) {
+ if (stransforms[prop]) {
+ s += prop + ':' + stransforms[prop] + ';';
+ }
+ }
+ s += ';';
+ return s;
+ };
+
+ CssTransformAxisLabel.prototype.calculateOffsets = function (box) {
+ var offsets = { x: 0, y: 0, degrees: 0 };
+ if (this.position == 'bottom') {
+ offsets.x = box.left + box.width / 2 - this.labelWidth / 2;
+ offsets.y = box.top + box.height - this.labelHeight;
+ } else if (this.position == 'top') {
+ offsets.x = box.left + box.width / 2 - this.labelWidth / 2;
+ offsets.y = box.top;
+ } else if (this.position == 'left') {
+ offsets.degrees = -90;
+ offsets.x = box.left - this.labelWidth / 2 + this.labelHeight / 2;
+ offsets.y = box.height / 2 + box.top;
+ } else if (this.position == 'right') {
+ offsets.degrees = 90;
+ offsets.x = box.left + box.width - this.labelWidth / 2
+ - this.labelHeight / 2;
+ offsets.y = box.height / 2 + box.top;
+ }
+ return offsets;
+ };
+
+ CssTransformAxisLabel.prototype.draw = function (box) {
+ this.plot.getPlaceholder().find("." + this.axisName + "Label").remove();
+ var offsets = this.calculateOffsets(box);
+ var elem = $('' + this.opts.axisLabel + '
');
+ this.plot.getPlaceholder().append(elem);
+ };
+
+
+ IeTransformAxisLabel.prototype = new CssTransformAxisLabel();
+ IeTransformAxisLabel.prototype.constructor = IeTransformAxisLabel;
+ function IeTransformAxisLabel(axisName, position, padding, plot, opts) {
+ CssTransformAxisLabel.prototype.constructor.call(this, axisName,
+ position, padding,
+ plot, opts);
+ this.requiresResize = false;
+ }
+
+ IeTransformAxisLabel.prototype.transforms = function (degrees, x, y) {
+ // I didn't feel like learning the crazy Matrix stuff, so this uses
+ // a combination of the rotation transform and CSS positioning.
+ var s = '';
+ if (degrees != 0) {
+ var rotation = degrees / 90;
+ while (rotation < 0) {
+ rotation += 4;
+ }
+ s += ' filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=' + rotation + '); ';
+ // see below
+ this.requiresResize = (this.position == 'right');
+ }
+ if (x != 0) {
+ s += 'left: ' + x + 'px; ';
+ }
+ if (y != 0) {
+ s += 'top: ' + y + 'px; ';
+ }
+ return s;
+ };
+
+ IeTransformAxisLabel.prototype.calculateOffsets = function (box) {
+ var offsets = CssTransformAxisLabel.prototype.calculateOffsets.call(
+ this, box);
+ // adjust some values to take into account differences between
+ // CSS and IE rotations.
+ if (this.position == 'top') {
+ // FIXME: not sure why, but placing this exactly at the top causes
+ // the top axis label to flip to the bottom...
+ offsets.y = box.top + 1;
+ } else if (this.position == 'left') {
+ offsets.x = box.left;
+ offsets.y = box.height / 2 + box.top - this.labelWidth / 2;
+ } else if (this.position == 'right') {
+ offsets.x = box.left + box.width - this.labelHeight;
+ offsets.y = box.height / 2 + box.top - this.labelWidth / 2;
+ }
+ return offsets;
+ };
+
+ IeTransformAxisLabel.prototype.draw = function (box) {
+ CssTransformAxisLabel.prototype.draw.call(this, box);
+ if (this.requiresResize) {
+ var elem = this.plot.getPlaceholder().find("." + this.axisName + "Label");
+ // Since we used CSS positioning instead of transforms for
+ // translating the element, and since the positioning is done
+ // before any rotations, we have to reset the width and height
+ // in case the browser wrapped the text (specifically for the
+ // y2axis).
+ elem.css('width', this.labelWidth);
+ elem.css('height', this.labelHeight);
+ }
+ };
+
+
+ function init(plot) {
+ // This is kind of a hack. There are no hooks in Flot between
+ // the creation and measuring of the ticks (setTicks, measureTickLabels
+ // in setupGrid() ) and the drawing of the ticks and plot box
+ // (insertAxisLabels in setupGrid() ).
+ //
+ // Therefore, we use a trick where we run the draw routine twice:
+ // the first time to get the tick measurements, so that we can change
+ // them, and then have it draw it again.
+ var secondPass = false;
+
+ var axisLabels = {};
+ var axisOffsetCounts = { left: 0, right: 0, top: 0, bottom: 0 };
+
+ var defaultPadding = 2; // padding between axis and tick labels
+ plot.hooks.draw.push(function (plot, ctx) {
+ if (!secondPass) {
+ // MEASURE AND SET OPTIONS
+ $.each(plot.getAxes(), function (axisName, axis) {
+ var opts = axis.options // Flot 0.7
+ || plot.getOptions()[axisName]; // Flot 0.6
+ if (!opts || !opts.axisLabel)
+ return;
+
+ var renderer = null;
+
+ if (!opts.axisLabelUseHtml &&
+ navigator.appName == 'Microsoft Internet Explorer') {
+ var ua = navigator.userAgent;
+ var re = new RegExp("MSIE ([0-9]{1,}[\.0-9]{0,})");
+ if (re.exec(ua) != null) {
+ rv = parseFloat(RegExp.$1);
+ }
+ if (rv >= 9 && !opts.axisLabelUseCanvas && !opts.axisLabelUseHtml) {
+ renderer = CssTransformAxisLabel;
+ } else if (!opts.axisLabelUseCanvas && !opts.axisLabelUseHtml) {
+ renderer = IeTransformAxisLabel;
+ } else if (opts.axisLabelUseCanvas) {
+ renderer = CanvasAxisLabel;
+ } else {
+ renderer = HtmlAxisLabel;
+ }
+ } else {
+ if (opts.axisLabelUseHtml || (!css3TransitionSupported() && !canvasTextSupported()) && !opts.axisLabelUseCanvas) {
+ renderer = HtmlAxisLabel;
+ } else if (opts.axisLabelUseCanvas || !css3TransitionSupported()) {
+ renderer = CanvasAxisLabel;
+ } else {
+ renderer = CssTransformAxisLabel;
+ }
+ }
+
+ var padding = opts.axisLabelPadding === undefined ?
+ defaultPadding : opts.axisLabelPadding;
+
+ axisLabels[axisName] = new renderer(axisName,
+ axis.position, padding,
+ plot, opts);
+
+ // flot interprets axis.labelHeight and .labelWidth as
+ // the height and width of the tick labels. We increase
+ // these values to make room for the axis label and
+ // padding.
+
+ axisLabels[axisName].calculateSize();
+
+ // AxisLabel.height and .width are the size of the
+ // axis label and padding.
+ axis.labelHeight += axisLabels[axisName].height;
+ axis.labelWidth += axisLabels[axisName].width;
+ opts.labelHeight = axis.labelHeight;
+ opts.labelWidth = axis.labelWidth;
+ });
+ // re-draw with new label widths and heights
+ secondPass = true;
+ plot.setupGrid();
+ plot.draw();
+ } else {
+ // DRAW
+ $.each(plot.getAxes(), function (axisName, axis) {
+ var opts = axis.options // Flot 0.7
+ || plot.getOptions()[axisName]; // Flot 0.6
+ if (!opts || !opts.axisLabel)
+ return;
+
+ axisLabels[axisName].draw(axis.box);
+ });
+ }
+ });
+ }
+
+
+ $.plot.plugins.push({
+ init: init,
+ options: options,
+ name: 'axisLabels',
+ version: '2.0b0'
+ });
+})(jQuery);
\ No newline at end of file
diff --git a/coordinator/apps/gui-legacy/js/ipfixConfig.js b/coordinator/apps/gui-legacy/js/ipfixConfig.js
new file mode 100644
index 0000000..883b55a
--- /dev/null
+++ b/coordinator/apps/gui-legacy/js/ipfixConfig.js
@@ -0,0 +1,67 @@
+//general ipfix configuration, add/edit as needed
+var ipfixConfig =
+{
+ "port": "9911",
+ "appId": "ipfix-visual",
+ "flowActiveDuration":20000,
+ "addr": "148.88.226.119"
+};
+
+//plot graph variables, add/edit as needed
+var plotConfig =
+{
+ //time intervals to show on the x-axis
+ "axisIntervalsInMinutes" : 2
+};
+
+
+var referenceIpFixThreshold =
+{
+ "subtype":"none",
+ "treatment":"none",
+ "fields":{
+ "sourceIPv4Address":"none",
+ "sourceTransportPort":-1,
+ "destinationTransportPort":-1,
+ "destinationIPv4Address":"none",
+ "protocolIdentifier":"none"
+ },
+ "treatment_fields":{
+ "sourceIPv4Address":"none",
+ "sourceTransportPort":-1,
+ "destinationMacAddress":"none",
+ "destinationTransportPort":-1,
+ "sourceMacAddress":"none",
+ "protocolIdentifier":"none",
+ "destinationIPv4Address":"none"
+ },
+ "priority":-1,
+ "metric":"none",
+ "threshold":-1
+};
+
+var referenceSnortThreshold = {
+ "alertmsg": "none",
+ "priority": -1,
+ "rule":"none",
+ "treatment": "block",
+ "treatment_fields":{
+ "sourceIPv4Address":"none",
+ "sourceTransportPort":-1,
+ "destinationMacAddress":"none",
+ "destinationTransportPort":-1,
+ "sourceMacAddress":"none",
+ "protocolIdentifier":"none",
+ "destinationIPv4Address":"none"
+ }
+};
+
+
+var mandatoryIpFixThresholdFields = ["subtype","fields","treatment","priority"];
+
+var digitIpfixThresholdFields = ["sourceTransportPort","destinationTransportPort","priority","threshold"];
+
+var mandatorySnortThresholdFields = ["alertmsg","treatment","priority"];
+
+var digitSnortThresholdFields = ["sourceTransportPort","destinationTransportPort","priority"];
+
diff --git a/coordinator/apps/gui-legacy/js/ipfix_thresholds.json b/coordinator/apps/gui-legacy/js/ipfix_thresholds.json
new file mode 100644
index 0000000..3377715
--- /dev/null
+++ b/coordinator/apps/gui-legacy/js/ipfix_thresholds.json
@@ -0,0 +1,57 @@
+{
+ "default_ipfix_0": {
+ "fields": {
+ "sourceIPv4Address": "10.0.0.1"
+ },
+ "metric": "total_bps",
+ "priority": 10,
+ "subtype": "prefix",
+ "threshold": 1,
+ "treatment": "snort_mirror"
+ },
+ "default_ipfix_1": {
+ "fields": {
+ "destinationIPv4Address": "10.0.0.1"
+ },
+ "metric": "total_bps",
+ "priority": 10,
+ "subtype": "prefix",
+ "threshold": 45,
+ "treatment": "snort_mirror"
+ },
+ "default_ipfix_2": {
+ "fields": {
+ "destinationIPv4Address": "8.8.8.8",
+ "sourceIPv4Address": "10.0.0.1"
+ },
+ "metric": "total_bps",
+ "priority": 10,
+ "subtype": "prefix",
+ "threshold": 1,
+ "treatment": "snort_mirror"
+ },
+ "default_ipfix_3": {
+ "fields": {
+ "sourceIPv4Address": "10.0.0.20"
+ },
+ "interval": 10,
+ "metric": "delta_bps",
+ "priority": 10,
+ "subtype": "ipfix",
+ "threshold": 10000,
+ "treatment": "snort_mirror"
+ },
+ "shabba" : {
+ "subtype": "interfix",
+ "treatment": "snort_mirror",
+ "fields":{
+ "sourceIPv4Address": "10.0.0.255"
+ },
+ "treatment_fields":{
+ "sourceIPv4Address": "10.0.0.255"
+ },
+ "priority": 10,
+ "metric": "delta_bps",
+ "threshold": 10000
+ }
+}
\ No newline at end of file
diff --git a/coordinator/apps/gui-legacy/js/jquery-3.2.1.min.js b/coordinator/apps/gui-legacy/js/jquery-3.2.1.min.js
new file mode 100644
index 0000000..644d35e
--- /dev/null
+++ b/coordinator/apps/gui-legacy/js/jquery-3.2.1.min.js
@@ -0,0 +1,4 @@
+/*! jQuery v3.2.1 | (c) JS Foundation and other contributors | jquery.org/license */
+!function(a,b){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){"use strict";var c=[],d=a.document,e=Object.getPrototypeOf,f=c.slice,g=c.concat,h=c.push,i=c.indexOf,j={},k=j.toString,l=j.hasOwnProperty,m=l.toString,n=m.call(Object),o={};function p(a,b){b=b||d;var c=b.createElement("script");c.text=a,b.head.appendChild(c).parentNode.removeChild(c)}var q="3.2.1",r=function(a,b){return new r.fn.init(a,b)},s=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,t=/^-ms-/,u=/-([a-z])/g,v=function(a,b){return b.toUpperCase()};r.fn=r.prototype={jquery:q,constructor:r,length:0,toArray:function(){return f.call(this)},get:function(a){return null==a?f.call(this):a<0?this[a+this.length]:this[a]},pushStack:function(a){var b=r.merge(this.constructor(),a);return b.prevObject=this,b},each:function(a){return r.each(this,a)},map:function(a){return this.pushStack(r.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(f.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(a<0?b:0);return this.pushStack(c>=0&&c0&&b-1 in a)}var x=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+1*new Date,v=a.document,w=0,x=0,y=ha(),z=ha(),A=ha(),B=function(a,b){return a===b&&(l=!0),0},C={}.hasOwnProperty,D=[],E=D.pop,F=D.push,G=D.push,H=D.slice,I=function(a,b){for(var c=0,d=a.length;c+~]|"+K+")"+K+"*"),S=new RegExp("="+K+"*([^\\]'\"]*?)"+K+"*\\]","g"),T=new RegExp(N),U=new RegExp("^"+L+"$"),V={ID:new RegExp("^#("+L+")"),CLASS:new RegExp("^\\.("+L+")"),TAG:new RegExp("^("+L+"|[*])"),ATTR:new RegExp("^"+M),PSEUDO:new RegExp("^"+N),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+K+"*(even|odd|(([+-]|)(\\d*)n|)"+K+"*(?:([+-]|)"+K+"*(\\d+)|))"+K+"*\\)|)","i"),bool:new RegExp("^(?:"+J+")$","i"),needsContext:new RegExp("^"+K+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+K+"*((?:-\\d)?\\d*)"+K+"*\\)|)(?=[^-]|$)","i")},W=/^(?:input|select|textarea|button)$/i,X=/^h\d$/i,Y=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,$=/[+~]/,_=new RegExp("\\\\([\\da-f]{1,6}"+K+"?|("+K+")|.)","ig"),aa=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:d<0?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)},ba=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ca=function(a,b){return b?"\0"===a?"\ufffd":a.slice(0,-1)+"\\"+a.charCodeAt(a.length-1).toString(16)+" ":"\\"+a},da=function(){m()},ea=ta(function(a){return a.disabled===!0&&("form"in a||"label"in a)},{dir:"parentNode",next:"legend"});try{G.apply(D=H.call(v.childNodes),v.childNodes),D[v.childNodes.length].nodeType}catch(fa){G={apply:D.length?function(a,b){F.apply(a,H.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function ga(a,b,d,e){var f,h,j,k,l,o,r,s=b&&b.ownerDocument,w=b?b.nodeType:9;if(d=d||[],"string"!=typeof a||!a||1!==w&&9!==w&&11!==w)return d;if(!e&&((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,p)){if(11!==w&&(l=Z.exec(a)))if(f=l[1]){if(9===w){if(!(j=b.getElementById(f)))return d;if(j.id===f)return d.push(j),d}else if(s&&(j=s.getElementById(f))&&t(b,j)&&j.id===f)return d.push(j),d}else{if(l[2])return G.apply(d,b.getElementsByTagName(a)),d;if((f=l[3])&&c.getElementsByClassName&&b.getElementsByClassName)return G.apply(d,b.getElementsByClassName(f)),d}if(c.qsa&&!A[a+" "]&&(!q||!q.test(a))){if(1!==w)s=b,r=a;else if("object"!==b.nodeName.toLowerCase()){(k=b.getAttribute("id"))?k=k.replace(ba,ca):b.setAttribute("id",k=u),o=g(a),h=o.length;while(h--)o[h]="#"+k+" "+sa(o[h]);r=o.join(","),s=$.test(a)&&qa(b.parentNode)||b}if(r)try{return G.apply(d,s.querySelectorAll(r)),d}catch(x){}finally{k===u&&b.removeAttribute("id")}}}return i(a.replace(P,"$1"),b,d,e)}function ha(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function ia(a){return a[u]=!0,a}function ja(a){var b=n.createElement("fieldset");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function ka(a,b){var c=a.split("|"),e=c.length;while(e--)d.attrHandle[c[e]]=b}function la(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&a.sourceIndex-b.sourceIndex;if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function ma(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function na(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function oa(a){return function(b){return"form"in b?b.parentNode&&b.disabled===!1?"label"in b?"label"in b.parentNode?b.parentNode.disabled===a:b.disabled===a:b.isDisabled===a||b.isDisabled!==!a&&ea(b)===a:b.disabled===a:"label"in b&&b.disabled===a}}function pa(a){return ia(function(b){return b=+b,ia(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function qa(a){return a&&"undefined"!=typeof a.getElementsByTagName&&a}c=ga.support={},f=ga.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return!!b&&"HTML"!==b.nodeName},m=ga.setDocument=function(a){var b,e,g=a?a.ownerDocument||a:v;return g!==n&&9===g.nodeType&&g.documentElement?(n=g,o=n.documentElement,p=!f(n),v!==n&&(e=n.defaultView)&&e.top!==e&&(e.addEventListener?e.addEventListener("unload",da,!1):e.attachEvent&&e.attachEvent("onunload",da)),c.attributes=ja(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ja(function(a){return a.appendChild(n.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=Y.test(n.getElementsByClassName),c.getById=ja(function(a){return o.appendChild(a).id=u,!n.getElementsByName||!n.getElementsByName(u).length}),c.getById?(d.filter.ID=function(a){var b=a.replace(_,aa);return function(a){return a.getAttribute("id")===b}},d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c=b.getElementById(a);return c?[c]:[]}}):(d.filter.ID=function(a){var b=a.replace(_,aa);return function(a){var c="undefined"!=typeof a.getAttributeNode&&a.getAttributeNode("id");return c&&c.value===b}},d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c,d,e,f=b.getElementById(a);if(f){if(c=f.getAttributeNode("id"),c&&c.value===a)return[f];e=b.getElementsByName(a),d=0;while(f=e[d++])if(c=f.getAttributeNode("id"),c&&c.value===a)return[f]}return[]}}),d.find.TAG=c.getElementsByTagName?function(a,b){return"undefined"!=typeof b.getElementsByTagName?b.getElementsByTagName(a):c.qsa?b.querySelectorAll(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){if("undefined"!=typeof b.getElementsByClassName&&p)return b.getElementsByClassName(a)},r=[],q=[],(c.qsa=Y.test(n.querySelectorAll))&&(ja(function(a){o.appendChild(a).innerHTML=" ",a.querySelectorAll("[msallowcapture^='']").length&&q.push("[*^$]="+K+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+K+"*(?:value|"+J+")"),a.querySelectorAll("[id~="+u+"-]").length||q.push("~="),a.querySelectorAll(":checked").length||q.push(":checked"),a.querySelectorAll("a#"+u+"+*").length||q.push(".#.+[+~]")}),ja(function(a){a.innerHTML=" ";var b=n.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+K+"*[*^$|!~]?="),2!==a.querySelectorAll(":enabled").length&&q.push(":enabled",":disabled"),o.appendChild(a).disabled=!0,2!==a.querySelectorAll(":disabled").length&&q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=Y.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ja(function(a){c.disconnectedMatch=s.call(a,"*"),s.call(a,"[s!='']:x"),r.push("!=",N)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=Y.test(o.compareDocumentPosition),t=b||Y.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===n||a.ownerDocument===v&&t(v,a)?-1:b===n||b.ownerDocument===v&&t(v,b)?1:k?I(k,a)-I(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,e=a.parentNode,f=b.parentNode,g=[a],h=[b];if(!e||!f)return a===n?-1:b===n?1:e?-1:f?1:k?I(k,a)-I(k,b):0;if(e===f)return la(a,b);c=a;while(c=c.parentNode)g.unshift(c);c=b;while(c=c.parentNode)h.unshift(c);while(g[d]===h[d])d++;return d?la(g[d],h[d]):g[d]===v?-1:h[d]===v?1:0},n):n},ga.matches=function(a,b){return ga(a,null,null,b)},ga.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(S,"='$1']"),c.matchesSelector&&p&&!A[b+" "]&&(!r||!r.test(b))&&(!q||!q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return ga(b,n,null,[a]).length>0},ga.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},ga.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&C.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},ga.escape=function(a){return(a+"").replace(ba,ca)},ga.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},ga.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=ga.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=ga.selectors={cacheLength:50,createPseudo:ia,match:V,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(_,aa),a[3]=(a[3]||a[4]||a[5]||"").replace(_,aa),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||ga.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&ga.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return V.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&T.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(_,aa).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+K+")"+a+"("+K+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||"undefined"!=typeof a.getAttribute&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=ga.attr(d,a);return null==e?"!="===b:!b||(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e.replace(O," ")+" ").indexOf(c)>-1:"|="===b&&(e===c||e.slice(0,c.length+1)===c+"-"))}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h,t=!1;if(q){if(f){while(p){m=b;while(m=m[p])if(h?m.nodeName.toLowerCase()===r:1===m.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){m=q,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n&&j[2],m=n&&q.childNodes[n];while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if(1===m.nodeType&&++t&&m===b){k[a]=[w,n,t];break}}else if(s&&(m=b,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n),t===!1)while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if((h?m.nodeName.toLowerCase()===r:1===m.nodeType)&&++t&&(s&&(l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),k[a]=[w,t]),m===b))break;return t-=e,t===d||t%d===0&&t/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||ga.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?ia(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=I(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:ia(function(a){var b=[],c=[],d=h(a.replace(P,"$1"));return d[u]?ia(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),b[0]=null,!c.pop()}}),has:ia(function(a){return function(b){return ga(a,b).length>0}}),contains:ia(function(a){return a=a.replace(_,aa),function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:ia(function(a){return U.test(a||"")||ga.error("unsupported lang: "+a),a=a.replace(_,aa).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:oa(!1),disabled:oa(!0),checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return X.test(a.nodeName)},input:function(a){return W.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:pa(function(){return[0]}),last:pa(function(a,b){return[b-1]}),eq:pa(function(a,b,c){return[c<0?c+b:c]}),even:pa(function(a,b){for(var c=0;c=0;)a.push(d);return a}),gt:pa(function(a,b,c){for(var d=c<0?c+b:c;++d1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function va(a,b,c){for(var d=0,e=b.length;d-1&&(f[j]=!(g[j]=l))}}else r=wa(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):G.apply(g,r)})}function ya(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=ta(function(a){return a===b},h,!0),l=ta(function(a){return I(b,a)>-1},h,!0),m=[function(a,c,d){var e=!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d));return b=null,e}];i1&&ua(m),i>1&&sa(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(P,"$1"),c,i0,e=a.length>0,f=function(f,g,h,i,k){var l,o,q,r=0,s="0",t=f&&[],u=[],v=j,x=f||e&&d.find.TAG("*",k),y=w+=null==v?1:Math.random()||.1,z=x.length;for(k&&(j=g===n||g||k);s!==z&&null!=(l=x[s]);s++){if(e&&l){o=0,g||l.ownerDocument===n||(m(l),h=!p);while(q=a[o++])if(q(l,g||n,h)){i.push(l);break}k&&(w=y)}c&&((l=!q&&l)&&r--,f&&t.push(l))}if(r+=s,c&&s!==r){o=0;while(q=b[o++])q(t,u,g,h);if(f){if(r>0)while(s--)t[s]||u[s]||(u[s]=E.call(i));u=wa(u)}G.apply(i,u),k&&!f&&u.length>0&&r+b.length>1&&ga.uniqueSort(i)}return k&&(w=y,j=v),t};return c?ia(f):f}return h=ga.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=ya(b[c]),f[u]?d.push(f):e.push(f);f=A(a,za(e,d)),f.selector=a}return f},i=ga.select=function(a,b,c,e){var f,i,j,k,l,m="function"==typeof a&&a,n=!e&&g(a=m.selector||a);if(c=c||[],1===n.length){if(i=n[0]=n[0].slice(0),i.length>2&&"ID"===(j=i[0]).type&&9===b.nodeType&&p&&d.relative[i[1].type]){if(b=(d.find.ID(j.matches[0].replace(_,aa),b)||[])[0],!b)return c;m&&(b=b.parentNode),a=a.slice(i.shift().value.length)}f=V.needsContext.test(a)?0:i.length;while(f--){if(j=i[f],d.relative[k=j.type])break;if((l=d.find[k])&&(e=l(j.matches[0].replace(_,aa),$.test(i[0].type)&&qa(b.parentNode)||b))){if(i.splice(f,1),a=e.length&&sa(i),!a)return G.apply(c,e),c;break}}}return(m||h(a,n))(e,b,!p,c,!b||$.test(a)&&qa(b.parentNode)||b),c},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ja(function(a){return 1&a.compareDocumentPosition(n.createElement("fieldset"))}),ja(function(a){return a.innerHTML=" ","#"===a.firstChild.getAttribute("href")})||ka("type|href|height|width",function(a,b,c){if(!c)return a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ja(function(a){return a.innerHTML=" ",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||ka("value",function(a,b,c){if(!c&&"input"===a.nodeName.toLowerCase())return a.defaultValue}),ja(function(a){return null==a.getAttribute("disabled")})||ka(J,function(a,b,c){var d;if(!c)return a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),ga}(a);r.find=x,r.expr=x.selectors,r.expr[":"]=r.expr.pseudos,r.uniqueSort=r.unique=x.uniqueSort,r.text=x.getText,r.isXMLDoc=x.isXML,r.contains=x.contains,r.escapeSelector=x.escape;var y=function(a,b,c){var d=[],e=void 0!==c;while((a=a[b])&&9!==a.nodeType)if(1===a.nodeType){if(e&&r(a).is(c))break;d.push(a)}return d},z=function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c},A=r.expr.match.needsContext;function B(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()}var C=/^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i,D=/^.[^:#\[\.,]*$/;function E(a,b,c){return r.isFunction(b)?r.grep(a,function(a,d){return!!b.call(a,d,a)!==c}):b.nodeType?r.grep(a,function(a){return a===b!==c}):"string"!=typeof b?r.grep(a,function(a){return i.call(b,a)>-1!==c}):D.test(b)?r.filter(b,a,c):(b=r.filter(b,a),r.grep(a,function(a){return i.call(b,a)>-1!==c&&1===a.nodeType}))}r.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?r.find.matchesSelector(d,a)?[d]:[]:r.find.matches(a,r.grep(b,function(a){return 1===a.nodeType}))},r.fn.extend({find:function(a){var b,c,d=this.length,e=this;if("string"!=typeof a)return this.pushStack(r(a).filter(function(){for(b=0;b1?r.uniqueSort(c):c},filter:function(a){return this.pushStack(E(this,a||[],!1))},not:function(a){return this.pushStack(E(this,a||[],!0))},is:function(a){return!!E(this,"string"==typeof a&&A.test(a)?r(a):a||[],!1).length}});var F,G=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/,H=r.fn.init=function(a,b,c){var e,f;if(!a)return this;if(c=c||F,"string"==typeof a){if(e="<"===a[0]&&">"===a[a.length-1]&&a.length>=3?[null,a,null]:G.exec(a),!e||!e[1]&&b)return!b||b.jquery?(b||c).find(a):this.constructor(b).find(a);if(e[1]){if(b=b instanceof r?b[0]:b,r.merge(this,r.parseHTML(e[1],b&&b.nodeType?b.ownerDocument||b:d,!0)),C.test(e[1])&&r.isPlainObject(b))for(e in b)r.isFunction(this[e])?this[e](b[e]):this.attr(e,b[e]);return this}return f=d.getElementById(e[2]),f&&(this[0]=f,this.length=1),this}return a.nodeType?(this[0]=a,this.length=1,this):r.isFunction(a)?void 0!==c.ready?c.ready(a):a(r):r.makeArray(a,this)};H.prototype=r.fn,F=r(d);var I=/^(?:parents|prev(?:Until|All))/,J={children:!0,contents:!0,next:!0,prev:!0};r.fn.extend({has:function(a){var b=r(a,this),c=b.length;return this.filter(function(){for(var a=0;a-1:1===c.nodeType&&r.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?r.uniqueSort(f):f)},index:function(a){return a?"string"==typeof a?i.call(r(a),this[0]):i.call(this,a.jquery?a[0]:a):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(r.uniqueSort(r.merge(this.get(),r(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function K(a,b){while((a=a[b])&&1!==a.nodeType);return a}r.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return y(a,"parentNode")},parentsUntil:function(a,b,c){return y(a,"parentNode",c)},next:function(a){return K(a,"nextSibling")},prev:function(a){return K(a,"previousSibling")},nextAll:function(a){return y(a,"nextSibling")},prevAll:function(a){return y(a,"previousSibling")},nextUntil:function(a,b,c){return y(a,"nextSibling",c)},prevUntil:function(a,b,c){return y(a,"previousSibling",c)},siblings:function(a){return z((a.parentNode||{}).firstChild,a)},children:function(a){return z(a.firstChild)},contents:function(a){return B(a,"iframe")?a.contentDocument:(B(a,"template")&&(a=a.content||a),r.merge([],a.childNodes))}},function(a,b){r.fn[a]=function(c,d){var e=r.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=r.filter(d,e)),this.length>1&&(J[a]||r.uniqueSort(e),I.test(a)&&e.reverse()),this.pushStack(e)}});var L=/[^\x20\t\r\n\f]+/g;function M(a){var b={};return r.each(a.match(L)||[],function(a,c){b[c]=!0}),b}r.Callbacks=function(a){a="string"==typeof a?M(a):r.extend({},a);var b,c,d,e,f=[],g=[],h=-1,i=function(){for(e=e||a.once,d=b=!0;g.length;h=-1){c=g.shift();while(++h-1)f.splice(c,1),c<=h&&h--}),this},has:function(a){return a?r.inArray(a,f)>-1:f.length>0},empty:function(){return f&&(f=[]),this},disable:function(){return e=g=[],f=c="",this},disabled:function(){return!f},lock:function(){return e=g=[],c||b||(f=c=""),this},locked:function(){return!!e},fireWith:function(a,c){return e||(c=c||[],c=[a,c.slice?c.slice():c],g.push(c),b||i()),this},fire:function(){return j.fireWith(this,arguments),this},fired:function(){return!!d}};return j};function N(a){return a}function O(a){throw a}function P(a,b,c,d){var e;try{a&&r.isFunction(e=a.promise)?e.call(a).done(b).fail(c):a&&r.isFunction(e=a.then)?e.call(a,b,c):b.apply(void 0,[a].slice(d))}catch(a){c.apply(void 0,[a])}}r.extend({Deferred:function(b){var c=[["notify","progress",r.Callbacks("memory"),r.Callbacks("memory"),2],["resolve","done",r.Callbacks("once memory"),r.Callbacks("once memory"),0,"resolved"],["reject","fail",r.Callbacks("once memory"),r.Callbacks("once memory"),1,"rejected"]],d="pending",e={state:function(){return d},always:function(){return f.done(arguments).fail(arguments),this},"catch":function(a){return e.then(null,a)},pipe:function(){var a=arguments;return r.Deferred(function(b){r.each(c,function(c,d){var e=r.isFunction(a[d[4]])&&a[d[4]];f[d[1]](function(){var a=e&&e.apply(this,arguments);a&&r.isFunction(a.promise)?a.promise().progress(b.notify).done(b.resolve).fail(b.reject):b[d[0]+"With"](this,e?[a]:arguments)})}),a=null}).promise()},then:function(b,d,e){var f=0;function g(b,c,d,e){return function(){var h=this,i=arguments,j=function(){var a,j;if(!(b=f&&(d!==O&&(h=void 0,i=[a]),c.rejectWith(h,i))}};b?k():(r.Deferred.getStackHook&&(k.stackTrace=r.Deferred.getStackHook()),a.setTimeout(k))}}return r.Deferred(function(a){c[0][3].add(g(0,a,r.isFunction(e)?e:N,a.notifyWith)),c[1][3].add(g(0,a,r.isFunction(b)?b:N)),c[2][3].add(g(0,a,r.isFunction(d)?d:O))}).promise()},promise:function(a){return null!=a?r.extend(a,e):e}},f={};return r.each(c,function(a,b){var g=b[2],h=b[5];e[b[1]]=g.add,h&&g.add(function(){d=h},c[3-a][2].disable,c[0][2].lock),g.add(b[3].fire),f[b[0]]=function(){return f[b[0]+"With"](this===f?void 0:this,arguments),this},f[b[0]+"With"]=g.fireWith}),e.promise(f),b&&b.call(f,f),f},when:function(a){var b=arguments.length,c=b,d=Array(c),e=f.call(arguments),g=r.Deferred(),h=function(a){return function(c){d[a]=this,e[a]=arguments.length>1?f.call(arguments):c,--b||g.resolveWith(d,e)}};if(b<=1&&(P(a,g.done(h(c)).resolve,g.reject,!b),"pending"===g.state()||r.isFunction(e[c]&&e[c].then)))return g.then();while(c--)P(e[c],h(c),g.reject);return g.promise()}});var Q=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;r.Deferred.exceptionHook=function(b,c){a.console&&a.console.warn&&b&&Q.test(b.name)&&a.console.warn("jQuery.Deferred exception: "+b.message,b.stack,c)},r.readyException=function(b){a.setTimeout(function(){throw b})};var R=r.Deferred();r.fn.ready=function(a){return R.then(a)["catch"](function(a){r.readyException(a)}),this},r.extend({isReady:!1,readyWait:1,ready:function(a){(a===!0?--r.readyWait:r.isReady)||(r.isReady=!0,a!==!0&&--r.readyWait>0||R.resolveWith(d,[r]))}}),r.ready.then=R.then;function S(){d.removeEventListener("DOMContentLoaded",S),
+a.removeEventListener("load",S),r.ready()}"complete"===d.readyState||"loading"!==d.readyState&&!d.documentElement.doScroll?a.setTimeout(r.ready):(d.addEventListener("DOMContentLoaded",S),a.addEventListener("load",S));var T=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===r.type(c)){e=!0;for(h in c)T(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,r.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(r(a),c)})),b))for(;h1,null,!0)},removeData:function(a){return this.each(function(){X.remove(this,a)})}}),r.extend({queue:function(a,b,c){var d;if(a)return b=(b||"fx")+"queue",d=W.get(a,b),c&&(!d||Array.isArray(c)?d=W.access(a,b,r.makeArray(c)):d.push(c)),d||[]},dequeue:function(a,b){b=b||"fx";var c=r.queue(a,b),d=c.length,e=c.shift(),f=r._queueHooks(a,b),g=function(){r.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return W.get(a,c)||W.access(a,c,{empty:r.Callbacks("once memory").add(function(){W.remove(a,[b+"queue",c])})})}}),r.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.length\x20\t\r\n\f]+)/i,la=/^$|\/(?:java|ecma)script/i,ma={option:[1,""," "],thead:[1,""],col:[2,""],tr:[2,""],td:[3,""],_default:[0,"",""]};ma.optgroup=ma.option,ma.tbody=ma.tfoot=ma.colgroup=ma.caption=ma.thead,ma.th=ma.td;function na(a,b){var c;return c="undefined"!=typeof a.getElementsByTagName?a.getElementsByTagName(b||"*"):"undefined"!=typeof a.querySelectorAll?a.querySelectorAll(b||"*"):[],void 0===b||b&&B(a,b)?r.merge([a],c):c}function oa(a,b){for(var c=0,d=a.length;c-1)e&&e.push(f);else if(j=r.contains(f.ownerDocument,f),g=na(l.appendChild(f),"script"),j&&oa(g),c){k=0;while(f=g[k++])la.test(f.type||"")&&c.push(f)}return l}!function(){var a=d.createDocumentFragment(),b=a.appendChild(d.createElement("div")),c=d.createElement("input");c.setAttribute("type","radio"),c.setAttribute("checked","checked"),c.setAttribute("name","t"),b.appendChild(c),o.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,b.innerHTML="",o.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue}();var ra=d.documentElement,sa=/^key/,ta=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,ua=/^([^.]*)(?:\.(.+)|)/;function va(){return!0}function wa(){return!1}function xa(){try{return d.activeElement}catch(a){}}function ya(a,b,c,d,e,f){var g,h;if("object"==typeof b){"string"!=typeof c&&(d=d||c,c=void 0);for(h in b)ya(a,h,c,d,b[h],f);return a}if(null==d&&null==e?(e=c,d=c=void 0):null==e&&("string"==typeof c?(e=d,d=void 0):(e=d,d=c,c=void 0)),e===!1)e=wa;else if(!e)return a;return 1===f&&(g=e,e=function(a){return r().off(a),g.apply(this,arguments)},e.guid=g.guid||(g.guid=r.guid++)),a.each(function(){r.event.add(this,b,e,d,c)})}r.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,n,o,p,q=W.get(a);if(q){c.handler&&(f=c,c=f.handler,e=f.selector),e&&r.find.matchesSelector(ra,e),c.guid||(c.guid=r.guid++),(i=q.events)||(i=q.events={}),(g=q.handle)||(g=q.handle=function(b){return"undefined"!=typeof r&&r.event.triggered!==b.type?r.event.dispatch.apply(a,arguments):void 0}),b=(b||"").match(L)||[""],j=b.length;while(j--)h=ua.exec(b[j])||[],n=p=h[1],o=(h[2]||"").split(".").sort(),n&&(l=r.event.special[n]||{},n=(e?l.delegateType:l.bindType)||n,l=r.event.special[n]||{},k=r.extend({type:n,origType:p,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&r.expr.match.needsContext.test(e),namespace:o.join(".")},f),(m=i[n])||(m=i[n]=[],m.delegateCount=0,l.setup&&l.setup.call(a,d,o,g)!==!1||a.addEventListener&&a.addEventListener(n,g)),l.add&&(l.add.call(a,k),k.handler.guid||(k.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,k):m.push(k),r.event.global[n]=!0)}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,n,o,p,q=W.hasData(a)&&W.get(a);if(q&&(i=q.events)){b=(b||"").match(L)||[""],j=b.length;while(j--)if(h=ua.exec(b[j])||[],n=p=h[1],o=(h[2]||"").split(".").sort(),n){l=r.event.special[n]||{},n=(d?l.delegateType:l.bindType)||n,m=i[n]||[],h=h[2]&&new RegExp("(^|\\.)"+o.join("\\.(?:.*\\.|)")+"(\\.|$)"),g=f=m.length;while(f--)k=m[f],!e&&p!==k.origType||c&&c.guid!==k.guid||h&&!h.test(k.namespace)||d&&d!==k.selector&&("**"!==d||!k.selector)||(m.splice(f,1),k.selector&&m.delegateCount--,l.remove&&l.remove.call(a,k));g&&!m.length&&(l.teardown&&l.teardown.call(a,o,q.handle)!==!1||r.removeEvent(a,n,q.handle),delete i[n])}else for(n in i)r.event.remove(a,n+b[j],c,d,!0);r.isEmptyObject(i)&&W.remove(a,"handle events")}},dispatch:function(a){var b=r.event.fix(a),c,d,e,f,g,h,i=new Array(arguments.length),j=(W.get(this,"events")||{})[b.type]||[],k=r.event.special[b.type]||{};for(i[0]=b,c=1;c=1))for(;j!==this;j=j.parentNode||this)if(1===j.nodeType&&("click"!==a.type||j.disabled!==!0)){for(f=[],g={},c=0;c-1:r.find(e,this,null,[j]).length),g[e]&&f.push(d);f.length&&h.push({elem:j,handlers:f})}return j=this,i\x20\t\r\n\f]*)[^>]*)\/>/gi,Aa=/
+
+
+
+
+
+
+
+
+
+
+ Rendering engine
+ Browser
+ Platform(s)
+ Engine version
+ CSS grade
+
+
+
+
+ Trident
+ Internet
+ Explorer 4.0
+ Win 95+
+ 4
+ X
+
+
+ Trident
+ Internet
+ Explorer 5.0
+ Win 95+
+ 5
+ C
+
+
+ Trident
+ Internet
+ Explorer 5.5
+ Win 95+
+ 5.5
+ A
+
+
+ Trident
+ Internet
+ Explorer 6
+ Win 98+
+ 6
+ A
+
+
+ Trident
+ Internet Explorer 7
+ Win XP SP2+
+ 7
+ A
+
+
+ Trident
+ AOL browser (AOL desktop)
+ Win XP
+ 6
+ A
+
+
+ Gecko
+ Firefox 1.0
+ Win 98+ / OSX.2+
+ 1.7
+ A
+
+
+ Gecko
+ Firefox 1.5
+ Win 98+ / OSX.2+
+ 1.8
+ A
+
+
+ Gecko
+ Firefox 2.0
+ Win 98+ / OSX.2+
+ 1.8
+ A
+
+
+ Gecko
+ Firefox 3.0
+ Win 2k+ / OSX.3+
+ 1.9
+ A
+
+
+ Gecko
+ Camino 1.0
+ OSX.2+
+ 1.8
+ A
+
+
+ Gecko
+ Camino 1.5
+ OSX.3+
+ 1.8
+ A
+
+
+ Gecko
+ Netscape 7.2
+ Win 95+ / Mac OS 8.6-9.2
+ 1.7
+ A
+
+
+ Gecko
+ Netscape Browser 8
+ Win 98SE+
+ 1.7
+ A
+
+
+ Gecko
+ Netscape Navigator 9
+ Win 98+ / OSX.2+
+ 1.8
+ A
+
+
+ Gecko
+ Mozilla 1.0
+ Win 95+ / OSX.1+
+ 1
+ A
+
+
+ Gecko
+ Mozilla 1.1
+ Win 95+ / OSX.1+
+ 1.1
+ A
+
+
+ Gecko
+ Mozilla 1.2
+ Win 95+ / OSX.1+
+ 1.2
+ A
+
+
+ Gecko
+ Mozilla 1.3
+ Win 95+ / OSX.1+
+ 1.3
+ A
+
+
+ Gecko
+ Mozilla 1.4
+ Win 95+ / OSX.1+
+ 1.4
+ A
+
+
+ Gecko
+ Mozilla 1.5
+ Win 95+ / OSX.1+
+ 1.5
+ A
+
+
+ Gecko
+ Mozilla 1.6
+ Win 95+ / OSX.1+
+ 1.6
+ A
+
+
+ Gecko
+ Mozilla 1.7
+ Win 98+ / OSX.1+
+ 1.7
+ A
+
+
+ Gecko
+ Mozilla 1.8
+ Win 98+ / OSX.1+
+ 1.8
+ A
+
+
+ Gecko
+ Seamonkey 1.1
+ Win 98+ / OSX.2+
+ 1.8
+ A
+
+
+ Gecko
+ Epiphany 2.20
+ Gnome
+ 1.8
+ A
+
+
+ Webkit
+ Safari 1.2
+ OSX.3
+ 125.5
+ A
+
+
+ Webkit
+ Safari 1.3
+ OSX.3
+ 312.8
+ A
+
+
+ Webkit
+ Safari 2.0
+ OSX.4+
+ 419.3
+ A
+
+
+ Webkit
+ Safari 3.0
+ OSX.4+
+ 522.1
+ A
+
+
+ Webkit
+ OmniWeb 5.5
+ OSX.4+
+ 420
+ A
+
+
+ Webkit
+ iPod Touch / iPhone
+ iPod
+ 420.1
+ A
+
+
+ Webkit
+ S60
+ S60
+ 413
+ A
+
+
+ Presto
+ Opera 7.0
+ Win 95+ / OSX.1+
+ -
+ A
+
+
+ Presto
+ Opera 7.5
+ Win 95+ / OSX.2+
+ -
+ A
+
+
+ Presto
+ Opera 8.0
+ Win 95+ / OSX.2+
+ -
+ A
+
+
+ Presto
+ Opera 8.5
+ Win 95+ / OSX.2+
+ -
+ A
+
+
+ Presto
+ Opera 9.0
+ Win 95+ / OSX.3+
+ -
+ A
+
+
+ Presto
+ Opera 9.2
+ Win 88+ / OSX.3+
+ -
+ A
+
+
+ Presto
+ Opera 9.5
+ Win 88+ / OSX.3+
+ -
+ A
+
+
+ Presto
+ Opera for Wii
+ Wii
+ -
+ A
+
+
+ Presto
+ Nokia N800
+ N800
+ -
+ A
+
+
+ Presto
+ Nintendo DS browser
+ Nintendo DS
+ 8.5
+ C/A1
+
+
+ KHTML
+ Konqureror 3.1
+ KDE 3.1
+ 3.1
+ C
+
+
+ KHTML
+ Konqureror 3.3
+ KDE 3.3
+ 3.3
+ A
+
+
+ KHTML
+ Konqureror 3.5
+ KDE 3.5
+ 3.5
+ A
+
+
+ Tasman
+ Internet Explorer 4.5
+ Mac OS 8-9
+ -
+ X
+
+
+ Tasman
+ Internet Explorer 5.1
+ Mac OS 7.6-9
+ 1
+ C
+
+
+ Tasman
+ Internet Explorer 5.2
+ Mac OS 8-X
+ 1
+ C
+
+
+ Misc
+ NetFront 3.1
+ Embedded devices
+ -
+ C
+
+
+ Misc
+ NetFront 3.4
+ Embedded devices
+ -
+ A
+
+
+ Misc
+ Dillo 0.8
+ Embedded devices
+ -
+ X
+
+
+ Misc
+ Links
+ Text only
+ -
+ X
+
+
+ Misc
+ Lynx
+ Text only
+ -
+ X
+
+
+ Misc
+ IE Mobile
+ Windows Mobile 6
+ -
+ C
+
+
+ Misc
+ PSP browser
+ PSP
+ -
+ C
+
+
+ Other browsers
+ All others
+ -
+ -
+ U
+
+
+
+
+
+
+