aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog22
-rw-r--r--INSTALL.md64
-rw-r--r--Makefile.am1
-rw-r--r--README.md22
-rw-r--r--TODO.md25
-rw-r--r--configure.ac2
-rw-r--r--doc/advanced.mux4
-rw-r--r--doc/example.mux6
-rw-r--r--gui/README.md32
-rw-r--r--gui/muxconfig.py171
-rw-r--r--gui/muxrc.py107
-rwxr-xr-xgui/odr-dabmux-gui.py182
-rw-r--r--gui/rcparam.json48
-rw-r--r--gui/static/intercooler-1.0.1.min.js2
-rw-r--r--gui/static/jquery-1.10.2.min.js6
-rw-r--r--gui/static/script.js4
-rw-r--r--gui/static/stats.js17
-rw-r--r--gui/static/style.css73
-rw-r--r--gui/views/configeditor.tpl29
-rw-r--r--gui/views/index.tpl129
-rw-r--r--gui/views/rcparam.tpl37
-rw-r--r--gui/views/services.tpl31
-rw-r--r--gui/views/stats.tpl21
-rw-r--r--lib/Socket.cpp1
-rw-r--r--lib/Socket.h2
-rw-r--r--lib/ThreadsafeQueue.h2
-rw-r--r--lib/edi/STIDecoder.cpp21
-rw-r--r--lib/edi/STIDecoder.hpp5
-rw-r--r--lib/edioutput/EDIConfig.h3
-rw-r--r--lib/edioutput/Transport.cpp32
-rw-r--r--lib/edioutput/Transport.h7
-rw-r--r--lib/fec/decode_rs.h12
-rw-r--r--man/odr-dabmux.12
-rw-r--r--src/ConfigParser.cpp15
-rw-r--r--src/ConfigParser.h8
-rw-r--r--src/DabMultiplexer.cpp196
-rw-r--r--src/DabMultiplexer.h77
-rw-r--r--src/DabMux.cpp137
-rw-r--r--src/DabMux.h45
-rw-r--r--src/Eti.cpp17
-rw-r--r--src/Eti.h18
-rw-r--r--src/Interleaver.cpp5
-rw-r--r--src/ManagementServer.cpp15
-rw-r--r--src/ManagementServer.h18
-rw-r--r--src/MuxElements.cpp9
-rw-r--r--src/MuxElements.h26
-rw-r--r--src/PcDebug.h62
-rw-r--r--src/fig/FIG0_6.h2
-rw-r--r--src/fig/FIG1.h13
-rw-r--r--src/fig/FIG2.h14
-rw-r--r--src/input/Edi.cpp7
-rw-r--r--src/input/File.cpp18
-rw-r--r--src/mpeg.h15
53 files changed, 430 insertions, 1409 deletions
diff --git a/ChangeLog b/ChangeLog
index 8a27ded..dbe28df 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,6 +1,28 @@
This file contains information about the changes done to
ODR-DabMux in this repository
+2025-10-01: Matthias P. Braendli <matthias@mpb.li>
+ (v5.4.1):
+ Fix race condition in TCP output stats that can lock up
+ odr-dabmux on some systems.
+ Add linkage-set hot-reload.
+
+2025-09-10: Matthias P. Braendli <matthias@mpb.li>
+ (v5.4.0):
+ Add support for UDP EDI input to specify local interface IP.
+ Make sourceport optional in EDI output config.
+
+2025-06-25: Matthias P. Braendli <matthias@mpb.li>
+ (v5.3.0):
+ Remove broken gui/ and point towards ODR-DabMux-GUI in README instead.
+ Improve logging about SSnn zero.
+ Rework FCT and TIST startup initialisation to guarantee TIST@FCT0 setting
+
+2025-05-19: Matthias P. Braendli <matthias@mpb.li>
+ (v5.2.0):
+ Rework FIG0/10 DAB time indication to match EDI time.
+ Make PFT per-output configurable.
+
2025-03-18: Matthias P. Braendli <matthias@mpb.li>
(v5.1.0):
Fix startup value of DLFC and FCT.
diff --git a/INSTALL.md b/INSTALL.md
index 96fc2a4..7e15018 100644
--- a/INSTALL.md
+++ b/INSTALL.md
@@ -1,25 +1,26 @@
+# Installation
+
You have 3 ways to install odr-dabmux on your host:
-# Using your linux distribution packaging system
-`odr-dabmux` is available on the official repositories of several debian-based distributions, such as Debian
-(from Debian 12), Ubuntu (from 24.10), Opensuse and Arch.
+## Installing binary packages on some linux distributions
-If you are using Debian 12 (Bookworm), you will need to
-[add the backports repository](https://backports.debian.org/Instructions/)
+[![Packaging status](https://repology.org/badge/vertical-allrepos/odr-dabmux.svg)](https://repology.org/project/odr-dabmux/versions)
-**Notice**: this debian package does not include the Mux Web Management GUI
+## Using installation scripts
-# Using installation scripts
If your linux distribution is debian-based, you can install odr-dabmux
-as well as the other main components of the mmbTools set with the
+as well as the other main components of the mmbTools set with the
[Opendigitalradio dab-scripts](https://github.com/opendigitalradio/dab-scripts.git)
-# Compiling manually
+## Compiling manually
+
Unlike the 2 previous options, this one allows you to compile odr-dabmux with the features you really need.
-## Dependencies
-### Debian Bullseye-based OS:
-```
+### Dependencies
+
+#### Debian Bullseye-based OS
+
+```sh
# Required packages
## C++11 compiler
sudo apt-get install --yes build-essential automake libtool
@@ -35,7 +36,8 @@ sudo apt-get install --yes libboost-system-dev
sudo apt-get install --yes libcurl4-openssl-dev
```
-### Dependencies on other linux distributions
+#### Other linux distributions
+
For CentOS, in addition to the packages needed to install a compiler, install the packages:
boost-devel libcurl-devel zeromq-devel
@@ -47,49 +49,59 @@ the [radio RaBe repository](https://github.com/radiorabe/).
For openSUSE, mnhauke is maintaining packages, also built using
[OBS](https://build.opensuse.org/project/show/home:mnhauke:ODR-mmbTools).
-## Compilation
+### Compilation
+
The *master* branch in the repository always points to the
latest release. If you are looking for a new feature or bug-fix
that did not yet make its way into a release, you can clone the
*next* branch from the repository.
1. Clone this repository:
- ```
+
+ ```sh
# stable version:
git clone https://github.com/Opendigitalradio/ODR-DabMux.git
# or development version (at your own risk):
git clone https://github.com/Opendigitalradio/ODR-DabMux.git -b next
```
+
1. Configure the project
- ```
+
+ ```sh
cd ODR-DabMux
./bootstrap
./configure
```
+
1. Compile and install:
- ```
+
+ ```sh
make
sudo make install
```
Notes:
+
- It is advised to run the bootstrap and configure steps again every time you pull updates from the repository.
- The configure script can be launched with a variety of options. Run `./configure --help` to display a complete list
-# Develop on OSX and FreeBSD
-If you want to develop on OSX platform install the necessary build tools
-and dependencies with brew
+## Develop on OSX and FreeBSD
+
+If you want to develop on OSX platform install the necessary build tools and dependencies with brew
- brew install boost zeromq automake curl
+```sh
+brew install boost zeromq automake curl
+```
On FreeBSD, pkg installs all dependencies to /usr/local, but the build
tools will not search there by default. Set the following environment variables
before calling ./configure
- LDFLAGS="-L/usr/local/lib"
- CFLAGS="-I/usr/local/include"
- CXXFLAGS="-I/usr/local/include"
+```sh
+LDFLAGS="-L/usr/local/lib"
+CFLAGS="-I/usr/local/include"
+CXXFLAGS="-I/usr/local/include"
+```
-On both systems, RAW output is not available. Note that these systems
-are not tested regularly.
+On both systems, RAW output is not available. Note that these systems are not tested regularly.
diff --git a/Makefile.am b/Makefile.am
index be2eed3..455a3a0 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -60,7 +60,6 @@ odr_dabmux_LDADD =$(ZMQ_LIBS) $(BOOST_LDFLAGS) \
$(PTHREAD_CFLAGS) $(PTHREAD_LIBS) $(BOOST_SYSTEM_LIB)
odr_dabmux_SOURCES =src/DabMux.cpp \
- src/DabMux.h \
src/DabMultiplexer.cpp \
src/DabMultiplexer.h \
src/input/inputs.h \
diff --git a/README.md b/README.md
index 198adc3..90d6402 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,4 @@
-Overview
-========
+# Overview
ODR-DabMux is a *DAB (Digital Audio Broadcasting) multiplexer* compliant to
ETSI EN 300 401. It is the continuation of the work started by the
@@ -20,8 +19,6 @@ Features of ODR-DabMux:
- Includes a Telnet and ZMQ Remote Control for setting/getting parameters
- EDI input and output, both over UDP and TCP
- Support for FarSync TE1 and TE1e cards (G.703)
-- Something that will (with your help?) one day become a nice GUI for
- configuration, see `gui/README.md`
- Experimental STI-D(PI, X)/RTP input intended to be compatible
with compliant encoders.
- ZeroMQ and TCP ETI outputs that can be used with ODR-DabMod
@@ -46,18 +43,17 @@ Up to v4.5, this repository also contained
This was superseded by `digris-zmq-converter` in the
[digris-edi-zmq-bridge](https://github.com/digris/digris-edi-zmq-bridge) repository.
-Install
-=======
+## Install
-See `INSTALL.md` file for installation instructions.
+[Check the installation instructions.](INSTALL.md)
-Licence
-=======
+You may find [ODR-DabMux-GUI](https://github.com/Opendigitalradio/ODR-DabMux-GUI/) for configuring a DAB Ensemble.
+
+## Licence
See the files `LICENCE` and `COPYING`
-Contributions and Contact
-=========================
+## Contributions and Contact
Contributions to this tool are welcome, you can reach users and developers
through the
@@ -73,12 +69,10 @@ Matthias P. Braendli *matthias [at] mpb [dot] li*
Pascal Charest *pascal [dot] charest [at] crc [dot] ca*
-Acknowledgements
-================
+## Acknowledgements
David Lutton, Yoann Queret, Stefan Pöschel and Maik for bug-fix patches,
Wim Nelis for the Xymon monitoring scripts,
and many more for feedback and bug reports.
- [http://opendigitalradio.org/](http://opendigitalradio.org/)
-
diff --git a/TODO.md b/TODO.md
index 3ddc797..5e3e7e8 100644
--- a/TODO.md
+++ b/TODO.md
@@ -1,48 +1,43 @@
+# To do
+
This TODO file lists ideas and features for future developments. They are
more or less ordered according to their benefit, but that is subjective
to some degree.
Unless written, no activity has been started on the topics.
+## Explicit Service Linking
-Explicit Service Linking
-------------------------
It is impossible to activate/deactive linkage sets. Commit 5c3c6d7 added
some code to transmit a FIG0/6 CEI, but this was subsequently reverted
because it was not tested enough.
+## Inputs for packet data
-Inputs for packet data
-----------------------
It is currently unclear what input formats and sources work for packet data,
and which ones would make sense to add.
Also, there is no documentation on the possibilites of packet data.
+## Improvements for inputs
-Improvements for inputs
------------------------
Add statistics to UDP input, in a similar way that ZeroMQ offers statistics.
This would mean we have to move the packet buffer from the operating system
into our own buffer, so that we can actually get the statistics.
+## Fix DMB input
-Fix DMB input
--------------
The code that does interleaving and reed-solomon encoding for DMB is not used
-anymore, and is untested. The relevant parts are `src/dabInputDmb*` and
-`src/Dmb.cpp`
+anymore, and is untested. The relevant parts are `src/dabInputDmb*` and `src/Dmb.cpp`
+## Communicate Leap Seconds
-Communicate Leap Seconds
-------------------------
Actually, we're supposed to say in FIG0/10 when there is a UTC leap second
upcoming, but since that's not trivial to find out because the POSIX time
concept is totally unaware of that, this is not done. We need to know for EDI
TIST, and the ClockTAI class can get the information from the Internet, but it
is not used in FIG0/10.
+## Implement FIG0/20 Service List
-Implement FIG0/20 Service List
-------------------------------
-See ETSI TS 103 176
+See [ETSI TS 103 176](https://www.etsi.org/deliver/etsi_ts/103100_103199/103176/02.01.01_60/ts_103176v020101p.pdf)
diff --git a/configure.ac b/configure.ac
index 23463d0..6d336b0 100644
--- a/configure.ac
+++ b/configure.ac
@@ -19,7 +19,7 @@
# along with ODR-DabMux. If not, see <http://www.gnu.org/licenses/>.
AC_PREREQ([2.69])
-AC_INIT([ODR-DabMux],[5.1.0],[matthias.braendli@mpb.li])
+AC_INIT([ODR-DabMux],[5.4.1],[matthias.braendli@mpb.li])
AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_MACRO_DIR([m4])
AC_CANONICAL_TARGET
diff --git a/doc/advanced.mux b/doc/advanced.mux
index 0fc1b53..d2cc0fd 100644
--- a/doc/advanced.mux
+++ b/doc/advanced.mux
@@ -36,8 +36,8 @@ general {
; number in seconds. Granularity: 24ms
; tist_offset 0.480
- ; Specify the TIST value for the frame with FCT==0, in microseconds
- ; tist_at_fct0 768000
+ ; Specify the TIST value for the frame with FCT==0, in milliseconds
+ ; tist_at_fct0 768
; The management server is a simple TCP server that can present
; statistics data (buffers, overruns, underruns, etc)
diff --git a/doc/example.mux b/doc/example.mux
index 34cd2ee..ae12fb2 100644
--- a/doc/example.mux
+++ b/doc/example.mux
@@ -211,11 +211,13 @@ subchannels {
inputuri "tcp://0.0.0.0:9001"
; For UDP, PFT should be enabled at the sender.
- ; Unicast UDP input:
+ ; Unicast UDP input, bound to all interfaces:
;inputuri "udp://:9001"
+ ; Unicast UDP input, bound to interface with IP 192.168.0.10:
+ ;inputuri "udp://192.168.0.10:9001"
; Multicast UDP input:
;inputuri "udp://@239.10.0.1:9001"
- ; Multicast UDP input with local interface (192.168.0.10) specification
+ ; Multicast UDP input with local interface 192.168.0.10 specification
;inputuri "udp://192.168.0.10@239.10.0.1:9001"
; Two buffer-management types are available: prebuffering and timestamped.
diff --git a/gui/README.md b/gui/README.md
deleted file mode 100644
index fc0311d..0000000
--- a/gui/README.md
+++ /dev/null
@@ -1,32 +0,0 @@
-The ODR-DabMux Web Management GUI
-=================================
-
-The whole world has repeatedly been asking for a graphical administration
-console for the ODR-mmbTools. I give in now, and start working on this
-web-based GUI.
-
-In the current state, it can display part of the configuration of a running
-ODR-DabMux in your browser. It doesn't seem like much, but you *will* be
-impressed.
-
-Usage
------
-
-Launch ODR-DabMux with your preferred multiplex, and enable the statistics and
-management server in the configuration file to port 12720, and the zeromq RC on
-tcp://lo:12722
-
-Start the gui/odr-dabmux-gui.py script on the same machine
-
-Connect to http://localhost:8000
-
-Admire the fabulously well-designed presentation of the configuration. In the
-remote control tab, you can interact with the ODR-DabMux RC to get an set
-parameters.
-
-Expect more features to come: Better design; integrated statistics, dynamically
-updated information, configuration upload and download, less ridiculous README,
-and much more. We can even start dreaming about live multiplex reconfiguration.
-
-2016-10-07 mpb
-
diff --git a/gui/muxconfig.py b/gui/muxconfig.py
deleted file mode 100644
index 35587f4..0000000
--- a/gui/muxconfig.py
+++ /dev/null
@@ -1,171 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-#
-# Copyright (C) 2015
-# Matthias P. Braendli, matthias.braendli@mpb.li
-#
-# http://www.opendigitalradio.org
-#
-# This file is part of ODR-DabMux.
-#
-# ODR-DabMux is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
-#
-# ODR-DabMux 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
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with ODR-DabMux. If not, see <http://www.gnu.org/licenses/>.
-import zmq
-import json
-
-class General(object):
- """Container object for general options"""
- def __init__(self, pt):
- ptree = pt['general']
- for fieldname in [
- "nbframes",
- "statsserverport",
- "writescca",
- "tist",
- "dabmode",
- "syslog"]:
- if fieldname in ptree:
- setattr(self, fieldname.replace("-", "_"), ptree[fieldname])
- else:
- setattr(self, fieldname.replace("-", "_"), "")
- self.telnetport = pt['remotecontrol']['telnetport']
-
-class Service(object):
- """Container object for a service"""
- def __init__(self, name, ptree):
- self.name = name
-
- for fieldname in [
- "id",
- "label",
- "shortlabel",
- "pty",
- "language" ]:
- if fieldname in ptree:
- setattr(self, fieldname.replace("-", "_"), ptree[fieldname])
- else:
- setattr(self, fieldname.replace("-", "_"), "")
-
-class Subchannel(object):
- """Container object for a subchannel"""
- def __init__(self, name, ptree):
- self.name = name
- for fieldname in [
- "type",
- "inputfile",
- "zmq-buffer",
- "zmq-prebuffering",
- "bitrate",
- "id",
- "protection",
- "encryption",
- "secret-key",
- "public-key",
- "encoder-key"]:
- if fieldname in ptree:
- setattr(self, fieldname.replace("-", "_"), ptree[fieldname])
- else:
- setattr(self, fieldname.replace("-", "_"), "")
-
-class Component(object):
- """Container object for a component"""
- def __init__(self, name, ptree):
- self.name = name
- for fieldname in ['label', 'shortlabel', 'service',
- 'subchannel', 'figtype']:
- if fieldname in ptree:
- setattr(self, fieldname.replace("-", "_"), ptree[fieldname])
- else:
- setattr(self, fieldname.replace("-", "_"), "")
-
-class ConfigurationHandler(object):
- """Load and present the configration from ODR-DabMux"""
-
- def __init__(self, mux_host, mux_port=12720):
- self._host = mux_host
- self._port = mux_port
-
- # local copy of the configuration
- self._server_version = None
- self._config = None
- self._statistics = None
-
- #self._ctx = zmq.Context()
- #self.sock = zmq.Socket(self._ctx, zmq.REQ)
- #self.sock.setsockopt(zmq.LINGER, 0)
- #self.sock.connect("tcp://{}:{}".format(self._host, self._port))
-
- def zRead(self, key):
- self._ctx = zmq.Context()
- self.sock = zmq.Socket(self._ctx, zmq.REQ)
- self.sock.setsockopt(zmq.LINGER, 0)
- self.sock.connect("tcp://{}:{}".format(self._host, self._port))
- self.sock.send(key)
-
- # use poll for timeouts:
- poller = zmq.Poller()
- poller.register(self.sock, zmq.POLLIN)
- if poller.poll(5*1000): # 5s timeout in milliseconds
- recv = self.sock.recv()
- self.sock.close()
- self._ctx.term()
- return recv
- else:
- raise IOError("Timeout processing ZMQ request")
-
- def load(self):
- """Load the configuration from the multiplexer and save it locally"""
- server_info = self.zRead(b'info')
- config_info = self.zRead(b'getptree')
-
- self._server_version = json.loads(server_info)['service']
- self._config = json.loads(config_info)
-
- def update_stats(self):
- """Load the statistics from the multiplexer and
- save them locally"""
- server_info = self.zRead(b'info')
- stats_info = self.zRead(b'values')
-
- self._statistics = json.loads(stats_info)['values']
-
- def get_full_configuration(self):
- return self._config
-
- def set_full_configuration(self, config_json):
- self.sock.send(b'setptree', flags=zmq.SNDMORE)
- self.sock.send(config_json)
- return self.sock.recv() == "OK"
-
- def get_mux_version(self):
- return self._server_version
-
- def get_services(self):
- srv_pt = self._config['services']
- return [Service(name, srv_pt[name]) for name in srv_pt]
-
- def get_subchannels(self):
- sub_pt = self._config['subchannels']
- return [Subchannel(name, sub_pt[name]) for name in sub_pt]
-
- def get_components(self):
- comp_pt = self._config['components']
- return [Component(name, comp_pt[name]) for name in comp_pt]
-
- def get_general_options(self):
- return General(self._config)
-
- def get_stats_dict(self):
- """Return a dictionary with all stats"""
- self.update_stats()
- return self._statistics
diff --git a/gui/muxrc.py b/gui/muxrc.py
deleted file mode 100644
index 7f28f54..0000000
--- a/gui/muxrc.py
+++ /dev/null
@@ -1,107 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-#
-# Copyright (C) 2019
-# Matthias P. Braendli, matthias.braendli@mpb.li
-#
-# http://www.opendigitalradio.org
-#
-# This file is part of ODR-DabMux.
-#
-# ODR-DabMux is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
-#
-# ODR-DabMux 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
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with ODR-DabMux. If not, see <http://www.gnu.org/licenses/>.
-import zmq
-import json
-
-class RCParameter(object):
- def __init__(self, param, value):
- self.param = param
- self.value = value
-
-class RCModule(object):
- """Container object for RC module"""
- def __init__(self, name):
- self.name = name
- self.parameters = []
-
-class MuxRemoteControl(object):
- """Interact with ODR-DabMux using the ZMQ RC"""
-
- def __init__(self, mux_host, mux_port=12722):
- self._host = mux_host
- self._port = mux_port
- self._ctx = zmq.Context()
-
- self.module_list = []
-
- def zRead(self, message_parts):
- sock = zmq.Socket(self._ctx, zmq.REQ)
- sock.setsockopt(zmq.LINGER, 0)
- sock.connect("tcp://{}:{}".format(self._host, self._port))
-
- for i, part in enumerate(message_parts):
- if i == len(message_parts) - 1:
- f = 0
- else:
- f = zmq.SNDMORE
-
- print("Send {} {}".format(i, part))
- sock.send(part.encode(), flags=f)
-
- print("Poll")
-
- # use poll for timeouts:
- poller = zmq.Poller()
- poller.register(sock, zmq.POLLIN)
- if poller.poll(5*1000): # 5s timeout in milliseconds
- recv = sock.recv_multipart()
- print("RX {}".format(recv))
- sock.close()
- return recv
- else:
- raise IOError("Timeout processing ZMQ request")
-
- def load(self):
- """Load the list of RC modules"""
- module_jsons = self.zRead(['list'])
-
- self.module_list = []
-
- for module_json in module_jsons:
- module = json.loads(module_json)
- name = module['name']
- mod = RCModule(name)
- module_params = self.zRead(['show', name])
- print("m_p", module_params)
-
- for param in module_params:
- p, v = param.split(b': ')
- mod.parameters.append(RCParameter(p, v))
-
- self.module_list.append(mod)
-
- def get_modules(self):
- return self.module_list
-
- def get_param_value(self, module, param):
- value = self.zRead(['get', module, param])
- if value[0] == b'fail':
- raise ValueError("Error getting param: {}".format(value[1]))
- else:
- return value[0]
-
- def set_param_value(self, module, param, value):
- ret = self.zRead(['set', module, param, value])
- if ret[0] == b'fail':
- raise ValueError("Error getting param: {}".format(ret[1]))
-
diff --git a/gui/odr-dabmux-gui.py b/gui/odr-dabmux-gui.py
deleted file mode 100755
index c469b35..0000000
--- a/gui/odr-dabmux-gui.py
+++ /dev/null
@@ -1,182 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-#
-# Copyright (C) 2016
-# Matthias P. Braendli, matthias.braendli@mpb.li
-#
-# http://www.opendigitalradio.org
-#
-# This is a management server for ODR-DabMux, and it will become much
-# more interesting in the future.
-#
-# Run this script and connect your browser to
-# http://localhost:8000 to show the currently running
-#
-# This file is part of ODR-DabMux.
-#
-# ODR-DabMux is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
-#
-# ODR-DabMux 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
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with ODR-DabMux. If not, see <http://www.gnu.org/licenses/>.
-
-import os
-import argparse
-import json
-import cherrypy
-import muxconfig
-import muxrc
-import jinja2
-
-class Root:
- def __init__(self, env, conf, rc):
- self.mconf = conf
- self.mrc = rc
- self.env = env
- self.mparam = ModuleParameter(env, rc)
-
- def _cp_dispatch(self, vpath):
- if len(vpath) == 3:
- vpath.pop(0) # /rc/
- cherrypy.request.params['module'] = vpath.pop(0) # /module name/
- cherrypy.request.params['param'] = vpath.pop(0) # /parameter name/
- return self.mparam
-
- return vpath
-
- @cherrypy.expose
- def config(self, config=None):
- if config == None:
- """Show the JSON ptree in a textbox for editing"""
- self.mconf.load()
- tmpl = self.env.get_template('configeditor.tpl')
- return tmpl.render(
- version = self.mconf.get_mux_version(),
- config = json.dumps(self.mconf.get_full_configuration(), indent=4),
- message = "")
- else:
- """Record the new configuration"""
- success = self.mconf.set_full_configuration(config)
- if success:
- successmessage = "Success"
- else:
- successmessage = "Failure"
- self.mconf.load()
- return template('configeditor',
- version = self.mconf.get_mux_version(),
- config = json.dumps(self.mconf.get_full_configuration(), indent=4),
- message = successmessage)
-
- @cherrypy.expose
- @cherrypy.tools.json_out()
- def config_json(self):
- """Return a application/json containing the full
- ptree of the mux"""
-
- self.mconf.load()
- return { 'version': self.mconf.get_mux_version(),
- 'config': self.mconf.get_full_configuration() }
-
- @cherrypy.expose
- def index(self):
- self.mconf.load()
- self.mrc.load()
- tmpl = self.env.get_template('index.tpl')
- return tmpl.render(
- version = self.mconf.get_mux_version(),
- g = self.mconf.get_general_options(),
- services = self.mconf.get_services(),
- subchannels = self.mconf.get_subchannels(),
- components = self.mconf.get_components(),
- rcmodules = self.mrc.get_modules())
-
- @cherrypy.expose
- def services(self):
- self.mconf.load()
- tmpl = self.env.get_template('services.tpl')
- return tmpl.render(
- version = self.mconf.get_mux_version(),
- services = self.mconf.get_services())
-
- @cherrypy.expose
- def stats(self):
- self.mconf.load()
- tmpl = self.env.get_template('stats.tpl')
- return tmpl.render(
- version = self.mconf.get_mux_version())
-
-
- @cherrypy.expose
- @cherrypy.tools.json_out()
- def stats_json(self):
- return self.mconf.get_stats_dict()
-
-class ModuleParameter:
- def __init__(self, env, rc):
- self.mrc = rc
- self.env = env
-
- @cherrypy.expose
- def index(self, module, param, newvalue=None):
- if newvalue != None:
- rc.set_param_value(module, param, newvalue)
- raise cherrypy.HTTPRedirect('/#rcmodules')
- else:
- self.mrc.load()
- value = self.mrc.get_param_value(module, param)
-
- if param in paramObj:
- paramList = paramObj[param]
- label = paramObj["labels"][param]
- else:
- paramList = []
- label = ""
-
- tmpl = self.env.get_template('rcparam.tpl')
- return tmpl.render(
- module = module,
- param = param,
- value = value,
- label = label,
- list = paramList)
-
-if __name__ == '__main__':
- # Get configuration file in argument
- parser = argparse.ArgumentParser(description='management server for ODR-DabMux')
- parser.add_argument('--host', default='127.0.0.1', help='socket host (default: 127.0.0.1)',required=False)
- parser.add_argument('--port', default='8000', help='socket port (default: 8000)',required=False)
- parser.add_argument('--mhost', default='127.0.0.1', help='mux host (default: 127.0.0.1)',required=False)
- parser.add_argument('--mport', default='12720', help='mux management server port (default: 12720)',required=False)
- parser.add_argument('--rcport', default='12722', help='mux zmq rc port (default: 12722)',required=False)
- cli_args = parser.parse_args()
-
- # Instanciate mux-configuration and mux-remote-control objects
- conf = muxconfig.ConfigurationHandler(cli_args.mhost, int(cli_args.mport))
- rc = muxrc.MuxRemoteControl(cli_args.mhost, int(cli_args.rcport))
-
- # Import selectable paramaters values
- paramFile = open("rcparam.json")
- paramStr = paramFile.read()
- paramObj = json.loads(paramStr)
-
- # Start cherrypy
- env = jinja2.Environment(loader=jinja2.FileSystemLoader('views'), trim_blocks=True)
- cherrypy.config.update({'server.socket_host': cli_args.host, 'server.socket_port': int(cli_args.port),})
- appconf = {
- '/': {
- 'tools.sessions.on': True,
- 'tools.staticdir.root': os.path.abspath(os.getcwd())
- },
- '/static': {
- 'tools.staticdir.on': True,
- 'tools.staticdir.dir': './static'
- }
- }
- cherrypy.quickstart(Root(env, conf, rc), '/', appconf)
diff --git a/gui/rcparam.json b/gui/rcparam.json
deleted file mode 100644
index f350060..0000000
--- a/gui/rcparam.json
+++ /dev/null
@@ -1,48 +0,0 @@
-{
- "labels": {
- "buffermanagement":"Buffer management",
- "ptysd":"Program-type mode",
- "pty":"Program type"
- },
- "buffermanagement": [
- {"value":"prebuffering", "desc":"prebuffering"},
- {"value":"timestamped", "desc":"timestamped"}
- ],
- "ptysd": [
- {"value":"dynamic", "desc":"dynamic"},
- {"value":"static", "desc":"static"}
- ],
- "pty": [
- {"value":"0", "desc":"None"},
- {"value":"1", "desc":"News"},
- {"value":"2", "desc":"Affairs"},
- {"value":"3", "desc":"Info"},
- {"value":"4", "desc":"Sport"},
- {"value":"5", "desc":"Educate"},
- {"value":"6", "desc":"Drama"},
- {"value":"7", "desc":"Arts"},
- {"value":"8", "desc":"Science"},
- {"value":"9", "desc":"Talk"},
- {"value":"10", "desc":"Pop"},
- {"value":"11", "desc":"Rock"},
- {"value":"12", "desc":"Easy"},
- {"value":"13", "desc":"Light classics"},
- {"value":"14", "desc":"Classics"},
- {"value":"15", "desc":"Other music"},
- {"value":"16", "desc":"Weather"},
- {"value":"17", "desc":"Finance"},
- {"value":"18", "desc":"Children"},
- {"value":"19", "desc":"Factual"},
- {"value":"20", "desc":"Religion"},
- {"value":"21", "desc":"Phone in"},
- {"value":"22", "desc":"Travel"},
- {"value":"23", "desc":"Leisure"},
- {"value":"24", "desc":"Jazz"},
- {"value":"25", "desc":"Country"},
- {"value":"26", "desc":"National music"},
- {"value":"27", "desc":"Oldies"},
- {"value":"28", "desc":"Folk"},
- {"value":"29", "desc":"Document"}
- ]
- }
- \ No newline at end of file
diff --git a/gui/static/intercooler-1.0.1.min.js b/gui/static/intercooler-1.0.1.min.js
deleted file mode 100644
index c89fdb9..0000000
--- a/gui/static/intercooler-1.0.1.min.js
+++ /dev/null
@@ -1,2 +0,0 @@
-/*! intercooler 1.0.1 2016-09-13 */
-!function(a,b){"function"==typeof define&&define.amd?define("intercooler",["jquery"],function(c){return a.Intercooler=b(c)}):"object"==typeof exports?module.exports=b(require("jquery")):a.Intercooler=b(jQuery)}(this,function($){var Intercooler=Intercooler||function(){"use strict";function remove(a){a.remove()}function showIndicator(a){a.closest(".ic-use-transition").length>0?(a.data("ic-use-transition",!0),a.removeClass("ic-use-transition")):a.show()}function hideIndicator(a){a.data("ic-use-transition")?(a.data("ic-use-transition",null),a.addClass("ic-use-transition")):a.hide()}function fixICAttributeName(a){return USE_DATA?"data-"+a:a}function getICAttribute(a,b){return a.attr(fixICAttributeName(b))}function setICAttribute(a,b,c){a.attr(fixICAttributeName(b),c)}function prepend(a,b){try{a.prepend(b)}catch(b){log(a,formatError(b),"ERROR")}if(getICAttribute(a,"ic-limit-children")){var c=parseInt(getICAttribute(a,"ic-limit-children"));a.children().length>c&&a.children().slice(c,a.children().length).remove()}}function append(a,b){try{a.append(b)}catch(b){log(a,formatError(b),"ERROR")}if(getICAttribute(a,"ic-limit-children")){var c=parseInt(getICAttribute(a,"ic-limit-children"));a.children().length>c&&a.children().slice(0,a.children().length-c).remove()}}function log(a,b,c){if(null==a&&(a=$("body")),a.trigger("log.ic",[b,c,a]),"ERROR"==c){window.console&&window.console.log("Intercooler Error : "+b);var d=closestAttrValue($("body"),"ic-post-errors-to");d&&$.post(d,{error:b})}}function uuid(){return _UUID++}function icSelectorFor(a){return getICAttributeSelector("ic-id='"+getIntercoolerId(a)+"'")}function parseInterval(a){return log(null,"POLL: Parsing interval string "+a,"DEBUG"),"null"==a||"false"==a||""==a?null:a.lastIndexOf("ms")==a.length-2?parseFloat(a.substr(0,a.length-2)):a.lastIndexOf("s")==a.length-1?1e3*parseFloat(a.substr(0,a.length-1)):1e3}function getICAttributeSelector(a){return"["+fixICAttributeName(a)+"]"}function initScrollHandler(){null==_scrollHandler&&(_scrollHandler=function(){$(getICAttributeSelector("ic-trigger-on='scrolled-into-view'")).each(function(){isScrolledIntoView(getTriggeredElement($(this)))&&1!=$(this).data("ic-scrolled-into-view-loaded")&&($(this).data("ic-scrolled-into-view-loaded",!0),fireICRequest($(this)))})},$(window).scroll(_scrollHandler))}function currentUrl(){return window.location.pathname+window.location.search+window.location.hash}function createDocument(a){var b=null;return/<(html|body)/i.test(a)?(b=document.documentElement.cloneNode(),b.innerHTML=a):(b=document.documentElement.cloneNode(!0),b.querySelector("body").innerHTML=a),$(b)}function getTarget(a){var b=$(a).closest(getICAttributeSelector("ic-target")),c=getICAttribute(b,"ic-target");return"this"==c?b:c&&0!=c.indexOf("this.")?0==c.indexOf("closest ")?a.closest(c.substr(8)):0==c.indexOf("find ")?a.find(c.substr(5)):$(c):a}function processHeaders(elt,xhr){elt.trigger("beforeHeaders.ic",[elt,xhr]),log(elt,"response headers: "+xhr.getAllResponseHeaders(),"DEBUG");var target=null;if(xhr.getResponseHeader("X-IC-Title")&&(document.title=xhr.getResponseHeader("X-IC-Title")),xhr.getResponseHeader("X-IC-Refresh")){var pathsToRefresh=xhr.getResponseHeader("X-IC-Refresh").split(",");log(elt,"X-IC-Refresh: refreshing "+pathsToRefresh,"DEBUG"),$.each(pathsToRefresh,function(a,b){refreshDependencies(b.replace(/ /g,""),elt)})}if(xhr.getResponseHeader("X-IC-Script")&&(log(elt,"X-IC-Script: evaling "+xhr.getResponseHeader("X-IC-Script"),"DEBUG"),eval(xhr.getResponseHeader("X-IC-Script"))),xhr.getResponseHeader("X-IC-Redirect")&&(log(elt,"X-IC-Redirect: redirecting to "+xhr.getResponseHeader("X-IC-Redirect"),"DEBUG"),window.location=xhr.getResponseHeader("X-IC-Redirect")),"true"==xhr.getResponseHeader("X-IC-CancelPolling")&&cancelPolling($(elt).closest(getICAttributeSelector("ic-poll"))),"true"==xhr.getResponseHeader("X-IC-ResumePolling")){var pollingElt=$(elt).closest(getICAttributeSelector("ic-poll"));setICAttribute(pollingElt,"ic-pause-polling",null),startPolling(pollingElt)}if(xhr.getResponseHeader("X-IC-SetPollInterval")){var pollingElt=$(elt).closest(getICAttributeSelector("ic-poll"));cancelPolling(pollingElt),setICAttribute(pollingElt,"ic-poll",xhr.getResponseHeader("X-IC-SetPollInterval")),startPolling(pollingElt)}xhr.getResponseHeader("X-IC-Open")&&(log(elt,"X-IC-Open: opening "+xhr.getResponseHeader("X-IC-Open"),"DEBUG"),window.open(xhr.getResponseHeader("X-IC-Open")));var triggerValue=xhr.getResponseHeader("X-IC-Trigger");if(triggerValue)if(log(elt,"X-IC-Trigger: found trigger "+triggerValue,"DEBUG"),target=getTarget(elt),xhr.getResponseHeader("X-IC-Trigger-Data")){var triggerArgs=$.parseJSON(xhr.getResponseHeader("X-IC-Trigger-Data"));target.trigger(triggerValue,triggerArgs)}else triggerValue.indexOf("{")>=0?$.each($.parseJSON(triggerValue),function(a,b){target.trigger(a,b)}):target.trigger(triggerValue,[]);var localVars=xhr.getResponseHeader("X-IC-Set-Local-Vars");return localVars&&$.each($.parseJSON(localVars),function(a,b){localStorage.setItem(a,b)}),xhr.getResponseHeader("X-IC-Remove")&&elt&&(target=getTarget(elt),log(elt,"X-IC-Remove header found.","DEBUG"),remove(target)),elt.trigger("afterHeaders.ic",[elt,xhr]),!0}function beforeRequest(a){a.addClass("disabled"),a.data("ic-request-in-flight",!0)}function requestCleanup(a,b){a.length>0&&hideIndicator(a),b.removeClass("disabled"),b.data("ic-request-in-flight",!1),b.data("ic-next-request")&&(b.data("ic-next-request")(),b.data("ic-next-request",null))}function replaceOrAddMethod(a,b){if("string"===$.type(a)){var c=/(&|^)_method=[^&]*/,d="&_method="+b;return c.test(a)?a.replace(c,d):a+d}return a.append("_method",b),a}function globalEval(a){return window.eval.call(window,a)}function closestAttrValue(a,b){var c=$(a).closest(getICAttributeSelector(b));return c.length>0?getICAttribute(c,b):null}function formatError(a){var b=a.toString()+"\n";try{b+=a.stack}catch(a){}return b}function handleRemoteRequest(a,b,c,d,e){beforeRequest(a),d=replaceOrAddMethod(d,b);var f=findIndicator(a);f.length>0&&showIndicator(f);var g,h=uuid(),i=new Date;g=USE_ACTUAL_HTTP_METHOD?b:"GET"==b?"GET":"POST";var j={type:g,url:c,data:d,dataType:"text",headers:{Accept:"text/html-partial, */*; q=0.9","X-IC-Request":!0,"X-HTTP-Method-Override":b},beforeSend:function(e,f){a.trigger("beforeSend.ic",[a,d,f,e,h]),log(a,"before AJAX request "+h+": "+b+" to "+c,"DEBUG");var g=closestAttrValue(a,"ic-on-beforeSend");g&&globalEval("(function (data, settings, xhr) {"+g+"})")(d,f,e)},success:function(b,c,d){a.trigger("success.ic",[a,b,c,d,h]),log(a,"AJAX request "+h+" was successful.","DEBUG");var g=closestAttrValue(a,"ic-on-success");if(!g||0!=globalEval("(function (data, textStatus, xhr) {"+g+"})")(b,c,d)){var i=new Date;try{if(processHeaders(a,d)){log(a,"Processed headers for request "+h+" in "+(new Date-i)+"ms","DEBUG");var j=new Date;if(d.getResponseHeader("X-IC-PushURL")||"true"==closestAttrValue(a,"ic-push-url"))try{requestCleanup(f,a);var k=d.getResponseHeader("X-IC-PushURL")||closestAttrValue(a,"ic-src");if(!_history)throw"History support not enabled";_history.snapshotForHistory(k)}catch(b){log(a,"Error during history snapshot for "+h+": "+formatError(b),"ERROR")}e(b,c,a,d),log(a,"Process content for request "+h+" in "+(new Date-j)+"ms","DEBUG")}a.trigger("after.success.ic",[a,b,c,d,h])}catch(b){log(a,"Error processing successful request "+h+" : "+formatError(b),"ERROR")}}},error:function(b,d,e){a.trigger("error.ic",[a,d,e,b]);var f=closestAttrValue(a,"ic-on-error");f&&globalEval("(function (status, str, xhr) {"+f+"})")(d,e,b),log(a,"AJAX request "+h+" to "+c+" experienced an error: "+e,"ERROR")},complete:function(b,c){log(a,"AJAX request "+h+" completed in "+(new Date-i)+"ms","DEBUG"),requestCleanup(f,a);try{$.contains(document,a[0])?$(a).trigger("complete.ic",[a,d,c,b,h]):$("body").trigger("complete.ic",[a,d,c,b,h])}catch(b){log(a,"Error during complete.ic event for "+h+" : "+formatError(b),"ERROR")}var e=closestAttrValue(a,"ic-on-complete");e&&globalEval("(function (xhr, status) {"+e+"})")(b,c)}};"string"!=$.type(d)&&(j.dataType=null,j.processData=!1,j.contentType=!1),$(document).trigger("beforeAjaxSend.ic",j),$.ajax(j)}function findIndicator(a){var b=null;if(getICAttribute($(a),"ic-indicator"))b=$(getICAttribute($(a),"ic-indicator")).first();else if(b=$(a).find(".ic-indicator").first(),0==b.length){var c=closestAttrValue(a,"ic-indicator");c?b=$(c).first():$(a).next().is(".ic-indicator")&&(b=$(a).next())}return b}function processIncludes(a,b){if(0==$.trim(b).indexOf("{")){var c=$.parseJSON(b);$.each(c,function(b,c){a=appendData(a,b,c)})}else $(b).each(function(){var b=$(this).serializeArray();$.each(b,function(b,c){a=appendData(a,c.name,c.value)})});return a}function processLocalVars(a,b){return $(b.split(",")).each(function(){var b=$.trim(this),c=localStorage.getItem(b);c&&(a=appendData(a,b,c))}),a}function appendData(a,b,c){return"string"===$.type(a)?a+"&"+b+"="+encodeURIComponent(c):(a.append(b,c),a)}function getParametersForElement(a,b,c){var d=getTarget(b),e=null;b.is("form")&&"multipart/form-data"==b.attr("enctype")?(e=new FormData(b[0]),e=appendData(e,"ic-request",!0)):(e="ic-request=true",e+="GET"!=a&&b.closest("form").length>0?"&"+b.closest("form").serialize():"&"+b.serialize());var f=closestAttrValue(b,"ic-prompt");if(f){var g=prompt(f);if(!g)return null;var h=closestAttrValue(b,"ic-prompt-name")||"ic-prompt-value";e=appendData(e,h,g)}b.attr("id")&&(e=appendData(e,"ic-element-id",b.attr("id"))),b.attr("name")&&(e=appendData(e,"ic-element-name",b.attr("name"))),getICAttribute(d,"ic-id")&&(e=appendData(e,"ic-id",getICAttribute(d,"ic-id"))),d.attr("id")&&(e=appendData(e,"ic-target-id",d.attr("id"))),c&&c.attr("id")&&(e=appendData(e,"ic-trigger-id",c.attr("id"))),c&&c.attr("name")&&(e=appendData(e,"ic-trigger-name",c.attr("name")));var i=closestAttrValue(b,"ic-include");i&&(e=processIncludes(e,i));var j=closestAttrValue(b,"ic-local-vars");return j&&(e=processLocalVars(e,j)),$(getICAttributeSelector("ic-global-include")).each(function(){e=processIncludes(e,getICAttribute($(this),"ic-global-include"))}),e=appendData(e,"ic-current-url",currentUrl()),log(b,"request parameters "+e,"DEBUG"),e}function maybeSetIntercoolerInfo(a){var b=getTarget(a);getIntercoolerId(b),1!=a.data("elementAdded.ic")&&(a.data("elementAdded.ic",!0),a.trigger("elementAdded.ic"))}function getIntercoolerId(a){return getICAttribute(a,"ic-id")||setICAttribute(a,"ic-id",uuid()),getICAttribute(a,"ic-id")}function processNodes(a){a.length>1?a.each(function(){processNodes($(this))}):(processMacros(a),processSources(a),processPolling(a),processTriggerOn(a),processRemoveAfter(a),processAddClasses(a),processRemoveClasses(a))}function fireReadyStuff(a){a.trigger("nodesProcessed.ic"),$.each(_readyHandlers,function(b,c){try{c(a)}catch(b){log(a,formatError(b),"ERROR")}})}function autoFocus(a){a.find("[autofocus]:last").focus()}function processMacros(a){$.each(_MACROS,function(b,c){0==$(a).closest(".ic-ignore").length&&($(a).is("["+c+"]")&&processMacro(c,$(a)),$(a).find("["+c+"]").each(function(){0==$(this).closest(".ic-ignore").length&&processMacro(c,$(this))}))})}function processSources(a){0==$(a).closest(".ic-ignore").length&&($(a).is(getICAttributeSelector("ic-src"))&&maybeSetIntercoolerInfo($(a)),$(a).find(getICAttributeSelector("ic-src")).each(function(){0==$(this).closest(".ic-ignore").length&&maybeSetIntercoolerInfo($(this))}))}function processPolling(a){0==$(a).closest(".ic-ignore").length&&($(a).is(getICAttributeSelector("ic-poll"))&&(maybeSetIntercoolerInfo($(a)),startPolling(a)),$(a).find(getICAttributeSelector("ic-poll")).each(function(){0==$(this).closest(".ic-ignore").length&&(maybeSetIntercoolerInfo($(this)),startPolling($(this)))}))}function processTriggerOn(a){0==$(a).closest(".ic-ignore").length&&(handleTriggerOn(a),$(a).find(getICAttributeSelector("ic-trigger-on")).each(function(){0==$(this).closest(".ic-ignore").length&&handleTriggerOn($(this))}))}function processRemoveAfter(a){0==$(a).closest(".ic-ignore").length&&(handleRemoveAfter(a),$(a).find(getICAttributeSelector("ic-remove-after")).each(function(){0==$(this).closest(".ic-ignore").length&&handleRemoveAfter($(this))}))}function processAddClasses(a){0==$(a).closest(".ic-ignore").length&&(handleAddClasses(a),$(a).find(getICAttributeSelector("ic-add-class")).each(function(){0==$(this).closest(".ic-ignore").length&&handleAddClasses($(this))}))}function processRemoveClasses(a){0==$(a).closest(".ic-ignore").length&&(handleRemoveClasses(a),$(a).find(getICAttributeSelector("ic-remove-class")).each(function(){0==$(this).closest(".ic-ignore").length&&handleRemoveClasses($(this))}))}function startPolling(a){if(null==a.data("ic-poll-interval-id")&&"true"!=getICAttribute($(a),"ic-pause-polling")){var b=parseInterval(getICAttribute(a,"ic-poll"));if(null!=b){var c=icSelectorFor(a),d=parseInt(getICAttribute(a,"ic-poll-repeats"))||-1,e=0;log(a,"POLL: Starting poll for element "+c,"DEBUG");var f=setInterval(function(){var b=$(c);a.trigger("onPoll.ic",b),0==b.length||e==d||a.data("ic-poll-interval-id")!=f?(log(a,"POLL: Clearing poll for element "+c,"DEBUG"),clearTimeout(f)):fireICRequest(b),e++},b);a.data("ic-poll-interval-id",f)}}}function cancelPolling(a){null!=a.data("ic-poll-interval-id")&&(clearTimeout(a.data("ic-poll-interval-id")),a.data("ic-poll-interval-id",null))}function refreshDependencies(a,b){log(b,"refreshing dependencies for path "+a,"DEBUG"),$(getICAttributeSelector("ic-src")).each(function(){var c=!1;"GET"==verbFor($(this))&&"ignore"!=getICAttribute($(this),"ic-deps")&&"undefined"==typeof getICAttribute($(this),"ic-poll")&&(isDependent(a,getICAttribute($(this),"ic-src"))?null!=b&&$(b)[0]==$(this)[0]||(fireICRequest($(this)),c=!0):(isDependent(a,getICAttribute($(this),"ic-deps"))||"*"==getICAttribute($(this),"ic-deps"))&&(null!=b&&$(b)[0]==$(this)[0]||(fireICRequest($(this)),c=!0))),c&&log($(this),"depends on path "+a+", refreshing...","DEBUG")})}function isDependent(a,b){return!!_isDependentFunction(a,b)}function verbFor(a){return getICAttribute(a,"ic-verb")?getICAttribute(a,"ic-verb").toUpperCase():"GET"}function eventFor(a,b){return"default"==a?$(b).is("button")?"click":$(b).is("form")?"submit":$(b).is(":input")?"change":"click":a}function preventDefault(a,b){return a.is("form")||a.is(":submit")&&1==a.closest("form").length||a.is("a")&&a.is("[href]")&&0!=a.attr("href").indexOf("#")}function handleRemoveAfter(a){if(getICAttribute($(a),"ic-remove-after")){var b=parseInterval(getICAttribute($(a),"ic-remove-after"));setTimeout(function(){remove(a)},b)}}function parseAndApplyClass(a,b,c){var d="",e=50;if(a.indexOf(":")>0){var f=a.split(":");d=f[0],e=parseInterval(f[1])}else d=a;setTimeout(function(){b[c](d)},e)}function handleAddClasses(a){if(getICAttribute($(a),"ic-add-class"))for(var b=getICAttribute($(a),"ic-add-class").split(","),c=b.length,d=0;d<c;d++)parseAndApplyClass($.trim(b[d]),a,"addClass")}function handleRemoveClasses(a){if(getICAttribute($(a),"ic-remove-class"))for(var b=getICAttribute($(a),"ic-remove-class").split(","),c=b.length,d=0;d<c;d++)parseAndApplyClass($.trim(b[d]),a,"removeClass")}function getTriggeredElement(elt){var triggerFrom=getICAttribute(elt,"ic-trigger-from");return triggerFrom?$($.inArray(triggerFrom,["document","window"])>=0?eval(triggerFrom):triggerFrom):elt}function handleTriggerOn(a){if(getICAttribute($(a),"ic-trigger-on"))if("load"==getICAttribute($(a),"ic-trigger-on"))fireICRequest(a);else if("scrolled-into-view"==getICAttribute($(a),"ic-trigger-on"))initScrollHandler(),setTimeout(function(){$(window).trigger("scroll")},100);else{var b=getICAttribute($(a),"ic-trigger-on").split(" ");$(getTriggeredElement(a)).on(eventFor(b[0],$(a)),function(c){var d=closestAttrValue(a,"ic-on-beforeTrigger");if(d&&0==globalEval("(function (evt, elt) {"+d+"})")(c,$(a)))return log($(a),"ic-trigger cancelled by ic-on-beforeTrigger","DEBUG"),!1;if("changed"==b[1]){var e=$(a).val(),f=$(a).data("ic-previous-val");$(a).data("ic-previous-val",e),e!=f&&fireICRequest($(a))}else fireICRequest($(a));return!preventDefault(a,c)||(c.preventDefault(),!1)})}}function macroIs(a,b){return a==fixICAttributeName(b)}function processMacro(a,b){macroIs(a,"ic-post-to")&&(setIfAbsent(b,"ic-src",getICAttribute(b,"ic-post-to")),setIfAbsent(b,"ic-verb","POST"),setIfAbsent(b,"ic-trigger-on","default"),setIfAbsent(b,"ic-deps","ignore")),macroIs(a,"ic-put-to")&&(setIfAbsent(b,"ic-src",getICAttribute(b,"ic-put-to")),setIfAbsent(b,"ic-verb","PUT"),setIfAbsent(b,"ic-trigger-on","default"),setIfAbsent(b,"ic-deps","ignore")),macroIs(a,"ic-patch-to")&&(setIfAbsent(b,"ic-src",getICAttribute(b,"ic-patch-to")),setIfAbsent(b,"ic-verb","PATCH"),setIfAbsent(b,"ic-trigger-on","default"),setIfAbsent(b,"ic-deps","ignore")),macroIs(a,"ic-get-from")&&(setIfAbsent(b,"ic-src",getICAttribute(b,"ic-get-from")),setIfAbsent(b,"ic-trigger-on","default"),setIfAbsent(b,"ic-deps","ignore")),macroIs(a,"ic-delete-from")&&(setIfAbsent(b,"ic-src",getICAttribute(b,"ic-delete-from")),setIfAbsent(b,"ic-verb","DELETE"),setIfAbsent(b,"ic-trigger-on","default"),setIfAbsent(b,"ic-deps","ignore")),macroIs(a,"ic-action")&&setIfAbsent(b,"ic-trigger-on","default");var c=null,d=null;if(macroIs(a,"ic-style-src")){c=getICAttribute(b,"ic-style-src").split(":");var e=c[0];d=c[1],setIfAbsent(b,"ic-src",d),setIfAbsent(b,"ic-target","this.style."+e)}if(macroIs(a,"ic-attr-src")){c=getICAttribute(b,"ic-attr-src").split(":");var f=c[0];d=c[1],setIfAbsent(b,"ic-src",d),setIfAbsent(b,"ic-target","this."+f)}macroIs(a,"ic-prepend-from")&&setIfAbsent(b,"ic-src",getICAttribute(b,"ic-prepend-from")),macroIs(a,"ic-append-from")&&setIfAbsent(b,"ic-src",getICAttribute(b,"ic-append-from"))}function setIfAbsent(a,b,c){null==getICAttribute(a,b)&&setICAttribute(a,b,c)}function isScrolledIntoView(a){var b=$(window).scrollTop(),c=b+$(window).height(),d=$(a).offset().top,e=d+$(a).height();return e>=b&&d<=c&&e<=c&&d>=b}function maybeScrollToTarget(a,b){if("false"!=closestAttrValue(a,"ic-scroll-to-target")&&("true"==closestAttrValue(a,"ic-scroll-to-target")||"true"==closestAttrValue(b,"ic-scroll-to-target"))){var c=-50;closestAttrValue(a,"ic-scroll-offset")?c=parseInt(closestAttrValue(a,"ic-scroll-offset")):closestAttrValue(b,"ic-scroll-offset")&&(c=parseInt(closestAttrValue(b,"ic-scroll-offset")));var d=b.offset().top,e=$(window).scrollTop(),f=e+window.innerHeight;(d<e||d>f)&&(c+=d,$("html,body").animate({scrollTop:c},400))}}function getTransitionDuration(a,b){var c=closestAttrValue(a,"ic-transition-duration");if(c)return parseInterval(c);if(c=closestAttrValue(b,"ic-transition-duration"))return parseInterval(c);var d=0,e=$(b).css("transition-duration");e&&(d+=parseInterval(e));var f=$(b).css("transition-delay");return f&&(d+=parseInterval(f)),d}function processICResponse(a,b,c){if(a&&""!=a&&" "!=a){log(b,"response content: \n"+a,"DEBUG");var d=getTarget(b),e=maybeFilter(a,closestAttrValue(b,"ic-select-from-response")),f=function(){if("true"==closestAttrValue(b,"ic-replace-target")){try{d.replaceWith(e)}catch(a){log(b,formatError(a),"ERROR")}processNodes(e),fireReadyStuff($(d)),autoFocus($(d))}else{if(b.is(getICAttributeSelector("ic-prepend-from")))prepend(d,e),processNodes(e),fireReadyStuff($(d)),autoFocus($(d));else if(b.is(getICAttributeSelector("ic-append-from")))append(d,e),processNodes(e),fireReadyStuff($(d)),autoFocus($(d));else{try{d.empty().append(e)}catch(a){log(b,formatError(a),"ERROR")}$(d).children().each(function(){processNodes($(this))}),fireReadyStuff($(d)),autoFocus($(d))}1!=c&&maybeScrollToTarget(b,d)}};if(0==d.length)return void log(b,"Invalid target for element: "+getICAttribute($(b).closest(getICAttributeSelector("ic-target")),"ic-target"),"ERROR");var g=getTransitionDuration(b,d);d.addClass("ic-transitioning"),setTimeout(function(){try{f()}catch(a){log(b,"Error during content swaop : "+formatError(a),"ERROR")}setTimeout(function(){try{d.removeClass("ic-transitioning"),_history&&_history.updateHistory(),d.trigger("complete_transition.ic",[d])}catch(a){log(b,"Error during transition complete : "+formatError(a),"ERROR")}},20)},g)}else log(b,"Empty response, nothing to do here.","DEBUG")}function maybeFilter(a,b){var c=$.parseHTML(a,null,!0),d=$(c);return b?d.filter(b).add(d.find(b)).contents():d}function getStyleTarget(a){var b=closestAttrValue(a,"ic-target");return b&&0==b.indexOf("this.style.")?b.substr(11):null}function getAttrTarget(a){var b=closestAttrValue(a,"ic-target");return b&&0==b.indexOf("this.")?b.substr(5):null}function fireICRequest(a,b){var c=a;a.is(getICAttributeSelector("ic-src"))||void 0!=getICAttribute(a,"ic-action")||(a=a.closest(getICAttributeSelector("ic-src")));var d=closestAttrValue(a,"ic-confirm");if((!d||confirm(d))&&a.length>0){var e=uuid();a.data("ic-event-id",e);var f=function(){if(1==a.data("ic-request-in-flight"))return void a.data("ic-next-request",f);if(a.data("ic-event-id")==e){var d=getStyleTarget(a),g=d?null:getAttrTarget(a),h=verbFor(a),i=getICAttribute(a,"ic-src");if(i){var j=b||function(b){d?a.css(d,b):g?a.attr(g,b):(processICResponse(b,a),"GET"!=h&&refreshDependencies(getICAttribute(a,"ic-src"),a))},k=getParametersForElement(h,a,c);k&&handleRemoteRequest(a,h,i,k,j)}var l=getICAttribute(a,"ic-action");l&&invokeLocalAction(a,l)}},g=closestAttrValue(a,"ic-trigger-delay");g?setTimeout(f,parseInterval(g)):f()}}function invokeLocalAction(a,b){var c=getTarget(a),d=b.split(";"),e=[],f=0;$.each(d,function(a,b){var d=$.trim(b),g=d,h=[];d.indexOf(":")>0&&(g=d.substr(0,d.indexOf(":")),h=computeArgs(d.substr(d.indexOf(":")+1,d.length))),""==g||("delay"==g?(null==f&&(f=0),f+=parseInterval(h[0]+"")):(null==f&&(f=420),e.push([f,makeApplyAction(c,g,h)]),f=null))}),f=0,$.each(e,function(a,b){f+=b[0],setTimeout(b[1],f)})}function computeArgs(args){try{return eval("["+args+"]")}catch(a){return[$.trim(args)]}}function makeApplyAction(a,b,c){return function(){var d=a[b]||window[b];d?d.apply(a,c):log(a,"Action "+b+" was not found","ERROR")}}function newIntercoolerHistory(a,b,c,d){function e(a){return null==a||a.slotLimit!=c||a.historyVersion!=d||null==a.lruList}function f(){for(var b=[],e=0;e<a.length;e++)0==a.key(e).indexOf(s)&&b.push(a.key(e));for(var f=0;f<b.length;f++)a.removeItem(b[f]);a.removeItem(r),t={slotLimit:c,historyVersion:d,lruList:[]}}function g(b){var c=t.lruList,d=c.indexOf(b),e=n($("body"));if(d>=0)log(e,"URL found in LRU list, moving to end","INFO"),c.splice(d,1),c.push(b);else if(log(e,"URL not found in LRU list, adding","INFO"),c.push(b),c.length>t.slotLimit){var f=c.shift();log(e,"History overflow, removing local history for "+f,"INFO"),a.removeItem(s+f)}return a.setItem(r,JSON.stringify(t)),c}function h(b){var d=JSON.stringify(b);try{a.setItem(b.id,d)}catch(e){try{f(),a.setItem(b.id,d)}catch(a){log(n($("body")),"Unable to save intercooler history with entire history cleared, is something else eating local storage? History Limit:"+c,"ERROR")}}}function i(a,b,c){var d={url:c,id:s+c,content:a,yOffset:b,timestamp:(new Date).getTime()};return g(c),h(d),d}function j(a){if(null==a.onpopstate||1!=a.onpopstate["ic-on-pop-state-handler"]){var b=a.onpopstate;a.onpopstate=function(a){n($("body")).trigger("handle.onpopstate.ic"),m(a)||b&&b(a),n($("body")).trigger("pageLoad.ic")},a.onpopstate["ic-on-pop-state-handler"]=!0}}function k(){u&&(l(u.newUrl,currentUrl(),u.oldHtml,u.yOffset),u=null)}function l(a,c,d,e){var f=i(d,e,c);b.replaceState({"ic-id":f.id},"","");var g=n($("body")),h=i(g.html(),window.pageYOffset,a);b.pushState({"ic-id":h.id},"",a),g.trigger("pushUrl.ic",[g,h])}function m(b){var c=b.state;if(c&&c["ic-id"]){var d=JSON.parse(a.getItem(c["ic-id"]));if(d)return processICResponse(d.content,n($("body")),!0),d.yOffset&&window.scrollTo(0,d.yOffset),!0;$.get(currentUrl(),{"ic-restore-history":!0},function(a,b){var c=createDocument(a),d=n(c).html();processICResponse(d,n($("body")),!0)})}return!1}function n(a){var b=a.find(getICAttributeSelector("ic-history-elt"));return b.length>0?b:a}function o(a){var b=n($("body"));b.trigger("beforeHistorySnapshot.ic",[b]),u={newUrl:a,oldHtml:b.html(),yOffset:window.pageYOffset}}function p(){var b="",c=[];for(var d in a)c.push(d);c.sort();var e=0;for(var f in c){var g=2*a[c[f]].length;e+=g,b+=c[f]+"="+(g/1024/1024).toFixed(2)+" MB\n"}return b+"\nTOTAL LOCAL STORAGE: "+(e/1024/1024).toFixed(2)+" MB"}function q(){return t}var r="ic-history-support",s="ic-hist-elt-",t=JSON.parse(a.getItem(r)),u=null;return e(t)&&(log(n($("body")),"Intercooler History configuration changed, clearing history","INFO"),f()),null==t&&(t={slotLimit:c,historyVersion:d,lruList:[]}),{clearHistory:f,updateHistory:k,addPopStateHandler:j,snapshotForHistory:o,_internal:{addPopStateHandler:j,supportData:q,dumpLocalStorage:p,updateLRUList:g}}}function getSlotLimit(){return 20}function refresh(a){return"string"==typeof a||a instanceof String?refreshDependencies(a):fireICRequest(a),Intercooler}function init(){var a=$("body");processNodes(a),fireReadyStuff(a),_history&&_history.addPopStateHandler(window),location.search&&location.search.indexOf("ic-launch-debugger=true")>=0&&Intercooler.debug()}var USE_DATA="true"==$('meta[name="intercoolerjs:use-data-prefix"]').attr("content"),USE_ACTUAL_HTTP_METHOD="true"==$('meta[name="intercoolerjs:use-actual-http-method"]').attr("content"),_MACROS=$.map(["ic-get-from","ic-post-to","ic-put-to","ic-patch-to","ic-delete-from","ic-style-src","ic-attr-src","ic-prepend-from","ic-append-from","ic-action"],function(a){return fixICAttributeName(a)}),_scrollHandler=null,_UUID=1,_readyHandlers=[],_isDependentFunction=function(a,b){if(!a||!b)return!1;var c=a.split(/[\?#]/,1)[0].split("/").filter(function(a){return""!=a}),d=b.split(/[\?#]/,1)[0].split("/").filter(function(a){return""!=a});return""!=c&&""!=d&&(d.slice(0,c.length).join("/")==c.join("/")||c.slice(0,d.length).join("/")==d.join("/"))},_history=null;try{_history=newIntercoolerHistory(localStorage,window.history,getSlotLimit(),.1)}catch(a){log($("body"),"Could not initialize history","WARN")}return $.ajaxTransport("text",function(a,b){if("#"==b.url[0]){var c=fixICAttributeName("ic-local-"),d=$(b.url),e=[],f=200,g="OK";d.each(function(a,b){$.each(b.attributes,function(a,b){if(b.name.substr(0,c.length)==c){var d=b.name.substring(c.length);if("status"==d){var h=b.value.match(/(\d+)\s?(.*)/);null!=h?(f=h[1],g=h[2]):(f="500",g="Attribute Error")}else e.push(d+": "+b.value)}})});var h=d.length>0?d.html():"";return{send:function(a,b){b(f,g,{html:h},e.join("\n"))},abort:function(){}}}return null}),$(function(){init()}),{refresh:refresh,history:_history,triggerRequest:fireICRequest,processNodes:processNodes,closestAttrValue:closestAttrValue,verbFor:verbFor,isDependent:isDependent,getTarget:getTarget,processHeaders:processHeaders,setIsDependentFunction:function(a){_isDependentFunction=a},ready:function(a){_readyHandlers.push(a)},debug:function(){var a=closestAttrValue("body","ic-debugger-url")||"https://intercoolerreleases-leaddynocom.netdna-ssl.com/intercooler-debugger.js";$.getScript(a).fail(function(a,b,c){log($("body"),formatError(c),"ERROR")})},_internal:{init:init,replaceOrAddMethod:replaceOrAddMethod}}}();return Intercooler}); \ No newline at end of file
diff --git a/gui/static/jquery-1.10.2.min.js b/gui/static/jquery-1.10.2.min.js
deleted file mode 100644
index da41706..0000000
--- a/gui/static/jquery-1.10.2.min.js
+++ /dev/null
@@ -1,6 +0,0 @@
-/*! jQuery v1.10.2 | (c) 2005, 2013 jQuery Foundation, Inc. | jquery.org/license
-//@ sourceMappingURL=jquery-1.10.2.min.map
-*/
-(function(e,t){var n,r,i=typeof t,o=e.location,a=e.document,s=a.documentElement,l=e.jQuery,u=e.$,c={},p=[],f="1.10.2",d=p.concat,h=p.push,g=p.slice,m=p.indexOf,y=c.toString,v=c.hasOwnProperty,b=f.trim,x=function(e,t){return new x.fn.init(e,t,r)},w=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,T=/\S+/g,C=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,N=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,k=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,E=/^[\],:{}\s]*$/,S=/(?:^|:|,)(?:\s*\[)+/g,A=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,j=/"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g,D=/^-ms-/,L=/-([\da-z])/gi,H=function(e,t){return t.toUpperCase()},q=function(e){(a.addEventListener||"load"===e.type||"complete"===a.readyState)&&(_(),x.ready())},_=function(){a.addEventListener?(a.removeEventListener("DOMContentLoaded",q,!1),e.removeEventListener("load",q,!1)):(a.detachEvent("onreadystatechange",q),e.detachEvent("onload",q))};x.fn=x.prototype={jquery:f,constructor:x,init:function(e,n,r){var i,o;if(!e)return this;if("string"==typeof e){if(i="<"===e.charAt(0)&&">"===e.charAt(e.length-1)&&e.length>=3?[null,e,null]:N.exec(e),!i||!i[1]&&n)return!n||n.jquery?(n||r).find(e):this.constructor(n).find(e);if(i[1]){if(n=n instanceof x?n[0]:n,x.merge(this,x.parseHTML(i[1],n&&n.nodeType?n.ownerDocument||n:a,!0)),k.test(i[1])&&x.isPlainObject(n))for(i in n)x.isFunction(this[i])?this[i](n[i]):this.attr(i,n[i]);return this}if(o=a.getElementById(i[2]),o&&o.parentNode){if(o.id!==i[2])return r.find(e);this.length=1,this[0]=o}return this.context=a,this.selector=e,this}return e.nodeType?(this.context=this[0]=e,this.length=1,this):x.isFunction(e)?r.ready(e):(e.selector!==t&&(this.selector=e.selector,this.context=e.context),x.makeArray(e,this))},selector:"",length:0,toArray:function(){return g.call(this)},get:function(e){return null==e?this.toArray():0>e?this[this.length+e]:this[e]},pushStack:function(e){var t=x.merge(this.constructor(),e);return t.prevObject=this,t.context=this.context,t},each:function(e,t){return x.each(this,e,t)},ready:function(e){return x.ready.promise().done(e),this},slice:function(){return this.pushStack(g.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(0>e?t:0);return this.pushStack(n>=0&&t>n?[this[n]]:[])},map:function(e){return this.pushStack(x.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:h,sort:[].sort,splice:[].splice},x.fn.init.prototype=x.fn,x.extend=x.fn.extend=function(){var e,n,r,i,o,a,s=arguments[0]||{},l=1,u=arguments.length,c=!1;for("boolean"==typeof s&&(c=s,s=arguments[1]||{},l=2),"object"==typeof s||x.isFunction(s)||(s={}),u===l&&(s=this,--l);u>l;l++)if(null!=(o=arguments[l]))for(i in o)e=s[i],r=o[i],s!==r&&(c&&r&&(x.isPlainObject(r)||(n=x.isArray(r)))?(n?(n=!1,a=e&&x.isArray(e)?e:[]):a=e&&x.isPlainObject(e)?e:{},s[i]=x.extend(c,a,r)):r!==t&&(s[i]=r));return s},x.extend({expando:"jQuery"+(f+Math.random()).replace(/\D/g,""),noConflict:function(t){return e.$===x&&(e.$=u),t&&e.jQuery===x&&(e.jQuery=l),x},isReady:!1,readyWait:1,holdReady:function(e){e?x.readyWait++:x.ready(!0)},ready:function(e){if(e===!0?!--x.readyWait:!x.isReady){if(!a.body)return setTimeout(x.ready);x.isReady=!0,e!==!0&&--x.readyWait>0||(n.resolveWith(a,[x]),x.fn.trigger&&x(a).trigger("ready").off("ready"))}},isFunction:function(e){return"function"===x.type(e)},isArray:Array.isArray||function(e){return"array"===x.type(e)},isWindow:function(e){return null!=e&&e==e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?c[y.call(e)]||"object":typeof e},isPlainObject:function(e){var n;if(!e||"object"!==x.type(e)||e.nodeType||x.isWindow(e))return!1;try{if(e.constructor&&!v.call(e,"constructor")&&!v.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(r){return!1}if(x.support.ownLast)for(n in e)return v.call(e,n);for(n in e);return n===t||v.call(e,n)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw Error(e)},parseHTML:function(e,t,n){if(!e||"string"!=typeof e)return null;"boolean"==typeof t&&(n=t,t=!1),t=t||a;var r=k.exec(e),i=!n&&[];return r?[t.createElement(r[1])]:(r=x.buildFragment([e],t,i),i&&x(i).remove(),x.merge([],r.childNodes))},parseJSON:function(n){return e.JSON&&e.JSON.parse?e.JSON.parse(n):null===n?n:"string"==typeof n&&(n=x.trim(n),n&&E.test(n.replace(A,"@").replace(j,"]").replace(S,"")))?Function("return "+n)():(x.error("Invalid JSON: "+n),t)},parseXML:function(n){var r,i;if(!n||"string"!=typeof n)return null;try{e.DOMParser?(i=new DOMParser,r=i.parseFromString(n,"text/xml")):(r=new ActiveXObject("Microsoft.XMLDOM"),r.async="false",r.loadXML(n))}catch(o){r=t}return r&&r.documentElement&&!r.getElementsByTagName("parsererror").length||x.error("Invalid XML: "+n),r},noop:function(){},globalEval:function(t){t&&x.trim(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){return e.replace(D,"ms-").replace(L,H)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,t,n){var r,i=0,o=e.length,a=M(e);if(n){if(a){for(;o>i;i++)if(r=t.apply(e[i],n),r===!1)break}else for(i in e)if(r=t.apply(e[i],n),r===!1)break}else if(a){for(;o>i;i++)if(r=t.call(e[i],i,e[i]),r===!1)break}else for(i in e)if(r=t.call(e[i],i,e[i]),r===!1)break;return e},trim:b&&!b.call("\ufeff\u00a0")?function(e){return null==e?"":b.call(e)}:function(e){return null==e?"":(e+"").replace(C,"")},makeArray:function(e,t){var n=t||[];return null!=e&&(M(Object(e))?x.merge(n,"string"==typeof e?[e]:e):h.call(n,e)),n},inArray:function(e,t,n){var r;if(t){if(m)return m.call(t,e,n);for(r=t.length,n=n?0>n?Math.max(0,r+n):n:0;r>n;n++)if(n in t&&t[n]===e)return n}return-1},merge:function(e,n){var r=n.length,i=e.length,o=0;if("number"==typeof r)for(;r>o;o++)e[i++]=n[o];else while(n[o]!==t)e[i++]=n[o++];return e.length=i,e},grep:function(e,t,n){var r,i=[],o=0,a=e.length;for(n=!!n;a>o;o++)r=!!t(e[o],o),n!==r&&i.push(e[o]);return i},map:function(e,t,n){var r,i=0,o=e.length,a=M(e),s=[];if(a)for(;o>i;i++)r=t(e[i],i,n),null!=r&&(s[s.length]=r);else for(i in e)r=t(e[i],i,n),null!=r&&(s[s.length]=r);return d.apply([],s)},guid:1,proxy:function(e,n){var r,i,o;return"string"==typeof n&&(o=e[n],n=e,e=o),x.isFunction(e)?(r=g.call(arguments,2),i=function(){return e.apply(n||this,r.concat(g.call(arguments)))},i.guid=e.guid=e.guid||x.guid++,i):t},access:function(e,n,r,i,o,a,s){var l=0,u=e.length,c=null==r;if("object"===x.type(r)){o=!0;for(l in r)x.access(e,n,l,r[l],!0,a,s)}else if(i!==t&&(o=!0,x.isFunction(i)||(s=!0),c&&(s?(n.call(e,i),n=null):(c=n,n=function(e,t,n){return c.call(x(e),n)})),n))for(;u>l;l++)n(e[l],r,s?i:i.call(e[l],l,n(e[l],r)));return o?e:c?n.call(e):u?n(e[0],r):a},now:function(){return(new Date).getTime()},swap:function(e,t,n,r){var i,o,a={};for(o in t)a[o]=e.style[o],e.style[o]=t[o];i=n.apply(e,r||[]);for(o in t)e.style[o]=a[o];return i}}),x.ready.promise=function(t){if(!n)if(n=x.Deferred(),"complete"===a.readyState)setTimeout(x.ready);else if(a.addEventListener)a.addEventListener("DOMContentLoaded",q,!1),e.addEventListener("load",q,!1);else{a.attachEvent("onreadystatechange",q),e.attachEvent("onload",q);var r=!1;try{r=null==e.frameElement&&a.documentElement}catch(i){}r&&r.doScroll&&function o(){if(!x.isReady){try{r.doScroll("left")}catch(e){return setTimeout(o,50)}_(),x.ready()}}()}return n.promise(t)},x.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(e,t){c["[object "+t+"]"]=t.toLowerCase()});function M(e){var t=e.length,n=x.type(e);return x.isWindow(e)?!1:1===e.nodeType&&t?!0:"array"===n||"function"!==n&&(0===t||"number"==typeof t&&t>0&&t-1 in e)}r=x(a),function(e,t){var n,r,i,o,a,s,l,u,c,p,f,d,h,g,m,y,v,b="sizzle"+-new Date,w=e.document,T=0,C=0,N=st(),k=st(),E=st(),S=!1,A=function(e,t){return e===t?(S=!0,0):0},j=typeof t,D=1<<31,L={}.hasOwnProperty,H=[],q=H.pop,_=H.push,M=H.push,O=H.slice,F=H.indexOf||function(e){var t=0,n=this.length;for(;n>t;t++)if(this[t]===e)return t;return-1},B="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",P="[\\x20\\t\\r\\n\\f]",R="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",W=R.replace("w","w#"),$="\\["+P+"*("+R+")"+P+"*(?:([*^$|!~]?=)"+P+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+W+")|)|)"+P+"*\\]",I=":("+R+")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+$.replace(3,8)+")*)|.*)\\)|)",z=RegExp("^"+P+"+|((?:^|[^\\\\])(?:\\\\.)*)"+P+"+$","g"),X=RegExp("^"+P+"*,"+P+"*"),U=RegExp("^"+P+"*([>+~]|"+P+")"+P+"*"),V=RegExp(P+"*[+~]"),Y=RegExp("="+P+"*([^\\]'\"]*)"+P+"*\\]","g"),J=RegExp(I),G=RegExp("^"+W+"$"),Q={ID:RegExp("^#("+R+")"),CLASS:RegExp("^\\.("+R+")"),TAG:RegExp("^("+R.replace("w","w*")+")"),ATTR:RegExp("^"+$),PSEUDO:RegExp("^"+I),CHILD:RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+P+"*(even|odd|(([+-]|)(\\d*)n|)"+P+"*(?:([+-]|)"+P+"*(\\d+)|))"+P+"*\\)|)","i"),bool:RegExp("^(?:"+B+")$","i"),needsContext:RegExp("^"+P+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+P+"*((?:-\\d)?\\d*)"+P+"*\\)|)(?=[^-]|$)","i")},K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,et=/^(?:input|select|textarea|button)$/i,tt=/^h\d$/i,nt=/'|\\/g,rt=RegExp("\\\\([\\da-f]{1,6}"+P+"?|("+P+")|.)","ig"),it=function(e,t,n){var r="0x"+t-65536;return r!==r||n?t:0>r?String.fromCharCode(r+65536):String.fromCharCode(55296|r>>10,56320|1023&r)};try{M.apply(H=O.call(w.childNodes),w.childNodes),H[w.childNodes.length].nodeType}catch(ot){M={apply:H.length?function(e,t){_.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function at(e,t,n,i){var o,a,s,l,u,c,d,m,y,x;if((t?t.ownerDocument||t:w)!==f&&p(t),t=t||f,n=n||[],!e||"string"!=typeof e)return n;if(1!==(l=t.nodeType)&&9!==l)return[];if(h&&!i){if(o=Z.exec(e))if(s=o[1]){if(9===l){if(a=t.getElementById(s),!a||!a.parentNode)return n;if(a.id===s)return n.push(a),n}else if(t.ownerDocument&&(a=t.ownerDocument.getElementById(s))&&v(t,a)&&a.id===s)return n.push(a),n}else{if(o[2])return M.apply(n,t.getElementsByTagName(e)),n;if((s=o[3])&&r.getElementsByClassName&&t.getElementsByClassName)return M.apply(n,t.getElementsByClassName(s)),n}if(r.qsa&&(!g||!g.test(e))){if(m=d=b,y=t,x=9===l&&e,1===l&&"object"!==t.nodeName.toLowerCase()){c=mt(e),(d=t.getAttribute("id"))?m=d.replace(nt,"\\$&"):t.setAttribute("id",m),m="[id='"+m+"'] ",u=c.length;while(u--)c[u]=m+yt(c[u]);y=V.test(e)&&t.parentNode||t,x=c.join(",")}if(x)try{return M.apply(n,y.querySelectorAll(x)),n}catch(T){}finally{d||t.removeAttribute("id")}}}return kt(e.replace(z,"$1"),t,n,i)}function st(){var e=[];function t(n,r){return e.push(n+=" ")>o.cacheLength&&delete t[e.shift()],t[n]=r}return t}function lt(e){return e[b]=!0,e}function ut(e){var t=f.createElement("div");try{return!!e(t)}catch(n){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function ct(e,t){var n=e.split("|"),r=e.length;while(r--)o.attrHandle[n[r]]=t}function pt(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&(~t.sourceIndex||D)-(~e.sourceIndex||D);if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function ft(e){return function(t){var n=t.nodeName.toLowerCase();return"input"===n&&t.type===e}}function dt(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function ht(e){return lt(function(t){return t=+t,lt(function(n,r){var i,o=e([],n.length,t),a=o.length;while(a--)n[i=o[a]]&&(n[i]=!(r[i]=n[i]))})})}s=at.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?"HTML"!==t.nodeName:!1},r=at.support={},p=at.setDocument=function(e){var n=e?e.ownerDocument||e:w,i=n.defaultView;return n!==f&&9===n.nodeType&&n.documentElement?(f=n,d=n.documentElement,h=!s(n),i&&i.attachEvent&&i!==i.top&&i.attachEvent("onbeforeunload",function(){p()}),r.attributes=ut(function(e){return e.className="i",!e.getAttribute("className")}),r.getElementsByTagName=ut(function(e){return e.appendChild(n.createComment("")),!e.getElementsByTagName("*").length}),r.getElementsByClassName=ut(function(e){return e.innerHTML="<div class='a'></div><div class='a i'></div>",e.firstChild.className="i",2===e.getElementsByClassName("i").length}),r.getById=ut(function(e){return d.appendChild(e).id=b,!n.getElementsByName||!n.getElementsByName(b).length}),r.getById?(o.find.ID=function(e,t){if(typeof t.getElementById!==j&&h){var n=t.getElementById(e);return n&&n.parentNode?[n]:[]}},o.filter.ID=function(e){var t=e.replace(rt,it);return function(e){return e.getAttribute("id")===t}}):(delete o.find.ID,o.filter.ID=function(e){var t=e.replace(rt,it);return function(e){var n=typeof e.getAttributeNode!==j&&e.getAttributeNode("id");return n&&n.value===t}}),o.find.TAG=r.getElementsByTagName?function(e,n){return typeof n.getElementsByTagName!==j?n.getElementsByTagName(e):t}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},o.find.CLASS=r.getElementsByClassName&&function(e,n){return typeof n.getElementsByClassName!==j&&h?n.getElementsByClassName(e):t},m=[],g=[],(r.qsa=K.test(n.querySelectorAll))&&(ut(function(e){e.innerHTML="<select><option selected=''></option></select>",e.querySelectorAll("[selected]").length||g.push("\\["+P+"*(?:value|"+B+")"),e.querySelectorAll(":checked").length||g.push(":checked")}),ut(function(e){var t=n.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("t",""),e.querySelectorAll("[t^='']").length&&g.push("[*^$]="+P+"*(?:''|\"\")"),e.querySelectorAll(":enabled").length||g.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),g.push(",.*:")})),(r.matchesSelector=K.test(y=d.webkitMatchesSelector||d.mozMatchesSelector||d.oMatchesSelector||d.msMatchesSelector))&&ut(function(e){r.disconnectedMatch=y.call(e,"div"),y.call(e,"[s!='']:x"),m.push("!=",I)}),g=g.length&&RegExp(g.join("|")),m=m.length&&RegExp(m.join("|")),v=K.test(d.contains)||d.compareDocumentPosition?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},A=d.compareDocumentPosition?function(e,t){if(e===t)return S=!0,0;var i=t.compareDocumentPosition&&e.compareDocumentPosition&&e.compareDocumentPosition(t);return i?1&i||!r.sortDetached&&t.compareDocumentPosition(e)===i?e===n||v(w,e)?-1:t===n||v(w,t)?1:c?F.call(c,e)-F.call(c,t):0:4&i?-1:1:e.compareDocumentPosition?-1:1}:function(e,t){var r,i=0,o=e.parentNode,a=t.parentNode,s=[e],l=[t];if(e===t)return S=!0,0;if(!o||!a)return e===n?-1:t===n?1:o?-1:a?1:c?F.call(c,e)-F.call(c,t):0;if(o===a)return pt(e,t);r=e;while(r=r.parentNode)s.unshift(r);r=t;while(r=r.parentNode)l.unshift(r);while(s[i]===l[i])i++;return i?pt(s[i],l[i]):s[i]===w?-1:l[i]===w?1:0},n):f},at.matches=function(e,t){return at(e,null,null,t)},at.matchesSelector=function(e,t){if((e.ownerDocument||e)!==f&&p(e),t=t.replace(Y,"='$1']"),!(!r.matchesSelector||!h||m&&m.test(t)||g&&g.test(t)))try{var n=y.call(e,t);if(n||r.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(i){}return at(t,f,null,[e]).length>0},at.contains=function(e,t){return(e.ownerDocument||e)!==f&&p(e),v(e,t)},at.attr=function(e,n){(e.ownerDocument||e)!==f&&p(e);var i=o.attrHandle[n.toLowerCase()],a=i&&L.call(o.attrHandle,n.toLowerCase())?i(e,n,!h):t;return a===t?r.attributes||!h?e.getAttribute(n):(a=e.getAttributeNode(n))&&a.specified?a.value:null:a},at.error=function(e){throw Error("Syntax error, unrecognized expression: "+e)},at.uniqueSort=function(e){var t,n=[],i=0,o=0;if(S=!r.detectDuplicates,c=!r.sortStable&&e.slice(0),e.sort(A),S){while(t=e[o++])t===e[o]&&(i=n.push(o));while(i--)e.splice(n[i],1)}return e},a=at.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=a(e)}else if(3===i||4===i)return e.nodeValue}else for(;t=e[r];r++)n+=a(t);return n},o=at.selectors={cacheLength:50,createPseudo:lt,match:Q,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(rt,it),e[3]=(e[4]||e[5]||"").replace(rt,it),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||at.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&at.error(e[0]),e},PSEUDO:function(e){var n,r=!e[5]&&e[2];return Q.CHILD.test(e[0])?null:(e[3]&&e[4]!==t?e[2]=e[4]:r&&J.test(r)&&(n=mt(r,!0))&&(n=r.indexOf(")",r.length-n)-r.length)&&(e[0]=e[0].slice(0,n),e[2]=r.slice(0,n)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(rt,it).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=N[e+" "];return t||(t=RegExp("(^|"+P+")"+e+"("+P+"|$)"))&&N(e,function(e){return t.test("string"==typeof e.className&&e.className||typeof e.getAttribute!==j&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r){var i=at.attr(r,e);return null==i?"!="===t:t?(i+="","="===t?i===n:"!="===t?i!==n:"^="===t?n&&0===i.indexOf(n):"*="===t?n&&i.indexOf(n)>-1:"$="===t?n&&i.slice(-n.length)===n:"~="===t?(" "+i+" ").indexOf(n)>-1:"|="===t?i===n||i.slice(0,n.length+1)===n+"-":!1):!0}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),a="last"!==e.slice(-4),s="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,l){var u,c,p,f,d,h,g=o!==a?"nextSibling":"previousSibling",m=t.parentNode,y=s&&t.nodeName.toLowerCase(),v=!l&&!s;if(m){if(o){while(g){p=t;while(p=p[g])if(s?p.nodeName.toLowerCase()===y:1===p.nodeType)return!1;h=g="only"===e&&!h&&"nextSibling"}return!0}if(h=[a?m.firstChild:m.lastChild],a&&v){c=m[b]||(m[b]={}),u=c[e]||[],d=u[0]===T&&u[1],f=u[0]===T&&u[2],p=d&&m.childNodes[d];while(p=++d&&p&&p[g]||(f=d=0)||h.pop())if(1===p.nodeType&&++f&&p===t){c[e]=[T,d,f];break}}else if(v&&(u=(t[b]||(t[b]={}))[e])&&u[0]===T)f=u[1];else while(p=++d&&p&&p[g]||(f=d=0)||h.pop())if((s?p.nodeName.toLowerCase()===y:1===p.nodeType)&&++f&&(v&&((p[b]||(p[b]={}))[e]=[T,f]),p===t))break;return f-=i,f===r||0===f%r&&f/r>=0}}},PSEUDO:function(e,t){var n,r=o.pseudos[e]||o.setFilters[e.toLowerCase()]||at.error("unsupported pseudo: "+e);return r[b]?r(t):r.length>1?(n=[e,e,"",t],o.setFilters.hasOwnProperty(e.toLowerCase())?lt(function(e,n){var i,o=r(e,t),a=o.length;while(a--)i=F.call(e,o[a]),e[i]=!(n[i]=o[a])}):function(e){return r(e,0,n)}):r}},pseudos:{not:lt(function(e){var t=[],n=[],r=l(e.replace(z,"$1"));return r[b]?lt(function(e,t,n,i){var o,a=r(e,null,i,[]),s=e.length;while(s--)(o=a[s])&&(e[s]=!(t[s]=o))}):function(e,i,o){return t[0]=e,r(t,null,o,n),!n.pop()}}),has:lt(function(e){return function(t){return at(e,t).length>0}}),contains:lt(function(e){return function(t){return(t.textContent||t.innerText||a(t)).indexOf(e)>-1}}),lang:lt(function(e){return G.test(e||"")||at.error("unsupported lang: "+e),e=e.replace(rt,it).toLowerCase(),function(t){var n;do if(n=h?t.lang:t.getAttribute("xml:lang")||t.getAttribute("lang"))return n=n.toLowerCase(),n===e||0===n.indexOf(e+"-");while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===d},focus:function(e){return e===f.activeElement&&(!f.hasFocus||f.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeName>"@"||3===e.nodeType||4===e.nodeType)return!1;return!0},parent:function(e){return!o.pseudos.empty(e)},header:function(e){return tt.test(e.nodeName)},input:function(e){return et.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||t.toLowerCase()===e.type)},first:ht(function(){return[0]}),last:ht(function(e,t){return[t-1]}),eq:ht(function(e,t,n){return[0>n?n+t:n]}),even:ht(function(e,t){var n=0;for(;t>n;n+=2)e.push(n);return e}),odd:ht(function(e,t){var n=1;for(;t>n;n+=2)e.push(n);return e}),lt:ht(function(e,t,n){var r=0>n?n+t:n;for(;--r>=0;)e.push(r);return e}),gt:ht(function(e,t,n){var r=0>n?n+t:n;for(;t>++r;)e.push(r);return e})}},o.pseudos.nth=o.pseudos.eq;for(n in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})o.pseudos[n]=ft(n);for(n in{submit:!0,reset:!0})o.pseudos[n]=dt(n);function gt(){}gt.prototype=o.filters=o.pseudos,o.setFilters=new gt;function mt(e,t){var n,r,i,a,s,l,u,c=k[e+" "];if(c)return t?0:c.slice(0);s=e,l=[],u=o.preFilter;while(s){(!n||(r=X.exec(s)))&&(r&&(s=s.slice(r[0].length)||s),l.push(i=[])),n=!1,(r=U.exec(s))&&(n=r.shift(),i.push({value:n,type:r[0].replace(z," ")}),s=s.slice(n.length));for(a in o.filter)!(r=Q[a].exec(s))||u[a]&&!(r=u[a](r))||(n=r.shift(),i.push({value:n,type:a,matches:r}),s=s.slice(n.length));if(!n)break}return t?s.length:s?at.error(e):k(e,l).slice(0)}function yt(e){var t=0,n=e.length,r="";for(;n>t;t++)r+=e[t].value;return r}function vt(e,t,n){var r=t.dir,o=n&&"parentNode"===r,a=C++;return t.first?function(t,n,i){while(t=t[r])if(1===t.nodeType||o)return e(t,n,i)}:function(t,n,s){var l,u,c,p=T+" "+a;if(s){while(t=t[r])if((1===t.nodeType||o)&&e(t,n,s))return!0}else while(t=t[r])if(1===t.nodeType||o)if(c=t[b]||(t[b]={}),(u=c[r])&&u[0]===p){if((l=u[1])===!0||l===i)return l===!0}else if(u=c[r]=[p],u[1]=e(t,n,s)||i,u[1]===!0)return!0}}function bt(e){return e.length>1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function xt(e,t,n,r,i){var o,a=[],s=0,l=e.length,u=null!=t;for(;l>s;s++)(o=e[s])&&(!n||n(o,r,i))&&(a.push(o),u&&t.push(s));return a}function wt(e,t,n,r,i,o){return r&&!r[b]&&(r=wt(r)),i&&!i[b]&&(i=wt(i,o)),lt(function(o,a,s,l){var u,c,p,f=[],d=[],h=a.length,g=o||Nt(t||"*",s.nodeType?[s]:s,[]),m=!e||!o&&t?g:xt(g,f,e,s,l),y=n?i||(o?e:h||r)?[]:a:m;if(n&&n(m,y,s,l),r){u=xt(y,d),r(u,[],s,l),c=u.length;while(c--)(p=u[c])&&(y[d[c]]=!(m[d[c]]=p))}if(o){if(i||e){if(i){u=[],c=y.length;while(c--)(p=y[c])&&u.push(m[c]=p);i(null,y=[],u,l)}c=y.length;while(c--)(p=y[c])&&(u=i?F.call(o,p):f[c])>-1&&(o[u]=!(a[u]=p))}}else y=xt(y===a?y.splice(h,y.length):y),i?i(null,a,y,l):M.apply(a,y)})}function Tt(e){var t,n,r,i=e.length,a=o.relative[e[0].type],s=a||o.relative[" "],l=a?1:0,c=vt(function(e){return e===t},s,!0),p=vt(function(e){return F.call(t,e)>-1},s,!0),f=[function(e,n,r){return!a&&(r||n!==u)||((t=n).nodeType?c(e,n,r):p(e,n,r))}];for(;i>l;l++)if(n=o.relative[e[l].type])f=[vt(bt(f),n)];else{if(n=o.filter[e[l].type].apply(null,e[l].matches),n[b]){for(r=++l;i>r;r++)if(o.relative[e[r].type])break;return wt(l>1&&bt(f),l>1&&yt(e.slice(0,l-1).concat({value:" "===e[l-2].type?"*":""})).replace(z,"$1"),n,r>l&&Tt(e.slice(l,r)),i>r&&Tt(e=e.slice(r)),i>r&&yt(e))}f.push(n)}return bt(f)}function Ct(e,t){var n=0,r=t.length>0,a=e.length>0,s=function(s,l,c,p,d){var h,g,m,y=[],v=0,b="0",x=s&&[],w=null!=d,C=u,N=s||a&&o.find.TAG("*",d&&l.parentNode||l),k=T+=null==C?1:Math.random()||.1;for(w&&(u=l!==f&&l,i=n);null!=(h=N[b]);b++){if(a&&h){g=0;while(m=e[g++])if(m(h,l,c)){p.push(h);break}w&&(T=k,i=++n)}r&&((h=!m&&h)&&v--,s&&x.push(h))}if(v+=b,r&&b!==v){g=0;while(m=t[g++])m(x,y,l,c);if(s){if(v>0)while(b--)x[b]||y[b]||(y[b]=q.call(p));y=xt(y)}M.apply(p,y),w&&!s&&y.length>0&&v+t.length>1&&at.uniqueSort(p)}return w&&(T=k,u=C),x};return r?lt(s):s}l=at.compile=function(e,t){var n,r=[],i=[],o=E[e+" "];if(!o){t||(t=mt(e)),n=t.length;while(n--)o=Tt(t[n]),o[b]?r.push(o):i.push(o);o=E(e,Ct(i,r))}return o};function Nt(e,t,n){var r=0,i=t.length;for(;i>r;r++)at(e,t[r],n);return n}function kt(e,t,n,i){var a,s,u,c,p,f=mt(e);if(!i&&1===f.length){if(s=f[0]=f[0].slice(0),s.length>2&&"ID"===(u=s[0]).type&&r.getById&&9===t.nodeType&&h&&o.relative[s[1].type]){if(t=(o.find.ID(u.matches[0].replace(rt,it),t)||[])[0],!t)return n;e=e.slice(s.shift().value.length)}a=Q.needsContext.test(e)?0:s.length;while(a--){if(u=s[a],o.relative[c=u.type])break;if((p=o.find[c])&&(i=p(u.matches[0].replace(rt,it),V.test(s[0].type)&&t.parentNode||t))){if(s.splice(a,1),e=i.length&&yt(s),!e)return M.apply(n,i),n;break}}}return l(e,f)(i,t,!h,n,V.test(e)),n}r.sortStable=b.split("").sort(A).join("")===b,r.detectDuplicates=S,p(),r.sortDetached=ut(function(e){return 1&e.compareDocumentPosition(f.createElement("div"))}),ut(function(e){return e.innerHTML="<a href='#'></a>","#"===e.firstChild.getAttribute("href")})||ct("type|href|height|width",function(e,n,r){return r?t:e.getAttribute(n,"type"===n.toLowerCase()?1:2)}),r.attributes&&ut(function(e){return e.innerHTML="<input/>",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")})||ct("value",function(e,n,r){return r||"input"!==e.nodeName.toLowerCase()?t:e.defaultValue}),ut(function(e){return null==e.getAttribute("disabled")})||ct(B,function(e,n,r){var i;return r?t:(i=e.getAttributeNode(n))&&i.specified?i.value:e[n]===!0?n.toLowerCase():null}),x.find=at,x.expr=at.selectors,x.expr[":"]=x.expr.pseudos,x.unique=at.uniqueSort,x.text=at.getText,x.isXMLDoc=at.isXML,x.contains=at.contains}(e);var O={};function F(e){var t=O[e]={};return x.each(e.match(T)||[],function(e,n){t[n]=!0}),t}x.Callbacks=function(e){e="string"==typeof e?O[e]||F(e):x.extend({},e);var n,r,i,o,a,s,l=[],u=!e.once&&[],c=function(t){for(r=e.memory&&t,i=!0,a=s||0,s=0,o=l.length,n=!0;l&&o>a;a++)if(l[a].apply(t[0],t[1])===!1&&e.stopOnFalse){r=!1;break}n=!1,l&&(u?u.length&&c(u.shift()):r?l=[]:p.disable())},p={add:function(){if(l){var t=l.length;(function i(t){x.each(t,function(t,n){var r=x.type(n);"function"===r?e.unique&&p.has(n)||l.push(n):n&&n.length&&"string"!==r&&i(n)})})(arguments),n?o=l.length:r&&(s=t,c(r))}return this},remove:function(){return l&&x.each(arguments,function(e,t){var r;while((r=x.inArray(t,l,r))>-1)l.splice(r,1),n&&(o>=r&&o--,a>=r&&a--)}),this},has:function(e){return e?x.inArray(e,l)>-1:!(!l||!l.length)},empty:function(){return l=[],o=0,this},disable:function(){return l=u=r=t,this},disabled:function(){return!l},lock:function(){return u=t,r||p.disable(),this},locked:function(){return!u},fireWith:function(e,t){return!l||i&&!u||(t=t||[],t=[e,t.slice?t.slice():t],n?u.push(t):c(t)),this},fire:function(){return p.fireWith(this,arguments),this},fired:function(){return!!i}};return p},x.extend({Deferred:function(e){var t=[["resolve","done",x.Callbacks("once memory"),"resolved"],["reject","fail",x.Callbacks("once memory"),"rejected"],["notify","progress",x.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return x.Deferred(function(n){x.each(t,function(t,o){var a=o[0],s=x.isFunction(e[t])&&e[t];i[o[1]](function(){var e=s&&s.apply(this,arguments);e&&x.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[a+"With"](this===r?n.promise():this,s?[e]:arguments)})}),e=null}).promise()},promise:function(e){return null!=e?x.extend(e,r):r}},i={};return r.pipe=r.then,x.each(t,function(e,o){var a=o[2],s=o[3];r[o[1]]=a.add,s&&a.add(function(){n=s},t[1^e][2].disable,t[2][2].lock),i[o[0]]=function(){return i[o[0]+"With"](this===i?r:this,arguments),this},i[o[0]+"With"]=a.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t=0,n=g.call(arguments),r=n.length,i=1!==r||e&&x.isFunction(e.promise)?r:0,o=1===i?e:x.Deferred(),a=function(e,t,n){return function(r){t[e]=this,n[e]=arguments.length>1?g.call(arguments):r,n===s?o.notifyWith(t,n):--i||o.resolveWith(t,n)}},s,l,u;if(r>1)for(s=Array(r),l=Array(r),u=Array(r);r>t;t++)n[t]&&x.isFunction(n[t].promise)?n[t].promise().done(a(t,u,n)).fail(o.reject).progress(a(t,l,s)):--i;return i||o.resolveWith(u,n),o.promise()}}),x.support=function(t){var n,r,o,s,l,u,c,p,f,d=a.createElement("div");if(d.setAttribute("className","t"),d.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",n=d.getElementsByTagName("*")||[],r=d.getElementsByTagName("a")[0],!r||!r.style||!n.length)return t;s=a.createElement("select"),u=s.appendChild(a.createElement("option")),o=d.getElementsByTagName("input")[0],r.style.cssText="top:1px;float:left;opacity:.5",t.getSetAttribute="t"!==d.className,t.leadingWhitespace=3===d.firstChild.nodeType,t.tbody=!d.getElementsByTagName("tbody").length,t.htmlSerialize=!!d.getElementsByTagName("link").length,t.style=/top/.test(r.getAttribute("style")),t.hrefNormalized="/a"===r.getAttribute("href"),t.opacity=/^0.5/.test(r.style.opacity),t.cssFloat=!!r.style.cssFloat,t.checkOn=!!o.value,t.optSelected=u.selected,t.enctype=!!a.createElement("form").enctype,t.html5Clone="<:nav></:nav>"!==a.createElement("nav").cloneNode(!0).outerHTML,t.inlineBlockNeedsLayout=!1,t.shrinkWrapBlocks=!1,t.pixelPosition=!1,t.deleteExpando=!0,t.noCloneEvent=!0,t.reliableMarginRight=!0,t.boxSizingReliable=!0,o.checked=!0,t.noCloneChecked=o.cloneNode(!0).checked,s.disabled=!0,t.optDisabled=!u.disabled;try{delete d.test}catch(h){t.deleteExpando=!1}o=a.createElement("input"),o.setAttribute("value",""),t.input=""===o.getAttribute("value"),o.value="t",o.setAttribute("type","radio"),t.radioValue="t"===o.value,o.setAttribute("checked","t"),o.setAttribute("name","t"),l=a.createDocumentFragment(),l.appendChild(o),t.appendChecked=o.checked,t.checkClone=l.cloneNode(!0).cloneNode(!0).lastChild.checked,d.attachEvent&&(d.attachEvent("onclick",function(){t.noCloneEvent=!1}),d.cloneNode(!0).click());for(f in{submit:!0,change:!0,focusin:!0})d.setAttribute(c="on"+f,"t"),t[f+"Bubbles"]=c in e||d.attributes[c].expando===!1;d.style.backgroundClip="content-box",d.cloneNode(!0).style.backgroundClip="",t.clearCloneStyle="content-box"===d.style.backgroundClip;for(f in x(t))break;return t.ownLast="0"!==f,x(function(){var n,r,o,s="padding:0;margin:0;border:0;display:block;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;",l=a.getElementsByTagName("body")[0];l&&(n=a.createElement("div"),n.style.cssText="border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px",l.appendChild(n).appendChild(d),d.innerHTML="<table><tr><td></td><td>t</td></tr></table>",o=d.getElementsByTagName("td"),o[0].style.cssText="padding:0;margin:0;border:0;display:none",p=0===o[0].offsetHeight,o[0].style.display="",o[1].style.display="none",t.reliableHiddenOffsets=p&&0===o[0].offsetHeight,d.innerHTML="",d.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;",x.swap(l,null!=l.style.zoom?{zoom:1}:{},function(){t.boxSizing=4===d.offsetWidth}),e.getComputedStyle&&(t.pixelPosition="1%"!==(e.getComputedStyle(d,null)||{}).top,t.boxSizingReliable="4px"===(e.getComputedStyle(d,null)||{width:"4px"}).width,r=d.appendChild(a.createElement("div")),r.style.cssText=d.style.cssText=s,r.style.marginRight=r.style.width="0",d.style.width="1px",t.reliableMarginRight=!parseFloat((e.getComputedStyle(r,null)||{}).marginRight)),typeof d.style.zoom!==i&&(d.innerHTML="",d.style.cssText=s+"width:1px;padding:1px;display:inline;zoom:1",t.inlineBlockNeedsLayout=3===d.offsetWidth,d.style.display="block",d.innerHTML="<div></div>",d.firstChild.style.width="5px",t.shrinkWrapBlocks=3!==d.offsetWidth,t.inlineBlockNeedsLayout&&(l.style.zoom=1)),l.removeChild(n),n=d=o=r=null)}),n=s=l=u=r=o=null,t
-}({});var B=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,P=/([A-Z])/g;function R(e,n,r,i){if(x.acceptData(e)){var o,a,s=x.expando,l=e.nodeType,u=l?x.cache:e,c=l?e[s]:e[s]&&s;if(c&&u[c]&&(i||u[c].data)||r!==t||"string"!=typeof n)return c||(c=l?e[s]=p.pop()||x.guid++:s),u[c]||(u[c]=l?{}:{toJSON:x.noop}),("object"==typeof n||"function"==typeof n)&&(i?u[c]=x.extend(u[c],n):u[c].data=x.extend(u[c].data,n)),a=u[c],i||(a.data||(a.data={}),a=a.data),r!==t&&(a[x.camelCase(n)]=r),"string"==typeof n?(o=a[n],null==o&&(o=a[x.camelCase(n)])):o=a,o}}function W(e,t,n){if(x.acceptData(e)){var r,i,o=e.nodeType,a=o?x.cache:e,s=o?e[x.expando]:x.expando;if(a[s]){if(t&&(r=n?a[s]:a[s].data)){x.isArray(t)?t=t.concat(x.map(t,x.camelCase)):t in r?t=[t]:(t=x.camelCase(t),t=t in r?[t]:t.split(" ")),i=t.length;while(i--)delete r[t[i]];if(n?!I(r):!x.isEmptyObject(r))return}(n||(delete a[s].data,I(a[s])))&&(o?x.cleanData([e],!0):x.support.deleteExpando||a!=a.window?delete a[s]:a[s]=null)}}}x.extend({cache:{},noData:{applet:!0,embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(e){return e=e.nodeType?x.cache[e[x.expando]]:e[x.expando],!!e&&!I(e)},data:function(e,t,n){return R(e,t,n)},removeData:function(e,t){return W(e,t)},_data:function(e,t,n){return R(e,t,n,!0)},_removeData:function(e,t){return W(e,t,!0)},acceptData:function(e){if(e.nodeType&&1!==e.nodeType&&9!==e.nodeType)return!1;var t=e.nodeName&&x.noData[e.nodeName.toLowerCase()];return!t||t!==!0&&e.getAttribute("classid")===t}}),x.fn.extend({data:function(e,n){var r,i,o=null,a=0,s=this[0];if(e===t){if(this.length&&(o=x.data(s),1===s.nodeType&&!x._data(s,"parsedAttrs"))){for(r=s.attributes;r.length>a;a++)i=r[a].name,0===i.indexOf("data-")&&(i=x.camelCase(i.slice(5)),$(s,i,o[i]));x._data(s,"parsedAttrs",!0)}return o}return"object"==typeof e?this.each(function(){x.data(this,e)}):arguments.length>1?this.each(function(){x.data(this,e,n)}):s?$(s,e,x.data(s,e)):null},removeData:function(e){return this.each(function(){x.removeData(this,e)})}});function $(e,n,r){if(r===t&&1===e.nodeType){var i="data-"+n.replace(P,"-$1").toLowerCase();if(r=e.getAttribute(i),"string"==typeof r){try{r="true"===r?!0:"false"===r?!1:"null"===r?null:+r+""===r?+r:B.test(r)?x.parseJSON(r):r}catch(o){}x.data(e,n,r)}else r=t}return r}function I(e){var t;for(t in e)if(("data"!==t||!x.isEmptyObject(e[t]))&&"toJSON"!==t)return!1;return!0}x.extend({queue:function(e,n,r){var i;return e?(n=(n||"fx")+"queue",i=x._data(e,n),r&&(!i||x.isArray(r)?i=x._data(e,n,x.makeArray(r)):i.push(r)),i||[]):t},dequeue:function(e,t){t=t||"fx";var n=x.queue(e,t),r=n.length,i=n.shift(),o=x._queueHooks(e,t),a=function(){x.dequeue(e,t)};"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,a,o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return x._data(e,n)||x._data(e,n,{empty:x.Callbacks("once memory").add(function(){x._removeData(e,t+"queue"),x._removeData(e,n)})})}}),x.fn.extend({queue:function(e,n){var r=2;return"string"!=typeof e&&(n=e,e="fx",r--),r>arguments.length?x.queue(this[0],e):n===t?this:this.each(function(){var t=x.queue(this,e,n);x._queueHooks(this,e),"fx"===e&&"inprogress"!==t[0]&&x.dequeue(this,e)})},dequeue:function(e){return this.each(function(){x.dequeue(this,e)})},delay:function(e,t){return e=x.fx?x.fx.speeds[e]||e:e,t=t||"fx",this.queue(t,function(t,n){var r=setTimeout(t,e);n.stop=function(){clearTimeout(r)}})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,n){var r,i=1,o=x.Deferred(),a=this,s=this.length,l=function(){--i||o.resolveWith(a,[a])};"string"!=typeof e&&(n=e,e=t),e=e||"fx";while(s--)r=x._data(a[s],e+"queueHooks"),r&&r.empty&&(i++,r.empty.add(l));return l(),o.promise(n)}});var z,X,U=/[\t\r\n\f]/g,V=/\r/g,Y=/^(?:input|select|textarea|button|object)$/i,J=/^(?:a|area)$/i,G=/^(?:checked|selected)$/i,Q=x.support.getSetAttribute,K=x.support.input;x.fn.extend({attr:function(e,t){return x.access(this,x.attr,e,t,arguments.length>1)},removeAttr:function(e){return this.each(function(){x.removeAttr(this,e)})},prop:function(e,t){return x.access(this,x.prop,e,t,arguments.length>1)},removeProp:function(e){return e=x.propFix[e]||e,this.each(function(){try{this[e]=t,delete this[e]}catch(n){}})},addClass:function(e){var t,n,r,i,o,a=0,s=this.length,l="string"==typeof e&&e;if(x.isFunction(e))return this.each(function(t){x(this).addClass(e.call(this,t,this.className))});if(l)for(t=(e||"").match(T)||[];s>a;a++)if(n=this[a],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(U," "):" ")){o=0;while(i=t[o++])0>r.indexOf(" "+i+" ")&&(r+=i+" ");n.className=x.trim(r)}return this},removeClass:function(e){var t,n,r,i,o,a=0,s=this.length,l=0===arguments.length||"string"==typeof e&&e;if(x.isFunction(e))return this.each(function(t){x(this).removeClass(e.call(this,t,this.className))});if(l)for(t=(e||"").match(T)||[];s>a;a++)if(n=this[a],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(U," "):"")){o=0;while(i=t[o++])while(r.indexOf(" "+i+" ")>=0)r=r.replace(" "+i+" "," ");n.className=e?x.trim(r):""}return this},toggleClass:function(e,t){var n=typeof e;return"boolean"==typeof t&&"string"===n?t?this.addClass(e):this.removeClass(e):x.isFunction(e)?this.each(function(n){x(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if("string"===n){var t,r=0,o=x(this),a=e.match(T)||[];while(t=a[r++])o.hasClass(t)?o.removeClass(t):o.addClass(t)}else(n===i||"boolean"===n)&&(this.className&&x._data(this,"__className__",this.className),this.className=this.className||e===!1?"":x._data(this,"__className__")||"")})},hasClass:function(e){var t=" "+e+" ",n=0,r=this.length;for(;r>n;n++)if(1===this[n].nodeType&&(" "+this[n].className+" ").replace(U," ").indexOf(t)>=0)return!0;return!1},val:function(e){var n,r,i,o=this[0];{if(arguments.length)return i=x.isFunction(e),this.each(function(n){var o;1===this.nodeType&&(o=i?e.call(this,n,x(this).val()):e,null==o?o="":"number"==typeof o?o+="":x.isArray(o)&&(o=x.map(o,function(e){return null==e?"":e+""})),r=x.valHooks[this.type]||x.valHooks[this.nodeName.toLowerCase()],r&&"set"in r&&r.set(this,o,"value")!==t||(this.value=o))});if(o)return r=x.valHooks[o.type]||x.valHooks[o.nodeName.toLowerCase()],r&&"get"in r&&(n=r.get(o,"value"))!==t?n:(n=o.value,"string"==typeof n?n.replace(V,""):null==n?"":n)}}}),x.extend({valHooks:{option:{get:function(e){var t=x.find.attr(e,"value");return null!=t?t:e.text}},select:{get:function(e){var t,n,r=e.options,i=e.selectedIndex,o="select-one"===e.type||0>i,a=o?null:[],s=o?i+1:r.length,l=0>i?s:o?i:0;for(;s>l;l++)if(n=r[l],!(!n.selected&&l!==i||(x.support.optDisabled?n.disabled:null!==n.getAttribute("disabled"))||n.parentNode.disabled&&x.nodeName(n.parentNode,"optgroup"))){if(t=x(n).val(),o)return t;a.push(t)}return a},set:function(e,t){var n,r,i=e.options,o=x.makeArray(t),a=i.length;while(a--)r=i[a],(r.selected=x.inArray(x(r).val(),o)>=0)&&(n=!0);return n||(e.selectedIndex=-1),o}}},attr:function(e,n,r){var o,a,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return typeof e.getAttribute===i?x.prop(e,n,r):(1===s&&x.isXMLDoc(e)||(n=n.toLowerCase(),o=x.attrHooks[n]||(x.expr.match.bool.test(n)?X:z)),r===t?o&&"get"in o&&null!==(a=o.get(e,n))?a:(a=x.find.attr(e,n),null==a?t:a):null!==r?o&&"set"in o&&(a=o.set(e,r,n))!==t?a:(e.setAttribute(n,r+""),r):(x.removeAttr(e,n),t))},removeAttr:function(e,t){var n,r,i=0,o=t&&t.match(T);if(o&&1===e.nodeType)while(n=o[i++])r=x.propFix[n]||n,x.expr.match.bool.test(n)?K&&Q||!G.test(n)?e[r]=!1:e[x.camelCase("default-"+n)]=e[r]=!1:x.attr(e,n,""),e.removeAttribute(Q?n:r)},attrHooks:{type:{set:function(e,t){if(!x.support.radioValue&&"radio"===t&&x.nodeName(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},propFix:{"for":"htmlFor","class":"className"},prop:function(e,n,r){var i,o,a,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return a=1!==s||!x.isXMLDoc(e),a&&(n=x.propFix[n]||n,o=x.propHooks[n]),r!==t?o&&"set"in o&&(i=o.set(e,r,n))!==t?i:e[n]=r:o&&"get"in o&&null!==(i=o.get(e,n))?i:e[n]},propHooks:{tabIndex:{get:function(e){var t=x.find.attr(e,"tabindex");return t?parseInt(t,10):Y.test(e.nodeName)||J.test(e.nodeName)&&e.href?0:-1}}}}),X={set:function(e,t,n){return t===!1?x.removeAttr(e,n):K&&Q||!G.test(n)?e.setAttribute(!Q&&x.propFix[n]||n,n):e[x.camelCase("default-"+n)]=e[n]=!0,n}},x.each(x.expr.match.bool.source.match(/\w+/g),function(e,n){var r=x.expr.attrHandle[n]||x.find.attr;x.expr.attrHandle[n]=K&&Q||!G.test(n)?function(e,n,i){var o=x.expr.attrHandle[n],a=i?t:(x.expr.attrHandle[n]=t)!=r(e,n,i)?n.toLowerCase():null;return x.expr.attrHandle[n]=o,a}:function(e,n,r){return r?t:e[x.camelCase("default-"+n)]?n.toLowerCase():null}}),K&&Q||(x.attrHooks.value={set:function(e,n,r){return x.nodeName(e,"input")?(e.defaultValue=n,t):z&&z.set(e,n,r)}}),Q||(z={set:function(e,n,r){var i=e.getAttributeNode(r);return i||e.setAttributeNode(i=e.ownerDocument.createAttribute(r)),i.value=n+="","value"===r||n===e.getAttribute(r)?n:t}},x.expr.attrHandle.id=x.expr.attrHandle.name=x.expr.attrHandle.coords=function(e,n,r){var i;return r?t:(i=e.getAttributeNode(n))&&""!==i.value?i.value:null},x.valHooks.button={get:function(e,n){var r=e.getAttributeNode(n);return r&&r.specified?r.value:t},set:z.set},x.attrHooks.contenteditable={set:function(e,t,n){z.set(e,""===t?!1:t,n)}},x.each(["width","height"],function(e,n){x.attrHooks[n]={set:function(e,r){return""===r?(e.setAttribute(n,"auto"),r):t}}})),x.support.hrefNormalized||x.each(["href","src"],function(e,t){x.propHooks[t]={get:function(e){return e.getAttribute(t,4)}}}),x.support.style||(x.attrHooks.style={get:function(e){return e.style.cssText||t},set:function(e,t){return e.style.cssText=t+""}}),x.support.optSelected||(x.propHooks.selected={get:function(e){var t=e.parentNode;return t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex),null}}),x.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){x.propFix[this.toLowerCase()]=this}),x.support.enctype||(x.propFix.enctype="encoding"),x.each(["radio","checkbox"],function(){x.valHooks[this]={set:function(e,n){return x.isArray(n)?e.checked=x.inArray(x(e).val(),n)>=0:t}},x.support.checkOn||(x.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})});var Z=/^(?:input|select|textarea)$/i,et=/^key/,tt=/^(?:mouse|contextmenu)|click/,nt=/^(?:focusinfocus|focusoutblur)$/,rt=/^([^.]*)(?:\.(.+)|)$/;function it(){return!0}function ot(){return!1}function at(){try{return a.activeElement}catch(e){}}x.event={global:{},add:function(e,n,r,o,a){var s,l,u,c,p,f,d,h,g,m,y,v=x._data(e);if(v){r.handler&&(c=r,r=c.handler,a=c.selector),r.guid||(r.guid=x.guid++),(l=v.events)||(l=v.events={}),(f=v.handle)||(f=v.handle=function(e){return typeof x===i||e&&x.event.triggered===e.type?t:x.event.dispatch.apply(f.elem,arguments)},f.elem=e),n=(n||"").match(T)||[""],u=n.length;while(u--)s=rt.exec(n[u])||[],g=y=s[1],m=(s[2]||"").split(".").sort(),g&&(p=x.event.special[g]||{},g=(a?p.delegateType:p.bindType)||g,p=x.event.special[g]||{},d=x.extend({type:g,origType:y,data:o,handler:r,guid:r.guid,selector:a,needsContext:a&&x.expr.match.needsContext.test(a),namespace:m.join(".")},c),(h=l[g])||(h=l[g]=[],h.delegateCount=0,p.setup&&p.setup.call(e,o,m,f)!==!1||(e.addEventListener?e.addEventListener(g,f,!1):e.attachEvent&&e.attachEvent("on"+g,f))),p.add&&(p.add.call(e,d),d.handler.guid||(d.handler.guid=r.guid)),a?h.splice(h.delegateCount++,0,d):h.push(d),x.event.global[g]=!0);e=null}},remove:function(e,t,n,r,i){var o,a,s,l,u,c,p,f,d,h,g,m=x.hasData(e)&&x._data(e);if(m&&(c=m.events)){t=(t||"").match(T)||[""],u=t.length;while(u--)if(s=rt.exec(t[u])||[],d=g=s[1],h=(s[2]||"").split(".").sort(),d){p=x.event.special[d]||{},d=(r?p.delegateType:p.bindType)||d,f=c[d]||[],s=s[2]&&RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),l=o=f.length;while(o--)a=f[o],!i&&g!==a.origType||n&&n.guid!==a.guid||s&&!s.test(a.namespace)||r&&r!==a.selector&&("**"!==r||!a.selector)||(f.splice(o,1),a.selector&&f.delegateCount--,p.remove&&p.remove.call(e,a));l&&!f.length&&(p.teardown&&p.teardown.call(e,h,m.handle)!==!1||x.removeEvent(e,d,m.handle),delete c[d])}else for(d in c)x.event.remove(e,d+t[u],n,r,!0);x.isEmptyObject(c)&&(delete m.handle,x._removeData(e,"events"))}},trigger:function(n,r,i,o){var s,l,u,c,p,f,d,h=[i||a],g=v.call(n,"type")?n.type:n,m=v.call(n,"namespace")?n.namespace.split("."):[];if(u=f=i=i||a,3!==i.nodeType&&8!==i.nodeType&&!nt.test(g+x.event.triggered)&&(g.indexOf(".")>=0&&(m=g.split("."),g=m.shift(),m.sort()),l=0>g.indexOf(":")&&"on"+g,n=n[x.expando]?n:new x.Event(g,"object"==typeof n&&n),n.isTrigger=o?2:3,n.namespace=m.join("."),n.namespace_re=n.namespace?RegExp("(^|\\.)"+m.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,n.result=t,n.target||(n.target=i),r=null==r?[n]:x.makeArray(r,[n]),p=x.event.special[g]||{},o||!p.trigger||p.trigger.apply(i,r)!==!1)){if(!o&&!p.noBubble&&!x.isWindow(i)){for(c=p.delegateType||g,nt.test(c+g)||(u=u.parentNode);u;u=u.parentNode)h.push(u),f=u;f===(i.ownerDocument||a)&&h.push(f.defaultView||f.parentWindow||e)}d=0;while((u=h[d++])&&!n.isPropagationStopped())n.type=d>1?c:p.bindType||g,s=(x._data(u,"events")||{})[n.type]&&x._data(u,"handle"),s&&s.apply(u,r),s=l&&u[l],s&&x.acceptData(u)&&s.apply&&s.apply(u,r)===!1&&n.preventDefault();if(n.type=g,!o&&!n.isDefaultPrevented()&&(!p._default||p._default.apply(h.pop(),r)===!1)&&x.acceptData(i)&&l&&i[g]&&!x.isWindow(i)){f=i[l],f&&(i[l]=null),x.event.triggered=g;try{i[g]()}catch(y){}x.event.triggered=t,f&&(i[l]=f)}return n.result}},dispatch:function(e){e=x.event.fix(e);var n,r,i,o,a,s=[],l=g.call(arguments),u=(x._data(this,"events")||{})[e.type]||[],c=x.event.special[e.type]||{};if(l[0]=e,e.delegateTarget=this,!c.preDispatch||c.preDispatch.call(this,e)!==!1){s=x.event.handlers.call(this,e,u),n=0;while((o=s[n++])&&!e.isPropagationStopped()){e.currentTarget=o.elem,a=0;while((i=o.handlers[a++])&&!e.isImmediatePropagationStopped())(!e.namespace_re||e.namespace_re.test(i.namespace))&&(e.handleObj=i,e.data=i.data,r=((x.event.special[i.origType]||{}).handle||i.handler).apply(o.elem,l),r!==t&&(e.result=r)===!1&&(e.preventDefault(),e.stopPropagation()))}return c.postDispatch&&c.postDispatch.call(this,e),e.result}},handlers:function(e,n){var r,i,o,a,s=[],l=n.delegateCount,u=e.target;if(l&&u.nodeType&&(!e.button||"click"!==e.type))for(;u!=this;u=u.parentNode||this)if(1===u.nodeType&&(u.disabled!==!0||"click"!==e.type)){for(o=[],a=0;l>a;a++)i=n[a],r=i.selector+" ",o[r]===t&&(o[r]=i.needsContext?x(r,this).index(u)>=0:x.find(r,this,null,[u]).length),o[r]&&o.push(i);o.length&&s.push({elem:u,handlers:o})}return n.length>l&&s.push({elem:this,handlers:n.slice(l)}),s},fix:function(e){if(e[x.expando])return e;var t,n,r,i=e.type,o=e,s=this.fixHooks[i];s||(this.fixHooks[i]=s=tt.test(i)?this.mouseHooks:et.test(i)?this.keyHooks:{}),r=s.props?this.props.concat(s.props):this.props,e=new x.Event(o),t=r.length;while(t--)n=r[t],e[n]=o[n];return e.target||(e.target=o.srcElement||a),3===e.target.nodeType&&(e.target=e.target.parentNode),e.metaKey=!!e.metaKey,s.filter?s.filter(e,o):e},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(e,t){return null==e.which&&(e.which=null!=t.charCode?t.charCode:t.keyCode),e}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(e,n){var r,i,o,s=n.button,l=n.fromElement;return null==e.pageX&&null!=n.clientX&&(i=e.target.ownerDocument||a,o=i.documentElement,r=i.body,e.pageX=n.clientX+(o&&o.scrollLeft||r&&r.scrollLeft||0)-(o&&o.clientLeft||r&&r.clientLeft||0),e.pageY=n.clientY+(o&&o.scrollTop||r&&r.scrollTop||0)-(o&&o.clientTop||r&&r.clientTop||0)),!e.relatedTarget&&l&&(e.relatedTarget=l===e.target?n.toElement:l),e.which||s===t||(e.which=1&s?1:2&s?3:4&s?2:0),e}},special:{load:{noBubble:!0},focus:{trigger:function(){if(this!==at()&&this.focus)try{return this.focus(),!1}catch(e){}},delegateType:"focusin"},blur:{trigger:function(){return this===at()&&this.blur?(this.blur(),!1):t},delegateType:"focusout"},click:{trigger:function(){return x.nodeName(this,"input")&&"checkbox"===this.type&&this.click?(this.click(),!1):t},_default:function(e){return x.nodeName(e.target,"a")}},beforeunload:{postDispatch:function(e){e.result!==t&&(e.originalEvent.returnValue=e.result)}}},simulate:function(e,t,n,r){var i=x.extend(new x.Event,n,{type:e,isSimulated:!0,originalEvent:{}});r?x.event.trigger(i,null,t):x.event.dispatch.call(t,i),i.isDefaultPrevented()&&n.preventDefault()}},x.removeEvent=a.removeEventListener?function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n,!1)}:function(e,t,n){var r="on"+t;e.detachEvent&&(typeof e[r]===i&&(e[r]=null),e.detachEvent(r,n))},x.Event=function(e,n){return this instanceof x.Event?(e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||e.returnValue===!1||e.getPreventDefault&&e.getPreventDefault()?it:ot):this.type=e,n&&x.extend(this,n),this.timeStamp=e&&e.timeStamp||x.now(),this[x.expando]=!0,t):new x.Event(e,n)},x.Event.prototype={isDefaultPrevented:ot,isPropagationStopped:ot,isImmediatePropagationStopped:ot,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=it,e&&(e.preventDefault?e.preventDefault():e.returnValue=!1)},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=it,e&&(e.stopPropagation&&e.stopPropagation(),e.cancelBubble=!0)},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=it,this.stopPropagation()}},x.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(e,t){x.event.special[e]={delegateType:t,bindType:t,handle:function(e){var n,r=this,i=e.relatedTarget,o=e.handleObj;return(!i||i!==r&&!x.contains(r,i))&&(e.type=o.origType,n=o.handler.apply(this,arguments),e.type=t),n}}}),x.support.submitBubbles||(x.event.special.submit={setup:function(){return x.nodeName(this,"form")?!1:(x.event.add(this,"click._submit keypress._submit",function(e){var n=e.target,r=x.nodeName(n,"input")||x.nodeName(n,"button")?n.form:t;r&&!x._data(r,"submitBubbles")&&(x.event.add(r,"submit._submit",function(e){e._submit_bubble=!0}),x._data(r,"submitBubbles",!0))}),t)},postDispatch:function(e){e._submit_bubble&&(delete e._submit_bubble,this.parentNode&&!e.isTrigger&&x.event.simulate("submit",this.parentNode,e,!0))},teardown:function(){return x.nodeName(this,"form")?!1:(x.event.remove(this,"._submit"),t)}}),x.support.changeBubbles||(x.event.special.change={setup:function(){return Z.test(this.nodeName)?(("checkbox"===this.type||"radio"===this.type)&&(x.event.add(this,"propertychange._change",function(e){"checked"===e.originalEvent.propertyName&&(this._just_changed=!0)}),x.event.add(this,"click._change",function(e){this._just_changed&&!e.isTrigger&&(this._just_changed=!1),x.event.simulate("change",this,e,!0)})),!1):(x.event.add(this,"beforeactivate._change",function(e){var t=e.target;Z.test(t.nodeName)&&!x._data(t,"changeBubbles")&&(x.event.add(t,"change._change",function(e){!this.parentNode||e.isSimulated||e.isTrigger||x.event.simulate("change",this.parentNode,e,!0)}),x._data(t,"changeBubbles",!0))}),t)},handle:function(e){var n=e.target;return this!==n||e.isSimulated||e.isTrigger||"radio"!==n.type&&"checkbox"!==n.type?e.handleObj.handler.apply(this,arguments):t},teardown:function(){return x.event.remove(this,"._change"),!Z.test(this.nodeName)}}),x.support.focusinBubbles||x.each({focus:"focusin",blur:"focusout"},function(e,t){var n=0,r=function(e){x.event.simulate(t,e.target,x.event.fix(e),!0)};x.event.special[t]={setup:function(){0===n++&&a.addEventListener(e,r,!0)},teardown:function(){0===--n&&a.removeEventListener(e,r,!0)}}}),x.fn.extend({on:function(e,n,r,i,o){var a,s;if("object"==typeof e){"string"!=typeof n&&(r=r||n,n=t);for(a in e)this.on(a,n,r,e[a],o);return this}if(null==r&&null==i?(i=n,r=n=t):null==i&&("string"==typeof n?(i=r,r=t):(i=r,r=n,n=t)),i===!1)i=ot;else if(!i)return this;return 1===o&&(s=i,i=function(e){return x().off(e),s.apply(this,arguments)},i.guid=s.guid||(s.guid=x.guid++)),this.each(function(){x.event.add(this,e,i,r,n)})},one:function(e,t,n,r){return this.on(e,t,n,r,1)},off:function(e,n,r){var i,o;if(e&&e.preventDefault&&e.handleObj)return i=e.handleObj,x(e.delegateTarget).off(i.namespace?i.origType+"."+i.namespace:i.origType,i.selector,i.handler),this;if("object"==typeof e){for(o in e)this.off(o,n,e[o]);return this}return(n===!1||"function"==typeof n)&&(r=n,n=t),r===!1&&(r=ot),this.each(function(){x.event.remove(this,e,r,n)})},trigger:function(e,t){return this.each(function(){x.event.trigger(e,t,this)})},triggerHandler:function(e,n){var r=this[0];return r?x.event.trigger(e,n,r,!0):t}});var st=/^.[^:#\[\.,]*$/,lt=/^(?:parents|prev(?:Until|All))/,ut=x.expr.match.needsContext,ct={children:!0,contents:!0,next:!0,prev:!0};x.fn.extend({find:function(e){var t,n=[],r=this,i=r.length;if("string"!=typeof e)return this.pushStack(x(e).filter(function(){for(t=0;i>t;t++)if(x.contains(r[t],this))return!0}));for(t=0;i>t;t++)x.find(e,r[t],n);return n=this.pushStack(i>1?x.unique(n):n),n.selector=this.selector?this.selector+" "+e:e,n},has:function(e){var t,n=x(e,this),r=n.length;return this.filter(function(){for(t=0;r>t;t++)if(x.contains(this,n[t]))return!0})},not:function(e){return this.pushStack(ft(this,e||[],!0))},filter:function(e){return this.pushStack(ft(this,e||[],!1))},is:function(e){return!!ft(this,"string"==typeof e&&ut.test(e)?x(e):e||[],!1).length},closest:function(e,t){var n,r=0,i=this.length,o=[],a=ut.test(e)||"string"!=typeof e?x(e,t||this.context):0;for(;i>r;r++)for(n=this[r];n&&n!==t;n=n.parentNode)if(11>n.nodeType&&(a?a.index(n)>-1:1===n.nodeType&&x.find.matchesSelector(n,e))){n=o.push(n);break}return this.pushStack(o.length>1?x.unique(o):o)},index:function(e){return e?"string"==typeof e?x.inArray(this[0],x(e)):x.inArray(e.jquery?e[0]:e,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){var n="string"==typeof e?x(e,t):x.makeArray(e&&e.nodeType?[e]:e),r=x.merge(this.get(),n);return this.pushStack(x.unique(r))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}});function pt(e,t){do e=e[t];while(e&&1!==e.nodeType);return e}x.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return x.dir(e,"parentNode")},parentsUntil:function(e,t,n){return x.dir(e,"parentNode",n)},next:function(e){return pt(e,"nextSibling")},prev:function(e){return pt(e,"previousSibling")},nextAll:function(e){return x.dir(e,"nextSibling")},prevAll:function(e){return x.dir(e,"previousSibling")},nextUntil:function(e,t,n){return x.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return x.dir(e,"previousSibling",n)},siblings:function(e){return x.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return x.sibling(e.firstChild)},contents:function(e){return x.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:x.merge([],e.childNodes)}},function(e,t){x.fn[e]=function(n,r){var i=x.map(this,t,n);return"Until"!==e.slice(-5)&&(r=n),r&&"string"==typeof r&&(i=x.filter(r,i)),this.length>1&&(ct[e]||(i=x.unique(i)),lt.test(e)&&(i=i.reverse())),this.pushStack(i)}}),x.extend({filter:function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?x.find.matchesSelector(r,e)?[r]:[]:x.find.matches(e,x.grep(t,function(e){return 1===e.nodeType}))},dir:function(e,n,r){var i=[],o=e[n];while(o&&9!==o.nodeType&&(r===t||1!==o.nodeType||!x(o).is(r)))1===o.nodeType&&i.push(o),o=o[n];return i},sibling:function(e,t){var n=[];for(;e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n}});function ft(e,t,n){if(x.isFunction(t))return x.grep(e,function(e,r){return!!t.call(e,r,e)!==n});if(t.nodeType)return x.grep(e,function(e){return e===t!==n});if("string"==typeof t){if(st.test(t))return x.filter(t,e,n);t=x.filter(t,e)}return x.grep(e,function(e){return x.inArray(e,t)>=0!==n})}function dt(e){var t=ht.split("|"),n=e.createDocumentFragment();if(n.createElement)while(t.length)n.createElement(t.pop());return n}var ht="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",gt=/ jQuery\d+="(?:null|\d+)"/g,mt=RegExp("<(?:"+ht+")[\\s/>]","i"),yt=/^\s+/,vt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,bt=/<([\w:]+)/,xt=/<tbody/i,wt=/<|&#?\w+;/,Tt=/<(?:script|style|link)/i,Ct=/^(?:checkbox|radio)$/i,Nt=/checked\s*(?:[^=]|=\s*.checked.)/i,kt=/^$|\/(?:java|ecma)script/i,Et=/^true\/(.*)/,St=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,At={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],area:[1,"<map>","</map>"],param:[1,"<object>","</object>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:x.support.htmlSerialize?[0,"",""]:[1,"X<div>","</div>"]},jt=dt(a),Dt=jt.appendChild(a.createElement("div"));At.optgroup=At.option,At.tbody=At.tfoot=At.colgroup=At.caption=At.thead,At.th=At.td,x.fn.extend({text:function(e){return x.access(this,function(e){return e===t?x.text(this):this.empty().append((this[0]&&this[0].ownerDocument||a).createTextNode(e))},null,e,arguments.length)},append:function(){return this.domManip(arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Lt(this,e);t.appendChild(e)}})},prepend:function(){return this.domManip(arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Lt(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return this.domManip(arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return this.domManip(arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},remove:function(e,t){var n,r=e?x.filter(e,this):this,i=0;for(;null!=(n=r[i]);i++)t||1!==n.nodeType||x.cleanData(Ft(n)),n.parentNode&&(t&&x.contains(n.ownerDocument,n)&&_t(Ft(n,"script")),n.parentNode.removeChild(n));return this},empty:function(){var e,t=0;for(;null!=(e=this[t]);t++){1===e.nodeType&&x.cleanData(Ft(e,!1));while(e.firstChild)e.removeChild(e.firstChild);e.options&&x.nodeName(e,"select")&&(e.options.length=0)}return this},clone:function(e,t){return e=null==e?!1:e,t=null==t?e:t,this.map(function(){return x.clone(this,e,t)})},html:function(e){return x.access(this,function(e){var n=this[0]||{},r=0,i=this.length;if(e===t)return 1===n.nodeType?n.innerHTML.replace(gt,""):t;if(!("string"!=typeof e||Tt.test(e)||!x.support.htmlSerialize&&mt.test(e)||!x.support.leadingWhitespace&&yt.test(e)||At[(bt.exec(e)||["",""])[1].toLowerCase()])){e=e.replace(vt,"<$1></$2>");try{for(;i>r;r++)n=this[r]||{},1===n.nodeType&&(x.cleanData(Ft(n,!1)),n.innerHTML=e);n=0}catch(o){}}n&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(){var e=x.map(this,function(e){return[e.nextSibling,e.parentNode]}),t=0;return this.domManip(arguments,function(n){var r=e[t++],i=e[t++];i&&(r&&r.parentNode!==i&&(r=this.nextSibling),x(this).remove(),i.insertBefore(n,r))},!0),t?this:this.remove()},detach:function(e){return this.remove(e,!0)},domManip:function(e,t,n){e=d.apply([],e);var r,i,o,a,s,l,u=0,c=this.length,p=this,f=c-1,h=e[0],g=x.isFunction(h);if(g||!(1>=c||"string"!=typeof h||x.support.checkClone)&&Nt.test(h))return this.each(function(r){var i=p.eq(r);g&&(e[0]=h.call(this,r,i.html())),i.domManip(e,t,n)});if(c&&(l=x.buildFragment(e,this[0].ownerDocument,!1,!n&&this),r=l.firstChild,1===l.childNodes.length&&(l=r),r)){for(a=x.map(Ft(l,"script"),Ht),o=a.length;c>u;u++)i=l,u!==f&&(i=x.clone(i,!0,!0),o&&x.merge(a,Ft(i,"script"))),t.call(this[u],i,u);if(o)for(s=a[a.length-1].ownerDocument,x.map(a,qt),u=0;o>u;u++)i=a[u],kt.test(i.type||"")&&!x._data(i,"globalEval")&&x.contains(s,i)&&(i.src?x._evalUrl(i.src):x.globalEval((i.text||i.textContent||i.innerHTML||"").replace(St,"")));l=r=null}return this}});function Lt(e,t){return x.nodeName(e,"table")&&x.nodeName(1===t.nodeType?t:t.firstChild,"tr")?e.getElementsByTagName("tbody")[0]||e.appendChild(e.ownerDocument.createElement("tbody")):e}function Ht(e){return e.type=(null!==x.find.attr(e,"type"))+"/"+e.type,e}function qt(e){var t=Et.exec(e.type);return t?e.type=t[1]:e.removeAttribute("type"),e}function _t(e,t){var n,r=0;for(;null!=(n=e[r]);r++)x._data(n,"globalEval",!t||x._data(t[r],"globalEval"))}function Mt(e,t){if(1===t.nodeType&&x.hasData(e)){var n,r,i,o=x._data(e),a=x._data(t,o),s=o.events;if(s){delete a.handle,a.events={};for(n in s)for(r=0,i=s[n].length;i>r;r++)x.event.add(t,n,s[n][r])}a.data&&(a.data=x.extend({},a.data))}}function Ot(e,t){var n,r,i;if(1===t.nodeType){if(n=t.nodeName.toLowerCase(),!x.support.noCloneEvent&&t[x.expando]){i=x._data(t);for(r in i.events)x.removeEvent(t,r,i.handle);t.removeAttribute(x.expando)}"script"===n&&t.text!==e.text?(Ht(t).text=e.text,qt(t)):"object"===n?(t.parentNode&&(t.outerHTML=e.outerHTML),x.support.html5Clone&&e.innerHTML&&!x.trim(t.innerHTML)&&(t.innerHTML=e.innerHTML)):"input"===n&&Ct.test(e.type)?(t.defaultChecked=t.checked=e.checked,t.value!==e.value&&(t.value=e.value)):"option"===n?t.defaultSelected=t.selected=e.defaultSelected:("input"===n||"textarea"===n)&&(t.defaultValue=e.defaultValue)}}x.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,t){x.fn[e]=function(e){var n,r=0,i=[],o=x(e),a=o.length-1;for(;a>=r;r++)n=r===a?this:this.clone(!0),x(o[r])[t](n),h.apply(i,n.get());return this.pushStack(i)}});function Ft(e,n){var r,o,a=0,s=typeof e.getElementsByTagName!==i?e.getElementsByTagName(n||"*"):typeof e.querySelectorAll!==i?e.querySelectorAll(n||"*"):t;if(!s)for(s=[],r=e.childNodes||e;null!=(o=r[a]);a++)!n||x.nodeName(o,n)?s.push(o):x.merge(s,Ft(o,n));return n===t||n&&x.nodeName(e,n)?x.merge([e],s):s}function Bt(e){Ct.test(e.type)&&(e.defaultChecked=e.checked)}x.extend({clone:function(e,t,n){var r,i,o,a,s,l=x.contains(e.ownerDocument,e);if(x.support.html5Clone||x.isXMLDoc(e)||!mt.test("<"+e.nodeName+">")?o=e.cloneNode(!0):(Dt.innerHTML=e.outerHTML,Dt.removeChild(o=Dt.firstChild)),!(x.support.noCloneEvent&&x.support.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||x.isXMLDoc(e)))for(r=Ft(o),s=Ft(e),a=0;null!=(i=s[a]);++a)r[a]&&Ot(i,r[a]);if(t)if(n)for(s=s||Ft(e),r=r||Ft(o),a=0;null!=(i=s[a]);a++)Mt(i,r[a]);else Mt(e,o);return r=Ft(o,"script"),r.length>0&&_t(r,!l&&Ft(e,"script")),r=s=i=null,o},buildFragment:function(e,t,n,r){var i,o,a,s,l,u,c,p=e.length,f=dt(t),d=[],h=0;for(;p>h;h++)if(o=e[h],o||0===o)if("object"===x.type(o))x.merge(d,o.nodeType?[o]:o);else if(wt.test(o)){s=s||f.appendChild(t.createElement("div")),l=(bt.exec(o)||["",""])[1].toLowerCase(),c=At[l]||At._default,s.innerHTML=c[1]+o.replace(vt,"<$1></$2>")+c[2],i=c[0];while(i--)s=s.lastChild;if(!x.support.leadingWhitespace&&yt.test(o)&&d.push(t.createTextNode(yt.exec(o)[0])),!x.support.tbody){o="table"!==l||xt.test(o)?"<table>"!==c[1]||xt.test(o)?0:s:s.firstChild,i=o&&o.childNodes.length;while(i--)x.nodeName(u=o.childNodes[i],"tbody")&&!u.childNodes.length&&o.removeChild(u)}x.merge(d,s.childNodes),s.textContent="";while(s.firstChild)s.removeChild(s.firstChild);s=f.lastChild}else d.push(t.createTextNode(o));s&&f.removeChild(s),x.support.appendChecked||x.grep(Ft(d,"input"),Bt),h=0;while(o=d[h++])if((!r||-1===x.inArray(o,r))&&(a=x.contains(o.ownerDocument,o),s=Ft(f.appendChild(o),"script"),a&&_t(s),n)){i=0;while(o=s[i++])kt.test(o.type||"")&&n.push(o)}return s=null,f},cleanData:function(e,t){var n,r,o,a,s=0,l=x.expando,u=x.cache,c=x.support.deleteExpando,f=x.event.special;for(;null!=(n=e[s]);s++)if((t||x.acceptData(n))&&(o=n[l],a=o&&u[o])){if(a.events)for(r in a.events)f[r]?x.event.remove(n,r):x.removeEvent(n,r,a.handle);
-u[o]&&(delete u[o],c?delete n[l]:typeof n.removeAttribute!==i?n.removeAttribute(l):n[l]=null,p.push(o))}},_evalUrl:function(e){return x.ajax({url:e,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0})}}),x.fn.extend({wrapAll:function(e){if(x.isFunction(e))return this.each(function(t){x(this).wrapAll(e.call(this,t))});if(this[0]){var t=x(e,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstChild&&1===e.firstChild.nodeType)e=e.firstChild;return e}).append(this)}return this},wrapInner:function(e){return x.isFunction(e)?this.each(function(t){x(this).wrapInner(e.call(this,t))}):this.each(function(){var t=x(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=x.isFunction(e);return this.each(function(n){x(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){x.nodeName(this,"body")||x(this).replaceWith(this.childNodes)}).end()}});var Pt,Rt,Wt,$t=/alpha\([^)]*\)/i,It=/opacity\s*=\s*([^)]*)/,zt=/^(top|right|bottom|left)$/,Xt=/^(none|table(?!-c[ea]).+)/,Ut=/^margin/,Vt=RegExp("^("+w+")(.*)$","i"),Yt=RegExp("^("+w+")(?!px)[a-z%]+$","i"),Jt=RegExp("^([+-])=("+w+")","i"),Gt={BODY:"block"},Qt={position:"absolute",visibility:"hidden",display:"block"},Kt={letterSpacing:0,fontWeight:400},Zt=["Top","Right","Bottom","Left"],en=["Webkit","O","Moz","ms"];function tn(e,t){if(t in e)return t;var n=t.charAt(0).toUpperCase()+t.slice(1),r=t,i=en.length;while(i--)if(t=en[i]+n,t in e)return t;return r}function nn(e,t){return e=t||e,"none"===x.css(e,"display")||!x.contains(e.ownerDocument,e)}function rn(e,t){var n,r,i,o=[],a=0,s=e.length;for(;s>a;a++)r=e[a],r.style&&(o[a]=x._data(r,"olddisplay"),n=r.style.display,t?(o[a]||"none"!==n||(r.style.display=""),""===r.style.display&&nn(r)&&(o[a]=x._data(r,"olddisplay",ln(r.nodeName)))):o[a]||(i=nn(r),(n&&"none"!==n||!i)&&x._data(r,"olddisplay",i?n:x.css(r,"display"))));for(a=0;s>a;a++)r=e[a],r.style&&(t&&"none"!==r.style.display&&""!==r.style.display||(r.style.display=t?o[a]||"":"none"));return e}x.fn.extend({css:function(e,n){return x.access(this,function(e,n,r){var i,o,a={},s=0;if(x.isArray(n)){for(o=Rt(e),i=n.length;i>s;s++)a[n[s]]=x.css(e,n[s],!1,o);return a}return r!==t?x.style(e,n,r):x.css(e,n)},e,n,arguments.length>1)},show:function(){return rn(this,!0)},hide:function(){return rn(this)},toggle:function(e){return"boolean"==typeof e?e?this.show():this.hide():this.each(function(){nn(this)?x(this).show():x(this).hide()})}}),x.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Wt(e,"opacity");return""===n?"1":n}}}},cssNumber:{columnCount:!0,fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":x.support.cssFloat?"cssFloat":"styleFloat"},style:function(e,n,r,i){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var o,a,s,l=x.camelCase(n),u=e.style;if(n=x.cssProps[l]||(x.cssProps[l]=tn(u,l)),s=x.cssHooks[n]||x.cssHooks[l],r===t)return s&&"get"in s&&(o=s.get(e,!1,i))!==t?o:u[n];if(a=typeof r,"string"===a&&(o=Jt.exec(r))&&(r=(o[1]+1)*o[2]+parseFloat(x.css(e,n)),a="number"),!(null==r||"number"===a&&isNaN(r)||("number"!==a||x.cssNumber[l]||(r+="px"),x.support.clearCloneStyle||""!==r||0!==n.indexOf("background")||(u[n]="inherit"),s&&"set"in s&&(r=s.set(e,r,i))===t)))try{u[n]=r}catch(c){}}},css:function(e,n,r,i){var o,a,s,l=x.camelCase(n);return n=x.cssProps[l]||(x.cssProps[l]=tn(e.style,l)),s=x.cssHooks[n]||x.cssHooks[l],s&&"get"in s&&(a=s.get(e,!0,r)),a===t&&(a=Wt(e,n,i)),"normal"===a&&n in Kt&&(a=Kt[n]),""===r||r?(o=parseFloat(a),r===!0||x.isNumeric(o)?o||0:a):a}}),e.getComputedStyle?(Rt=function(t){return e.getComputedStyle(t,null)},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),l=s?s.getPropertyValue(n)||s[n]:t,u=e.style;return s&&(""!==l||x.contains(e.ownerDocument,e)||(l=x.style(e,n)),Yt.test(l)&&Ut.test(n)&&(i=u.width,o=u.minWidth,a=u.maxWidth,u.minWidth=u.maxWidth=u.width=l,l=s.width,u.width=i,u.minWidth=o,u.maxWidth=a)),l}):a.documentElement.currentStyle&&(Rt=function(e){return e.currentStyle},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),l=s?s[n]:t,u=e.style;return null==l&&u&&u[n]&&(l=u[n]),Yt.test(l)&&!zt.test(n)&&(i=u.left,o=e.runtimeStyle,a=o&&o.left,a&&(o.left=e.currentStyle.left),u.left="fontSize"===n?"1em":l,l=u.pixelLeft+"px",u.left=i,a&&(o.left=a)),""===l?"auto":l});function on(e,t,n){var r=Vt.exec(t);return r?Math.max(0,r[1]-(n||0))+(r[2]||"px"):t}function an(e,t,n,r,i){var o=n===(r?"border":"content")?4:"width"===t?1:0,a=0;for(;4>o;o+=2)"margin"===n&&(a+=x.css(e,n+Zt[o],!0,i)),r?("content"===n&&(a-=x.css(e,"padding"+Zt[o],!0,i)),"margin"!==n&&(a-=x.css(e,"border"+Zt[o]+"Width",!0,i))):(a+=x.css(e,"padding"+Zt[o],!0,i),"padding"!==n&&(a+=x.css(e,"border"+Zt[o]+"Width",!0,i)));return a}function sn(e,t,n){var r=!0,i="width"===t?e.offsetWidth:e.offsetHeight,o=Rt(e),a=x.support.boxSizing&&"border-box"===x.css(e,"boxSizing",!1,o);if(0>=i||null==i){if(i=Wt(e,t,o),(0>i||null==i)&&(i=e.style[t]),Yt.test(i))return i;r=a&&(x.support.boxSizingReliable||i===e.style[t]),i=parseFloat(i)||0}return i+an(e,t,n||(a?"border":"content"),r,o)+"px"}function ln(e){var t=a,n=Gt[e];return n||(n=un(e,t),"none"!==n&&n||(Pt=(Pt||x("<iframe frameborder='0' width='0' height='0'/>").css("cssText","display:block !important")).appendTo(t.documentElement),t=(Pt[0].contentWindow||Pt[0].contentDocument).document,t.write("<!doctype html><html><body>"),t.close(),n=un(e,t),Pt.detach()),Gt[e]=n),n}function un(e,t){var n=x(t.createElement(e)).appendTo(t.body),r=x.css(n[0],"display");return n.remove(),r}x.each(["height","width"],function(e,n){x.cssHooks[n]={get:function(e,r,i){return r?0===e.offsetWidth&&Xt.test(x.css(e,"display"))?x.swap(e,Qt,function(){return sn(e,n,i)}):sn(e,n,i):t},set:function(e,t,r){var i=r&&Rt(e);return on(e,t,r?an(e,n,r,x.support.boxSizing&&"border-box"===x.css(e,"boxSizing",!1,i),i):0)}}}),x.support.opacity||(x.cssHooks.opacity={get:function(e,t){return It.test((t&&e.currentStyle?e.currentStyle.filter:e.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":t?"1":""},set:function(e,t){var n=e.style,r=e.currentStyle,i=x.isNumeric(t)?"alpha(opacity="+100*t+")":"",o=r&&r.filter||n.filter||"";n.zoom=1,(t>=1||""===t)&&""===x.trim(o.replace($t,""))&&n.removeAttribute&&(n.removeAttribute("filter"),""===t||r&&!r.filter)||(n.filter=$t.test(o)?o.replace($t,i):o+" "+i)}}),x(function(){x.support.reliableMarginRight||(x.cssHooks.marginRight={get:function(e,n){return n?x.swap(e,{display:"inline-block"},Wt,[e,"marginRight"]):t}}),!x.support.pixelPosition&&x.fn.position&&x.each(["top","left"],function(e,n){x.cssHooks[n]={get:function(e,r){return r?(r=Wt(e,n),Yt.test(r)?x(e).position()[n]+"px":r):t}}})}),x.expr&&x.expr.filters&&(x.expr.filters.hidden=function(e){return 0>=e.offsetWidth&&0>=e.offsetHeight||!x.support.reliableHiddenOffsets&&"none"===(e.style&&e.style.display||x.css(e,"display"))},x.expr.filters.visible=function(e){return!x.expr.filters.hidden(e)}),x.each({margin:"",padding:"",border:"Width"},function(e,t){x.cssHooks[e+t]={expand:function(n){var r=0,i={},o="string"==typeof n?n.split(" "):[n];for(;4>r;r++)i[e+Zt[r]+t]=o[r]||o[r-2]||o[0];return i}},Ut.test(e)||(x.cssHooks[e+t].set=on)});var cn=/%20/g,pn=/\[\]$/,fn=/\r?\n/g,dn=/^(?:submit|button|image|reset|file)$/i,hn=/^(?:input|select|textarea|keygen)/i;x.fn.extend({serialize:function(){return x.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=x.prop(this,"elements");return e?x.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!x(this).is(":disabled")&&hn.test(this.nodeName)&&!dn.test(e)&&(this.checked||!Ct.test(e))}).map(function(e,t){var n=x(this).val();return null==n?null:x.isArray(n)?x.map(n,function(e){return{name:t.name,value:e.replace(fn,"\r\n")}}):{name:t.name,value:n.replace(fn,"\r\n")}}).get()}}),x.param=function(e,n){var r,i=[],o=function(e,t){t=x.isFunction(t)?t():null==t?"":t,i[i.length]=encodeURIComponent(e)+"="+encodeURIComponent(t)};if(n===t&&(n=x.ajaxSettings&&x.ajaxSettings.traditional),x.isArray(e)||e.jquery&&!x.isPlainObject(e))x.each(e,function(){o(this.name,this.value)});else for(r in e)gn(r,e[r],n,o);return i.join("&").replace(cn,"+")};function gn(e,t,n,r){var i;if(x.isArray(t))x.each(t,function(t,i){n||pn.test(e)?r(e,i):gn(e+"["+("object"==typeof i?t:"")+"]",i,n,r)});else if(n||"object"!==x.type(t))r(e,t);else for(i in t)gn(e+"["+i+"]",t[i],n,r)}x.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(e,t){x.fn[t]=function(e,n){return arguments.length>0?this.on(t,null,e,n):this.trigger(t)}}),x.fn.extend({hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)},bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)}});var mn,yn,vn=x.now(),bn=/\?/,xn=/#.*$/,wn=/([?&])_=[^&]*/,Tn=/^(.*?):[ \t]*([^\r\n]*)\r?$/gm,Cn=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Nn=/^(?:GET|HEAD)$/,kn=/^\/\//,En=/^([\w.+-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,Sn=x.fn.load,An={},jn={},Dn="*/".concat("*");try{yn=o.href}catch(Ln){yn=a.createElement("a"),yn.href="",yn=yn.href}mn=En.exec(yn.toLowerCase())||[];function Hn(e){return function(t,n){"string"!=typeof t&&(n=t,t="*");var r,i=0,o=t.toLowerCase().match(T)||[];if(x.isFunction(n))while(r=o[i++])"+"===r[0]?(r=r.slice(1)||"*",(e[r]=e[r]||[]).unshift(n)):(e[r]=e[r]||[]).push(n)}}function qn(e,n,r,i){var o={},a=e===jn;function s(l){var u;return o[l]=!0,x.each(e[l]||[],function(e,l){var c=l(n,r,i);return"string"!=typeof c||a||o[c]?a?!(u=c):t:(n.dataTypes.unshift(c),s(c),!1)}),u}return s(n.dataTypes[0])||!o["*"]&&s("*")}function _n(e,n){var r,i,o=x.ajaxSettings.flatOptions||{};for(i in n)n[i]!==t&&((o[i]?e:r||(r={}))[i]=n[i]);return r&&x.extend(!0,e,r),e}x.fn.load=function(e,n,r){if("string"!=typeof e&&Sn)return Sn.apply(this,arguments);var i,o,a,s=this,l=e.indexOf(" ");return l>=0&&(i=e.slice(l,e.length),e=e.slice(0,l)),x.isFunction(n)?(r=n,n=t):n&&"object"==typeof n&&(a="POST"),s.length>0&&x.ajax({url:e,type:a,dataType:"html",data:n}).done(function(e){o=arguments,s.html(i?x("<div>").append(x.parseHTML(e)).find(i):e)}).complete(r&&function(e,t){s.each(r,o||[e.responseText,t,e])}),this},x.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){x.fn[t]=function(e){return this.on(t,e)}}),x.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:yn,type:"GET",isLocal:Cn.test(mn[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Dn,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":x.parseJSON,"text xml":x.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?_n(_n(e,x.ajaxSettings),t):_n(x.ajaxSettings,e)},ajaxPrefilter:Hn(An),ajaxTransport:Hn(jn),ajax:function(e,n){"object"==typeof e&&(n=e,e=t),n=n||{};var r,i,o,a,s,l,u,c,p=x.ajaxSetup({},n),f=p.context||p,d=p.context&&(f.nodeType||f.jquery)?x(f):x.event,h=x.Deferred(),g=x.Callbacks("once memory"),m=p.statusCode||{},y={},v={},b=0,w="canceled",C={readyState:0,getResponseHeader:function(e){var t;if(2===b){if(!c){c={};while(t=Tn.exec(a))c[t[1].toLowerCase()]=t[2]}t=c[e.toLowerCase()]}return null==t?null:t},getAllResponseHeaders:function(){return 2===b?a:null},setRequestHeader:function(e,t){var n=e.toLowerCase();return b||(e=v[n]=v[n]||e,y[e]=t),this},overrideMimeType:function(e){return b||(p.mimeType=e),this},statusCode:function(e){var t;if(e)if(2>b)for(t in e)m[t]=[m[t],e[t]];else C.always(e[C.status]);return this},abort:function(e){var t=e||w;return u&&u.abort(t),k(0,t),this}};if(h.promise(C).complete=g.add,C.success=C.done,C.error=C.fail,p.url=((e||p.url||yn)+"").replace(xn,"").replace(kn,mn[1]+"//"),p.type=n.method||n.type||p.method||p.type,p.dataTypes=x.trim(p.dataType||"*").toLowerCase().match(T)||[""],null==p.crossDomain&&(r=En.exec(p.url.toLowerCase()),p.crossDomain=!(!r||r[1]===mn[1]&&r[2]===mn[2]&&(r[3]||("http:"===r[1]?"80":"443"))===(mn[3]||("http:"===mn[1]?"80":"443")))),p.data&&p.processData&&"string"!=typeof p.data&&(p.data=x.param(p.data,p.traditional)),qn(An,p,n,C),2===b)return C;l=p.global,l&&0===x.active++&&x.event.trigger("ajaxStart"),p.type=p.type.toUpperCase(),p.hasContent=!Nn.test(p.type),o=p.url,p.hasContent||(p.data&&(o=p.url+=(bn.test(o)?"&":"?")+p.data,delete p.data),p.cache===!1&&(p.url=wn.test(o)?o.replace(wn,"$1_="+vn++):o+(bn.test(o)?"&":"?")+"_="+vn++)),p.ifModified&&(x.lastModified[o]&&C.setRequestHeader("If-Modified-Since",x.lastModified[o]),x.etag[o]&&C.setRequestHeader("If-None-Match",x.etag[o])),(p.data&&p.hasContent&&p.contentType!==!1||n.contentType)&&C.setRequestHeader("Content-Type",p.contentType),C.setRequestHeader("Accept",p.dataTypes[0]&&p.accepts[p.dataTypes[0]]?p.accepts[p.dataTypes[0]]+("*"!==p.dataTypes[0]?", "+Dn+"; q=0.01":""):p.accepts["*"]);for(i in p.headers)C.setRequestHeader(i,p.headers[i]);if(p.beforeSend&&(p.beforeSend.call(f,C,p)===!1||2===b))return C.abort();w="abort";for(i in{success:1,error:1,complete:1})C[i](p[i]);if(u=qn(jn,p,n,C)){C.readyState=1,l&&d.trigger("ajaxSend",[C,p]),p.async&&p.timeout>0&&(s=setTimeout(function(){C.abort("timeout")},p.timeout));try{b=1,u.send(y,k)}catch(N){if(!(2>b))throw N;k(-1,N)}}else k(-1,"No Transport");function k(e,n,r,i){var c,y,v,w,T,N=n;2!==b&&(b=2,s&&clearTimeout(s),u=t,a=i||"",C.readyState=e>0?4:0,c=e>=200&&300>e||304===e,r&&(w=Mn(p,C,r)),w=On(p,w,C,c),c?(p.ifModified&&(T=C.getResponseHeader("Last-Modified"),T&&(x.lastModified[o]=T),T=C.getResponseHeader("etag"),T&&(x.etag[o]=T)),204===e||"HEAD"===p.type?N="nocontent":304===e?N="notmodified":(N=w.state,y=w.data,v=w.error,c=!v)):(v=N,(e||!N)&&(N="error",0>e&&(e=0))),C.status=e,C.statusText=(n||N)+"",c?h.resolveWith(f,[y,N,C]):h.rejectWith(f,[C,N,v]),C.statusCode(m),m=t,l&&d.trigger(c?"ajaxSuccess":"ajaxError",[C,p,c?y:v]),g.fireWith(f,[C,N]),l&&(d.trigger("ajaxComplete",[C,p]),--x.active||x.event.trigger("ajaxStop")))}return C},getJSON:function(e,t,n){return x.get(e,t,n,"json")},getScript:function(e,n){return x.get(e,t,n,"script")}}),x.each(["get","post"],function(e,n){x[n]=function(e,r,i,o){return x.isFunction(r)&&(o=o||i,i=r,r=t),x.ajax({url:e,type:n,dataType:o,data:r,success:i})}});function Mn(e,n,r){var i,o,a,s,l=e.contents,u=e.dataTypes;while("*"===u[0])u.shift(),o===t&&(o=e.mimeType||n.getResponseHeader("Content-Type"));if(o)for(s in l)if(l[s]&&l[s].test(o)){u.unshift(s);break}if(u[0]in r)a=u[0];else{for(s in r){if(!u[0]||e.converters[s+" "+u[0]]){a=s;break}i||(i=s)}a=a||i}return a?(a!==u[0]&&u.unshift(a),r[a]):t}function On(e,t,n,r){var i,o,a,s,l,u={},c=e.dataTypes.slice();if(c[1])for(a in e.converters)u[a.toLowerCase()]=e.converters[a];o=c.shift();while(o)if(e.responseFields[o]&&(n[e.responseFields[o]]=t),!l&&r&&e.dataFilter&&(t=e.dataFilter(t,e.dataType)),l=o,o=c.shift())if("*"===o)o=l;else if("*"!==l&&l!==o){if(a=u[l+" "+o]||u["* "+o],!a)for(i in u)if(s=i.split(" "),s[1]===o&&(a=u[l+" "+s[0]]||u["* "+s[0]])){a===!0?a=u[i]:u[i]!==!0&&(o=s[0],c.unshift(s[1]));break}if(a!==!0)if(a&&e["throws"])t=a(t);else try{t=a(t)}catch(p){return{state:"parsererror",error:a?p:"No conversion from "+l+" to "+o}}}return{state:"success",data:t}}x.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(e){return x.globalEval(e),e}}}),x.ajaxPrefilter("script",function(e){e.cache===t&&(e.cache=!1),e.crossDomain&&(e.type="GET",e.global=!1)}),x.ajaxTransport("script",function(e){if(e.crossDomain){var n,r=a.head||x("head")[0]||a.documentElement;return{send:function(t,i){n=a.createElement("script"),n.async=!0,e.scriptCharset&&(n.charset=e.scriptCharset),n.src=e.url,n.onload=n.onreadystatechange=function(e,t){(t||!n.readyState||/loaded|complete/.test(n.readyState))&&(n.onload=n.onreadystatechange=null,n.parentNode&&n.parentNode.removeChild(n),n=null,t||i(200,"success"))},r.insertBefore(n,r.firstChild)},abort:function(){n&&n.onload(t,!0)}}}});var Fn=[],Bn=/(=)\?(?=&|$)|\?\?/;x.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Fn.pop()||x.expando+"_"+vn++;return this[e]=!0,e}}),x.ajaxPrefilter("json jsonp",function(n,r,i){var o,a,s,l=n.jsonp!==!1&&(Bn.test(n.url)?"url":"string"==typeof n.data&&!(n.contentType||"").indexOf("application/x-www-form-urlencoded")&&Bn.test(n.data)&&"data");return l||"jsonp"===n.dataTypes[0]?(o=n.jsonpCallback=x.isFunction(n.jsonpCallback)?n.jsonpCallback():n.jsonpCallback,l?n[l]=n[l].replace(Bn,"$1"+o):n.jsonp!==!1&&(n.url+=(bn.test(n.url)?"&":"?")+n.jsonp+"="+o),n.converters["script json"]=function(){return s||x.error(o+" was not called"),s[0]},n.dataTypes[0]="json",a=e[o],e[o]=function(){s=arguments},i.always(function(){e[o]=a,n[o]&&(n.jsonpCallback=r.jsonpCallback,Fn.push(o)),s&&x.isFunction(a)&&a(s[0]),s=a=t}),"script"):t});var Pn,Rn,Wn=0,$n=e.ActiveXObject&&function(){var e;for(e in Pn)Pn[e](t,!0)};function In(){try{return new e.XMLHttpRequest}catch(t){}}function zn(){try{return new e.ActiveXObject("Microsoft.XMLHTTP")}catch(t){}}x.ajaxSettings.xhr=e.ActiveXObject?function(){return!this.isLocal&&In()||zn()}:In,Rn=x.ajaxSettings.xhr(),x.support.cors=!!Rn&&"withCredentials"in Rn,Rn=x.support.ajax=!!Rn,Rn&&x.ajaxTransport(function(n){if(!n.crossDomain||x.support.cors){var r;return{send:function(i,o){var a,s,l=n.xhr();if(n.username?l.open(n.type,n.url,n.async,n.username,n.password):l.open(n.type,n.url,n.async),n.xhrFields)for(s in n.xhrFields)l[s]=n.xhrFields[s];n.mimeType&&l.overrideMimeType&&l.overrideMimeType(n.mimeType),n.crossDomain||i["X-Requested-With"]||(i["X-Requested-With"]="XMLHttpRequest");try{for(s in i)l.setRequestHeader(s,i[s])}catch(u){}l.send(n.hasContent&&n.data||null),r=function(e,i){var s,u,c,p;try{if(r&&(i||4===l.readyState))if(r=t,a&&(l.onreadystatechange=x.noop,$n&&delete Pn[a]),i)4!==l.readyState&&l.abort();else{p={},s=l.status,u=l.getAllResponseHeaders(),"string"==typeof l.responseText&&(p.text=l.responseText);try{c=l.statusText}catch(f){c=""}s||!n.isLocal||n.crossDomain?1223===s&&(s=204):s=p.text?200:404}}catch(d){i||o(-1,d)}p&&o(s,c,p,u)},n.async?4===l.readyState?setTimeout(r):(a=++Wn,$n&&(Pn||(Pn={},x(e).unload($n)),Pn[a]=r),l.onreadystatechange=r):r()},abort:function(){r&&r(t,!0)}}}});var Xn,Un,Vn=/^(?:toggle|show|hide)$/,Yn=RegExp("^(?:([+-])=|)("+w+")([a-z%]*)$","i"),Jn=/queueHooks$/,Gn=[nr],Qn={"*":[function(e,t){var n=this.createTween(e,t),r=n.cur(),i=Yn.exec(t),o=i&&i[3]||(x.cssNumber[e]?"":"px"),a=(x.cssNumber[e]||"px"!==o&&+r)&&Yn.exec(x.css(n.elem,e)),s=1,l=20;if(a&&a[3]!==o){o=o||a[3],i=i||[],a=+r||1;do s=s||".5",a/=s,x.style(n.elem,e,a+o);while(s!==(s=n.cur()/r)&&1!==s&&--l)}return i&&(a=n.start=+a||+r||0,n.unit=o,n.end=i[1]?a+(i[1]+1)*i[2]:+i[2]),n}]};function Kn(){return setTimeout(function(){Xn=t}),Xn=x.now()}function Zn(e,t,n){var r,i=(Qn[t]||[]).concat(Qn["*"]),o=0,a=i.length;for(;a>o;o++)if(r=i[o].call(n,t,e))return r}function er(e,t,n){var r,i,o=0,a=Gn.length,s=x.Deferred().always(function(){delete l.elem}),l=function(){if(i)return!1;var t=Xn||Kn(),n=Math.max(0,u.startTime+u.duration-t),r=n/u.duration||0,o=1-r,a=0,l=u.tweens.length;for(;l>a;a++)u.tweens[a].run(o);return s.notifyWith(e,[u,o,n]),1>o&&l?n:(s.resolveWith(e,[u]),!1)},u=s.promise({elem:e,props:x.extend({},t),opts:x.extend(!0,{specialEasing:{}},n),originalProperties:t,originalOptions:n,startTime:Xn||Kn(),duration:n.duration,tweens:[],createTween:function(t,n){var r=x.Tween(e,u.opts,t,n,u.opts.specialEasing[t]||u.opts.easing);return u.tweens.push(r),r},stop:function(t){var n=0,r=t?u.tweens.length:0;if(i)return this;for(i=!0;r>n;n++)u.tweens[n].run(1);return t?s.resolveWith(e,[u,t]):s.rejectWith(e,[u,t]),this}}),c=u.props;for(tr(c,u.opts.specialEasing);a>o;o++)if(r=Gn[o].call(u,e,c,u.opts))return r;return x.map(c,Zn,u),x.isFunction(u.opts.start)&&u.opts.start.call(e,u),x.fx.timer(x.extend(l,{elem:e,anim:u,queue:u.opts.queue})),u.progress(u.opts.progress).done(u.opts.done,u.opts.complete).fail(u.opts.fail).always(u.opts.always)}function tr(e,t){var n,r,i,o,a;for(n in e)if(r=x.camelCase(n),i=t[r],o=e[n],x.isArray(o)&&(i=o[1],o=e[n]=o[0]),n!==r&&(e[r]=o,delete e[n]),a=x.cssHooks[r],a&&"expand"in a){o=a.expand(o),delete e[r];for(n in o)n in e||(e[n]=o[n],t[n]=i)}else t[r]=i}x.Animation=x.extend(er,{tweener:function(e,t){x.isFunction(e)?(t=e,e=["*"]):e=e.split(" ");var n,r=0,i=e.length;for(;i>r;r++)n=e[r],Qn[n]=Qn[n]||[],Qn[n].unshift(t)},prefilter:function(e,t){t?Gn.unshift(e):Gn.push(e)}});function nr(e,t,n){var r,i,o,a,s,l,u=this,c={},p=e.style,f=e.nodeType&&nn(e),d=x._data(e,"fxshow");n.queue||(s=x._queueHooks(e,"fx"),null==s.unqueued&&(s.unqueued=0,l=s.empty.fire,s.empty.fire=function(){s.unqueued||l()}),s.unqueued++,u.always(function(){u.always(function(){s.unqueued--,x.queue(e,"fx").length||s.empty.fire()})})),1===e.nodeType&&("height"in t||"width"in t)&&(n.overflow=[p.overflow,p.overflowX,p.overflowY],"inline"===x.css(e,"display")&&"none"===x.css(e,"float")&&(x.support.inlineBlockNeedsLayout&&"inline"!==ln(e.nodeName)?p.zoom=1:p.display="inline-block")),n.overflow&&(p.overflow="hidden",x.support.shrinkWrapBlocks||u.always(function(){p.overflow=n.overflow[0],p.overflowX=n.overflow[1],p.overflowY=n.overflow[2]}));for(r in t)if(i=t[r],Vn.exec(i)){if(delete t[r],o=o||"toggle"===i,i===(f?"hide":"show"))continue;c[r]=d&&d[r]||x.style(e,r)}if(!x.isEmptyObject(c)){d?"hidden"in d&&(f=d.hidden):d=x._data(e,"fxshow",{}),o&&(d.hidden=!f),f?x(e).show():u.done(function(){x(e).hide()}),u.done(function(){var t;x._removeData(e,"fxshow");for(t in c)x.style(e,t,c[t])});for(r in c)a=Zn(f?d[r]:0,r,u),r in d||(d[r]=a.start,f&&(a.end=a.start,a.start="width"===r||"height"===r?1:0))}}function rr(e,t,n,r,i){return new rr.prototype.init(e,t,n,r,i)}x.Tween=rr,rr.prototype={constructor:rr,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||"swing",this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(x.cssNumber[n]?"":"px")},cur:function(){var e=rr.propHooks[this.prop];return e&&e.get?e.get(this):rr.propHooks._default.get(this)},run:function(e){var t,n=rr.propHooks[this.prop];return this.pos=t=this.options.duration?x.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):rr.propHooks._default.set(this),this}},rr.prototype.init.prototype=rr.prototype,rr.propHooks={_default:{get:function(e){var t;return null==e.elem[e.prop]||e.elem.style&&null!=e.elem.style[e.prop]?(t=x.css(e.elem,e.prop,""),t&&"auto"!==t?t:0):e.elem[e.prop]},set:function(e){x.fx.step[e.prop]?x.fx.step[e.prop](e):e.elem.style&&(null!=e.elem.style[x.cssProps[e.prop]]||x.cssHooks[e.prop])?x.style(e.elem,e.prop,e.now+e.unit):e.elem[e.prop]=e.now}}},rr.propHooks.scrollTop=rr.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},x.each(["toggle","show","hide"],function(e,t){var n=x.fn[t];x.fn[t]=function(e,r,i){return null==e||"boolean"==typeof e?n.apply(this,arguments):this.animate(ir(t,!0),e,r,i)}}),x.fn.extend({fadeTo:function(e,t,n,r){return this.filter(nn).css("opacity",0).show().end().animate({opacity:t},e,n,r)},animate:function(e,t,n,r){var i=x.isEmptyObject(e),o=x.speed(t,n,r),a=function(){var t=er(this,x.extend({},e),o);(i||x._data(this,"finish"))&&t.stop(!0)};return a.finish=a,i||o.queue===!1?this.each(a):this.queue(o.queue,a)},stop:function(e,n,r){var i=function(e){var t=e.stop;delete e.stop,t(r)};return"string"!=typeof e&&(r=n,n=e,e=t),n&&e!==!1&&this.queue(e||"fx",[]),this.each(function(){var t=!0,n=null!=e&&e+"queueHooks",o=x.timers,a=x._data(this);if(n)a[n]&&a[n].stop&&i(a[n]);else for(n in a)a[n]&&a[n].stop&&Jn.test(n)&&i(a[n]);for(n=o.length;n--;)o[n].elem!==this||null!=e&&o[n].queue!==e||(o[n].anim.stop(r),t=!1,o.splice(n,1));(t||!r)&&x.dequeue(this,e)})},finish:function(e){return e!==!1&&(e=e||"fx"),this.each(function(){var t,n=x._data(this),r=n[e+"queue"],i=n[e+"queueHooks"],o=x.timers,a=r?r.length:0;for(n.finish=!0,x.queue(this,e,[]),i&&i.stop&&i.stop.call(this,!0),t=o.length;t--;)o[t].elem===this&&o[t].queue===e&&(o[t].anim.stop(!0),o.splice(t,1));for(t=0;a>t;t++)r[t]&&r[t].finish&&r[t].finish.call(this);delete n.finish})}});function ir(e,t){var n,r={height:e},i=0;for(t=t?1:0;4>i;i+=2-t)n=Zt[i],r["margin"+n]=r["padding"+n]=e;return t&&(r.opacity=r.width=e),r}x.each({slideDown:ir("show"),slideUp:ir("hide"),slideToggle:ir("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(e,t){x.fn[e]=function(e,n,r){return this.animate(t,e,n,r)}}),x.speed=function(e,t,n){var r=e&&"object"==typeof e?x.extend({},e):{complete:n||!n&&t||x.isFunction(e)&&e,duration:e,easing:n&&t||t&&!x.isFunction(t)&&t};return r.duration=x.fx.off?0:"number"==typeof r.duration?r.duration:r.duration in x.fx.speeds?x.fx.speeds[r.duration]:x.fx.speeds._default,(null==r.queue||r.queue===!0)&&(r.queue="fx"),r.old=r.complete,r.complete=function(){x.isFunction(r.old)&&r.old.call(this),r.queue&&x.dequeue(this,r.queue)},r},x.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2}},x.timers=[],x.fx=rr.prototype.init,x.fx.tick=function(){var e,n=x.timers,r=0;for(Xn=x.now();n.length>r;r++)e=n[r],e()||n[r]!==e||n.splice(r--,1);n.length||x.fx.stop(),Xn=t},x.fx.timer=function(e){e()&&x.timers.push(e)&&x.fx.start()},x.fx.interval=13,x.fx.start=function(){Un||(Un=setInterval(x.fx.tick,x.fx.interval))},x.fx.stop=function(){clearInterval(Un),Un=null},x.fx.speeds={slow:600,fast:200,_default:400},x.fx.step={},x.expr&&x.expr.filters&&(x.expr.filters.animated=function(e){return x.grep(x.timers,function(t){return e===t.elem}).length}),x.fn.offset=function(e){if(arguments.length)return e===t?this:this.each(function(t){x.offset.setOffset(this,e,t)});var n,r,o={top:0,left:0},a=this[0],s=a&&a.ownerDocument;if(s)return n=s.documentElement,x.contains(n,a)?(typeof a.getBoundingClientRect!==i&&(o=a.getBoundingClientRect()),r=or(s),{top:o.top+(r.pageYOffset||n.scrollTop)-(n.clientTop||0),left:o.left+(r.pageXOffset||n.scrollLeft)-(n.clientLeft||0)}):o},x.offset={setOffset:function(e,t,n){var r=x.css(e,"position");"static"===r&&(e.style.position="relative");var i=x(e),o=i.offset(),a=x.css(e,"top"),s=x.css(e,"left"),l=("absolute"===r||"fixed"===r)&&x.inArray("auto",[a,s])>-1,u={},c={},p,f;l?(c=i.position(),p=c.top,f=c.left):(p=parseFloat(a)||0,f=parseFloat(s)||0),x.isFunction(t)&&(t=t.call(e,n,o)),null!=t.top&&(u.top=t.top-o.top+p),null!=t.left&&(u.left=t.left-o.left+f),"using"in t?t.using.call(e,u):i.css(u)}},x.fn.extend({position:function(){if(this[0]){var e,t,n={top:0,left:0},r=this[0];return"fixed"===x.css(r,"position")?t=r.getBoundingClientRect():(e=this.offsetParent(),t=this.offset(),x.nodeName(e[0],"html")||(n=e.offset()),n.top+=x.css(e[0],"borderTopWidth",!0),n.left+=x.css(e[0],"borderLeftWidth",!0)),{top:t.top-n.top-x.css(r,"marginTop",!0),left:t.left-n.left-x.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent||s;while(e&&!x.nodeName(e,"html")&&"static"===x.css(e,"position"))e=e.offsetParent;return e||s})}}),x.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(e,n){var r=/Y/.test(n);x.fn[e]=function(i){return x.access(this,function(e,i,o){var a=or(e);return o===t?a?n in a?a[n]:a.document.documentElement[i]:e[i]:(a?a.scrollTo(r?x(a).scrollLeft():o,r?o:x(a).scrollTop()):e[i]=o,t)},e,i,arguments.length,null)}});function or(e){return x.isWindow(e)?e:9===e.nodeType?e.defaultView||e.parentWindow:!1}x.each({Height:"height",Width:"width"},function(e,n){x.each({padding:"inner"+e,content:n,"":"outer"+e},function(r,i){x.fn[i]=function(i,o){var a=arguments.length&&(r||"boolean"!=typeof i),s=r||(i===!0||o===!0?"margin":"border");return x.access(this,function(n,r,i){var o;return x.isWindow(n)?n.document.documentElement["client"+e]:9===n.nodeType?(o=n.documentElement,Math.max(n.body["scroll"+e],o["scroll"+e],n.body["offset"+e],o["offset"+e],o["client"+e])):i===t?x.css(n,r,s):x.style(n,r,i,s)},n,a?i:t,a,null)}})}),x.fn.size=function(){return this.length},x.fn.andSelf=x.fn.addBack,"object"==typeof module&&module&&"object"==typeof module.exports?module.exports=x:(e.jQuery=e.$=x,"function"==typeof define&&define.amd&&define("jquery",[],function(){return x}))})(window);
diff --git a/gui/static/script.js b/gui/static/script.js
deleted file mode 100644
index a585f9f..0000000
--- a/gui/static/script.js
+++ /dev/null
@@ -1,4 +0,0 @@
-$(document).ready(function() {
-
-});
-
diff --git a/gui/static/stats.js b/gui/static/stats.js
deleted file mode 100644
index 7b07099..0000000
--- a/gui/static/stats.js
+++ /dev/null
@@ -1,17 +0,0 @@
-var updatefunc = function(event) {
- $('#statdata p').remove();
- $.getJSON('/stats.json', function(result) {
- $.each(result, function(name) {
- // TODO: use a hidden template inside the DOM instead
- // of building the HTML here
- $("<p></p>")
- .append(result[name]['inputstat']['num_underruns'])
- .appendTo('#statdata');
- });
- });
-}
-
-// Handle clicks on the to change visiblity of panes
-setInterval(updatefunc, 1000);
-
-
diff --git a/gui/static/style.css b/gui/static/style.css
deleted file mode 100644
index 43176f8..0000000
--- a/gui/static/style.css
+++ /dev/null
@@ -1,73 +0,0 @@
-body {
- font-family: "Lucida Sans Unicode","Lucida Grande",Sans-Serif;
- color: #3E3E3E;
- font-size: 12px;
-}
-
-p {
- padding: 5px;
-}
-
-div.cadre{
- border: 1px solid #999;
- padding: 0 10px;
- margin: 5px;
-}
-
-#info{
- width: 600px;
- border: 1px solid #999;
- padding: 0 10px;
-}
-#info p {
- width: inherit;
- background-color: inherit;
-}
-#info-nav{
- margin: 0;
- padding: 3px 0;
- width: 100%;
- list-style: none;
-}
-#info-nav li{
- display: inline;
- background: #ccc;
- border: 1px solid #888;
- border-bottom: 0;
- margin-right:2px;
- padding: 3px;
-}
-#info-nav li a:hover{
- color:#d15600;
-}
-#info-nav li.current{
- background: #fff;
- padding-bottom: 4px;
-}
-
-#celebs {
- clear: both;
-}
-
-table {
- border-collapse:collapse;
- font-size:12px;
- margin:0 20px 20px 20px;
- border-top:2px solid #015287;
- width:480px;
-}
-
-th {
- border-bottom: 2px solid #015287;
- color: #D15600;
- font-size: 14px;
- font-weight: normal;
- text-align: left;
- padding: 3px 8px;
-}
-
-td {
- padding: 6px;
-}
-
-
diff --git a/gui/views/configeditor.tpl b/gui/views/configeditor.tpl
deleted file mode 100644
index d302498..0000000
--- a/gui/views/configeditor.tpl
+++ /dev/null
@@ -1,29 +0,0 @@
-<!DOCTYPE html>
-<html>
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
- <meta name="viewport" content="width=device-width, initial-scale=1">
- <title>ODR-DabMux Configuration Editor</title>
- <link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">
- </head>
-<body class="w3-container">
- <h1>Configuration for {{version}}</h1>
-
- <p><a href="/config">Reload</a></p>
-
- {% if message %}
- <p>{{message}}</p>
- {% endif %}
-
- <form action="/config" method="post">
- <p>
- <textarea name="config" cols="60" rows="30">{{config}}</textarea>
- </p>
-
- <p>
- <input type="submit" value="Update ODR-DabMux configuration"></input>
- </p>
- </form>
-
- </body>
-</html> \ No newline at end of file
diff --git a/gui/views/index.tpl b/gui/views/index.tpl
deleted file mode 100644
index ce60533..0000000
--- a/gui/views/index.tpl
+++ /dev/null
@@ -1,129 +0,0 @@
-<!DOCTYPE html>
-<html>
- <head>
- <title>ODR-DabMux Configuration</title>
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
- <meta name="viewport" content="width=device-width, initial-scale=1">
- <link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">
- </head>
- <body class="w3-container">
- <div class="w3-top w3-bar w3-blue-grey">
- <a href="#general" class="w3-bar-item w3-button">General Options</a>
- <a href="#servicelist" class="w3-bar-item w3-button">Services</a>
- <a href="#subchannels" class="w3-bar-item w3-button">Subchannels</a>
- <a href="#components" class="w3-bar-item w3-button">Components</a>
- <a href="#rcmodules" class="w3-bar-item w3-button">RC Modules</a>
- </div>
- <div id="general" class="w3-responsive w3-card-4">
- <br /><br />
- <table class="w3-table w3-striped w3-bordered">
- <tr class="w3-blue-grey">
- <th>General multiplex options</th>
- <th></th>
- </tr>
- <tr>
- <td>Number of frames to encode</td>
- <td>{{g.nbframes}}</td>
- </tr>
- <tr>
- <td>Statistics server port</td>
- <td>{{g.statsserverport}}</td>
- </tr>
- <tr>
- <td>Write SCCA field</td>
- <td>{{g.writescca}}</td>
- </tr>
- <tr>
- <td>Write TIST timestamp</td>
- <td>{{g.tist}}</td>
- </tr>
- <tr>
- <td>DAB mode</td>
- <td>{{g.dabmode}}</td>
- </tr>
- <tr>
- <td>Log to syslog</td>
- <td>{{g.syslog}}</td>
- </tr>
- </table>
- </div>
- <div id="servicelist" class="w3-responsive w3-card-4">
- <br /><br />
- <table class="w3-table w3-striped w3-bordered">
- <tr class="w3-blue-grey">
- <th>Service</th>
- <th>Id</th>
- <th>Label</th>
- <th>Short label</th>
- </tr>
- {% for s in services %}
- <tr>
- <td>{{s.name}}</td>
- <td>{{s.id}}</td>
- <td>{{s.label}}</td>
- <td>{{s.shortlabel}}</td>
- </tr>
- {% endfor %}
- </table>
- </div>
- <div id="subchannels" class="w3-responsive w3-card-4">
- <br /><br />
- <table class="w3-table w3-striped w3-bordered">
- <tr class="w3-blue-grey">
- <th>Sub channel</th>
- <th>Type</th>
- <th>Input file</th>
- <th>Bit rate (Kbps)</th>
- </tr>
- {% for s in subchannels %}
- <tr>
- <td>{{s.name}}</td>
- <td>{{s.type}}</td>
- <td>{{s.inputfile}}</td>
- <td>{{s.bitrate}}</td>
- </tr>
- {% endfor %}
- </table>
- </div>
- <div id="components" class="w3-responsive w3-card-4">
- <br /><br />
- <table class="w3-table w3-striped w3-bordered">
- <tr class="w3-blue-grey">
- <th>Component</th>
- <th>Label</th>
- <th>Short label</th>
- <th>Service</th>
- <th>Sub-channel</th>
- <th>Fig type</th>
- </tr>
- {% for s in components %}
- <tr>
- <td>{{s.name}}</td>
- <td>{{s.label}}</td>
- <td>{{s.shortlabel}}</td>
- <td>{{s.service}}</td>
- <td>{{s.subchannel}}</td>
- <td>{{s.figtype}}</td>
- </tr>
- {% endfor %}
- </table>
- </div>
- <div id="rcmodules" class="w3-responsive w3-card-4">
- <br /><br />
- <ul class="w3-ul">
- <li class="w3-blue-grey"><b>RC Modules</b></li>
- {% for m in rcmodules %}
- <li class="w3-light-grey"><b>{{m.name}}</b>
- <ul class="w3-ul">
- {% for p in m.parameters %}
- <li class="w3-white"><a href="/rc/{{m.name}}/{{p.param.decode()}}" class="w3-hover-blue-grey">{{p.param.decode()}}</a> : {{p.value.decode()}}</li>
- {% endfor %}
- </ul>
- </li>
- {% endfor %}
- </ul>
- </div>
- </div>
-
- </body>
-</html> \ No newline at end of file
diff --git a/gui/views/rcparam.tpl b/gui/views/rcparam.tpl
deleted file mode 100644
index edac5b7..0000000
--- a/gui/views/rcparam.tpl
+++ /dev/null
@@ -1,37 +0,0 @@
-<!DOCTYPE html>
-<html>
- <head>
- <title>ODR-DabMux Configuration</title>
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
- <meta name="viewport" content="width=device-width, initial-scale=1">
- <link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">
- </head>
-
- <body class="w3-container">
- <h1 class="w3-blue-grey">Remote-Control: module {{module}}</h1>
- <div class="w3-card-4">
- <form class="w3-container" method="post">
- <p />
- {% if not list %}
- <label>{{param}}:</label>
- <input name="newvalue" type="text" value="{{value.decode()}}" autofocus>
- {% else %}
- <label>{{label}}:</label>
- <select id="newvalue" name="newvalue">
- {% for l in list %}
- {% if (l["value"] == value.decode()) %}
- <option selected value={{l["value"]}}>{{l["desc"]}}</option>
- {% else %}
- <option value={{l["value"]}}>{{l["desc"]}}</option>
- {% endif %}
- {% endfor %}
- </select>
- {% endif %}
- <p />
- <button class="w3-button w3-blue-grey" type="submit">Update</button>
- <p />
- </form>
- </div>
- </body>
-
-</html> \ No newline at end of file
diff --git a/gui/views/services.tpl b/gui/views/services.tpl
deleted file mode 100644
index 42438a8..0000000
--- a/gui/views/services.tpl
+++ /dev/null
@@ -1,31 +0,0 @@
-<!DOCTYPE html>
-<html>
- <head>
- <title>ODR-DabMux Services</title>
- <meta name="viewport" content="width=device-width, initial-scale=1">
- <link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">
- </head>
- <body class="w3-container">
- <h1>Services for {{version}}</h1>
- <table class="w3-table w3-striped w3-bordered">
- <tr class="w3-blue-grey">
- <th>Service</th>
- <th>Id</th>
- <th>Label</th>
- <th>Short label</th>
- <th>Program type</th>
- <th>Language</th>
- </tr>
- {% for s in services %}
- <tr>
- <td>{{s.name}}</td>
- <td>{{s.id}}</td>
- <td>{{s.label}}</td>
- <td>{{s.shortlabel}}</td>
- <td>{{s.pty}}</td>
- <td>{{s.language}}</td>
- </tr>
- {% endfor %}
- </table>
- </body>
-</html> \ No newline at end of file
diff --git a/gui/views/stats.tpl b/gui/views/stats.tpl
deleted file mode 100644
index 4bb089f..0000000
--- a/gui/views/stats.tpl
+++ /dev/null
@@ -1,21 +0,0 @@
-<!DOCTYPE html>
-<html>
- <head>
- <title>ODR-DabMux Statistics</title>
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
- <meta name="viewport" content="width=device-width, initial-scale=1">
- <link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">
- <script type="text/javascript" src="static/jquery-1.10.2.min.js"></script>
- <script type="text/javascript" src="static/stats.js"></script>
- </head>
- <body class="w3-container">
- <h1>Subchannel stats for {{version}}</h1>
-
- <a id="update">Update</a>
-
- <div id="subchannels">
- <p>Subchannels</p>
- <div id="statdata"></div>
- </div>
- </body>
-</html> \ No newline at end of file
diff --git a/lib/Socket.cpp b/lib/Socket.cpp
index 5c920d7..33c9c73 100644
--- a/lib/Socket.cpp
+++ b/lib/Socket.cpp
@@ -1152,6 +1152,7 @@ void TCPDataDispatcher::process()
std::vector<TCPConnection::stats_t> TCPDataDispatcher::get_stats() const
{
std::vector<TCPConnection::stats_t> s;
+ auto lock = unique_lock<mutex>(m_mutex);
for (const auto& conn : m_connections) {
s.push_back(conn.get_stats());
}
diff --git a/lib/Socket.h b/lib/Socket.h
index 29b618a..b9a40ee 100644
--- a/lib/Socket.h
+++ b/lib/Socket.h
@@ -298,7 +298,7 @@ class TCPDataDispatcher
std::thread m_listener_thread;
TCPSocket m_listener_socket;
- std::mutex m_mutex;
+ mutable std::mutex m_mutex;
std::deque<std::vector<uint8_t> > m_preroll_queue;
std::list<TCPConnection> m_connections;
};
diff --git a/lib/ThreadsafeQueue.h b/lib/ThreadsafeQueue.h
index 13bc19e..a8d2e85 100644
--- a/lib/ThreadsafeQueue.h
+++ b/lib/ThreadsafeQueue.h
@@ -31,7 +31,7 @@
#include <functional>
#include <mutex>
#include <condition_variable>
-#include <queue>
+#include <deque>
#include <utility>
#include <cassert>
diff --git a/lib/edi/STIDecoder.cpp b/lib/edi/STIDecoder.cpp
index 2de828b..0499c53 100644
--- a/lib/edi/STIDecoder.cpp
+++ b/lib/edi/STIDecoder.cpp
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2020
+ Copyright (C) 2025
Matthias P. Braendli, matthias.braendli@mpb.li
http://opendigitalradio.org
@@ -20,7 +20,6 @@
*/
#include "STIDecoder.hpp"
#include "buffer_unpack.hpp"
-#include "crc.h"
#include "Log.h"
#include <cstdio>
#include <cassert>
@@ -180,7 +179,13 @@ bool STIDecoder::decode_ssn(const std::vector<uint8_t>& value, const tag_name_t&
n |= (uint16_t)(name[3]);
if (n == 0) {
- etiLog.level(warn) << "EDI: Stream index SSnn tag is zero";
+ if (not m_ssnn_zero_warning_printed) {
+ etiLog.level(warn) << "EDI: Stream index SSnn tag is zero";
+ }
+ m_ssnn_zero_warning_printed = true;
+ }
+ else {
+ m_ssnn_zero_warning_printed = false;
}
if (m_filter_stream and m_filtered_stream_index != n) {
@@ -197,14 +202,20 @@ bool STIDecoder::decode_ssn(const std::vector<uint8_t>& value, const tag_name_t&
sti.stid = istc & 0xFFF;
if (sti.rfa != 0) {
- etiLog.level(warn) << "EDI: rfa field in SSnn tag non-null";
+ if (not m_rfa_nonnull_warning_printed) {
+ etiLog.level(warn) << "EDI: rfa field in SSnn tag non-null";
+ }
+ m_rfa_nonnull_warning_printed = true;
+ }
+ else {
+ m_rfa_nonnull_warning_printed = false;
}
copy( value.cbegin() + 3,
value.cend(),
back_inserter(sti.istd));
- m_data_collector.add_payload(move(sti));
+ m_data_collector.add_payload(std::move(sti));
return true;
}
diff --git a/lib/edi/STIDecoder.hpp b/lib/edi/STIDecoder.hpp
index 5e71ce7..81fbd82 100644
--- a/lib/edi/STIDecoder.hpp
+++ b/lib/edi/STIDecoder.hpp
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2020
+ Copyright (C) 2025
Matthias P. Braendli, matthias.braendli@mpb.li
http://opendigitalradio.org
@@ -139,6 +139,9 @@ class STIDecoder {
bool m_filter_stream = false;
uint16_t m_filtered_stream_index = 1;
+
+ bool m_ssnn_zero_warning_printed = false;
+ bool m_rfa_nonnull_warning_printed = false;
};
}
diff --git a/lib/edioutput/EDIConfig.h b/lib/edioutput/EDIConfig.h
index 7016e87..de4217f 100644
--- a/lib/edioutput/EDIConfig.h
+++ b/lib/edioutput/EDIConfig.h
@@ -27,6 +27,7 @@
#pragma once
+#include <optional>
#include <vector>
#include <string>
#include <memory>
@@ -60,7 +61,7 @@ struct udp_destination_t : public destination_t {
uint16_t dest_port = 0;
std::string source_addr;
uint16_t source_port = 0;
- uint8_t ttl = 10;
+ std::optional<uint8_t> ttl = std::nullopt;
};
// TCP server that can accept multiple connections
diff --git a/lib/edioutput/Transport.cpp b/lib/edioutput/Transport.cpp
index e9559b5..3898213 100644
--- a/lib/edioutput/Transport.cpp
+++ b/lib/edioutput/Transport.cpp
@@ -41,10 +41,15 @@ void configuration_t::print() const
if (auto udp_dest = dynamic_pointer_cast<edi::udp_destination_t>(edi_dest)) {
etiLog.level(info) << " UDP to " << udp_dest->dest_addr << ":" << udp_dest->dest_port;
if (not udp_dest->source_addr.empty()) {
- etiLog.level(info) << " source " << udp_dest->source_addr;
- etiLog.level(info) << " ttl " << udp_dest->ttl;
+ etiLog.level(info) << " source address=" << udp_dest->source_addr;
}
- etiLog.level(info) << " source port " << udp_dest->source_port;
+ if (udp_dest->ttl) {
+ etiLog.level(info) << " ttl=" << (int)(*udp_dest->ttl);
+ }
+ else {
+ etiLog.level(info) << " ttl=(default)";
+ }
+ etiLog.level(info) << " source port=" << udp_dest->source_port;
}
else if (auto tcp_dest = dynamic_pointer_cast<edi::tcp_server_t>(edi_dest)) {
etiLog.level(info) << " TCP listening on port " << tcp_dest->listen_port;
@@ -80,7 +85,10 @@ Sender::Sender(const configuration_t& conf) :
if (not udp_dest->source_addr.empty()) {
udp_socket.setMulticastSource(udp_dest->source_addr.c_str());
- udp_socket.setMulticastTTL(udp_dest->ttl);
+ }
+
+ if (udp_dest->ttl) {
+ udp_socket.setMulticastTTL(*udp_dest->ttl);
}
auto sender = make_shared<udp_sender_t>(
@@ -99,7 +107,7 @@ Sender::Sender(const configuration_t& conf) :
make_shared<PFTSpreader>(tcp_dest->pft_settings, sender));
}
else if (auto tcp_dest = dynamic_pointer_cast<edi::tcp_client_t>(edi_dest)) {
- auto sender = make_shared<tcp_send_client_t>(tcp_dest->dest_addr, tcp_dest->dest_port);
+ auto sender = make_shared<tcp_send_client_t>(tcp_dest->dest_addr, tcp_dest->dest_port, m_conf.verbose);
m_pft_spreaders.emplace_back(
make_shared<PFTSpreader>(tcp_dest->pft_settings, sender));
}
@@ -199,7 +207,13 @@ void Sender::tcp_dispatcher_t::send_packet(const std::vector<uint8_t> &frame)
void Sender::tcp_send_client_t::send_packet(const std::vector<uint8_t> &frame)
{
- sock.sendall(frame);
+ const auto error_stats = sock.sendall(frame);
+
+ if (verbose and error_stats.has_seen_new_errors) {
+ etiLog.level(warn) << "TCP output " << dest_addr << ":" << dest_port
+ << " has " << error_stats.num_reconnects
+ << " reconnects: most recent error: " << error_stats.last_error;
+ }
}
Sender::udp_sender_t::udp_sender_t(std::string dest_addr,
@@ -221,7 +235,11 @@ Sender::tcp_dispatcher_t::tcp_dispatcher_t(uint16_t listen_port,
}
Sender::tcp_send_client_t::tcp_send_client_t(const std::string &dest_addr,
- uint16_t dest_port) :
+ uint16_t dest_port,
+ bool verbose) :
+ dest_addr(dest_addr),
+ dest_port(dest_port),
+ verbose(verbose),
sock(dest_addr, dest_port)
{
}
diff --git a/lib/edioutput/Transport.h b/lib/edioutput/Transport.h
index b8a9008..96784c0 100644
--- a/lib/edioutput/Transport.h
+++ b/lib/edioutput/Transport.h
@@ -118,8 +118,13 @@ class Sender {
struct tcp_send_client_t : public i_sender {
tcp_send_client_t(
const std::string& dest_addr,
- uint16_t dest_port);
+ uint16_t dest_port,
+ bool verbose);
+ std::string dest_addr;
+ uint16_t dest_port;
+ bool verbose;
+ size_t m_num_reconnects_prev = 0;
Socket::TCPSendClient sock;
virtual void send_packet(const std::vector<uint8_t> &frame) override;
};
diff --git a/lib/fec/decode_rs.h b/lib/fec/decode_rs.h
index c165cf3..647b885 100644
--- a/lib/fec/decode_rs.h
+++ b/lib/fec/decode_rs.h
@@ -145,15 +145,15 @@
count++;
}
if (count != no_eras) {
- printf("count = %d no_eras = %d\n lambda(x) is WRONG\n",count,no_eras);
+ fprintf(stderr, "count = %d no_eras = %d\n lambda(x) is WRONG\n",count,no_eras);
count = -1;
goto finish;
}
#if DEBUG >= 2
- printf("\n Erasure positions as determined by roots of Eras Loc Poly:\n");
+ fprintf(stderr, "\n Erasure positions as determined by roots of Eras Loc Poly:\n");
for (i = 0; i < count; i++)
- printf("%d ", loc[i]);
- printf("\n");
+ fprintf(stderr, "%d ", loc[i]);
+ fprintf(stderr, "\n");
#endif
#endif
}
@@ -227,7 +227,7 @@
continue; /* Not a root */
/* store root (index-form) and error location number */
#if DEBUG>=2
- printf("count %d root %d loc %d\n",count,i,k);
+ fprintf(stderr, "count %d root %d loc %d\n",count,i,k);
#endif
root[count] = i;
loc[count] = k;
@@ -279,7 +279,7 @@
}
#if DEBUG >= 1
if (den == 0) {
- printf("\n ERROR: denominator = 0\n");
+ fprintf(stderr, "\n ERROR: denominator = 0\n");
count = -1;
goto finish;
}
diff --git a/man/odr-dabmux.1 b/man/odr-dabmux.1
index 6e946a5..07cc992 100644
--- a/man/odr-dabmux.1
+++ b/man/odr-dabmux.1
@@ -1,4 +1,4 @@
-.TH ODR-DABMUX "1" "March 2025" "odr-dabmux 5.1.0" "User Commands"
+.TH ODR-DABMUX "1" "October 2025" "odr-dabmux 5.4.1" "User Commands"
.SH NAME
\fBodr\-dabmux\fR \- A software DAB multiplexer
.SH SYNOPSIS
diff --git a/src/ConfigParser.cpp b/src/ConfigParser.cpp
index 7d166b6..2d500b3 100644
--- a/src/ConfigParser.cpp
+++ b/src/ConfigParser.cpp
@@ -3,7 +3,7 @@
2011, 2012 Her Majesty the Queen in Right of Canada (Communications
Research Center Canada)
- Copyright (C) 2022
+ Copyright (C) 2025
Matthias P. Braendli, matthias.braendli@mpb.li
http://www.opendigitalradio.org
@@ -110,10 +110,10 @@ static void parse_fig2_label(ptree& pt, DabLabel& label) {
}
// Parse the linkage section
-static void parse_linkage(ptree& pt,
- std::shared_ptr<dabEnsemble> ensemble)
+void parse_linkage(
+ const boost::optional<boost::property_tree::ptree&> pt_linking,
+ std::vector<std::shared_ptr<LinkageSet> >& linkageSets)
{
- auto pt_linking = pt.get_child_optional("linking");
if (pt_linking) {
for (const auto& it : *pt_linking) {
const string setuid = it.first;
@@ -132,7 +132,7 @@ static void parse_linkage(ptree& pt,
string service_uid = pt_set.get("keyservice", "");
auto linkageset = make_shared<LinkageSet>(setuid, lsn, active, hard, international);
- linkageset->keyservice = service_uid; // TODO check if it exists
+ linkageset->keyservice = service_uid; // existence check is done in validate_linkage_sets()
auto pt_list = pt_set.get_child_optional("list");
@@ -189,7 +189,7 @@ static void parse_linkage(ptree& pt,
linkageset->id_list.push_back(link);
}
}
- ensemble->linkagesets.push_back(linkageset);
+ linkageSets.push_back(linkageset);
}
}
}
@@ -910,7 +910,8 @@ void parse_ptree(
}
- parse_linkage(pt, ensemble);
+ const auto pt_linking = pt.get_child_optional("linking");
+ parse_linkage(pt_linking, ensemble->linkagesets);
parse_freq_info(pt, ensemble);
parse_other_service_linking(pt, ensemble);
}
diff --git a/src/ConfigParser.h b/src/ConfigParser.h
index 9ca6c81..038247b 100644
--- a/src/ConfigParser.h
+++ b/src/ConfigParser.h
@@ -3,7 +3,7 @@
2011, 2012 Her Majesty the Queen in Right of Canada (Communications
Research Center Canada)
- Copyright (C) 2016
+ Copyright (C) 2025
Matthias P. Braendli, matthias.braendli@mpb.li
The Configuration parser sets up the ensemble according
@@ -34,6 +34,10 @@
#include <boost/property_tree/ptree.hpp>
#include <memory>
-void parse_ptree(boost::property_tree::ptree& pt,
+void parse_ptree(
+ boost::property_tree::ptree& pt,
std::shared_ptr<dabEnsemble> ensemble);
+void parse_linkage(
+ const boost::optional<boost::property_tree::ptree&> pt_linking,
+ std::vector<std::shared_ptr<LinkageSet> >& linkageSets);
diff --git a/src/DabMultiplexer.cpp b/src/DabMultiplexer.cpp
index e6e6782..7a8ac97 100644
--- a/src/DabMultiplexer.cpp
+++ b/src/DabMultiplexer.cpp
@@ -26,11 +26,15 @@
#include <cmath>
#include <set>
#include <memory>
+#include <boost/property_tree/info_parser.hpp>
+#include <boost/property_tree/json_parser.hpp>
+
#include "DabMultiplexer.h"
#include "ConfigParser.h"
#include "ManagementServer.h"
#include "crc.h"
#include "utils.h"
+#include "Eti.h"
using namespace std;
@@ -47,22 +51,21 @@ static vector<string> split_pipe_separated_string(const std::string& s)
return components;
}
-uint64_t MuxTime::init(uint32_t tist_at_fct0_us)
+uint64_t MuxTime::init(uint32_t tist_at_fct0_ms, double tist_offset)
{
- m_tist_at_fct0_us = tist_at_fct0_us;
-
- /* At startup, derive edi_time, TIST and CIF count such that there is
- * a consistency across mux restarts. Ensure edi_time and TIST represent
- * current time.
- *
- * FCT and DLFC are directly derived from m_currentFrame.
- * Every 6s, FCT overflows. DLFC overflows at 5000 every 120s.
- *
- * Keep a granularity of 24ms, which corresponds to the duration of an ETI
- * frame, to get nicer timestamps.
- */
+ // Things we must guarantee, up to granularity of 24ms:
+ // Difference between current time and EDI time = tist_offset
+ // TIST of frame 0 = tist_at_fct0_ms
+ // In order to achieve the second, we calculate the initial
+ // counter value so that FCT0 corresponds to the desired TIST.
+ //
+ // Changing the tist_offset at runtime will throw off the TIST@FCT0 value
+ m_tist_offset_ms = std::lround(tist_offset * 1000);
+
using Sec = chrono::seconds;
- const auto now = chrono::system_clock::now();
+ const auto now = chrono::system_clock::now() +
+ chrono::milliseconds(std::lround(tist_offset * 1000.0));
+
const auto offset = now - chrono::time_point_cast<Sec>(now);
if (offset >= chrono::seconds(1)) {
throw std::logic_error("Invalid startup offset calculation for TIST! " +
@@ -70,43 +73,24 @@ uint64_t MuxTime::init(uint32_t tist_at_fct0_us)
" ms");
}
const time_t t_now = chrono::system_clock::to_time_t(chrono::time_point_cast<Sec>(now));
+ const auto offset_ms = chrono::duration_cast<chrono::milliseconds>(offset).count();
- m_edi_time = t_now - (t_now % 6);
- uint64_t currentFrame = 0;
- time_t edi_time_at_cif0 = t_now - (t_now % 120);
- while (edi_time_at_cif0 < m_edi_time) {
- edi_time_at_cif0 += 6;
- currentFrame += 250;
- }
+ m_edi_time = t_now;
+ m_pps_offset_ms = std::lround(offset_ms / 24.0) * 24;
- if (edi_time_at_cif0 != m_edi_time) {
- throw std::logic_error("Invalid startup offset calculation for CIF!");
- }
+ const auto counter_offset = tist_at_fct0_ms / 24;
+ const auto offset_as_count = m_pps_offset_ms / 24;
- int64_t offset_ms = chrono::duration_cast<chrono::milliseconds>(offset).count();
- offset_ms += 1000 * (t_now - m_edi_time);
-
- if (tist_at_fct0_us >= 1000000) {
- etiLog.level(error) << "tist_at_fct0 may not be larger than 1s";
- throw MuxInitException();
- }
-
- m_timestamp = (uint64_t)tist_at_fct0_us * 16384 / 1000;
- while (offset_ms >= 24) {
- increment_timestamp();
- currentFrame++;
- offset_ms -= 24;
- }
- return currentFrame;
+ return (250 - counter_offset + offset_as_count) % 250;
}
constexpr int TIMESTAMP_LEVEL_2_SHIFT = 14;
void MuxTime::increment_timestamp()
{
- m_timestamp += 24 << TIMESTAMP_LEVEL_2_SHIFT; // Shift 24ms by 14 to Timestamp level 2
- if (m_timestamp > 0xf9FFff) {
- m_timestamp -= 0xfa0000; // Subtract 16384000, corresponding to one second
+ m_pps_offset_ms += 24;
+ if (m_pps_offset_ms >= 1000) {
+ m_pps_offset_ms -= 1000;
m_edi_time += 1;
// Also update MNSC time for next time FP==0
@@ -114,27 +98,34 @@ void MuxTime::increment_timestamp()
}
}
-std::pair<uint32_t, std::time_t> MuxTime::get_tist_seconds()
+void MuxTime::set_tist_offset(double new_tist_offset)
{
- // The user-visible configuration tist_offset is the effective
- // offset, but since we implicitly add the tist_at_fct0 to it,
- // we must compensate.
- double corrected_tist_offset = tist_offset - (m_tist_at_fct0_us / 1e6);
-
- // negative tist_offset not supported, because the calculation is annoying
- if (corrected_tist_offset < 0) return {m_timestamp, m_edi_time};
-
- double fractional_part = corrected_tist_offset - std::floor(corrected_tist_offset);
- const size_t steps = std::lround(std::floor(fractional_part / 24e-3));
- uint32_t timestamp = m_timestamp + (24 << TIMESTAMP_LEVEL_2_SHIFT) * steps;
-
- std::time_t edi_time = m_edi_time + std::lround(std::floor(corrected_tist_offset));
-
- if (timestamp > 0xf9FFff) {
- edi_time += 1;
+ const int32_t new_tist_offset_ms = std::lround(new_tist_offset * 1000.0);
+ int32_t delta = m_tist_offset_ms - new_tist_offset_ms;
+ if (delta > 0) {
+ while (delta > 0) {
+ increment_timestamp();
+ delta -= 24;
+ }
}
+ else if (delta < 0) {
+ while (delta < 0) {
+ m_edi_time -= 1;
+ delta += 1000;
+ }
+ // compensate the we subtracted too much
+ while (delta > 0) {
+ increment_timestamp();
+ delta -= 24;
+ }
+ }
+ m_tist_offset_ms = new_tist_offset_ms;
+}
- return {timestamp % 0xfa0000, edi_time};
+std::pair<uint32_t, std::time_t> MuxTime::get_tist_seconds()
+{
+ auto timestamp = m_pps_offset_ms * 16384;
+ return {timestamp % 0xfa0000, m_edi_time};
}
std::pair<uint32_t, std::time_t> MuxTime::get_milliseconds_seconds()
@@ -144,16 +135,35 @@ std::pair<uint32_t, std::time_t> MuxTime::get_milliseconds_seconds()
}
-DabMultiplexer::DabMultiplexer(boost::property_tree::ptree pt) :
+void DabMultiplexerConfig::read(const std::string& filename)
+{
+ m_config_file = "";
+ try {
+ if (stringEndsWith(filename, ".json")) {
+ read_json(filename, pt);
+ }
+ else {
+ read_info(filename, pt);
+ }
+ m_config_file = filename;
+ }
+ catch (const boost::property_tree::file_parser_error& e)
+ {
+ etiLog.level(warn) << "Failed to read " << filename;
+ }
+}
+
+DabMultiplexer::DabMultiplexer(DabMultiplexerConfig& config) :
RemoteControllable("mux"),
- m_pt(pt),
+ m_config(config),
m_time(),
ensemble(std::make_shared<dabEnsemble>()),
- m_clock_tai(split_pipe_separated_string(pt.get("general.tai_clock_bulletins", ""))),
+ m_clock_tai(split_pipe_separated_string(m_config.pt.get("general.tai_clock_bulletins", ""))),
fig_carousel(ensemble, [&]() { return m_time.get_milliseconds_seconds(); })
{
RC_ADD_PARAMETER(frames, "Show number of frames generated [read-only]");
- RC_ADD_PARAMETER(tist_offset, "Timestamp offset in fractional number of seconds");
+ RC_ADD_PARAMETER(tist_offset, "Configured tist-offset");
+ RC_ADD_PARAMETER(reload_linkagesets, "Write 1 to this parameter to trigger a reload of the linkage sets from the config [write-only]");
rcs.enrol(&m_clock_tai);
}
@@ -173,7 +183,7 @@ void DabMultiplexer::set_edi_config(const edi::configuration_t& new_edi_conf)
// Run a set of checks on the configuration
void DabMultiplexer::prepare(bool require_tai_clock)
{
- parse_ptree(m_pt, ensemble);
+ parse_ptree(m_config.pt, ensemble);
rcs.enrol(this);
rcs.enrol(ensemble.get());
@@ -199,12 +209,11 @@ void DabMultiplexer::prepare(bool require_tai_clock)
throw MuxInitException();
}
- const uint32_t tist_at_fct0_us = m_pt.get<double>("general.tist_at_fct0", 0);
- currentFrame = m_time.init(tist_at_fct0_us);
+ const uint32_t tist_at_fct0_ms = m_config.pt.get<double>("general.tist_at_fct0", 0);
+ currentFrame = m_time.init(tist_at_fct0_ms, m_config.pt.get<double>("general.tist_offset", 0.0));
m_time.mnsc_increment_time = false;
- bool tist_enabled = m_pt.get("general.tist", false);
- m_time.tist_offset = m_pt.get<double>("general.tist_offset", 0.0);
+ bool tist_enabled = m_config.pt.get("general.tist", false);
auto tist_edi_time = m_time.get_tist_seconds();
const auto timestamp = tist_edi_time.first;
@@ -453,6 +462,32 @@ void DabMultiplexer::prepare_data_inputs()
}
}
+void DabMultiplexer::reload_linkagesets()
+{
+ try {
+ DabMultiplexerConfig new_conf;
+ new_conf.read(m_config.config_file());
+ if (new_conf.valid()) {
+ const auto pt_linking = new_conf.pt.get_child_optional("linking");
+ std::vector<std::shared_ptr<LinkageSet> > linkagesets;
+ parse_linkage(pt_linking, linkagesets);
+
+ etiLog.level(info) << "Validating " << linkagesets.size() << " new linkage sets.";
+
+ if (ensemble->validate_linkage_sets(ensemble->services, linkagesets)) {
+ ensemble->linkagesets = linkagesets;
+ etiLog.level(info) << "Loaded new linkage sets.";
+ }
+ else {
+ etiLog.level(warn) << "New linkage set validation failed";
+ }
+ }
+ }
+ catch (const std::exception& e)
+ {
+ etiLog.level(warn) << "Failed to update linkage sets: " << e.what();
+ }
+}
/* Each call creates one ETI frame */
void DabMultiplexer::mux_frame(std::vector<std::shared_ptr<DabOutput> >& outputs)
@@ -472,7 +507,7 @@ void DabMultiplexer::mux_frame(std::vector<std::shared_ptr<DabOutput> >& outputs
// The above Tag Items will be assembled into a TAG Packet
edi::TagPacket edi_tagpacket(edi_conf.tagpacket_alignment);
- const bool tist_enabled = m_pt.get("general.tist", false);
+ const bool tist_enabled = m_config.pt.get("general.tist", false);
int tai_utc_offset = 0;
if (tist_enabled and m_tai_clock_required) {
@@ -487,6 +522,10 @@ void DabMultiplexer::mux_frame(std::vector<std::shared_ptr<DabOutput> >& outputs
auto tist_edi_time = m_time.get_tist_seconds();
const auto timestamp = tist_edi_time.first;
const auto edi_time = tist_edi_time.second;
+ /*
+ etiLog.level(debug) << "Frame " << currentFrame << " " << edi_time <<
+ " + " << (timestamp >> TIMESTAMP_LEVEL_2_SHIFT);
+ */
// Initialise the ETI frame
memset(etiFrame, 0, 6144);
@@ -520,7 +559,6 @@ void DabMultiplexer::mux_frame(std::vector<std::shared_ptr<DabOutput> >& outputs
eti_FC *fc = (eti_FC *) &etiFrame[4];
//****** FCT ******//
- // Incremente for each frame, overflows at 249
fc->FCT = currentFrame % 250;
edi_tagDETI.dlfc = currentFrame % 5000;
@@ -729,7 +767,7 @@ void DabMultiplexer::mux_frame(std::vector<std::shared_ptr<DabOutput> >& outputs
index = (FLtmp + 2 + 1) * 4;
eti_TIST *tist = (eti_TIST *) & etiFrame[index];
- bool enableTist = m_pt.get("general.tist", false);
+ bool enableTist = m_config.pt.get("general.tist", false);
if (enableTist) {
tist->TIST = htonl(timestamp) | 0xff;
edi_tagDETI.tsta = timestamp & 0xffffff;
@@ -857,7 +895,10 @@ void DabMultiplexer::set_parameter(const std::string& parameter,
throw ParameterError(ss.str());
}
else if (parameter == "tist_offset") {
- m_time.tist_offset = std::stod(value);
+ m_time.set_tist_offset(std::stod(value));
+ }
+ else if (parameter == "reload_linkagesets") {
+ reload_linkagesets();
}
else {
stringstream ss;
@@ -875,7 +916,12 @@ const std::string DabMultiplexer::get_parameter(const std::string& parameter) co
ss << currentFrame;
}
else if (parameter == "tist_offset") {
- ss << m_time.tist_offset;
+ ss << m_time.tist_offset();
+ }
+ else if (parameter == "reload_linkagesets") {
+ ss << "Parameter '" << parameter <<
+ "' is not write-only in controllable " << get_rc_name();
+ throw ParameterError(ss.str());
}
else {
ss << "Parameter '" << parameter <<
@@ -890,7 +936,7 @@ const json::map_t DabMultiplexer::get_all_values() const
{
json::map_t map;
map["frames"].v = currentFrame;
- map["tist_offset"].v = m_time.tist_offset;
+ map["tist_offset"].v = m_time.tist_offset();
return map;
}
diff --git a/src/DabMultiplexer.h b/src/DabMultiplexer.h
index 5a0d906..620e65d 100644
--- a/src/DabMultiplexer.h
+++ b/src/DabMultiplexer.h
@@ -45,46 +45,59 @@ constexpr uint32_t ETI_FSYNC1 = 0x49C5F8;
class MuxTime {
private:
- uint32_t m_timestamp = 0;
- std::time_t m_edi_time = 0;
- uint32_t m_tist_at_fct0_us = 0;
+ std::time_t m_edi_time = 0;
+ uint32_t m_pps_offset_ms = 0;
+ int64_t m_tist_offset_ms = 0;
public:
- std::pair<uint32_t, std::time_t> get_tist_seconds();
- std::pair<uint32_t, std::time_t> get_milliseconds_seconds();
-
- double tist_offset = 0;
-
- /* Pre v3 odr-dabmux did the MNSC calculation differently,
- * which works with the easydabv2. The rework in odr-dabmux,
- * deriving MNSC time from EDI time broke this.
- *
- * That's why we're now tracking MNSC time in separate variables,
- * to get the same behaviour back.
- *
- * I'm not aware of any devices using MNSC time besides the
- * easydab. ODR-DabMod now considers EDI seconds or ZMQ metadata.
- */
- bool mnsc_increment_time = false;
- std::time_t mnsc_time = 0;
-
- /* Setup the time and return the initial currentFrame counter value */
- uint64_t init(uint32_t tist_at_fct0_us);
- void increment_timestamp();
+ std::pair<uint32_t, std::time_t> get_tist_seconds();
+ std::pair<uint32_t, std::time_t> get_milliseconds_seconds();
+
+
+ /* Pre v3 odr-dabmux did the MNSC calculation differently,
+ * which works with the easydabv2. The rework in odr-dabmux,
+ * deriving MNSC time from EDI time broke this.
+ *
+ * That's why we're now tracking MNSC time in separate variables,
+ * to get the same behaviour back.
+ *
+ * I'm not aware of any devices using MNSC time besides the
+ * easydab. ODR-DabMod now considers EDI seconds or ZMQ metadata.
+ */
+ bool mnsc_increment_time = false;
+ std::time_t mnsc_time = 0;
+
+ /* Setup the time and return the initial currentFrame counter value */
+ uint64_t init(uint32_t tist_at_fct0_ms, double tist_offset);
+ void increment_timestamp();
+ double tist_offset() const { return m_tist_offset_ms / 1000.0; }
+ void set_tist_offset(double new_tist_offset);
+};
+
+class DabMultiplexerConfig {
+ public:
+ boost::property_tree::ptree pt;
+
+ void read(const std::string& filename);
+ bool valid() const { return m_config_file != ""; }
+ std::string config_file() const { return m_config_file; }
+
+ private:
+ std::string m_config_file;
};
class DabMultiplexer : public RemoteControllable {
public:
- DabMultiplexer(boost::property_tree::ptree pt);
+ DabMultiplexer(DabMultiplexerConfig& config);
DabMultiplexer(const DabMultiplexer& other) = delete;
DabMultiplexer& operator=(const DabMultiplexer& other) = delete;
- ~DabMultiplexer();
+ virtual ~DabMultiplexer();
void prepare(bool require_tai_clock);
void mux_frame(std::vector<std::shared_ptr<DabOutput> >& outputs);
- void print_info(void);
+ void print_info();
void set_edi_config(const edi::configuration_t& new_edi_conf);
@@ -98,11 +111,13 @@ class DabMultiplexer : public RemoteControllable {
virtual const json::map_t get_all_values() const;
private:
- void prepare_subchannels(void);
- void prepare_services_components(void);
- void prepare_data_inputs(void);
+ void prepare_subchannels();
+ void prepare_services_components();
+ void prepare_data_inputs();
+
+ void reload_linkagesets();
- boost::property_tree::ptree m_pt;
+ DabMultiplexerConfig& m_config;
MuxTime m_time;
uint64_t currentFrame = 0;
diff --git a/src/DabMux.cpp b/src/DabMux.cpp
index bf525c1..7b5f5d6 100644
--- a/src/DabMux.cpp
+++ b/src/DabMux.cpp
@@ -29,83 +29,25 @@
# include "config.h"
#endif
-#include <stdlib.h>
#include <memory>
#include <boost/property_tree/ptree.hpp>
-#include <boost/property_tree/info_parser.hpp>
-#include <boost/property_tree/json_parser.hpp>
+#include <ctime>
+#include <cstdlib>
#include <cstdio>
-#include <iostream>
-#include <fstream>
-#include <iomanip>
#include <cstring>
+#include <cmath>
#include <string>
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
-// for basename
-#include <libgen.h>
-
-#include <iterator>
#include <vector>
-#include <list>
#include <set>
-#include <map>
-#include <functional>
-#include <algorithm>
-
-#ifdef _WIN32
-# include <time.h>
-# include <process.h>
-# include <io.h>
-# include <conio.h>
-# include <winsock2.h> // For types...
-typedef u_char uint8_t;
-typedef WORD uint16_t;
-typedef DWORD32 uint32_t;
-
-# ifndef __MINGW32__
-# include "xgetopt.h"
-# endif
-# define read _read
-# define snprintf _snprintf
-# define sleep(a) Sleep((a) * 1000)
-#else
-# include <netinet/in.h>
-# include <unistd.h>
-# include <sys/time.h>
-# include <sys/wait.h>
-# include <sys/socket.h>
-# include <sys/ioctl.h>
-# include <sys/times.h>
-# include <sys/resource.h>
-
-#endif
-
-#include <time.h>
-
-#ifdef _WIN32
-# pragma warning ( disable : 4103 )
-# include "Eti.h"
-# pragma warning ( default : 4103 )
-#else
-# include "Eti.h"
-#endif
-#include "input/Prbs.h"
-#include "input/Zmq.h"
+#include "DabMultiplexer.h"
#include "dabOutput/dabOutput.h"
-#include "crc.h"
-#include "Socket.h"
-#include "PcDebug.h"
-#include "DabMux.h"
#include "MuxElements.h"
#include "utils.h"
-#include "ConfigParser.h"
#include "ManagementServer.h"
#include "Log.h"
#include "RemoteControl.h"
@@ -120,14 +62,10 @@ volatile sig_atomic_t running = 1;
*/
void signalHandler(int signum)
{
-#ifdef _WIN32
- fprintf(stderr, "\npid: %i\n", _getpid());
-#else
fprintf(stderr, "\npid: %i, ppid: %i\n", getpid(), getppid());
-#endif
+
#define SIG_MSG "Signal received: "
switch (signum) {
-#ifndef _WIN32
case SIGHUP:
fprintf(stderr, SIG_MSG "SIGHUP\n");
break;
@@ -138,7 +76,6 @@ void signalHandler(int signum)
fprintf(stderr, SIG_MSG "SIGPIPE\n");
return;
break;
-#endif
case SIGINT:
fprintf(stderr, SIG_MSG "SIGINT\n");
break;
@@ -150,9 +87,7 @@ void signalHandler(int signum)
default:
fprintf(stderr, SIG_MSG "number %i\n", signum);
}
-#ifndef _WIN32
killpg(0, SIGPIPE);
-#endif
running = 0;
}
@@ -185,12 +120,6 @@ int main(int argc, char *argv[])
}
}
-#ifdef _WIN32
- if (SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST) == 0) {
- etiLog.log(warn, "Can't increase priority: %s\n",
- strerror(errno));
- }
-#else
// Use the lowest real-time priority for this thread, and switch to real-time scheduling
const int policy = SCHED_RR;
sched_param sp;
@@ -199,15 +128,15 @@ int main(int argc, char *argv[])
if (thread_prio_ret != 0) {
etiLog.level(error) << "Could not set real-time priority for thread:" << thread_prio_ret;
}
-#endif
int returnCode = 0;
- ptree pt;
std::vector<std::shared_ptr<DabOutput> > outputs;
try {
string conf_file = "";
+ DabMultiplexerConfig mux_conf;
+
if (argc == 2) { // Assume the only argument is a config file
conf_file = argv[1];
@@ -224,8 +153,7 @@ int main(int argc, char *argv[])
}
conf_file = argv[2];
-
- read_info(conf_file, pt);
+ mux_conf.read(conf_file);
}
catch (runtime_error &e) {
throw MuxInitException(e.what());
@@ -238,23 +166,18 @@ int main(int argc, char *argv[])
}
try {
- if (stringEndsWith(conf_file, ".json")) {
- read_json(conf_file, pt);
- }
- else {
- read_info(conf_file, pt);
- }
+ mux_conf.read(conf_file);
}
catch (runtime_error &e) {
throw MuxInitException(e.what());
}
/* Enable Logging to syslog conditionally */
- if (pt.get<bool>("general.syslog", false)) {
+ if (mux_conf.pt.get<bool>("general.syslog", false)) {
etiLog.register_backend(std::make_shared<LogToSyslog>());
}
- const auto startupcheck = pt.get<string>("general.startupcheck", "");
+ const auto startupcheck = mux_conf.pt.get<string>("general.startupcheck", "");
if (not startupcheck.empty()) {
etiLog.level(info) << "Running startup check '" << startupcheck << "'";
int wstatus = system(startupcheck.c_str());
@@ -274,26 +197,26 @@ int main(int argc, char *argv[])
}
}
- int mgmtserverport = pt.get<int>("general.managementport",
- pt.get<int>("general.statsserverport", 0) );
+ int mgmtserverport = mux_conf.pt.get<int>("general.managementport",
+ mux_conf.pt.get<int>("general.statsserverport", 0) );
/* Management: stats and config server */
get_mgmt_server().open(mgmtserverport);
/************** READ REMOTE CONTROL PARAMETERS *************/
- int telnetport = pt.get<int>("remotecontrol.telnetport", 0);
+ int telnetport = mux_conf.pt.get<int>("remotecontrol.telnetport", 0);
if (telnetport != 0) {
auto rc = std::make_shared<RemoteControllerTelnet>(telnetport);
rcs.add_controller(rc);
}
- auto zmqendpoint = pt.get<string>("remotecontrol.zmqendpoint", "");
+ auto zmqendpoint = mux_conf.pt.get<string>("remotecontrol.zmqendpoint", "");
if (not zmqendpoint.empty()) {
auto rc = std::make_shared<RemoteControllerZmq>(zmqendpoint);
rcs.add_controller(rc);
}
- DabMultiplexer mux(pt);
+ DabMultiplexer mux(mux_conf);
etiLog.level(info) <<
PACKAGE_NAME << " " <<
@@ -310,7 +233,7 @@ int main(int argc, char *argv[])
/******************** READ OUTPUT PARAMETERS ***************/
set<string> all_output_names;
bool output_require_tai_clock = false;
- ptree pt_outputs = pt.get_child("outputs");
+ ptree pt_outputs = mux_conf.pt.get_child("outputs");
for (auto ptree_pair : pt_outputs) {
string outputuid = ptree_pair.first;
@@ -352,10 +275,9 @@ int main(int argc, char *argv[])
pft_settings.enable_pft = pt.get<bool>("enable_pft", default_enable_pft);
pft_settings.fec = pt.get<unsigned int>("fec", default_fec);
pft_settings.fragment_spreading_factor = default_spreading_factor;
- auto override_spread_percent = pt.get_optional<int>("packet_spread");
- if (override_spread_percent) {
+ if (auto override_spread_percent = pt.get_optional<int>("packet_spread"))
pft_settings.fragment_spreading_factor = check_spreading_factor(*override_spread_percent);
- }
+
pft_settings.verbose = pt.get<bool>("verbose", edi_conf.verbose);
};
@@ -364,12 +286,12 @@ int main(int argc, char *argv[])
if (proto == "udp") {
auto dest = make_shared<edi::udp_destination_t>();
dest->dest_addr = pt_edi_dest.second.get<string>("destination");
- dest->ttl = pt_edi_dest.second.get<unsigned int>("ttl", 1);
+ if (auto ttl = pt_edi_dest.second.get_optional<unsigned int>("ttl"))
+ dest->ttl = *ttl;
dest->source_addr = pt_edi_dest.second.get<string>("source", "");
- dest->source_port = pt_edi_dest.second.get<unsigned int>("sourceport");
-
- dest->dest_port = pt_edi_dest.second.get<unsigned int>("port", 0);
+ dest->source_port = pt_edi_dest.second.get<unsigned int>("sourceport", 0);
+ dest->dest_port = pt_edi_dest.second.get<unsigned int>("port", 0);
if (dest->dest_port == 0) {
// Compatiblity: we have removed the transport and addressing in the
// PFT layer, which removed the requirement that all outputs must share
@@ -515,7 +437,6 @@ int main(int argc, char *argv[])
}
outputs.push_back(output);
-
}
}
@@ -535,7 +456,7 @@ int main(int argc, char *argv[])
edi_conf.print();
}
- size_t limit = pt.get("general.nbframes", 0);
+ const size_t limit = mux_conf.pt.get("general.nbframes", 0);
etiLog.level(info) << "Start loop";
/* Each iteration of the main loop creates one ETI frame */
@@ -544,6 +465,7 @@ int main(int argc, char *argv[])
mux.mux_frame(outputs);
if (limit && currentFrame >= limit) {
+ etiLog.level(info) << "Max number of ETI frames reached: " << currentFrame;
break;
}
@@ -562,17 +484,12 @@ int main(int argc, char *argv[])
mgmt_server.restart();
}
- mgmt_server.update_ptree(pt);
+ mgmt_server.update_ptree(mux_conf.pt);
}
}
-
- if (limit) {
- etiLog.level(info) << "Max number of ETI frames reached: " << currentFrame;
- }
}
catch (const MuxInitException& except) {
- etiLog.level(error) << "Multiplex initialisation aborted: " <<
- except.what();
+ etiLog.level(error) << "Multiplex initialisation aborted: " << except.what();
returnCode = 1;
}
catch (const std::invalid_argument& except) {
diff --git a/src/DabMux.h b/src/DabMux.h
deleted file mode 100644
index 80b4881..0000000
--- a/src/DabMux.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
- 2011 Her Majesty the Queen in Right of Canada (Communications
- Research Center Canada)
-
- Copyright (C) 2014
- Matthias P. Braendli, matthias.braendli@mpb.li
-
- This file declares several structures used in the multiplexer,
- and defines default values for some parameters.
- */
-/*
- This file is part of ODR-DabMux.
-
- ODR-DabMux is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as
- published by the Free Software Foundation, either version 3 of the
- License, or (at your option) any later version.
-
- ODR-DabMux 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
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with ODR-DabMux. If not, see <http://www.gnu.org/licenses/>.
-*/
-#pragma once
-
-#include <stdint.h>
-#include <string>
-#include <vector>
-#include "DabMultiplexer.h"
-#include "RemoteControl.h"
-#include "dabOutput/dabOutput.h"
-#include "input/inputs.h"
-#include "Eti.h"
-#include "MuxElements.h"
-
-#ifdef _WIN32
-# include <time.h>
-#else
-# include <sys/time.h>
-#endif
-
diff --git a/src/Eti.cpp b/src/Eti.cpp
index e1b51fb..2f26f2d 100644
--- a/src/Eti.cpp
+++ b/src/Eti.cpp
@@ -22,19 +22,10 @@
along with ODR-DabMux. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifdef _WIN32
-# pragma warning ( disable : 4103 )
-# include "Eti.h"
-# pragma warning ( default : 4103 )
-#else
-# include "Eti.h"
-# include <time.h>
-#endif
-
+#include "Eti.h"
//definitions des structures des champs du ETI(NI, G703)
-
unsigned short eti_FC::getFrameLength()
{
return (unsigned short)((FL_high << 8) | FL_low);
@@ -80,7 +71,7 @@ void eti_MNSC_TIME_1::setFromTime(struct tm *time_tm)
{
second_unit = time_tm->tm_sec % 10;
second_tens = time_tm->tm_sec / 10;
-
+
minute_unit = time_tm->tm_min % 10;
minute_tens = time_tm->tm_min / 10;
}
@@ -89,7 +80,7 @@ void eti_MNSC_TIME_2::setFromTime(struct tm *time_tm)
{
hour_unit = time_tm->tm_hour % 10;
hour_tens = time_tm->tm_hour / 10;
-
+
day_unit = time_tm->tm_mday % 10;
day_tens = time_tm->tm_mday / 10;
}
@@ -98,7 +89,7 @@ void eti_MNSC_TIME_3::setFromTime(struct tm *time_tm)
{
month_unit = (time_tm->tm_mon + 1) % 10;
month_tens = (time_tm->tm_mon + 1) / 10;
-
+
// They didn't see the y2k bug coming, did they ?
year_unit = (time_tm->tm_year - 100) % 10;
year_tens = (time_tm->tm_year - 100) / 10;
diff --git a/src/Eti.h b/src/Eti.h
index 88055c3..0d7aea5 100644
--- a/src/Eti.h
+++ b/src/Eti.h
@@ -29,24 +29,12 @@
# include <config.h>
#endif
-#ifdef _WIN32
-# include <winsock2.h> // For types...
-typedef WORD uint16_t;
-typedef DWORD32 uint32_t;
-
-# define PACKED
-# pragma pack(push, 1)
-#else
-# include <stdint.h>
-# include <time.h>
-
-# define PACKED __attribute__ ((packed))
-#endif
-
+#include <cstdint>
+#include <ctime>
+#define PACKED __attribute__ ((packed))
//definitions des structures des champs du ETI(NI, G703)
-
struct eti_SYNC {
uint32_t ERR:8;
uint32_t FSYNC:24;
diff --git a/src/Interleaver.cpp b/src/Interleaver.cpp
index cf0d235..1786d08 100644
--- a/src/Interleaver.cpp
+++ b/src/Interleaver.cpp
@@ -23,11 +23,6 @@
#include <string.h>
-#ifdef _WIN32
-# define bzero(a, b) memset((a), 0, (b))
-#endif // _WIN32
-
-
Interleaver::Interleaver(unsigned short I, unsigned short M, bool reverse) :
I(I),
M(M),
diff --git a/src/ManagementServer.cpp b/src/ManagementServer.cpp
index dff093a..7344b8b 100644
--- a/src/ManagementServer.cpp
+++ b/src/ManagementServer.cpp
@@ -95,11 +95,6 @@ INPUT_COUNTER_RESET_TIME = std::chrono::minutes(30);
static constexpr int
INPUT_UNSTABLE_THRESHOLD = 3;
-/* For how long the input buffers must be empty before we move an input to the
- * NoData state. */
-static constexpr auto
-INPUT_NODATA_TIMEOUT = std::chrono::seconds(30);
-
/* Keep 30s of min/max buffer fill information so that we can catch meaningful
* values even if we have a slow poller */
static constexpr auto
@@ -478,7 +473,7 @@ void InputStat::notifyPeakLevels(int peak_left, int peak_right)
}
}
-void InputStat::notifyUnderrun(void)
+void InputStat::notifyUnderrun()
{
unique_lock<mutex> lock(m_mutex);
@@ -497,7 +492,7 @@ void InputStat::notifyUnderrun(void)
}
}
-void InputStat::notifyOverrun(void)
+void InputStat::notifyOverrun()
{
unique_lock<mutex> lock(m_mutex);
@@ -643,11 +638,7 @@ input_state_t InputStat::determineState()
// STATE CALCULATION
- /* If the buffer has been empty for more than
- * INPUT_NODATA_TIMEOUT, we go to the NoData state.
- *
- * Consider an empty deque to be NoData too.
- */
+ /* Consider an empty deque to be NoData. */
if (std::all_of(
m_buffer_fill_stats.begin(), m_buffer_fill_stats.end(),
[](const fill_stat_t& fs) { return fs.bufsize == 0; }) ) {
diff --git a/src/ManagementServer.h b/src/ManagementServer.h
index c7a4222..93ad28c 100644
--- a/src/ManagementServer.h
+++ b/src/ManagementServer.h
@@ -50,7 +50,6 @@
# include "config.h"
#endif
-#include "Socket.h"
#include "zmq.hpp"
#include <string>
#include <map>
@@ -65,7 +64,6 @@
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
-#include <cmath>
/*** State handing ***/
/* An input can be in one of the following three states:
@@ -95,20 +93,20 @@ class InputStat
InputStat(const InputStat& other) = delete;
InputStat& operator=(const InputStat& other) = delete;
~InputStat();
- void registerAtServer(void);
+ void registerAtServer();
- std::string get_name(void) const { return m_name; }
+ std::string get_name() const { return m_name; }
/* This function is called for every frame read by
* the multiplexer */
void notifyBuffer(long bufsize);
void notifyTimestampOffset(double offset);
void notifyPeakLevels(int peak_left, int peak_right);
- void notifyUnderrun(void);
- void notifyOverrun(void);
+ void notifyUnderrun();
+ void notifyOverrun();
void notifyVersion(const std::string& version, uint32_t uptime_s);
- std::string encodeValuesJSON(void);
- input_state_t determineState(void);
+ std::string encodeValuesJSON();
+ input_state_t determineState();
private:
std::string m_name;
@@ -185,7 +183,7 @@ class ManagementServer
void update_ptree(const boost::property_tree::ptree& pt);
bool fault_detected() const { return m_fault; }
- void restart(void);
+ void restart();
private:
void restart_thread(long);
@@ -194,7 +192,7 @@ class ManagementServer
zmq::context_t m_zmq_context;
zmq::socket_t m_zmq_sock;
- void serverThread(void);
+ void serverThread();
void handle_message(zmq::message_t& zmq_message);
bool isInputRegistered(std::string& id);
diff --git a/src/MuxElements.cpp b/src/MuxElements.cpp
index d17b283..1f02a6d 100644
--- a/src/MuxElements.cpp
+++ b/src/MuxElements.cpp
@@ -743,7 +743,14 @@ const json::map_t dabEnsemble::get_all_values() const
return map;
}
-bool dabEnsemble::validate_linkage_sets()
+bool dabEnsemble::validate_linkage_sets() const
+{
+ return validate_linkage_sets(services, linkagesets);
+}
+
+bool dabEnsemble::validate_linkage_sets(
+ const vec_sp_service& services,
+ std::vector<std::shared_ptr<LinkageSet> > linkagesets)
{
for (const auto& ls : linkagesets) {
const std::string keyserviceuid = ls->keyservice;
diff --git a/src/MuxElements.h b/src/MuxElements.h
index d118df9..dfc4380 100644
--- a/src/MuxElements.h
+++ b/src/MuxElements.h
@@ -33,16 +33,13 @@
#include <memory>
#include <mutex>
#include <string>
-#include <functional>
#include <exception>
-#include <algorithm>
#include <chrono>
#include <optional>
#include <stdint.h>
#include "dabOutput/dabOutput.h"
#include "input/inputs.h"
#include "RemoteControl.h"
-#include "Eti.h"
// Protection levels and bitrates for UEP.
const unsigned char ProtectionLevelTable[64] = {
@@ -87,7 +84,7 @@ class MuxInitException : public std::exception
MuxInitException(const std::string m = "ODR-DabMux initialisation error")
throw()
: msg(m) {}
- ~MuxInitException(void) throw() {}
+ ~MuxInitException() throw() {}
const char* what() const throw() { return msg.c_str(); }
private:
std::string msg;
@@ -140,12 +137,12 @@ class AnnouncementCluster : public RemoteControllable {
uint16_t flags = 0;
std::string subchanneluid;
- std::string tostring(void) const;
+ std::string tostring() const;
/* Check if the activation/deactivation timeout occurred,
* and return of if the Announcement is active
*/
- bool is_active(void);
+ bool is_active();
private:
mutable std::mutex m_active_mutex;
@@ -315,7 +312,10 @@ class dabEnsemble : public RemoteControllable {
virtual const json::map_t get_all_values() const;
/* Check if the Linkage Sets are valid */
- bool validate_linkage_sets(void);
+ bool validate_linkage_sets() const;
+ static bool validate_linkage_sets(
+ const vec_sp_service& services,
+ std::vector<std::shared_ptr<LinkageSet> > linkagesets);
/* all fields are public, since this was a struct before */
uint16_t id = 0;
@@ -372,7 +372,7 @@ struct dabProtectionEEP {
// select EEP profile A and B.
// Other values are for future use, see
// EN 300 401 Clause 6.2.1 "Basic sub-channel organisation"
- uint8_t GetOption(void) const {
+ uint8_t GetOption() const {
return (this->profile == EEP_A) ? 0 : 1;
}
};
@@ -402,16 +402,16 @@ public:
protection() { }
// Calculate subchannel size in number of CU
- unsigned short getSizeCu(void) const;
+ unsigned short getSizeCu() const;
// Calculate subchannel size in number of bytes
- unsigned short getSizeByte(void) const;
+ unsigned short getSizeByte() const;
// Calculate subchannel size in number of uint32_t
- unsigned short getSizeWord(void) const;
+ unsigned short getSizeWord() const;
// Calculate subchannel size in number of uint64_t
- unsigned short getSizeDWord(void) const;
+ unsigned short getSizeDWord() const;
// Read from the input, using the correct buffer management
size_t readFrame(uint8_t *buffer, size_t size, std::time_t seconds, int utco, uint32_t tsta);
@@ -574,7 +574,7 @@ class LinkageSet {
bool hard,
bool international);
- std::string get_name(void) const { return m_name; }
+ std::string get_name() const { return m_name; }
std::list<ServiceLink> id_list;
diff --git a/src/PcDebug.h b/src/PcDebug.h
index d0b2b2c..68fceb8 100644
--- a/src/PcDebug.h
+++ b/src/PcDebug.h
@@ -19,8 +19,7 @@
along with ODR-DabMux. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef PC_DEBUG_
-#define PC_DEBUG_
+#pragma once
#ifdef HAVE_CONFIG_H
# include "config.h"
@@ -31,49 +30,28 @@
#include <stdio.h>
-#define LOG stderr
+#define LOG stderr
-#if !defined(_WIN32) || defined(__MINGW32__)
-# ifndef PDEBUG
-# ifdef DEBUG
-# define PDEBUG(fmt, args...) fprintf (LOG, fmt , ## args)
-# else
-# define PDEBUG(fmt, args...)
-# endif
-# endif
+#ifndef PDEBUG
# ifdef DEBUG
-# define PDEBUG_VERBOSE(level, verbosity, fmt, args...) if (level <= verbosity) { fprintf(LOG, fmt, ## args); fflush(LOG); }
-# define PDEBUG0_VERBOSE(level, verbosity, txt) if (level <= verbosity) { fprintf(LOG, txt); fflush(LOG); }
-# define PDEBUG1_VERBOSE(level, verbosity, txt, arg0) if (level <= verbosity) { fprintf(LOG, txt, arg0); fflush(LOG); }
-# define PDEBUG2_VERBOSE(level, verbosity, txt, arg0, arg1) if (level <= verbosity) { fprintf(LOG, txt, arg0, arg1); fflush(LOG); }
-# define PDEBUG3_VERBOSE(level, verbosity, txt, arg0, arg1, arg2) if (level <= verbosity) { fprintf(LOG, txt, arg0, arg1, arg2); fflush(LOG); }
-# define PDEBUG4_VERBOSE(level, verbosity, txt, arg0, arg1, arg2, arg3) if (level <= verbosity) { fprintf(LOG, txt, arg0, arg1, arg2, arg3); fflush(LOG); }
-# else
-# define PDEBUG_VERBOSE(level, verbosity, fmt, args...)
-# define PDEBUG0_VERBOSE(level, verbosity, txt)
-# define PDEBUG1_VERBOSE(level, verbosity, txt, arg0)
-# define PDEBUG2_VERBOSE(level, verbosity, txt, arg0, arg1)
-# define PDEBUG3_VERBOSE(level, verbosity, txt, arg0, arg1, arg2)
-# define PDEBUG4_VERBOSE(level, verbosity, txt, arg0, arg1, arg2, arg3)
-# endif // DEBUG
-#else // _WIN32
-# ifdef _DEBUG
-# define PDEBUG
-# define PDEBUG_VERBOSE
-# define PDEBUG0_VERBOSE(level, verbosity, txt) if (level <= verbosity) { fprintf(LOG, txt); fflush(LOG); }
-# define PDEBUG1_VERBOSE(level, verbosity, txt, arg0) if (level <= verbosity) { fprintf(LOG, txt, arg0); fflush(LOG); }
-# define PDEBUG2_VERBOSE(level, verbosity, txt, arg0, arg1) if (level <= verbosity) { fprintf(LOG, txt, arg0, arg1); fflush(LOG); }
-# define PDEBUG3_VERBOSE(level, verbosity, txt, arg0, arg1, arg2) if (level <= verbosity) { fprintf(LOG, txt, arg0, arg1, arg2); fflush(LOG); }
-# define PDEBUG4_VERBOSE(level, verbosity, txt, arg0, arg1, arg2, arg3) if (level <= verbosity) { fprintf(LOG, txt, arg0, arg1, arg2, arg3); fflush(LOG); }
+# define PDEBUG(fmt, args...) fprintf (LOG, fmt , ## args)
# else
-# define PDEBUG
-# define PDEBUG_VERBOSE
-# define PDEBUG0_VERBOSE(level, verbosity, txt)
-# define PDEBUG1_VERBOSE(level, verbosity, txt, arg0)
-# define PDEBUG2_VERBOSE(level, verbosity, txt, arg0, arg1)
-# define PDEBUG3_VERBOSE(level, verbosity, txt, arg0, arg1, arg2)
-# define PDEBUG4_VERBOSE(level, verbosity, txt, arg0, arg1, arg2, arg3)
+# define PDEBUG(fmt, args...)
# endif
#endif
+#ifdef DEBUG
+# define PDEBUG_VERBOSE(level, verbosity, fmt, args...) if (level <= verbosity) { fprintf(LOG, fmt, ## args); fflush(LOG); }
+# define PDEBUG0_VERBOSE(level, verbosity, txt) if (level <= verbosity) { fprintf(LOG, txt); fflush(LOG); }
+# define PDEBUG1_VERBOSE(level, verbosity, txt, arg0) if (level <= verbosity) { fprintf(LOG, txt, arg0); fflush(LOG); }
+# define PDEBUG2_VERBOSE(level, verbosity, txt, arg0, arg1) if (level <= verbosity) { fprintf(LOG, txt, arg0, arg1); fflush(LOG); }
+# define PDEBUG3_VERBOSE(level, verbosity, txt, arg0, arg1, arg2) if (level <= verbosity) { fprintf(LOG, txt, arg0, arg1, arg2); fflush(LOG); }
+# define PDEBUG4_VERBOSE(level, verbosity, txt, arg0, arg1, arg2, arg3) if (level <= verbosity) { fprintf(LOG, txt, arg0, arg1, arg2, arg3); fflush(LOG); }
+#else
+# define PDEBUG_VERBOSE(level, verbosity, fmt, args...)
+# define PDEBUG0_VERBOSE(level, verbosity, txt)
+# define PDEBUG1_VERBOSE(level, verbosity, txt, arg0)
+# define PDEBUG2_VERBOSE(level, verbosity, txt, arg0, arg1)
+# define PDEBUG3_VERBOSE(level, verbosity, txt, arg0, arg1, arg2)
+# define PDEBUG4_VERBOSE(level, verbosity, txt, arg0, arg1, arg2, arg3)
+#endif // DEBUG
-#endif // PC_DEBUG_
diff --git a/src/fig/FIG0_6.h b/src/fig/FIG0_6.h
index 770c4d5..96464d2 100644
--- a/src/fig/FIG0_6.h
+++ b/src/fig/FIG0_6.h
@@ -26,8 +26,6 @@
#pragma once
#include <cstdint>
-#include <vector>
-#include <memory>
namespace FIC {
diff --git a/src/fig/FIG1.h b/src/fig/FIG1.h
index 0fedffe..fe36717 100644
--- a/src/fig/FIG1.h
+++ b/src/fig/FIG1.h
@@ -23,8 +23,7 @@
along with ODR-DabMux. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef __FIG1_H_
-#define __FIG1_H_
+#pragma once
#include <cstdint>
@@ -103,10 +102,6 @@ class FIG1_5 : public IFIG
vec_sp_service::iterator service;
};
-#ifdef _WIN32
-# pragma pack(push)
-#endif
-
struct FIGtype1_0 {
uint8_t Length:5;
uint8_t FIGtypeNumber:3;
@@ -165,11 +160,5 @@ struct FIGtype1_4_data {
} PACKED;
-#ifdef _WIN32
-# pragma pack(pop)
-#endif
-
} // namespace FIC
-#endif // __FIG1_H_
-
diff --git a/src/fig/FIG2.h b/src/fig/FIG2.h
index ee3fed9..e69c5db 100644
--- a/src/fig/FIG2.h
+++ b/src/fig/FIG2.h
@@ -22,9 +22,7 @@
You should have received a copy of the GNU General Public License
along with ODR-DabMux. If not, see <http://www.gnu.org/licenses/>.
*/
-
-#ifndef __FIG2_H_
-#define __FIG2_H_
+#pragma once
#include <cstdint>
#include <map>
@@ -117,10 +115,6 @@ class FIG2_4 : public IFIG
std::map<std::pair<uint32_t, uint8_t>, FIG2_Segments> segment_per_component;
};
-#ifdef _WIN32
-# pragma pack(push)
-#endif
-
struct FIGtype2 {
uint8_t Length:5;
uint8_t FIGtypeNumber:3;
@@ -159,11 +153,5 @@ struct FIG2_Extended_Label_WithTextControl {
uint8_t EncodingFlag:1;
} PACKED;
-#ifdef _WIN32
-# pragma pack(pop)
-#endif
-
} // namespace FIC
-#endif // __FIG2_H_
-
diff --git a/src/input/Edi.cpp b/src/input/Edi.cpp
index 141641f..b100f32 100644
--- a/src/input/Edi.cpp
+++ b/src/input/Edi.cpp
@@ -80,6 +80,7 @@ Edi::~Edi() {
void Edi::open(const std::string& name)
{
const std::regex re_udp("udp://:([0-9]+)");
+ const std::regex re_udp_bindto("udp://([^:]+):([0-9]+)");
const std::regex re_udp_multicast("udp://@([0-9.]+):([0-9]+)");
const std::regex re_udp_multicast_bindto("udp://([0-9.])+@([0-9.]+):([0-9]+)");
const std::regex re_tcp("tcp://(.*):([0-9]+)");
@@ -98,6 +99,12 @@ void Edi::open(const std::string& name)
m_udp_sock.reinit(udp_port);
m_udp_sock.setBlocking(false);
}
+ else if (std::regex_match(name, m, re_udp_bindto)) {
+ const int udp_port = std::stoi(m[2].str());
+ m_input_used = InputUsed::UDP;
+ m_udp_sock.reinit(udp_port, m[1].str());
+ m_udp_sock.setBlocking(false);
+ }
else if (std::regex_match(name, m, re_udp_multicast_bindto)) {
const string bind_to = m[1].str();
const string multicast_address = m[2].str();
diff --git a/src/input/File.cpp b/src/input/File.cpp
index d9fe02a..c70feee 100644
--- a/src/input/File.cpp
+++ b/src/input/File.cpp
@@ -28,9 +28,6 @@
#include <cstdio>
#include <fcntl.h>
#include <unistd.h>
-#ifndef _WIN32
-# define O_BINARY 0
-#endif
#include "input/File.h"
#include "mpeg.h"
#include "ReedSolomon.h"
@@ -39,9 +36,6 @@ using namespace std;
namespace Inputs {
-#ifdef _WIN32
-# pragma pack(push, 1)
-#endif
struct packetHeader {
unsigned char addressHigh:2;
unsigned char last:1;
@@ -52,11 +46,7 @@ struct packetHeader {
unsigned char dataLength:7;
unsigned char command;
}
-#ifdef _WIN32
-# pragma pack(pop)
-#else
__attribute((packed))
-#endif
;
@@ -68,7 +58,7 @@ void FileBase::open(const std::string& name)
load_entire_file();
}
else {
- int flags = O_RDONLY | O_BINARY;
+ int flags = O_RDONLY;
if (m_nonblock) {
flags |= O_NONBLOCK;
}
@@ -140,13 +130,13 @@ ssize_t FileBase::load_entire_file()
{
// Clear the buffer if the file open fails, this allows user to stop transmission
// of the current data.
- vector<uint8_t> old_file_contents = move(m_file_contents);
+ vector<uint8_t> old_file_contents = std::move(m_file_contents);
m_file_contents.clear();
m_file_contents_offset = 0;
// Read entire file in chunks of 4MiB
constexpr size_t blocksize = 4 * 1024 * 1024;
- constexpr int flags = O_RDONLY | O_BINARY;
+ constexpr int flags = O_RDONLY;
m_fd = ::open(m_filename.c_str(), flags);
if (m_fd == -1) {
if (not m_file_open_alert_shown) {
@@ -225,7 +215,7 @@ ssize_t FileBase::readFromFile(uint8_t *buffer, size_t size)
vector<uint8_t> remaining_buf;
copy(m_nonblock_buffer.begin() + size, m_nonblock_buffer.end(), back_inserter(remaining_buf));
- m_nonblock_buffer = move(remaining_buf);
+ m_nonblock_buffer = std::move(remaining_buf);
return size;
}
diff --git a/src/mpeg.h b/src/mpeg.h
index 15b9b80..29b3655 100644
--- a/src/mpeg.h
+++ b/src/mpeg.h
@@ -18,23 +18,13 @@
You should have received a copy of the GNU General Public License
along with ODR-DabMux. If not, see <http://www.gnu.org/licenses/>.
*/
-
-#ifndef _MPEG
-#define _MPEG
+#pragma once
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
-#ifdef _WIN32
-# include <stddef.h>
-# include <basetsd.h>
-# include <io.h>
-
-# define ssize_t SSIZE_T
-#else
-# include <unistd.h>
-#endif
+#include <unistd.h>
#ifdef __cplusplus
extern "C" {
@@ -86,4 +76,3 @@ int checkDabMpegFrame(void* data);
}
#endif
-#endif // _MPEG