diff --git a/.gitignore b/.gitignore
index cd3cdf4f3..fa7c75e95 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,10 +1,11 @@
.*
+*.*~
*.pyc
vendor/*
composer.phar
*~$
*log.*
-**/airtime_analyzer.egg-info/*
+**/*.egg-info/*
**/build/*
**/dist/*
*~
diff --git a/README b/README
index d83dbde3b..38e5b0f86 100644
--- a/README
+++ b/README
@@ -3,7 +3,7 @@
=========================================================================
Airtime is an open source application that provides remote and
-collaborative automation of a broadcast station.
+collaborative automation of a broadcast radio station.
Home page: http://www.sourcefabric.org/en/airtime/
@@ -18,28 +18,62 @@ Major features:
* Solid playout. Airtime uses the open source Liquidsoap streaming language
for reliable and precise playback to multiple outputs.
* Open, extensible architecture. Stations are free to extend and alter
- all parts of the program code, under the GNU GPLv3 license.
+ all parts of the program code, under the GNU AGPLv3 license.
INSTALLATION
------------
-Please see this chapter to begin a typical installation:
-http://sourcefabric.booktype.pro/airtime-25-for-broadcasters/preparing-the-server/
+Basic installation has two steps:
-If you are a developer, please see this page:
-http://wiki.sourcefabric.org/display/CC/Airtime+Dev+Site
+1) Run the install script, located in the Airtime root directory.
-For installation direct from a git checkout on Ubuntu 12.04 LTS, run:
+For an interactive installation, run:
- cd install_full/ubuntu
- sudo ./airtime-full-install
+ sudo ./install
-For installation from git on Debian wheezy, run:
+If you're using a terminal that is not running Bash, you'll need to run
- cd install_full/debian
- sudo ./airtime-full-install
+ sudo /bin/bash ./install
+instead. You may need to install Bash first.
+
+The installer will then prompt you about how you want to set up your Airtime
+installation.
+
+For a non-interactive full installation (do this if you're installing Airtime from
+scratch and don't have any of your own configuration set up), run
+
+ sudo ./install -fiap
+
+What this means:
+
+ -f - force; non-interactive (no prompts)
+ -i - install the default Icecast 2 setup for Airtime
+ -a - install the default apache setup for Airtime
+ -p - create a default Airtime postgres user
+
+This will install all components necessary for Airtime, and set up
+/usr/share/airtime as your web root (where apache looks for your Airtime files)
+
+There are several options for installation - to see them all, run
+
+ sudo ./install --help
+
+2) Once you've run the installer, open a web browser to http://localhost to run
+the interactive setup. (If you have a custom apache configuration, navigate to
+your Airtime web host instead.)
+
+If you just want to run Airtime with default settings, you won't need to change
+anything, but if you have any custom configuration settings you'll be able to
+specify them.
+
+Once you finish the setup process, you'll be presented with a configuration
+checklist so you can ensure that your Airtime installation is working
+correctly. If anything was mis-configured, the checklist will provide some .
+helpful tips to resolve the issue.
+
+If your checklist is all green, you're ready to get started with Airtime!
Quick links to our resources
----------------------------
@@ -48,4 +82,3 @@ Forums and mailing lists: http://forum.sourcefabric.org
Bug tracker: http://dev.sourcefabric.org
Source code: http://github.com/sourcefabric/Airtime
IRC chat: #airtime on Freenode
-
diff --git a/airtime_mvc/application/Bootstrap.php b/airtime_mvc/application/Bootstrap.php
index f7af625b3..7b62486e1 100644
--- a/airtime_mvc/application/Bootstrap.php
+++ b/airtime_mvc/application/Bootstrap.php
@@ -1,19 +1,19 @@
headScript()->appendScript("var USER_MANUAL_URL = '" . USER_MANUAL_URL . "';");
$view->headScript()->appendScript("var COMPANY_NAME = '" . COMPANY_NAME . "';");
}
+
+ protected function _initUpgrade() {
+ /* We need to wrap this here so that we aren't checking when we're running the unit test suite
+ */
+ if (getenv("AIRTIME_UNIT_TEST") != 1) {
+ UpgradeManager::checkIfUpgradeIsNeeded(); //This will do the upgrade too if it's needed...
+ }
+ }
protected function _initHeadLink()
{
@@ -224,8 +233,7 @@ class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
protected function _initViewHelpers()
{
$view = $this->getResource('view');
- $view->addHelperPath('../application/views/helpers', 'Airtime_View_Helper');
-
+ $view->addHelperPath(APPLICATION_PATH . 'views/helpers', 'Airtime_View_Helper');
$view->assign('suspended', (Application_Model_Preference::getProvisioningStatus() == PROVISIONING_STATUS_SUSPENDED));
}
@@ -238,7 +246,7 @@ class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
protected function _initZFDebug()
{
- Zend_Controller_Front::getInstance()->throwExceptions(true);
+ Zend_Controller_Front::getInstance()->throwExceptions(false);
/*
if (APPLICATION_ENV == "development") {
diff --git a/airtime_mvc/application/airtime-boot.php b/airtime_mvc/application/airtime-boot.php
new file mode 100644
index 000000000..0fb1212dd
--- /dev/null
+++ b/airtime_mvc/application/airtime-boot.php
@@ -0,0 +1,110 @@
+bootstrap()->run();
+ }
+} catch (Exception $e) {
+ if ($e->getCode() == 401)
+ {
+ header($_SERVER['SERVER_PROTOCOL'] . ' 401 Unauthorized', true, 401);
+ return;
+ }
+
+ header($_SERVER['SERVER_PROTOCOL'] . ' 500 Internal Server Error', true, 500);
+ Logging::error($e->getMessage());
+
+ if (VERBOSE_STACK_TRACE) {
+ echo $e->getMessage();
+ echo "
";
+ echo $e->getTraceAsString();
+ echo "
";
+ Logging::info($e->getMessage());
+ Logging::info($e->getTraceAsString());
+ } else {
+ Logging::info($e->getTrace());
+ }
+ throw $e;
+}
+
diff --git a/airtime_mvc/application/configs/conf.php b/airtime_mvc/application/configs/conf.php
index f89a5472e..5b11c30c8 100644
--- a/airtime_mvc/application/configs/conf.php
+++ b/airtime_mvc/application/configs/conf.php
@@ -2,8 +2,6 @@
/* THIS FILE IS NOT MEANT FOR CUSTOMIZING.
* PLEASE EDIT THE FOLLOWING TO CHANGE YOUR CONFIG:
* /etc/airtime/airtime.conf
- * /etc/airtime/pypo.cfg
- * /etc/airtime/recorder.cfg
*/
class Config {
@@ -37,7 +35,6 @@ class Config {
$CC_CONFIG['baseDir'] = $values['general']['base_dir'];
$CC_CONFIG['baseUrl'] = $values['general']['base_url'];
$CC_CONFIG['basePort'] = $values['general']['base_port'];
- $CC_CONFIG['phpDir'] = $values['general']['airtime_dir'];
if (isset($values['general']['dev_env'])) {
$CC_CONFIG['dev_env'] = $values['general']['dev_env'];
} else {
@@ -68,12 +65,9 @@ class Config {
// Tells us where file uploads will be uploaded to.
// It will either be set to a cloud storage backend or local file storage.
$CC_CONFIG["current_backend"] = $cloudStorageValues["current_backend"]["storage_backend"];
-
+
$CC_CONFIG['cache_ahead_hours'] = $values['general']['cache_ahead_hours'];
- $CC_CONFIG['monit_user'] = $values['monit']['monit_user'];
- $CC_CONFIG['monit_password'] = $values['monit']['monit_password'];
-
// Database config
$CC_CONFIG['dsn']['username'] = $values['database']['dbuser'];
$CC_CONFIG['dsn']['password'] = $values['database']['dbpass'];
diff --git a/airtime_mvc/application/configs/config-check.php b/airtime_mvc/application/configs/config-check.php
new file mode 100644
index 000000000..9cfb9927b
--- /dev/null
+++ b/airtime_mvc/application/configs/config-check.php
@@ -0,0 +1,265 @@
+
+
+
+
+
+
+
+
+
+
+
+ Configuration Checklist
+
+
+
+
+
Looks like something went wrong!
+
+ Take a look at the checklist below for possible solutions. If you're tried the suggestions and are
+ still experiencing issues, come
+ visit our forums
+ or check out the manual.
+
+
+
+ Your Airtime station is up and running! Get started by logging in with the default username and password: admin/admin
+
+ ">
+ Make sure you aren't missing any of the Postgres dependencies in the table above.
+ If your dependencies check out, make sure your database configuration settings in
+ /etc/airtime.conf are correct and the Airtime database was installed correctly.
+
+
+
+
+
+ RabbitMQ
+
+
+ RabbitMQ configuration for Airtime
+
+
+ ">
+ Make sure RabbitMQ is installed correctly, and that your settings in /etc/airtime/airtime.conf
+ are correct. Try using sudo rabbitmqctl list_users and sudo rabbitmqctl list_vhosts
+ to see if the airtime user (or your custom RabbitMQ user) exists, then checking that
+ sudo rabbitmqctl list_exchanges contains entries for airtime-media-monitor, airtime-pypo,
+ and airtime-uploads.
+
+
+
+
+
+ Media Monitor
+
+
+ Airtime media-monitor service
+
+
+ ">
+ Check that the airtime-media-monitor service is installed correctly in /etc/init,
+ and ensure that it's running with
+ initctl list | grep airtime-media-monitor
+ If not, try running sudo service airtime-media-monitor start
+
+
+
+
+
+ Pypo
+
+
+ Airtime playout service
+
+
+ ">
+ Check that the airtime-playout service is installed correctly in /etc/init,
+ and ensure that it's running with
+ initctl list | grep airtime-playout
+ If not, try running sudo service airtime-playout restart
+
+
+
+
+
+ Liquidsoap
+
+
+ Airtime liquidsoap service
+
+
+ ">
+ Check that the airtime-liquidsoap service is installed correctly in /etc/init,
+ and ensure that it's running with
+ initctl list | grep airtime-liquidsoap
+ If not, try running sudo service airtime-liquidsoap restart
+
+
+ ">
+ Make sure you aren't missing any of the Postgres dependencies in the table above.
+ If your dependencies check out, make sure your database configuration settings in
+ /etc/airtime.conf are correct and the Airtime database was installed correctly.
+
+
+
+
+
+ RabbitMQ
+
+
+ RabbitMQ configuration for Airtime
+
+
+ ">
+ Make sure RabbitMQ is installed correctly, and that your settings in /etc/airtime/airtime.conf
+ are correct. Try using sudo rabbitmqctl list_users and sudo rabbitmqctl list_vhosts
+ to see if the airtime user (or your custom RabbitMQ user) exists, then checking that
+ sudo rabbitmqctl list_exchanges contains entries for airtime-media-monitor, airtime-pypo,
+ and airtime-uploads.
+
+
+
+
+
+ Media Monitor
+
+
+ Airtime media-monitor service
+
+
+ ">
+ Check that the airtime-media-monitor service is installed correctly in /etc/init,
+ and ensure that it's running with
+ initctl list | grep airtime-media-monitor
+ If not, try sudo service airtime-media-monitor start
+
+
+
+
+
+ Pypo
+
+
+ Airtime playout service
+
+
+ ">
+ Check that the airtime-playout service is installed correctly in /etc/init,
+ and ensure that it's running with
+ initctl list | grep airtime-playout
+ If not, try sudo service airtime-playout restart
+
+
+
+
+
+ Liquidsoap
+
+
+ Airtime liquidsoap service
+
+
+ ">
+ Check that the airtime-liquidsoap service is installed correctly in /etc/init,
+ and ensure that it's running with
+ initctl list | grep airtime-liquidsoap
+ If not, try sudo service airtime-liquidsoap restart
+
+
+
+
+
+
+
+
diff --git a/airtime_mvc/build/airtime-setup/forms/database-settings.php b/airtime_mvc/build/airtime-setup/forms/database-settings.php
new file mode 100644
index 000000000..08db5e225
--- /dev/null
+++ b/airtime_mvc/build/airtime-setup/forms/database-settings.php
@@ -0,0 +1,53 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/airtime_mvc/build/airtime-setup/forms/finish-settings.php b/airtime_mvc/build/airtime-setup/forms/finish-settings.php
new file mode 100644
index 000000000..d6b298c34
--- /dev/null
+++ b/airtime_mvc/build/airtime-setup/forms/finish-settings.php
@@ -0,0 +1,30 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/airtime_mvc/build/airtime-setup/forms/general-settings.php b/airtime_mvc/build/airtime-setup/forms/general-settings.php
new file mode 100644
index 000000000..f15e06d5a
--- /dev/null
+++ b/airtime_mvc/build/airtime-setup/forms/general-settings.php
@@ -0,0 +1,33 @@
+
+
+
+
+
diff --git a/airtime_mvc/build/airtime-setup/forms/media-settings.php b/airtime_mvc/build/airtime-setup/forms/media-settings.php
new file mode 100644
index 000000000..bc3b02761
--- /dev/null
+++ b/airtime_mvc/build/airtime-setup/forms/media-settings.php
@@ -0,0 +1,30 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/airtime_mvc/build/airtime-setup/forms/rabbitmq-settings.php b/airtime_mvc/build/airtime-setup/forms/rabbitmq-settings.php
new file mode 100644
index 000000000..052956b0f
--- /dev/null
+++ b/airtime_mvc/build/airtime-setup/forms/rabbitmq-settings.php
@@ -0,0 +1,75 @@
+
+
+
+
+
diff --git a/airtime_mvc/build/airtime-setup/load.php b/airtime_mvc/build/airtime-setup/load.php
new file mode 100644
index 000000000..722d6aec8
--- /dev/null
+++ b/airtime_mvc/build/airtime-setup/load.php
@@ -0,0 +1,158 @@
+ checkZendDependencies(),
+ "postgres" => checkDatabaseDependencies()
+ );
+}
+
+/**
+ * Check that the Zend framework libraries are installed
+ *
+ * @return boolean true if Zend exists in /usr/share/php
+ */
+function checkZendDependencies() {
+ return file_exists('/usr/share/php/libzend-framework-php')
+ || file_exists('/usr/share/php/Zend'); // Debian version
+}
+
+/**
+ * Check that the PHP dependencies for the database exist
+ *
+ * @return boolean true if the database dependencies exist
+ */
+function checkDatabaseDependencies() {
+ global $extensions;
+ // Check the PHP extension list for the Postgres db extensions
+ return (in_array('pdo_pgsql', $extensions)
+ && in_array('pgsql', $extensions));
+}
+
+/**
+ * Check that all external services are configured correctly and return an associative
+ * array with the results
+ *
+ * @return array associative array of external service check results
+ */
+function checkExternalServices() {
+ return array(
+ "database" => checkDatabaseConfiguration(),
+ "media-monitor" => checkMediaMonitorService(),
+ "pypo" => checkPlayoutService(),
+ "liquidsoap" => checkLiquidsoapService(),
+ "rabbitmq" => checkRMQConnection()
+ );
+}
+
+/**
+ * Check the database configuration by fetching a connection from Propel
+ *
+ * @return boolean true if a connection is made to the database
+ */
+function checkDatabaseConfiguration() {
+ configureDatabase();
+
+ try {
+ // Try to establish a database connection. If something goes
+ // wrong, the database is improperly configured
+ Propel::getConnection();
+ Propel::close();
+ } catch (Exception $e) {
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * Initialize Propel to configure the Airtime database
+ */
+function configureDatabase() {
+ Propel::init(CONFIG_PATH . 'airtime-conf-production.php');
+}
+
+/**
+ * Check that we can connect to RabbitMQ
+ *
+ * @return true if the RabbitMQ connection can be established
+ */
+function checkRMQConnection() {
+ // Check for airtime.conf in /etc/airtime/ first, then check in the build directory,
+ if (file_exists(AIRTIME_CONFIG_STOR . AIRTIME_CONFIG)) {
+ $ini = parse_ini_file(AIRTIME_CONFIG_STOR . AIRTIME_CONFIG, true);
+ } else {
+ $ini = parse_ini_file(BUILD_PATH . "airtime.example.conf", true);
+ }
+
+ $conn = new AMQPConnection($ini[RMQ_INI_SECTION]["host"],
+ $ini[RMQ_INI_SECTION]["port"],
+ $ini[RMQ_INI_SECTION]["user"],
+ $ini[RMQ_INI_SECTION]["password"],
+ $ini[RMQ_INI_SECTION]["vhost"]);
+ return isset($conn);
+}
+
+/**
+ * Check if airtime-media-monitor is currently running
+ *
+ * @return boolean true if airtime-media-monitor is running
+ */
+function checkMediaMonitorService() {
+ exec("pgrep -f -u www-data airtime-media-monitor", $out, $status);
+ if (array_key_exists(0, $out) && $status == 0) {
+ return posix_kill(rtrim($out[0]), 0);
+ }
+ return $status == 0;
+}
+
+/**
+ * Check if airtime-playout is currently running
+ *
+ * @return boolean true if airtime-playout is running
+ */
+function checkPlayoutService() {
+ exec("pgrep -f -u www-data airtime-playout", $out, $status);
+ if (array_key_exists(0, $out) && $status == 0) {
+ return posix_kill(rtrim($out[0]), 0);
+ }
+ return $status == 0;
+}
+
+/**
+ * Check if airtime-liquidsoap is currently running
+ *
+ * @return boolean true if airtime-liquidsoap is running
+ */
+function checkLiquidsoapService() {
+ exec("pgrep -f -u www-data airtime-liquidsoap", $out, $status);
+ if (array_key_exists(0, $out) && $status == 0) {
+ return posix_kill(rtrim($out[0]), 0);
+ }
+ return $status == 0;
+}
diff --git a/airtime_mvc/build/airtime-setup/setup-config.php b/airtime_mvc/build/airtime-setup/setup-config.php
new file mode 100644
index 000000000..c116767cf
--- /dev/null
+++ b/airtime_mvc/build/airtime-setup/setup-config.php
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Setup
+
+ Step 1 of 5
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/airtime_mvc/build/airtime.conf b/airtime_mvc/build/airtime.conf
deleted file mode 100644
index 60633ed2b..000000000
--- a/airtime_mvc/build/airtime.conf
+++ /dev/null
@@ -1,32 +0,0 @@
-[database]
-host = localhost
-dbname = airtime
-dbuser = airtime
-dbpass = airtime
-
-[rabbitmq]
-host = 127.0.0.1
-port = 5672
-user = guest
-password = guest
-vhost = /
-
-[general]
-api_key = AAA
-web_server_user = www-data
-airtime_dir = x
-base_url = localhost
-base_port = 80
-base_dir = '/'
-
-;How many hours ahead of time should Airtime playout engine (PYPO)
-;cache scheduled media files.
-cache_ahead_hours = 1
-
-[monit]
-monit_user = guest
-monit_password = airtime
-
-[soundcloud]
-connection_retries = 3
-time_between_retries = 60
\ No newline at end of file
diff --git a/airtime_mvc/build/airtime.example.conf b/airtime_mvc/build/airtime.example.conf
new file mode 100644
index 000000000..98c5c7887
--- /dev/null
+++ b/airtime_mvc/build/airtime.example.conf
@@ -0,0 +1,274 @@
+# ----------------------------------------------------------------------
+# A I R T I M E C O N F I G U R A T I O N
+# ----------------------------------------------------------------------
+#
+# This is an example configuration for Airtime. If you just want to
+# get started with a basic Airtime setup, or don't know if you should
+# be reconfiguring any of the following values, just rename this file
+# to 'airtime.conf'.
+#
+# ----------------------------------------------------------------------
+
+
+# ----------------------------------------------------------------------
+# G E N E R A L S E T T I N G S
+# ----------------------------------------------------------------------
+#
+# These settings are used for Airtime's webserver configuration, and
+# for general-purpose properties.
+#
+# api_key: The API key for your Airtime installation.
+# The value is generated the first time you use Airtime.
+#
+# web_server_user: The default webserver user.
+# The default is www-data.
+#
+# base_url: The host name for your webserver.
+# The default is localhost.
+#
+# base_port: The port for your webserver.
+# The default is 80.
+#
+# base_dir: The root directory for your Airtime installation
+# on your webserver, relative to the base_url.
+# The default is /.
+#
+# cache_ahead_hours: How many hours ahead of time the Airtime playout
+# engine (pypo) should cache scheduled media files.
+# The default is 1.
+#
+[general]
+api_key =
+web_server_user = www-data
+base_url = localhost
+base_port = 80
+base_dir = /
+cache_ahead_hours = 1
+#
+# ----------------------------------------------------------------------
+
+
+# ----------------------------------------------------------------------
+# D A T A B A S E
+# ----------------------------------------------------------------------
+#
+# These settings are used to configure your database connection.
+#
+# host: The hostname of the database server.
+# On a default Airtime installation, set this to localhost.
+#
+# dbname: The name of the Airtime database.
+# The default is airtime.
+#
+# dbuser: The username for the Airtime database user.
+# The default is airtime.
+#
+# dbpass: The password for the Airtime database user.
+# The default is airtime.
+#
+[database]
+host = localhost
+dbname = airtime
+dbuser = airtime
+dbpass = airtime
+#
+# ----------------------------------------------------------------------
+
+
+# ----------------------------------------------------------------------
+# R A B B I T M Q
+# ----------------------------------------------------------------------
+#
+# These settings are used to configure the RabbitMQ messaging
+# configuration for your Airtime installation.
+#
+# host: The IP address for the RabbitMQ service.
+# The default is 127.0.0.1.
+#
+# port: The port for the RabbitMQ service.
+# The default is 5672.
+#
+# user: The username for the RabbitMQ user.
+# The default is airtime.
+#
+# password: The password for the RabbitMQ user.
+# The default is airtime.
+#
+# vhost: The virtual host for the RabbitMQ service database.
+# The default is /airtime.
+#
+[rabbitmq]
+host = 127.0.0.1
+port = 5672
+user = airtime
+password = airtime
+vhost = /airtime
+#
+# ----------------------------------------------------------------------
+
+
+# ----------------------------------------------------------------------
+# M E D I A M O N I T O R
+# ----------------------------------------------------------------------
+#
+# check_filesystem_events: How long to queue up events performed on the
+# files themselves, in seconds
+# The default is 5
+#
+# check_airtime_events: How long to queue metadata input from airtime,
+# in seconds
+# The default is 30
+#
+# touch_interval:
+# The default is 5
+#
+# chunking_number:
+# The default is 450
+#
+# request_max_wait: The maximum request wait time, in seconds
+# The default is 3.0
+#
+# rmq_event_wait: The RabbitMQ event wait time, in seconds
+# The default is 0.1
+#
+# logpath: The media monitor log file path
+# The default is '/var/log/airtime/media-monitor/media-monitor.log'
+#
+# index_path: The media monitor index path
+# The default is '/var/tmp/airtime/media-monitor/last_index'
+#
+[media-monitor]
+check_filesystem_events = 5
+check_airtime_events = 30
+touch_interval = 5
+chunking_number = 450
+request_max_wait = 3.0
+rmq_event_wait = 0.1
+logpath = '/var/log/airtime/media-monitor/media-monitor.log'
+index_path = '/var/tmp/airtime/media-monitor/last_index'
+#
+# ----------------------------------------------------------------------
+
+
+# ----------------------------------------------------------------------
+# P Y P O
+# ----------------------------------------------------------------------
+#
+# api_client: Set the type of client you are using.
+# Currently supported types:
+# 1) 'obp' = Open Broadcast Platform
+# 2) 'airtime'
+# The default is 'airtime'
+#
+# cache_dir: The directory for pypo cache files
+# The default is '/var/tmp/airtime/pypo/cache/'
+#
+# file_dir: The directory for pypo media files
+# The default is '/var/tmp/airtime/pypo/files/'
+#
+# tmp_dir: The directory for pypo temp files
+# The default is '/var/tmp/airtime/pypo/tmp/'
+#
+# cache_base_dir: The pypo base cache directory
+# The default is '/var/tmp/airtime/pypo/'
+#
+# log_base_dir: The base directory for Airtime log files
+# The default is '/var/log/airtime'
+#
+# pypo_log_dir: The directory for pypo log files
+# The default is '/var/log/airtime/pypo'
+#
+# liquidsoap_log_dir: The directory for liquidsoap log files
+# The default is '/var/log/airtime/pypo-liquidsoap'
+#
+# ls_host: Liquidsoap connection host
+# The default is '127.0.0.1'
+#
+# ls_port: Liquidsoap connection port
+# The default is '1234'
+#
+# poll_interval: Poll interval in seconds
+#
+# This will rarely need to be changed because any schedule
+# changes are automatically sent to pypo immediately
+# This is how often the poll script downloads new schedules
+# and files from the server in the event that no changes
+# are made to the schedule
+# The default is 3600
+#
+# push_interval: Push interval in seconds
+#
+# This is how often the push script checks whether it has
+# something new to push to liquidsoap
+# The default is 1
+#
+# cue_style: Can be set to 'pre' or 'otf'
+# 'pre' cues while playlist preparation
+# 'otf' (on the fly) cues while loading into ls
+# (needs the post_processor patch)
+# The default is 'pre'
+#
+# record_bitrate: The bitrate for recordings
+# The default is 256
+#
+# record_samplerate: The samplerate for recordings
+# The default is 44100
+#
+# record_channels: The number of channels for recordings
+# The default is 2
+#
+# record_sample_size: The sample size for recordings
+# The default is 16
+#
+# record_file_type: Can be either ogg|mp3, mp3 recording requires
+# installation of the package "lame"
+# The default is ogg
+#
+# base_recorded_files: Base path to store recordered shows at
+# The default is '/var/tmp/airtime/show-recorder/'
+#
+[pypo]
+api_client = 'airtime'
+# ---------- Cache directories - !! Include trailing slash !! ----------
+cache_dir = '/var/tmp/airtime/pypo/cache/'
+file_dir = '/var/tmp/airtime/pypo/files/'
+tmp_dir = '/var/tmp/airtime/pypo/tmp/'
+# ------- Setup directories - !! Don't include trailing slash !! -------
+cache_base_dir = '/var/tmp/airtime/pypo'
+log_base_dir = '/var/log/airtime'
+pypo_log_dir = '/var/log/airtime/pypo'
+liquidsoap_log_dir = '/var/log/airtime/pypo-liquidsoap'
+# ------------------------ Liquidsoap Settings -------------------------
+ls_host = '127.0.0.1'
+ls_port = '1234'
+# -------------------------- Pypo Preferences --------------------------
+poll_interval = 3600
+push_interval = 1
+cue_style = 'pre'
+# ---------------------- Recorded Audio Settings -----------------------
+record_bitrate = 256
+record_samplerate = 44100
+record_channels = 2
+record_sample_size = 16
+record_file_type = 'ogg'
+base_recorded_files = '/var/tmp/airtime/show-recorder/'
+#
+# ----------------------------------------------------------------------
+
+
+# ----------------------------------------------------------------------
+# S O U N D C L O U D
+# ----------------------------------------------------------------------
+#
+# connection_retries: The number of times to retry the connection to
+# Soundcloud.
+# The default is 3.
+#
+# time_between_retries: The time between connection retries, in seconds.
+# The default is 60.
+#
+[soundcloud]
+connection_retries = 3
+time_between_retries = 60
+#
+# ----------------------------------------------------------------------
\ No newline at end of file
diff --git a/airtime_mvc/build/sql/defaultdata.sql b/airtime_mvc/build/sql/defaultdata.sql
index 438dfc979..49bf3ff29 100644
--- a/airtime_mvc/build/sql/defaultdata.sql
+++ b/airtime_mvc/build/sql/defaultdata.sql
@@ -1,5 +1,5 @@
-- Schema version
-INSERT INTO cc_pref("keystr", "valstr") VALUES('system_version', '2.5.9');
+INSERT INTO cc_pref("keystr", "valstr") VALUES('schema_version', '2.5.12');
INSERT INTO cc_subjs ("login", "type", "pass") VALUES ('admin', 'A', md5('admin'));
-- added in 2.3
diff --git a/airtime_mvc/library/php-amqplib/amqp.inc b/airtime_mvc/library/php-amqplib/amqp.inc
index 57c642abd..310502840 100644
--- a/airtime_mvc/library/php-amqplib/amqp.inc
+++ b/airtime_mvc/library/php-amqplib/amqp.inc
@@ -436,10 +436,13 @@ class AMQPConnection extends AbstractChannel
$len = strlen($data);
while(true)
{
- if(false === ($written = fwrite($this->sock, $data)))
+ $written = fwrite($this->sock, $data);
+
+ if($written == false || $written <= 0)
{
throw new Exception ("Error sending data");
}
+
$len = $len - $written;
if($len>0)
$data=substr($data,0-$len);
@@ -601,12 +604,17 @@ class AMQPConnection extends AbstractChannel
*/
public function close($reply_code=0, $reply_text="", $method_sig=array(0, 0))
{
- $args = new AMQPWriter();
- $args->write_short($reply_code);
- $args->write_shortstr($reply_text);
- $args->write_short($method_sig[0]); // class_id
- $args->write_short($method_sig[1]); // method_id
- $this->send_method_frame(array(10, 60), $args);
+ try {
+ $args = new AMQPWriter();
+ $args->write_short($reply_code);
+ $args->write_shortstr($reply_text);
+ $args->write_short($method_sig[0]); // class_id
+ $args->write_short($method_sig[1]); // method_id
+ $this->send_method_frame(array(10, 60), $args);
+ } catch(Exception $e) {
+ return;
+ }
+
return $this->wait(array(
"10,61", // Connection.close_ok
));
diff --git a/airtime_mvc/public/css/bootstrap-3.3.1.min.css b/airtime_mvc/public/css/bootstrap-3.3.1.min.css
new file mode 100644
index 000000000..b6fe4e0fb
--- /dev/null
+++ b/airtime_mvc/public/css/bootstrap-3.3.1.min.css
@@ -0,0 +1,5 @@
+/*!
+ * Bootstrap v3.3.1 (http://getbootstrap.com)
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ *//*! normalize.css v3.0.2 | MIT License | git.io/normalize */html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{margin:.67em 0;font-size:2em}mark{color:#000;background:#ff0}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{height:0;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{margin:0;font:inherit;color:inherit}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}input{line-height:normal}input[type=checkbox],input[type=radio]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{padding:.35em .625em .75em;margin:0 2px;border:1px solid silver}legend{padding:0;border:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-spacing:0;border-collapse:collapse}td,th{padding:0}/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */@media print{*,:before,:after{color:#000!important;text-shadow:none!important;background:transparent!important;-webkit-box-shadow:none!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="#"]:after,a[href^="javascript:"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100%!important}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}select{background:#fff!important}.navbar{display:none}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered th,.table-bordered td{border:1px solid #ddd!important}}@font-face{font-family:'Glyphicons Halflings';src:url(../fonts/glyphicons-halflings-regular.eot);src:url(../fonts/glyphicons-halflings-regular.eot?#iefix) format('embedded-opentype'),url(../fonts/glyphicons-halflings-regular.woff) format('woff'),url(../fonts/glyphicons-halflings-regular.ttf) format('truetype'),url(../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular) format('svg')}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';font-style:normal;font-weight:400;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.glyphicon-asterisk:before{content:"\2a"}.glyphicon-plus:before{content:"\2b"}.glyphicon-euro:before,.glyphicon-eur:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-lock:before{content:"\e033"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-bookmark:before{content:"\e044"}.glyphicon-print:before{content:"\e045"}.glyphicon-camera:before{content:"\e046"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-fire:before{content:"\e104"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-calendar:before{content:"\e109"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-bell:before{content:"\e123"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-wrench:before{content:"\e136"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-briefcase:before{content:"\e139"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-paperclip:before{content:"\e142"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-pushpin:before{content:"\e146"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse-down:before{content:"\e159"}.glyphicon-collapse-up:before{content:"\e160"}.glyphicon-log-in:before{content:"\e161"}.glyphicon-flash:before{content:"\e162"}.glyphicon-log-out:before{content:"\e163"}.glyphicon-new-window:before{content:"\e164"}.glyphicon-record:before{content:"\e165"}.glyphicon-save:before{content:"\e166"}.glyphicon-open:before{content:"\e167"}.glyphicon-saved:before{content:"\e168"}.glyphicon-import:before{content:"\e169"}.glyphicon-export:before{content:"\e170"}.glyphicon-send:before{content:"\e171"}.glyphicon-floppy-disk:before{content:"\e172"}.glyphicon-floppy-saved:before{content:"\e173"}.glyphicon-floppy-remove:before{content:"\e174"}.glyphicon-floppy-save:before{content:"\e175"}.glyphicon-floppy-open:before{content:"\e176"}.glyphicon-credit-card:before{content:"\e177"}.glyphicon-transfer:before{content:"\e178"}.glyphicon-cutlery:before{content:"\e179"}.glyphicon-header:before{content:"\e180"}.glyphicon-compressed:before{content:"\e181"}.glyphicon-earphone:before{content:"\e182"}.glyphicon-phone-alt:before{content:"\e183"}.glyphicon-tower:before{content:"\e184"}.glyphicon-stats:before{content:"\e185"}.glyphicon-sd-video:before{content:"\e186"}.glyphicon-hd-video:before{content:"\e187"}.glyphicon-subtitles:before{content:"\e188"}.glyphicon-sound-stereo:before{content:"\e189"}.glyphicon-sound-dolby:before{content:"\e190"}.glyphicon-sound-5-1:before{content:"\e191"}.glyphicon-sound-6-1:before{content:"\e192"}.glyphicon-sound-7-1:before{content:"\e193"}.glyphicon-copyright-mark:before{content:"\e194"}.glyphicon-registration-mark:before{content:"\e195"}.glyphicon-cloud-download:before{content:"\e197"}.glyphicon-cloud-upload:before{content:"\e198"}.glyphicon-tree-conifer:before{content:"\e199"}.glyphicon-tree-deciduous:before{content:"\e200"}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}:before,:after{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;color:#333;background-color:#fff}input,button,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#337ab7;text-decoration:none}a:hover,a:focus{color:#23527c;text-decoration:underline}a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.img-responsive,.thumbnail>img,.thumbnail a>img,.carousel-inner>.item>img,.carousel-inner>.item>a>img{display:block;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{display:inline-block;max-width:100%;height:auto;padding:4px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}h1,h2,h3,h4,h5,h6,.h1,.h2,.h3,.h4,.h5,.h6{font-family:inherit;font-weight:500;line-height:1.1;color:inherit}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small,.h1 small,.h2 small,.h3 small,.h4 small,.h5 small,.h6 small,h1 .small,h2 .small,h3 .small,h4 .small,h5 .small,h6 .small,.h1 .small,.h2 .small,.h3 .small,.h4 .small,.h5 .small,.h6 .small{font-weight:400;line-height:1;color:#777}h1,.h1,h2,.h2,h3,.h3{margin-top:20px;margin-bottom:10px}h1 small,.h1 small,h2 small,.h2 small,h3 small,.h3 small,h1 .small,.h1 .small,h2 .small,.h2 .small,h3 .small,.h3 .small{font-size:65%}h4,.h4,h5,.h5,h6,.h6{margin-top:10px;margin-bottom:10px}h4 small,.h4 small,h5 small,.h5 small,h6 small,.h6 small,h4 .small,.h4 .small,h5 .small,.h5 .small,h6 .small,.h6 .small{font-size:75%}h1,.h1{font-size:36px}h2,.h2{font-size:30px}h3,.h3{font-size:24px}h4,.h4{font-size:18px}h5,.h5{font-size:14px}h6,.h6{font-size:12px}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:300;line-height:1.4}@media (min-width:768px){.lead{font-size:21px}}small,.small{font-size:85%}mark,.mark{padding:.2em;background-color:#fcf8e3}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.text-justify{text-align:justify}.text-nowrap{white-space:nowrap}.text-lowercase{text-transform:lowercase}.text-uppercase{text-transform:uppercase}.text-capitalize{text-transform:capitalize}.text-muted{color:#777}.text-primary{color:#337ab7}a.text-primary:hover{color:#286090}.text-success{color:#3c763d}a.text-success:hover{color:#2b542c}.text-info{color:#31708f}a.text-info:hover{color:#245269}.text-warning{color:#8a6d3b}a.text-warning:hover{color:#66512c}.text-danger{color:#a94442}a.text-danger:hover{color:#843534}.bg-primary{color:#fff;background-color:#337ab7}a.bg-primary:hover{background-color:#286090}.bg-success{background-color:#dff0d8}a.bg-success:hover{background-color:#c1e2b3}.bg-info{background-color:#d9edf7}a.bg-info:hover{background-color:#afd9ee}.bg-warning{background-color:#fcf8e3}a.bg-warning:hover{background-color:#f7ecb5}.bg-danger{background-color:#f2dede}a.bg-danger:hover{background-color:#e4b9b9}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ul,ol{margin-top:0;margin-bottom:10px}ul ul,ol ul,ul ol,ol ol{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;margin-left:-5px;list-style:none}.list-inline>li{display:inline-block;padding-right:5px;padding-left:5px}dl{margin-top:0;margin-bottom:20px}dt,dd{line-height:1.42857143}dt{font-weight:700}dd{margin-left:0}@media (min-width:768px){.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}}abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #777}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;font-size:17.5px;border-left:5px solid #eee}blockquote p:last-child,blockquote ul:last-child,blockquote ol:last-child{margin-bottom:0}blockquote footer,blockquote small,blockquote .small{display:block;font-size:80%;line-height:1.42857143;color:#777}blockquote footer:before,blockquote small:before,blockquote .small:before{content:'\2014 \00A0'}.blockquote-reverse,blockquote.pull-right{padding-right:15px;padding-left:0;text-align:right;border-right:5px solid #eee;border-left:0}.blockquote-reverse footer:before,blockquote.pull-right footer:before,.blockquote-reverse small:before,blockquote.pull-right small:before,.blockquote-reverse .small:before,blockquote.pull-right .small:before{content:''}.blockquote-reverse footer:after,blockquote.pull-right footer:after,.blockquote-reverse small:after,blockquote.pull-right small:after,.blockquote-reverse .small:after,blockquote.pull-right .small:after{content:'\00A0 \2014'}address{margin-bottom:20px;font-style:normal;line-height:1.42857143}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;background-color:#f9f2f4;border-radius:4px}kbd{padding:2px 4px;font-size:90%;color:#fff;background-color:#333;border-radius:3px;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.25);box-shadow:inset 0 -1px 0 rgba(0,0,0,.25)}kbd kbd{padding:0;font-size:100%;font-weight:700;-webkit-box-shadow:none;box-shadow:none}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.42857143;color:#333;word-break:break-all;word-wrap:break-word;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.container-fluid{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.row{margin-right:-15px;margin-left:-15px}.col-xs-1,.col-sm-1,.col-md-1,.col-lg-1,.col-xs-2,.col-sm-2,.col-md-2,.col-lg-2,.col-xs-3,.col-sm-3,.col-md-3,.col-lg-3,.col-xs-4,.col-sm-4,.col-md-4,.col-lg-4,.col-xs-5,.col-sm-5,.col-md-5,.col-lg-5,.col-xs-6,.col-sm-6,.col-md-6,.col-lg-6,.col-xs-7,.col-sm-7,.col-md-7,.col-lg-7,.col-xs-8,.col-sm-8,.col-md-8,.col-lg-8,.col-xs-9,.col-sm-9,.col-md-9,.col-lg-9,.col-xs-10,.col-sm-10,.col-md-10,.col-lg-10,.col-xs-11,.col-sm-11,.col-md-11,.col-lg-11,.col-xs-12,.col-sm-12,.col-md-12,.col-lg-12{position:relative;min-height:1px;padding-right:15px;padding-left:15px}.col-xs-1,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9,.col-xs-10,.col-xs-11,.col-xs-12{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666667%}.col-xs-10{width:83.33333333%}.col-xs-9{width:75%}.col-xs-8{width:66.66666667%}.col-xs-7{width:58.33333333%}.col-xs-6{width:50%}.col-xs-5{width:41.66666667%}.col-xs-4{width:33.33333333%}.col-xs-3{width:25%}.col-xs-2{width:16.66666667%}.col-xs-1{width:8.33333333%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666667%}.col-xs-pull-10{right:83.33333333%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666667%}.col-xs-pull-7{right:58.33333333%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666667%}.col-xs-pull-4{right:33.33333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.66666667%}.col-xs-pull-1{right:8.33333333%}.col-xs-pull-0{right:auto}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666667%}.col-xs-push-10{left:83.33333333%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666667%}.col-xs-push-7{left:58.33333333%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666667%}.col-xs-push-4{left:33.33333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.66666667%}.col-xs-push-1{left:8.33333333%}.col-xs-push-0{left:auto}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666667%}.col-xs-offset-10{margin-left:83.33333333%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666667%}.col-xs-offset-7{margin-left:58.33333333%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666667%}.col-xs-offset-4{margin-left:33.33333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.66666667%}.col-xs-offset-1{margin-left:8.33333333%}.col-xs-offset-0{margin-left:0}@media (min-width:768px){.col-sm-1,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-10,.col-sm-11,.col-sm-12{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666667%}.col-sm-10{width:83.33333333%}.col-sm-9{width:75%}.col-sm-8{width:66.66666667%}.col-sm-7{width:58.33333333%}.col-sm-6{width:50%}.col-sm-5{width:41.66666667%}.col-sm-4{width:33.33333333%}.col-sm-3{width:25%}.col-sm-2{width:16.66666667%}.col-sm-1{width:8.33333333%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666667%}.col-sm-pull-10{right:83.33333333%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666667%}.col-sm-pull-7{right:58.33333333%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666667%}.col-sm-pull-4{right:33.33333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.66666667%}.col-sm-pull-1{right:8.33333333%}.col-sm-pull-0{right:auto}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666667%}.col-sm-push-10{left:83.33333333%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666667%}.col-sm-push-7{left:58.33333333%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666667%}.col-sm-push-4{left:33.33333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.66666667%}.col-sm-push-1{left:8.33333333%}.col-sm-push-0{left:auto}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666667%}.col-sm-offset-10{margin-left:83.33333333%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666667%}.col-sm-offset-7{margin-left:58.33333333%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666667%}.col-sm-offset-4{margin-left:33.33333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.66666667%}.col-sm-offset-1{margin-left:8.33333333%}.col-sm-offset-0{margin-left:0}}@media (min-width:992px){.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11,.col-md-12{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666667%}.col-md-10{width:83.33333333%}.col-md-9{width:75%}.col-md-8{width:66.66666667%}.col-md-7{width:58.33333333%}.col-md-6{width:50%}.col-md-5{width:41.66666667%}.col-md-4{width:33.33333333%}.col-md-3{width:25%}.col-md-2{width:16.66666667%}.col-md-1{width:8.33333333%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666667%}.col-md-pull-10{right:83.33333333%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666667%}.col-md-pull-7{right:58.33333333%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666667%}.col-md-pull-4{right:33.33333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.66666667%}.col-md-pull-1{right:8.33333333%}.col-md-pull-0{right:auto}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666667%}.col-md-push-10{left:83.33333333%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666667%}.col-md-push-7{left:58.33333333%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666667%}.col-md-push-4{left:33.33333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.66666667%}.col-md-push-1{left:8.33333333%}.col-md-push-0{left:auto}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666667%}.col-md-offset-10{margin-left:83.33333333%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666667%}.col-md-offset-7{margin-left:58.33333333%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666667%}.col-md-offset-4{margin-left:33.33333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.66666667%}.col-md-offset-1{margin-left:8.33333333%}.col-md-offset-0{margin-left:0}}@media (min-width:1200px){.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11,.col-lg-12{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666667%}.col-lg-10{width:83.33333333%}.col-lg-9{width:75%}.col-lg-8{width:66.66666667%}.col-lg-7{width:58.33333333%}.col-lg-6{width:50%}.col-lg-5{width:41.66666667%}.col-lg-4{width:33.33333333%}.col-lg-3{width:25%}.col-lg-2{width:16.66666667%}.col-lg-1{width:8.33333333%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666667%}.col-lg-pull-10{right:83.33333333%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666667%}.col-lg-pull-7{right:58.33333333%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666667%}.col-lg-pull-4{right:33.33333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.66666667%}.col-lg-pull-1{right:8.33333333%}.col-lg-pull-0{right:auto}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666667%}.col-lg-push-10{left:83.33333333%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666667%}.col-lg-push-7{left:58.33333333%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666667%}.col-lg-push-4{left:33.33333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.66666667%}.col-lg-push-1{left:8.33333333%}.col-lg-push-0{left:auto}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666667%}.col-lg-offset-10{margin-left:83.33333333%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666667%}.col-lg-offset-7{margin-left:58.33333333%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666667%}.col-lg-offset-4{margin-left:33.33333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.66666667%}.col-lg-offset-1{margin-left:8.33333333%}.col-lg-offset-0{margin-left:0}}table{background-color:transparent}caption{padding-top:8px;padding-bottom:8px;color:#777;text-align:left}th{text-align:left}.table{width:100%;max-width:100%;margin-bottom:20px}.table>thead>tr>th,.table>tbody>tr>th,.table>tfoot>tr>th,.table>thead>tr>td,.table>tbody>tr>td,.table>tfoot>tr>td{padding:8px;line-height:1.42857143;vertical-align:top;border-top:1px solid #ddd}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>th,.table>caption+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>td,.table>thead:first-child>tr:first-child>td{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>thead>tr>th,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>tbody>tr>td,.table-condensed>tfoot>tr>td{padding:5px}.table-bordered{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>tbody>tr>td,.table-bordered>tfoot>tr>td{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>thead>tr>td{border-bottom-width:2px}.table-striped>tbody>tr:nth-child(odd){background-color:#f9f9f9}.table-hover>tbody>tr:hover{background-color:#f5f5f5}table col[class*=col-]{position:static;display:table-column;float:none}table td[class*=col-],table th[class*=col-]{position:static;display:table-cell;float:none}.table>thead>tr>td.active,.table>tbody>tr>td.active,.table>tfoot>tr>td.active,.table>thead>tr>th.active,.table>tbody>tr>th.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>tbody>tr.active>td,.table>tfoot>tr.active>td,.table>thead>tr.active>th,.table>tbody>tr.active>th,.table>tfoot>tr.active>th{background-color:#f5f5f5}.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover,.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr:hover>.active,.table-hover>tbody>tr.active:hover>th{background-color:#e8e8e8}.table>thead>tr>td.success,.table>tbody>tr>td.success,.table>tfoot>tr>td.success,.table>thead>tr>th.success,.table>tbody>tr>th.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>tbody>tr.success>td,.table>tfoot>tr.success>td,.table>thead>tr.success>th,.table>tbody>tr.success>th,.table>tfoot>tr.success>th{background-color:#dff0d8}.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover,.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr:hover>.success,.table-hover>tbody>tr.success:hover>th{background-color:#d0e9c6}.table>thead>tr>td.info,.table>tbody>tr>td.info,.table>tfoot>tr>td.info,.table>thead>tr>th.info,.table>tbody>tr>th.info,.table>tfoot>tr>th.info,.table>thead>tr.info>td,.table>tbody>tr.info>td,.table>tfoot>tr.info>td,.table>thead>tr.info>th,.table>tbody>tr.info>th,.table>tfoot>tr.info>th{background-color:#d9edf7}.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover,.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr:hover>.info,.table-hover>tbody>tr.info:hover>th{background-color:#c4e3f3}.table>thead>tr>td.warning,.table>tbody>tr>td.warning,.table>tfoot>tr>td.warning,.table>thead>tr>th.warning,.table>tbody>tr>th.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>tbody>tr.warning>td,.table>tfoot>tr.warning>td,.table>thead>tr.warning>th,.table>tbody>tr.warning>th,.table>tfoot>tr.warning>th{background-color:#fcf8e3}.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover,.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr:hover>.warning,.table-hover>tbody>tr.warning:hover>th{background-color:#faf2cc}.table>thead>tr>td.danger,.table>tbody>tr>td.danger,.table>tfoot>tr>td.danger,.table>thead>tr>th.danger,.table>tbody>tr>th.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>tbody>tr.danger>td,.table>tfoot>tr.danger>td,.table>thead>tr.danger>th,.table>tbody>tr.danger>th,.table>tfoot>tr.danger>th{background-color:#f2dede}.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover,.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr:hover>.danger,.table-hover>tbody>tr.danger:hover>th{background-color:#ebcccc}.table-responsive{min-height:.01%;overflow-x:auto}@media screen and (max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-y:hidden;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #ddd}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>thead>tr>th,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tfoot>tr>td{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>thead>tr>th:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.table-responsive>.table-bordered>thead>tr>th:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>th,.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>td{border-bottom:0}}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:inherit;color:#333;border:0;border-bottom:1px solid #e5e5e5}label{display:inline-block;max-width:100%;margin-bottom:5px;font-weight:700}input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=radio],input[type=checkbox]{margin:4px 0 0;margin-top:1px \9;line-height:normal}input[type=file]{display:block}input[type=range]{display:block;width:100%}select[multiple],select[size]{height:auto}input[type=file]:focus,input[type=radio]:focus,input[type=checkbox]:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}output{display:block;padding-top:7px;font-size:14px;line-height:1.42857143;color:#555}.form-control{display:block;width:100%;height:34px;padding:6px 12px;font-size:14px;line-height:1.42857143;color:#555;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075);-webkit-transition:border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;-o-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)}.form-control::-moz-placeholder{color:#999;opacity:1}.form-control:-ms-input-placeholder{color:#999}.form-control::-webkit-input-placeholder{color:#999}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{cursor:not-allowed;background-color:#eee;opacity:1}textarea.form-control{height:auto}input[type=search]{-webkit-appearance:none}@media screen and (-webkit-min-device-pixel-ratio:0){input[type=date],input[type=time],input[type=datetime-local],input[type=month]{line-height:34px}input[type=date].input-sm,input[type=time].input-sm,input[type=datetime-local].input-sm,input[type=month].input-sm{line-height:30px}input[type=date].input-lg,input[type=time].input-lg,input[type=datetime-local].input-lg,input[type=month].input-lg{line-height:46px}}.form-group{margin-bottom:15px}.radio,.checkbox{position:relative;display:block;margin-top:10px;margin-bottom:10px}.radio label,.checkbox label{min-height:20px;padding-left:20px;margin-bottom:0;font-weight:400;cursor:pointer}.radio input[type=radio],.radio-inline input[type=radio],.checkbox input[type=checkbox],.checkbox-inline input[type=checkbox]{position:absolute;margin-top:4px \9;margin-left:-20px}.radio+.radio,.checkbox+.checkbox{margin-top:-5px}.radio-inline,.checkbox-inline{display:inline-block;padding-left:20px;margin-bottom:0;font-weight:400;vertical-align:middle;cursor:pointer}.radio-inline+.radio-inline,.checkbox-inline+.checkbox-inline{margin-top:0;margin-left:10px}input[type=radio][disabled],input[type=checkbox][disabled],input[type=radio].disabled,input[type=checkbox].disabled,fieldset[disabled] input[type=radio],fieldset[disabled] input[type=checkbox]{cursor:not-allowed}.radio-inline.disabled,.checkbox-inline.disabled,fieldset[disabled] .radio-inline,fieldset[disabled] .checkbox-inline{cursor:not-allowed}.radio.disabled label,.checkbox.disabled label,fieldset[disabled] .radio label,fieldset[disabled] .checkbox label{cursor:not-allowed}.form-control-static{padding-top:7px;padding-bottom:7px;margin-bottom:0}.form-control-static.input-lg,.form-control-static.input-sm{padding-right:0;padding-left:0}.input-sm,.form-group-sm .form-control{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-sm,select.form-group-sm .form-control{height:30px;line-height:30px}textarea.input-sm,textarea.form-group-sm .form-control,select[multiple].input-sm,select[multiple].form-group-sm .form-control{height:auto}.input-lg,.form-group-lg .form-control{height:46px;padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}select.input-lg,select.form-group-lg .form-control{height:46px;line-height:46px}textarea.input-lg,textarea.form-group-lg .form-control,select[multiple].input-lg,select[multiple].form-group-lg .form-control{height:auto}.has-feedback{position:relative}.has-feedback .form-control{padding-right:42.5px}.form-control-feedback{position:absolute;top:0;right:0;z-index:2;display:block;width:34px;height:34px;line-height:34px;text-align:center;pointer-events:none}.input-lg+.form-control-feedback{width:46px;height:46px;line-height:46px}.input-sm+.form-control-feedback{width:30px;height:30px;line-height:30px}.has-success .help-block,.has-success .control-label,.has-success .radio,.has-success .checkbox,.has-success .radio-inline,.has-success .checkbox-inline,.has-success.radio label,.has-success.checkbox label,.has-success.radio-inline label,.has-success.checkbox-inline label{color:#3c763d}.has-success .form-control{border-color:#3c763d;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-success .form-control:focus{border-color:#2b542c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168}.has-success .input-group-addon{color:#3c763d;background-color:#dff0d8;border-color:#3c763d}.has-success .form-control-feedback{color:#3c763d}.has-warning .help-block,.has-warning .control-label,.has-warning .radio,.has-warning .checkbox,.has-warning .radio-inline,.has-warning .checkbox-inline,.has-warning.radio label,.has-warning.checkbox label,.has-warning.radio-inline label,.has-warning.checkbox-inline label{color:#8a6d3b}.has-warning .form-control{border-color:#8a6d3b;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-warning .form-control:focus{border-color:#66512c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b}.has-warning .input-group-addon{color:#8a6d3b;background-color:#fcf8e3;border-color:#8a6d3b}.has-warning .form-control-feedback{color:#8a6d3b}.has-error .help-block,.has-error .control-label,.has-error .radio,.has-error .checkbox,.has-error .radio-inline,.has-error .checkbox-inline,.has-error.radio label,.has-error.checkbox label,.has-error.radio-inline label,.has-error.checkbox-inline label{color:#a94442}.has-error .form-control{border-color:#a94442;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-error .form-control:focus{border-color:#843534;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483}.has-error .input-group-addon{color:#a94442;background-color:#f2dede;border-color:#a94442}.has-error .form-control-feedback{color:#a94442}.has-feedback label~.form-control-feedback{top:25px}.has-feedback label.sr-only~.form-control-feedback{top:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373}@media (min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-static{display:inline-block}.form-inline .input-group{display:inline-table;vertical-align:middle}.form-inline .input-group .input-group-addon,.form-inline .input-group .input-group-btn,.form-inline .input-group .form-control{width:auto}.form-inline .input-group>.form-control{width:100%}.form-inline .control-label{margin-bottom:0;vertical-align:middle}.form-inline .radio,.form-inline .checkbox{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.form-inline .radio label,.form-inline .checkbox label{padding-left:0}.form-inline .radio input[type=radio],.form-inline .checkbox input[type=checkbox]{position:relative;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}}.form-horizontal .radio,.form-horizontal .checkbox,.form-horizontal .radio-inline,.form-horizontal .checkbox-inline{padding-top:7px;margin-top:0;margin-bottom:0}.form-horizontal .radio,.form-horizontal .checkbox{min-height:27px}.form-horizontal .form-group{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.form-horizontal .control-label{padding-top:7px;margin-bottom:0;text-align:right}}.form-horizontal .has-feedback .form-control-feedback{right:15px}@media (min-width:768px){.form-horizontal .form-group-lg .control-label{padding-top:14.3px}}@media (min-width:768px){.form-horizontal .form-group-sm .control-label{padding-top:6px}}.btn{display:inline-block;padding:6px 12px;margin-bottom:0;font-size:14px;font-weight:400;line-height:1.42857143;text-align:center;white-space:nowrap;vertical-align:middle;-ms-touch-action:manipulation;touch-action:manipulation;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-image:none;border:1px solid transparent;border-radius:4px}.btn:focus,.btn:active:focus,.btn.active:focus,.btn.focus,.btn:active.focus,.btn.active.focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn:hover,.btn:focus,.btn.focus{color:#333;text-decoration:none}.btn:active,.btn.active{background-image:none;outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{pointer-events:none;cursor:not-allowed;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none;opacity:.65}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default:hover,.btn-default:focus,.btn-default.focus,.btn-default:active,.btn-default.active,.open>.dropdown-toggle.btn-default{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default:active,.btn-default.active,.open>.dropdown-toggle.btn-default{background-image:none}.btn-default.disabled,.btn-default[disabled],fieldset[disabled] .btn-default,.btn-default.disabled:hover,.btn-default[disabled]:hover,fieldset[disabled] .btn-default:hover,.btn-default.disabled:focus,.btn-default[disabled]:focus,fieldset[disabled] .btn-default:focus,.btn-default.disabled.focus,.btn-default[disabled].focus,fieldset[disabled] .btn-default.focus,.btn-default.disabled:active,.btn-default[disabled]:active,fieldset[disabled] .btn-default:active,.btn-default.disabled.active,.btn-default[disabled].active,fieldset[disabled] .btn-default.active{background-color:#fff;border-color:#ccc}.btn-default .badge{color:#fff;background-color:#333}.btn-primary{color:#fff;background-color:#337ab7;border-color:#2e6da4}.btn-primary:hover,.btn-primary:focus,.btn-primary.focus,.btn-primary:active,.btn-primary.active,.open>.dropdown-toggle.btn-primary{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary:active,.btn-primary.active,.open>.dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled,.btn-primary[disabled],fieldset[disabled] .btn-primary,.btn-primary.disabled:hover,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary:hover,.btn-primary.disabled:focus,.btn-primary[disabled]:focus,fieldset[disabled] .btn-primary:focus,.btn-primary.disabled.focus,.btn-primary[disabled].focus,fieldset[disabled] .btn-primary.focus,.btn-primary.disabled:active,.btn-primary[disabled]:active,fieldset[disabled] .btn-primary:active,.btn-primary.disabled.active,.btn-primary[disabled].active,fieldset[disabled] .btn-primary.active{background-color:#337ab7;border-color:#2e6da4}.btn-primary .badge{color:#337ab7;background-color:#fff}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success:hover,.btn-success:focus,.btn-success.focus,.btn-success:active,.btn-success.active,.open>.dropdown-toggle.btn-success{color:#fff;background-color:#449d44;border-color:#398439}.btn-success:active,.btn-success.active,.open>.dropdown-toggle.btn-success{background-image:none}.btn-success.disabled,.btn-success[disabled],fieldset[disabled] .btn-success,.btn-success.disabled:hover,.btn-success[disabled]:hover,fieldset[disabled] .btn-success:hover,.btn-success.disabled:focus,.btn-success[disabled]:focus,fieldset[disabled] .btn-success:focus,.btn-success.disabled.focus,.btn-success[disabled].focus,fieldset[disabled] .btn-success.focus,.btn-success.disabled:active,.btn-success[disabled]:active,fieldset[disabled] .btn-success:active,.btn-success.disabled.active,.btn-success[disabled].active,fieldset[disabled] .btn-success.active{background-color:#5cb85c;border-color:#4cae4c}.btn-success .badge{color:#5cb85c;background-color:#fff}.btn-info{color:#fff;background-color:#5bc0de;border-color:#46b8da}.btn-info:hover,.btn-info:focus,.btn-info.focus,.btn-info:active,.btn-info.active,.open>.dropdown-toggle.btn-info{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info:active,.btn-info.active,.open>.dropdown-toggle.btn-info{background-image:none}.btn-info.disabled,.btn-info[disabled],fieldset[disabled] .btn-info,.btn-info.disabled:hover,.btn-info[disabled]:hover,fieldset[disabled] .btn-info:hover,.btn-info.disabled:focus,.btn-info[disabled]:focus,fieldset[disabled] .btn-info:focus,.btn-info.disabled.focus,.btn-info[disabled].focus,fieldset[disabled] .btn-info.focus,.btn-info.disabled:active,.btn-info[disabled]:active,fieldset[disabled] .btn-info:active,.btn-info.disabled.active,.btn-info[disabled].active,fieldset[disabled] .btn-info.active{background-color:#5bc0de;border-color:#46b8da}.btn-info .badge{color:#5bc0de;background-color:#fff}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236}.btn-warning:hover,.btn-warning:focus,.btn-warning.focus,.btn-warning:active,.btn-warning.active,.open>.dropdown-toggle.btn-warning{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning:active,.btn-warning.active,.open>.dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled,.btn-warning[disabled],fieldset[disabled] .btn-warning,.btn-warning.disabled:hover,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning:hover,.btn-warning.disabled:focus,.btn-warning[disabled]:focus,fieldset[disabled] .btn-warning:focus,.btn-warning.disabled.focus,.btn-warning[disabled].focus,fieldset[disabled] .btn-warning.focus,.btn-warning.disabled:active,.btn-warning[disabled]:active,fieldset[disabled] .btn-warning:active,.btn-warning.disabled.active,.btn-warning[disabled].active,fieldset[disabled] .btn-warning.active{background-color:#f0ad4e;border-color:#eea236}.btn-warning .badge{color:#f0ad4e;background-color:#fff}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a}.btn-danger:hover,.btn-danger:focus,.btn-danger.focus,.btn-danger:active,.btn-danger.active,.open>.dropdown-toggle.btn-danger{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger:active,.btn-danger.active,.open>.dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled,.btn-danger[disabled],fieldset[disabled] .btn-danger,.btn-danger.disabled:hover,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger:hover,.btn-danger.disabled:focus,.btn-danger[disabled]:focus,fieldset[disabled] .btn-danger:focus,.btn-danger.disabled.focus,.btn-danger[disabled].focus,fieldset[disabled] .btn-danger.focus,.btn-danger.disabled:active,.btn-danger[disabled]:active,fieldset[disabled] .btn-danger:active,.btn-danger.disabled.active,.btn-danger[disabled].active,fieldset[disabled] .btn-danger.active{background-color:#d9534f;border-color:#d43f3a}.btn-danger .badge{color:#d9534f;background-color:#fff}.btn-link{font-weight:400;color:#337ab7;border-radius:0}.btn-link,.btn-link:active,.btn-link.active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:hover,.btn-link:focus,.btn-link:active{border-color:transparent}.btn-link:hover,.btn-link:focus{color:#23527c;text-decoration:underline;background-color:transparent}.btn-link[disabled]:hover,fieldset[disabled] .btn-link:hover,.btn-link[disabled]:focus,fieldset[disabled] .btn-link:focus{color:#777;text-decoration:none}.btn-lg,.btn-group-lg>.btn{padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}.btn-sm,.btn-group-sm>.btn{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-xs,.btn-group-xs>.btn{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:5px}input[type=submit].btn-block,input[type=reset].btn-block,input[type=button].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none;visibility:hidden}.collapse.in{display:block;visibility:visible}tr.collapse.in{display:table-row}tbody.collapse.in{display:table-row-group}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition-timing-function:ease;-o-transition-timing-function:ease;transition-timing-function:ease;-webkit-transition-duration:.35s;-o-transition-duration:.35s;transition-duration:.35s;-webkit-transition-property:height,visibility;-o-transition-property:height,visibility;transition-property:height,visibility}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px solid;border-right:4px solid transparent;border-left:4px solid transparent}.dropdown{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;font-size:14px;text-align:left;list-style:none;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,.175);box-shadow:0 6px 12px rgba(0,0,0,.175)}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:400;line-height:1.42857143;color:#333;white-space:nowrap}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{color:#262626;text-decoration:none;background-color:#f5f5f5}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{color:#fff;text-decoration:none;background-color:#337ab7;outline:0}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{color:#777}.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{text-decoration:none;cursor:not-allowed;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-menu-right{right:0;left:auto}.dropdown-menu-left{right:auto;left:0}.dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.42857143;color:#777;white-space:nowrap}.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{content:"";border-top:0;border-bottom:4px solid}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px}@media (min-width:768px){.navbar-right .dropdown-menu{right:0;left:auto}.navbar-right .dropdown-menu-left{right:auto;left:0}}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group>.btn,.btn-group-vertical>.btn{position:relative;float:left}.btn-group>.btn:hover,.btn-group-vertical>.btn:hover,.btn-group>.btn:focus,.btn-group-vertical>.btn:focus,.btn-group>.btn:active,.btn-group-vertical>.btn:active,.btn-group>.btn.active,.btn-group-vertical>.btn.active{z-index:2}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{margin-left:-5px}.btn-toolbar .btn-group,.btn-toolbar .input-group{float:left}.btn-toolbar>.btn,.btn-toolbar>.btn-group,.btn-toolbar>.input-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child>.btn:last-child,.btn-group>.btn-group:first-child>.dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:last-child>.btn:first-child{border-top-left-radius:0;border-bottom-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{padding-right:8px;padding-left:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-right:12px;padding-left:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group,.btn-group-vertical>.btn-group>.btn{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-top-left-radius:0;border-top-right-radius:0;border-bottom-left-radius:4px}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-top-right-radius:0}.btn-group-justified{display:table;width:100%;table-layout:fixed;border-collapse:separate}.btn-group-justified>.btn,.btn-group-justified>.btn-group{display:table-cell;float:none;width:1%}.btn-group-justified>.btn-group .btn{width:100%}.btn-group-justified>.btn-group .dropdown-menu{left:auto}[data-toggle=buttons]>.btn input[type=radio],[data-toggle=buttons]>.btn-group>.btn input[type=radio],[data-toggle=buttons]>.btn input[type=checkbox],[data-toggle=buttons]>.btn-group>.btn input[type=checkbox]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group{position:relative;display:table;border-collapse:separate}.input-group[class*=col-]{float:none;padding-right:0;padding-left:0}.input-group .form-control{position:relative;z-index:2;float:left;width:100%;margin-bottom:0}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:46px;padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:46px;line-height:46px}textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn,select[multiple].input-group-lg>.form-control,select[multiple].input-group-lg>.input-group-addon,select[multiple].input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px}textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn,select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.input-group-addon,select[multiple].input-group-sm>.input-group-btn>.btn{height:auto}.input-group-addon,.input-group-btn,.input-group .form-control{display:table-cell}.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child),.input-group .form-control:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:6px 12px;font-size:14px;font-weight:400;line-height:1;color:#555;text-align:center;background-color:#eee;border:1px solid #ccc;border-radius:4px}.input-group-addon.input-sm{padding:5px 10px;font-size:12px;border-radius:3px}.input-group-addon.input-lg{padding:10px 16px;font-size:18px;border-radius:6px}.input-group-addon input[type=radio],.input-group-addon input[type=checkbox]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle),.input-group-btn:last-child>.btn-group:not(:last-child)>.btn{border-top-right-radius:0;border-bottom-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group>.btn,.input-group-btn:last-child>.dropdown-toggle,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:first-child>.btn-group:not(:first-child)>.btn{border-top-left-radius:0;border-bottom-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;font-size:0;white-space:nowrap}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-1px}.input-group-btn>.btn:hover,.input-group-btn>.btn:focus,.input-group-btn>.btn:active{z-index:2}.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group{margin-right:-1px}.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group{margin-left:-1px}.nav{padding-left:0;margin-bottom:0;list-style:none}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:hover,.nav>li>a:focus{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#777}.nav>li.disabled>a:hover,.nav>li.disabled>a:focus{color:#777;text-decoration:none;cursor:not-allowed;background-color:transparent}.nav .open>a,.nav .open>a:hover,.nav .open>a:focus{background-color:#eee;border-color:#337ab7}.nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.42857143;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:hover,.nav-tabs>li.active>a:focus{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0}}.nav-tabs.nav-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border:1px solid #ddd}@media (min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border-bottom-color:#fff}}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:4px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:hover,.nav-pills>li.active>a:focus{color:#fff;background-color:#337ab7}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border:1px solid #ddd}@media (min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border-bottom-color:#fff}}.tab-content>.tab-pane{display:none;visibility:hidden}.tab-content>.active{display:block;visibility:visible}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.navbar{position:relative;min-height:50px;margin-bottom:20px;border:1px solid transparent}@media (min-width:768px){.navbar{border-radius:4px}}@media (min-width:768px){.navbar-header{float:left}}.navbar-collapse{padding-right:15px;padding-left:15px;overflow-x:visible;-webkit-overflow-scrolling:touch;border-top:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1)}.navbar-collapse.in{overflow-y:auto}@media (min-width:768px){.navbar-collapse{width:auto;border-top:0;-webkit-box-shadow:none;box-shadow:none}.navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important;visibility:visible!important}.navbar-collapse.in{overflow-y:visible}.navbar-fixed-top .navbar-collapse,.navbar-static-top .navbar-collapse,.navbar-fixed-bottom .navbar-collapse{padding-right:0;padding-left:0}}.navbar-fixed-top .navbar-collapse,.navbar-fixed-bottom .navbar-collapse{max-height:340px}@media (max-device-width:480px) and (orientation:landscape){.navbar-fixed-top .navbar-collapse,.navbar-fixed-bottom .navbar-collapse{max-height:200px}}.container>.navbar-header,.container-fluid>.navbar-header,.container>.navbar-collapse,.container-fluid>.navbar-collapse{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.container>.navbar-header,.container-fluid>.navbar-header,.container>.navbar-collapse,.container-fluid>.navbar-collapse{margin-right:0;margin-left:0}}.navbar-static-top{z-index:1000;border-width:0 0 1px}@media (min-width:768px){.navbar-static-top{border-radius:0}}.navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030}@media (min-width:768px){.navbar-fixed-top,.navbar-fixed-bottom{border-radius:0}}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.navbar-brand{float:left;height:50px;padding:15px 15px;font-size:18px;line-height:20px}.navbar-brand:hover,.navbar-brand:focus{text-decoration:none}.navbar-brand>img{display:block}@media (min-width:768px){.navbar>.container .navbar-brand,.navbar>.container-fluid .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;padding:9px 10px;margin-top:8px;margin-right:15px;margin-bottom:8px;background-color:transparent;background-image:none;border:1px solid transparent;border-radius:4px}.navbar-toggle:focus{outline:0}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media (min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:7.5px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px}@media (max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;-webkit-box-shadow:none;box-shadow:none}.navbar-nav .open .dropdown-menu>li>a,.navbar-nav .open .dropdown-menu .dropdown-header{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:hover,.navbar-nav .open .dropdown-menu>li>a:focus{background-image:none}}@media (min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:15px;padding-bottom:15px}}.navbar-form{padding:10px 15px;margin-top:8px;margin-right:-15px;margin-bottom:8px;margin-left:-15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1)}@media (min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block;width:auto;vertical-align:middle}.navbar-form .form-control-static{display:inline-block}.navbar-form .input-group{display:inline-table;vertical-align:middle}.navbar-form .input-group .input-group-addon,.navbar-form .input-group .input-group-btn,.navbar-form .input-group .form-control{width:auto}.navbar-form .input-group>.form-control{width:100%}.navbar-form .control-label{margin-bottom:0;vertical-align:middle}.navbar-form .radio,.navbar-form .checkbox{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.navbar-form .radio label,.navbar-form .checkbox label{padding-left:0}.navbar-form .radio input[type=radio],.navbar-form .checkbox input[type=checkbox]{position:relative;margin-left:0}.navbar-form .has-feedback .form-control-feedback{top:0}}@media (max-width:767px){.navbar-form .form-group{margin-bottom:5px}.navbar-form .form-group:last-child{margin-bottom:0}}@media (min-width:768px){.navbar-form{width:auto;padding-top:0;padding-bottom:0;margin-right:0;margin-left:0;border:0;-webkit-box-shadow:none;box-shadow:none}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-left-radius:0;border-top-right-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{border-top-left-radius:4px;border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-btn{margin-top:8px;margin-bottom:8px}.navbar-btn.btn-sm{margin-top:10px;margin-bottom:10px}.navbar-btn.btn-xs{margin-top:14px;margin-bottom:14px}.navbar-text{margin-top:15px;margin-bottom:15px}@media (min-width:768px){.navbar-text{float:left;margin-right:15px;margin-left:15px}}@media (min-width:768px){.navbar-left{float:left!important}.navbar-right{float:right!important;margin-right:-15px}.navbar-right~.navbar-right{margin-right:0}}.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7}.navbar-default .navbar-brand{color:#777}.navbar-default .navbar-brand:hover,.navbar-default .navbar-brand:focus{color:#5e5e5e;background-color:transparent}.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav>li>a{color:#777}.navbar-default .navbar-nav>li>a:hover,.navbar-default .navbar-nav>li>a:focus{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:hover,.navbar-default .navbar-nav>.active>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:hover,.navbar-default .navbar-nav>.disabled>a:focus{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:hover,.navbar-default .navbar-toggle:focus{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#888}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e7e7e7}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:hover,.navbar-default .navbar-nav>.open>a:focus{color:#555;background-color:#e7e7e7}@media (max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#777}.navbar-default .navbar-link:hover{color:#333}.navbar-default .btn-link{color:#777}.navbar-default .btn-link:hover,.navbar-default .btn-link:focus{color:#333}.navbar-default .btn-link[disabled]:hover,fieldset[disabled] .navbar-default .btn-link:hover,.navbar-default .btn-link[disabled]:focus,fieldset[disabled] .navbar-default .btn-link:focus{color:#ccc}.navbar-inverse{background-color:#222;border-color:#080808}.navbar-inverse .navbar-brand{color:#9d9d9d}.navbar-inverse .navbar-brand:hover,.navbar-inverse .navbar-brand:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-text{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a:hover,.navbar-inverse .navbar-nav>li>a:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:hover,.navbar-inverse .navbar-nav>.active>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:hover,.navbar-inverse .navbar-nav>.disabled>a:focus{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:hover,.navbar-inverse .navbar-toggle:focus{background-color:#333}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#101010}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:hover,.navbar-inverse .navbar-nav>.open>a:focus{color:#fff;background-color:#080808}@media (max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu .divider{background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#444;background-color:transparent}}.navbar-inverse .navbar-link{color:#9d9d9d}.navbar-inverse .navbar-link:hover{color:#fff}.navbar-inverse .btn-link{color:#9d9d9d}.navbar-inverse .btn-link:hover,.navbar-inverse .btn-link:focus{color:#fff}.navbar-inverse .btn-link[disabled]:hover,fieldset[disabled] .navbar-inverse .btn-link:hover,.navbar-inverse .btn-link[disabled]:focus,fieldset[disabled] .navbar-inverse .btn-link:focus{color:#444}.breadcrumb{padding:8px 15px;margin-bottom:20px;list-style:none;background-color:#f5f5f5;border-radius:4px}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{padding:0 5px;color:#ccc;content:"/\00a0"}.breadcrumb>.active{color:#777}.pagination{display:inline-block;padding-left:0;margin:20px 0;border-radius:4px}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:6px 12px;margin-left:-1px;line-height:1.42857143;color:#337ab7;text-decoration:none;background-color:#fff;border:1px solid #ddd}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-top-left-radius:4px;border-bottom-left-radius:4px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-top-right-radius:4px;border-bottom-right-radius:4px}.pagination>li>a:hover,.pagination>li>span:hover,.pagination>li>a:focus,.pagination>li>span:focus{color:#23527c;background-color:#eee;border-color:#ddd}.pagination>.active>a,.pagination>.active>span,.pagination>.active>a:hover,.pagination>.active>span:hover,.pagination>.active>a:focus,.pagination>.active>span:focus{z-index:2;color:#fff;cursor:default;background-color:#337ab7;border-color:#337ab7}.pagination>.disabled>span,.pagination>.disabled>span:hover,.pagination>.disabled>span:focus,.pagination>.disabled>a,.pagination>.disabled>a:hover,.pagination>.disabled>a:focus{color:#777;cursor:not-allowed;background-color:#fff;border-color:#ddd}.pagination-lg>li>a,.pagination-lg>li>span{padding:10px 16px;font-size:18px}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-top-left-radius:6px;border-bottom-left-radius:6px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-top-right-radius:6px;border-bottom-right-radius:6px}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-top-left-radius:3px;border-bottom-left-radius:3px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-top-right-radius:3px;border-bottom-right-radius:3px}.pager{padding-left:0;margin:20px 0;text-align:center;list-style:none}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px}.pager li>a:hover,.pager li>a:focus{text-decoration:none;background-color:#eee}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>a:focus,.pager .disabled>span{color:#777;cursor:not-allowed;background-color:#fff}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}a.label:hover,a.label:focus{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.btn .label{position:relative;top:-1px}.label-default{background-color:#777}.label-default[href]:hover,.label-default[href]:focus{background-color:#5e5e5e}.label-primary{background-color:#337ab7}.label-primary[href]:hover,.label-primary[href]:focus{background-color:#286090}.label-success{background-color:#5cb85c}.label-success[href]:hover,.label-success[href]:focus{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:hover,.label-info[href]:focus{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:hover,.label-warning[href]:focus{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:hover,.label-danger[href]:focus{background-color:#c9302c}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;background-color:#777;border-radius:10px}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.btn-xs .badge{top:0;padding:1px 5px}a.badge:hover,a.badge:focus{color:#fff;text-decoration:none;cursor:pointer}.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#337ab7;background-color:#fff}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding:30px 15px;margin-bottom:30px;color:inherit;background-color:#eee}.jumbotron h1,.jumbotron .h1{color:inherit}.jumbotron p{margin-bottom:15px;font-size:21px;font-weight:200}.jumbotron>hr{border-top-color:#d5d5d5}.container .jumbotron,.container-fluid .jumbotron{border-radius:6px}.jumbotron .container{max-width:100%}@media screen and (min-width:768px){.jumbotron{padding:48px 0}.container .jumbotron,.container-fluid .jumbotron{padding-right:60px;padding-left:60px}.jumbotron h1,.jumbotron .h1{font-size:63px}}.thumbnail{display:block;padding:4px;margin-bottom:20px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:border .2s ease-in-out;-o-transition:border .2s ease-in-out;transition:border .2s ease-in-out}.thumbnail>img,.thumbnail a>img{margin-right:auto;margin-left:auto}a.thumbnail:hover,a.thumbnail:focus,a.thumbnail.active{border-color:#337ab7}.thumbnail .caption{padding:9px;color:#333}.alert{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:700}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable,.alert-dismissible{padding-right:35px}.alert-dismissable .close,.alert-dismissible .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#2b542c}.alert-info{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.alert-info hr{border-top-color:#a6e1ec}.alert-info .alert-link{color:#245269}.alert-warning{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.alert-warning hr{border-top-color:#f7e1b5}.alert-warning .alert-link{color:#66512c}.alert-danger{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.alert-danger hr{border-top-color:#e4b9c0}.alert-danger .alert-link{color:#843534}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1);box-shadow:inset 0 1px 2px rgba(0,0,0,.1)}.progress-bar{float:left;width:0;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#337ab7;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);-webkit-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress-striped .progress-bar,.progress-bar-striped{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);-webkit-background-size:40px 40px;background-size:40px 40px}.progress.active .progress-bar,.progress-bar.active{-webkit-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#5cb85c}.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-info{background-color:#5bc0de}.progress-striped .progress-bar-info{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-warning{background-color:#f0ad4e}.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-danger{background-color:#d9534f}.progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.media{margin-top:15px}.media:first-child{margin-top:0}.media-right,.media>.pull-right{padding-left:10px}.media-left,.media>.pull-left{padding-right:10px}.media-left,.media-right,.media-body{display:table-cell;vertical-align:top}.media-middle{vertical-align:middle}.media-bottom{vertical-align:bottom}.media-heading{margin-top:0;margin-bottom:5px}.media-list{padding-left:0;list-style:none}.list-group{padding-left:0;margin-bottom:20px}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-left-radius:4px;border-top-right-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}a.list-group-item{color:#555}a.list-group-item .list-group-item-heading{color:#333}a.list-group-item:hover,a.list-group-item:focus{color:#555;text-decoration:none;background-color:#f5f5f5}.list-group-item.disabled,.list-group-item.disabled:hover,.list-group-item.disabled:focus{color:#777;cursor:not-allowed;background-color:#eee}.list-group-item.disabled .list-group-item-heading,.list-group-item.disabled:hover .list-group-item-heading,.list-group-item.disabled:focus .list-group-item-heading{color:inherit}.list-group-item.disabled .list-group-item-text,.list-group-item.disabled:hover .list-group-item-text,.list-group-item.disabled:focus .list-group-item-text{color:#777}.list-group-item.active,.list-group-item.active:hover,.list-group-item.active:focus{z-index:2;color:#fff;background-color:#337ab7;border-color:#337ab7}.list-group-item.active .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading,.list-group-item.active .list-group-item-heading>small,.list-group-item.active:hover .list-group-item-heading>small,.list-group-item.active:focus .list-group-item-heading>small,.list-group-item.active .list-group-item-heading>.small,.list-group-item.active:hover .list-group-item-heading>.small,.list-group-item.active:focus .list-group-item-heading>.small{color:inherit}.list-group-item.active .list-group-item-text,.list-group-item.active:hover .list-group-item-text,.list-group-item.active:focus .list-group-item-text{color:#c7ddef}.list-group-item-success{color:#3c763d;background-color:#dff0d8}a.list-group-item-success{color:#3c763d}a.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:hover,a.list-group-item-success:focus{color:#3c763d;background-color:#d0e9c6}a.list-group-item-success.active,a.list-group-item-success.active:hover,a.list-group-item-success.active:focus{color:#fff;background-color:#3c763d;border-color:#3c763d}.list-group-item-info{color:#31708f;background-color:#d9edf7}a.list-group-item-info{color:#31708f}a.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:hover,a.list-group-item-info:focus{color:#31708f;background-color:#c4e3f3}a.list-group-item-info.active,a.list-group-item-info.active:hover,a.list-group-item-info.active:focus{color:#fff;background-color:#31708f;border-color:#31708f}.list-group-item-warning{color:#8a6d3b;background-color:#fcf8e3}a.list-group-item-warning{color:#8a6d3b}a.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:hover,a.list-group-item-warning:focus{color:#8a6d3b;background-color:#faf2cc}a.list-group-item-warning.active,a.list-group-item-warning.active:hover,a.list-group-item-warning.active:focus{color:#fff;background-color:#8a6d3b;border-color:#8a6d3b}.list-group-item-danger{color:#a94442;background-color:#f2dede}a.list-group-item-danger{color:#a94442}a.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:hover,a.list-group-item-danger:focus{color:#a94442;background-color:#ebcccc}a.list-group-item-danger.active,a.list-group-item-danger.active:hover,a.list-group-item-danger.active:focus{color:#fff;background-color:#a94442;border-color:#a94442}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.05);box-shadow:0 1px 1px rgba(0,0,0,.05)}.panel-body{padding:15px}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-left-radius:3px;border-top-right-radius:3px}.panel-heading>.dropdown .dropdown-toggle{color:inherit}.panel-title{margin-top:0;margin-bottom:0;font-size:16px;color:inherit}.panel-title>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.list-group,.panel>.panel-collapse>.list-group{margin-bottom:0}.panel>.list-group .list-group-item,.panel>.panel-collapse>.list-group .list-group-item{border-width:1px 0;border-radius:0}.panel>.list-group:first-child .list-group-item:first-child,.panel>.panel-collapse>.list-group:first-child .list-group-item:first-child{border-top:0;border-top-left-radius:3px;border-top-right-radius:3px}.panel>.list-group:last-child .list-group-item:last-child,.panel>.panel-collapse>.list-group:last-child .list-group-item:last-child{border-bottom:0;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.list-group+.panel-footer{border-top-width:0}.panel>.table,.panel>.table-responsive>.table,.panel>.panel-collapse>.table{margin-bottom:0}.panel>.table caption,.panel>.table-responsive>.table caption,.panel>.panel-collapse>.table caption{padding-right:15px;padding-left:15px}.panel>.table:first-child,.panel>.table-responsive:first-child>.table:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table:first-child>thead:first-child>tr:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:first-child{border-top-left-radius:3px}.panel>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:last-child{border-top-right-radius:3px}.panel>.table:last-child,.panel>.table-responsive:last-child>.table:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table:last-child>tbody:last-child>tr:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:first-child{border-bottom-left-radius:3px}.panel>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:last-child{border-bottom-right-radius:3px}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive,.panel>.table+.panel-body,.panel>.table-responsive+.panel-body{border-top:1px solid #ddd}.panel>.table>tbody:first-child>tr:first-child th,.panel>.table>tbody:first-child>tr:first-child td{border-top:0}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.panel>.table-bordered>thead>tr:first-child>td,.panel>.table-responsive>.table-bordered>thead>tr:first-child>td,.panel>.table-bordered>tbody>tr:first-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>td,.panel>.table-bordered>thead>tr:first-child>th,.panel>.table-responsive>.table-bordered>thead>tr:first-child>th,.panel>.table-bordered>tbody>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>th{border-bottom:0}.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}.panel>.table-responsive{margin-bottom:0;border:0}.panel-group{margin-bottom:20px}.panel-group .panel{margin-bottom:0;border-radius:4px}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse>.panel-body,.panel-group .panel-heading+.panel-collapse>.list-group{border-top:1px solid #ddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.panel-default{border-color:#ddd}.panel-default>.panel-heading{color:#333;background-color:#f5f5f5;border-color:#ddd}.panel-default>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ddd}.panel-default>.panel-heading .badge{color:#f5f5f5;background-color:#333}.panel-default>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ddd}.panel-primary{border-color:#337ab7}.panel-primary>.panel-heading{color:#fff;background-color:#337ab7;border-color:#337ab7}.panel-primary>.panel-heading+.panel-collapse>.panel-body{border-top-color:#337ab7}.panel-primary>.panel-heading .badge{color:#337ab7;background-color:#fff}.panel-primary>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#337ab7}.panel-success{border-color:#d6e9c6}.panel-success>.panel-heading{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.panel-success>.panel-heading+.panel-collapse>.panel-body{border-top-color:#d6e9c6}.panel-success>.panel-heading .badge{color:#dff0d8;background-color:#3c763d}.panel-success>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#d6e9c6}.panel-info{border-color:#bce8f1}.panel-info>.panel-heading{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.panel-info>.panel-heading+.panel-collapse>.panel-body{border-top-color:#bce8f1}.panel-info>.panel-heading .badge{color:#d9edf7;background-color:#31708f}.panel-info>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#bce8f1}.panel-warning{border-color:#faebcc}.panel-warning>.panel-heading{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.panel-warning>.panel-heading+.panel-collapse>.panel-body{border-top-color:#faebcc}.panel-warning>.panel-heading .badge{color:#fcf8e3;background-color:#8a6d3b}.panel-warning>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#faebcc}.panel-danger{border-color:#ebccd1}.panel-danger>.panel-heading{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.panel-danger>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ebccd1}.panel-danger>.panel-heading .badge{color:#f2dede;background-color:#a94442}.panel-danger>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ebccd1}.embed-responsive{position:relative;display:block;height:0;padding:0;overflow:hidden}.embed-responsive .embed-responsive-item,.embed-responsive iframe,.embed-responsive embed,.embed-responsive object,.embed-responsive video{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0}.embed-responsive.embed-responsive-16by9{padding-bottom:56.25%}.embed-responsive.embed-responsive-4by3{padding-bottom:75%}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.05);box-shadow:inset 0 1px 1px rgba(0,0,0,.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{float:right;font-size:21px;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;filter:alpha(opacity=20);opacity:.2}.close:hover,.close:focus{color:#000;text-decoration:none;cursor:pointer;filter:alpha(opacity=50);opacity:.5}button.close{-webkit-appearance:none;padding:0;cursor:pointer;background:0 0;border:0}.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;display:none;overflow:hidden;-webkit-overflow-scrolling:touch;outline:0}.modal.fade .modal-dialog{-webkit-transition:-webkit-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out;-webkit-transform:translate(0,-25%);-ms-transform:translate(0,-25%);-o-transform:translate(0,-25%);transform:translate(0,-25%)}.modal.in .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);-o-transform:translate(0,0);transform:translate(0,0)}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #999;border:1px solid rgba(0,0,0,.2);border-radius:6px;outline:0;-webkit-box-shadow:0 3px 9px rgba(0,0,0,.5);box-shadow:0 3px 9px rgba(0,0,0,.5)}.modal-backdrop{position:absolute;top:0;right:0;left:0;background-color:#000}.modal-backdrop.fade{filter:alpha(opacity=0);opacity:0}.modal-backdrop.in{filter:alpha(opacity=50);opacity:.5}.modal-header{min-height:16.43px;padding:15px;border-bottom:1px solid #e5e5e5}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.42857143}.modal-body{position:relative;padding:15px}.modal-footer{padding:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,.5);box-shadow:0 5px 15px rgba(0,0,0,.5)}.modal-sm{width:300px}}@media (min-width:992px){.modal-lg{width:900px}}.tooltip{position:absolute;z-index:1070;display:block;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:12px;font-weight:400;line-height:1.4;visibility:visible;filter:alpha(opacity=0);opacity:0}.tooltip.in{filter:alpha(opacity=90);opacity:.9}.tooltip.top{padding:5px 0;margin-top:-3px}.tooltip.right{padding:0 5px;margin-left:3px}.tooltip.bottom{padding:5px 0;margin-top:3px}.tooltip.left{padding:0 5px;margin-left:-3px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;text-decoration:none;background-color:#000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-left .tooltip-arrow{right:5px;bottom:0;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-right .tooltip-arrow{bottom:0;left:5px;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-left .tooltip-arrow{top:0;right:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-right .tooltip-arrow{top:0;left:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.popover{position:absolute;top:0;left:0;z-index:1060;display:none;max-width:276px;padding:1px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;font-weight:400;line-height:1.42857143;text-align:left;white-space:normal;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2)}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover>.arrow,.popover>.arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover>.arrow{border-width:11px}.popover>.arrow:after{content:"";border-width:10px}.popover.top>.arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,.25);border-bottom-width:0}.popover.top>.arrow:after{bottom:1px;margin-left:-10px;content:" ";border-top-color:#fff;border-bottom-width:0}.popover.right>.arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,.25);border-left-width:0}.popover.right>.arrow:after{bottom:-10px;left:1px;content:" ";border-right-color:#fff;border-left-width:0}.popover.bottom>.arrow{top:-11px;left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,.25)}.popover.bottom>.arrow:after{top:1px;margin-left:-10px;content:" ";border-top-width:0;border-bottom-color:#fff}.popover.left>.arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:rgba(0,0,0,.25)}.popover.left>.arrow:after{right:1px;bottom:-10px;content:" ";border-right-width:0;border-left-color:#fff}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>img,.carousel-inner>.item>a>img{line-height:1}@media all and (transform-3d),(-webkit-transform-3d){.carousel-inner>.item{-webkit-transition:-webkit-transform .6s ease-in-out;-o-transition:-o-transform .6s ease-in-out;transition:transform .6s ease-in-out;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-perspective:1000;perspective:1000}.carousel-inner>.item.next,.carousel-inner>.item.active.right{left:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}.carousel-inner>.item.prev,.carousel-inner>.item.active.left{left:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}.carousel-inner>.item.next.left,.carousel-inner>.item.prev.right,.carousel-inner>.item.active{left:0;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;bottom:0;left:0;width:15%;font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6);filter:alpha(opacity=50);opacity:.5}.carousel-control.left{background-image:-webkit-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.5)),to(rgba(0,0,0,.0001)));background-image:linear-gradient(to right,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);background-repeat:repeat-x}.carousel-control.right{right:0;left:auto;background-image:-webkit-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.0001)),to(rgba(0,0,0,.5)));background-image:linear-gradient(to right,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);background-repeat:repeat-x}.carousel-control:hover,.carousel-control:focus{color:#fff;text-decoration:none;filter:alpha(opacity=90);outline:0;opacity:.9}.carousel-control .icon-prev,.carousel-control .icon-next,.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right{position:absolute;top:50%;z-index:5;display:inline-block}.carousel-control .icon-prev,.carousel-control .glyphicon-chevron-left{left:50%;margin-left:-10px}.carousel-control .icon-next,.carousel-control .glyphicon-chevron-right{right:50%;margin-right:-10px}.carousel-control .icon-prev,.carousel-control .icon-next{width:20px;height:20px;margin-top:-10px;font-family:serif}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;padding-left:0;margin-left:-30%;text-align:center;list-style:none}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;cursor:pointer;background-color:#000 \9;background-color:rgba(0,0,0,0);border:1px solid #fff;border-radius:10px}.carousel-indicators .active{width:12px;height:12px;margin:0;background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-prev,.carousel-control .icon-next{width:30px;height:30px;margin-top:-15px;font-size:30px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{margin-left:-15px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{margin-right:-15px}.carousel-caption{right:20%;left:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.clearfix:before,.clearfix:after,.dl-horizontal dd:before,.dl-horizontal dd:after,.container:before,.container:after,.container-fluid:before,.container-fluid:after,.row:before,.row:after,.form-horizontal .form-group:before,.form-horizontal .form-group:after,.btn-toolbar:before,.btn-toolbar:after,.btn-group-vertical>.btn-group:before,.btn-group-vertical>.btn-group:after,.nav:before,.nav:after,.navbar:before,.navbar:after,.navbar-header:before,.navbar-header:after,.navbar-collapse:before,.navbar-collapse:after,.pager:before,.pager:after,.panel-body:before,.panel-body:after,.modal-footer:before,.modal-footer:after{display:table;content:" "}.clearfix:after,.dl-horizontal dd:after,.container:after,.container-fluid:after,.row:after,.form-horizontal .form-group:after,.btn-toolbar:after,.btn-group-vertical>.btn-group:after,.nav:after,.navbar:after,.navbar-header:after,.navbar-collapse:after,.pager:after,.panel-body:after,.modal-footer:after{clear:both}.center-block{display:block;margin-right:auto;margin-left:auto}.pull-right{float:right!important}.pull-left{float:left!important}.hide{display:none!important}.show{display:block!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none!important;visibility:hidden!important}.affix{position:fixed}@-ms-viewport{width:device-width}.visible-xs,.visible-sm,.visible-md,.visible-lg{display:none!important}.visible-xs-block,.visible-xs-inline,.visible-xs-inline-block,.visible-sm-block,.visible-sm-inline,.visible-sm-inline-block,.visible-md-block,.visible-md-inline,.visible-md-inline-block,.visible-lg-block,.visible-lg-inline,.visible-lg-inline-block{display:none!important}@media (max-width:767px){.visible-xs{display:block!important}table.visible-xs{display:table}tr.visible-xs{display:table-row!important}th.visible-xs,td.visible-xs{display:table-cell!important}}@media (max-width:767px){.visible-xs-block{display:block!important}}@media (max-width:767px){.visible-xs-inline{display:inline!important}}@media (max-width:767px){.visible-xs-inline-block{display:inline-block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm{display:block!important}table.visible-sm{display:table}tr.visible-sm{display:table-row!important}th.visible-sm,td.visible-sm{display:table-cell!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-block{display:block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline{display:inline!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline-block{display:inline-block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md{display:block!important}table.visible-md{display:table}tr.visible-md{display:table-row!important}th.visible-md,td.visible-md{display:table-cell!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-block{display:block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline{display:inline!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline-block{display:inline-block!important}}@media (min-width:1200px){.visible-lg{display:block!important}table.visible-lg{display:table}tr.visible-lg{display:table-row!important}th.visible-lg,td.visible-lg{display:table-cell!important}}@media (min-width:1200px){.visible-lg-block{display:block!important}}@media (min-width:1200px){.visible-lg-inline{display:inline!important}}@media (min-width:1200px){.visible-lg-inline-block{display:inline-block!important}}@media (max-width:767px){.hidden-xs{display:none!important}}@media (min-width:768px) and (max-width:991px){.hidden-sm{display:none!important}}@media (min-width:992px) and (max-width:1199px){.hidden-md{display:none!important}}@media (min-width:1200px){.hidden-lg{display:none!important}}.visible-print{display:none!important}@media print{.visible-print{display:block!important}table.visible-print{display:table}tr.visible-print{display:table-row!important}th.visible-print,td.visible-print{display:table-cell!important}}.visible-print-block{display:none!important}@media print{.visible-print-block{display:block!important}}.visible-print-inline{display:none!important}@media print{.visible-print-inline{display:inline!important}}.visible-print-inline-block{display:none!important}@media print{.visible-print-inline-block{display:inline-block!important}}@media print{.hidden-print{display:none!important}}
\ No newline at end of file
diff --git a/airtime_mvc/public/css/setup/config-check.css b/airtime_mvc/public/css/setup/config-check.css
new file mode 100644
index 000000000..e63823c88
--- /dev/null
+++ b/airtime_mvc/public/css/setup/config-check.css
@@ -0,0 +1,39 @@
+.logo {
+ margin-bottom: .5em;
+}
+
+.table {
+ padding: 5px;
+ margin: 1em 0 0 0;
+}
+
+.checklist {
+ min-height: 200px;
+}
+
+.caption {
+ padding-left: .5em;
+}
+
+.component {
+ font-weight: bold;
+ width: 20%;
+}
+
+.error {
+ color: red;
+}
+
+.description {
+ width: 300px;
+}
+
+.check {
+ background: #dff0d8 url("../images/accept.png") no-repeat center;
+}
+
+.footer {
+ margin: inherit;
+ width: inherit;
+ bottom: 0;
+}
\ No newline at end of file
diff --git a/airtime_mvc/public/css/setup/setup-config.css b/airtime_mvc/public/css/setup/setup-config.css
new file mode 100644
index 000000000..62edb2d54
--- /dev/null
+++ b/airtime_mvc/public/css/setup/setup-config.css
@@ -0,0 +1,252 @@
+html {
+ background: -webkit-linear-gradient(#444, black); /* For Safari 5.1 to 6.0 */
+ background: -o-linear-gradient(#444, black); /* For Opera 11.1 to 12.0 */
+ background: -moz-linear-gradient(#444, black); /* For Firefox 3.6 to 15 */
+ background: linear-gradient(#444, black); /* Standard syntax */
+}
+
+body {
+ background: rgba(0,0,0,0); /* Make the bg transparent */
+ color: white;
+ min-width: 400px;
+ width: 30%;
+ height: 100%;
+ text-align: center;
+ margin: auto;
+}
+
+p, h1, h2, h3, h4, h5, h6 {
+ text-shadow: 0px 1px 1px #000;
+}
+
+code {
+ text-shadow: none;
+}
+
+.header {
+ padding-top: 1em;
+ height: 10%;
+ min-height: 75px;
+ text-align: center;
+}
+
+.header strong {
+ float: right;
+}
+
+.logo {
+ margin: auto;
+}
+
+.logo strong {
+ padding-left: .5em;
+ float: left;
+}
+
+#airtimeLogo {
+ float: left;
+ padding-top: 0.6em;
+}
+
+.btn-primary {
+ text-shadow: 0px 1px 1px #000000;
+ background-color: #ff5d1a;
+ border-color: #8d3715;
+}
+
+.btn-primary:focus, .btn-primary:active, .form-control:focus
+{
+ border-color: #ff5d1a;
+ outline: 0;
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(255, 93, 26, 0.6);
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(255, 93, 26, 0.6);
+}
+
+.btn-primary:hover, .btn-primary:focus, .btn-primary.focus, .btn-primary:active, .btn-primary.active, .open>.dropdown-toggle.btn-primary,
+.btn-primary.disabled, .btn-primary[disabled], fieldset[disabled] .btn-primary, .btn-primary.disabled:hover, .btn-primary[disabled]:hover,
+fieldset[disabled] .btn-primary:hover, .btn-primary.disabled:focus, .btn-primary[disabled]:focus, fieldset[disabled] .btn-primary:focus,
+.btn-primary.disabled.focus, .btn-primary[disabled].focus, fieldset[disabled] .btn-primary.focus, .btn-primary.disabled:active,
+.btn-primary[disabled]:active, fieldset[disabled] .btn-primary:active, .btn-primary.disabled.active, .btn-primary[disabled].active,
+fieldset[disabled] .btn-primary.active
+{
+ background-color: #dc5118;
+ border-color: #632910;
+}
+
+/* ############################################################################
+ *
+ * Form Styles
+ *
+ * ############################################################################ */
+
+form {
+ margin: auto;
+ top: 0;
+ width: 99%;
+ position: absolute;
+ float: right;
+
+}
+
+form p {
+ text-align: left;
+ margin-bottom: 1em;
+}
+
+form .form-group {
+ text-align: left;
+}
+
+.viewport {
+ position: absolute;
+ width: 30%;
+ min-width: 400px;
+ height: 89%; /* Keep 1% off of 100 to avoid overflow */
+ overflow-x: hidden;
+ overflow-y: auto;
+}
+
+.form-wrapper {
+ overflow: auto;
+}
+
+.form-title {
+ margin: 1em 0;
+}
+
+.form-slider {
+ position: absolute;
+ width: 100%;
+ height: 100%;
+}
+
+.form-control-feedback {
+ display: none;
+}
+
+/* ############################################################################
+ *
+ * Form Help Box Styles
+ *
+ * ############################################################################ */
+
+.help-block.help-message {
+ font-weight:bold;
+ margin-bottom: 15px;
+}
+
+.has-error, .has-error .control-label,
+.has-error .form-control-feedback,
+.has-error .form-control {
+ color: red;
+}
+
+.has-success {
+ color: lawngreen;
+}
+
+/* ############################################################################
+ *
+ * Overlay Styles
+ *
+ * ############################################################################ */
+
+#overlay {
+ display: none;
+ opacity: 0.6;
+ position: absolute;
+ top: 0;
+ left: 0;
+ background-color: #000;
+ width: 100%;
+ height: 100%;
+ z-index: 5000;
+}
+
+#loadingImage {
+ display: none;
+ position: absolute;
+ top: 40%;
+ left: 49%; /* Shave 1% to account for half image width */
+ z-index: 5001;
+}
+
+/* ############################################################################
+ *
+ * Button Styles
+ *
+ * ############################################################################ */
+
+.btn-primary {
+ font-weight: bold;
+}
+
+.btn-disabled {
+ disabled: disabled;
+ visibility: hidden;
+ display: block;
+}
+
+.btn-next {
+ float: right;
+ width: 49%;
+}
+
+.btn-skip {
+ margin-top: .5em;
+ width: 100%;
+}
+
+.btn-back {
+ float: left;
+ width: 49%;
+}
+
+.caret.caret-up {
+ border-top-width: 0;
+ border-bottom: 4px solid #fff;
+}
+
+/* ############################################################################
+ *
+ * RabbitMQ Settings Form Styles
+ *
+ * ############################################################################ */
+
+#rmqSettingsForm {
+ left: 100%;
+}
+
+#rmqFormBody {
+ display: none;
+}
+
+/* ############################################################################
+ *
+ * General Settings Form Styles
+ *
+ * ############################################################################ */
+
+#generalSettingsForm {
+ left: 200%;
+}
+
+/* ############################################################################
+ *
+ * Media Settings Form Styles
+ *
+ * ############################################################################ */
+
+#mediaSettingsForm {
+ left: 300%;
+}
+
+/* ############################################################################
+ *
+ * Finish Settings Form Styles
+ *
+ * ############################################################################ */
+
+#finishSettingsForm {
+ left: 400%;
+}
\ No newline at end of file
diff --git a/airtime_mvc/public/fonts/glyphicons-halflings-regular.eot b/airtime_mvc/public/fonts/glyphicons-halflings-regular.eot
new file mode 100644
index 000000000..4a4ca865d
Binary files /dev/null and b/airtime_mvc/public/fonts/glyphicons-halflings-regular.eot differ
diff --git a/airtime_mvc/public/fonts/glyphicons-halflings-regular.svg b/airtime_mvc/public/fonts/glyphicons-halflings-regular.svg
new file mode 100644
index 000000000..25691af8f
--- /dev/null
+++ b/airtime_mvc/public/fonts/glyphicons-halflings-regular.svg
@@ -0,0 +1,229 @@
+
+
+
\ No newline at end of file
diff --git a/airtime_mvc/public/fonts/glyphicons-halflings-regular.ttf b/airtime_mvc/public/fonts/glyphicons-halflings-regular.ttf
new file mode 100644
index 000000000..67fa00bf8
Binary files /dev/null and b/airtime_mvc/public/fonts/glyphicons-halflings-regular.ttf differ
diff --git a/airtime_mvc/public/fonts/glyphicons-halflings-regular.woff b/airtime_mvc/public/fonts/glyphicons-halflings-regular.woff
new file mode 100644
index 000000000..8c54182aa
Binary files /dev/null and b/airtime_mvc/public/fonts/glyphicons-halflings-regular.woff differ
diff --git a/airtime_mvc/public/index.php b/airtime_mvc/public/index.php
index 67c659008..02fc19e65 100644
--- a/airtime_mvc/public/index.php
+++ b/airtime_mvc/public/index.php
@@ -1,117 +1,65 @@
bootstrap()->run();
- }
-} catch (Exception $e) {
-
- if ($e->getCode() == 401)
- {
- header($_SERVER['SERVER_PROTOCOL'] . ' 401 Unauthorized', true, 401);
- return;
- }
-
- header($_SERVER['SERVER_PROTOCOL'] . ' 500 Internal Server Error', true, 500);
- Logging::error($e->getMessage());
-
- if (VERBOSE_STACK_TRACE) {
- echo $e->getMessage() . ' ';
- echo "
";
- echo $e->getTraceAsString();
- echo "
";
- Logging::error($e->getTraceAsString());
- } else {
- Logging::error($e->getTrace());
- }
- throw $e;
+// This allows us to pass ?config as a parameter to any page
+// and get to the config checklist.
+if (array_key_exists('config', $_GET)) {
+ showConfigCheckPage();
+}
+
+// If a configuration file exists, forward to our boot script
+if (file_exists(AIRTIME_CONFIG_STOR . AIRTIME_CONFIG)) {
+ require_once(APPLICATION_PATH . 'airtime-boot.php');
+}
+// Otherwise, we'll need to run our configuration setup
+else {
+ $airtimeSetup = true;
+ require_once(SETUP_PATH . 'setup-config.php');
}
diff --git a/airtime_mvc/public/js/setup/setup-config.js b/airtime_mvc/public/js/setup/setup-config.js
new file mode 100644
index 000000000..f5926c844
--- /dev/null
+++ b/airtime_mvc/public/js/setup/setup-config.js
@@ -0,0 +1,151 @@
+/**
+ * Do some cleanup when we get a success response from a POST request
+ * during setup
+ * @param data the POST request return data
+ * @param e the jquery event
+ */
+function cleanupStep(data, e) {
+ showFeedback(data);
+ // If there are no errors, we can continue with
+ // the installation process
+ if (data.errors.length == 0) {
+ // Call nextSlide from the submit button's context
+ nextSlide.call($(e.target));
+ }
+ removeOverlay();
+}
+
+/**
+ * Display the form feedback when we get POST results
+ * @param data the POST request return data
+ */
+function showFeedback(data) {
+ toggleMessage(data.message);
+ for (var i = 0; i < data.errors.length; i++) {
+ $("#" + data.errors[i]).parent().addClass("has-error has-feedback");
+ }
+ if (data.errors.length > 0) {
+ $(".help-message").addClass("has-error");
+ $(".has-error .form-control-feedback").show();
+ } else {
+ $(".help-message").addClass("has-success");
+ }
+}
+
+/**
+ * Reset form feedback when resubmitting
+ */
+function resetFeedback() {
+ $(".form-control-feedback").hide();
+ $(".has-success, .has-error, .has-feedback").removeClass("has-success has-error has-feedback");
+}
+
+/**
+ * Show the return message from the POST request, then set a timeout to hide it again
+ * @param msg the return message from the POST request
+ */
+function toggleMessage(msg) {
+ /*
+ * Since setting display:none; on this element causes odd behaviour
+ * with bootstrap, hide() the element so we can formSlide it in.
+ * This is only really only necessary the first time this
+ * function is called after page load.
+ */
+ var help = $(".help-message");
+ help.html(msg).show();
+}
+
+/**
+ * Show the overlay and loading gif
+ */
+function addOverlay() {
+ $("body").append("");
+}
+
+/**
+ * Remove the overlay and loading gif
+ */
+function removeOverlay() {
+ var overlay = $("#overlay, #loadingImage");
+ $("#loadingImage").fadeOut(250);
+ $("#overlay").fadeOut(500, function() {
+ overlay.remove();
+ });
+}
+
+function formSlide(dir) {
+ var delta = (dir == "next") ? "-=100%" : "+=100%",
+ parent = $(this).parents("div.form-wrapper"),
+ toForm = (dir == "next") ? parent.next() : parent.prev();
+
+ parent.find(".btn").attr("disabled", "disabled");
+ toForm.find(".btn").removeAttr("disabled");
+ toForm.find(":input :first").focus();
+
+ $(".form-slider").animate({left: delta}, 500);
+ var stepCount = $("#stepCount"),
+ steps = parseInt(stepCount.html());
+ stepCount.html((dir == "next") ? (steps + 1) : (steps - 1));
+ hideRMQForm();
+}
+
+/**
+ * Fade out the previous setup step and fade in the next one
+ */
+function nextSlide() {
+ formSlide.call($(this), "next");
+}
+
+/**
+ * Fade out the current setup step and fade in the previous one
+ */
+function prevSlide() {
+ formSlide.call($(this), "prev");
+}
+
+/**
+ * Hide the RMQ form when the slider is called to avoid showing
+ * scrollbars on slider panels that fit vertically
+ */
+function hideRMQForm() {
+ $("#rmqFormBody").slideUp(500);
+ $("#advCaret").removeClass("caret-up");
+}
+
+function submitForm(e, obj) {
+ resetFeedback();
+ e.preventDefault();
+ var d = $(e.target).serializeArray();
+ addOverlay();
+ // Append .promise().done() rather than using a
+ // callback to avoid call duplication
+ $("#overlay, #loadingImage").fadeIn(500).promise().done(function() {
+ // Proxy function for passing the event to the cleanup function
+ var cleanupProxy = function(data) {
+ cleanupStep.call(this, data, e);
+ };
+ $.post('setup/setup-functions.php?obj=' + obj, d, cleanupProxy, "json");
+ });
+}
+
+$(function() {
+ // Stop the user from dragging the slider
+ $(".form-slider").draggable('disable');
+ $(".btn").attr("disabled", "disabled");
+ $("form:first .btn").removeAttr("disabled");
+
+ window.onresize = function() {
+ var headerHeight = $(".header").outerHeight(),
+ viewport = $(".viewport"),
+ viewportHeight = viewport.outerHeight();
+ // If the viewport would go outside the page bounds,
+ // shrink it to fit the window
+ if (viewportHeight + headerHeight > window.innerHeight) {
+ viewport.css("height", window.innerHeight - headerHeight);
+ }
+ // Otherwise, go back to what we have in the stylesheet
+ else {
+ viewport.css("height", "");
+ }
+ };
+});
diff --git a/airtime_mvc/public/setup/database-setup.php b/airtime_mvc/public/setup/database-setup.php
new file mode 100644
index 000000000..821f549cf
--- /dev/null
+++ b/airtime_mvc/public/setup/database-setup.php
@@ -0,0 +1,196 @@
+value pairs for airtime.conf
+ static $properties;
+
+ static $dbh = null;
+
+ public function __construct($settings) {
+ $this->user = $settings[self::DB_USER];
+ $this->pass = $settings[self::DB_PASS];
+ $this->name = $settings[self::DB_NAME];
+ $this->host = $settings[self::DB_HOST];
+
+ self::$properties = array(
+ "host" => $this->host,
+ "dbname" => $this->name,
+ "dbuser" => $this->user,
+ "dbpass" => $this->pass,
+ );
+ }
+
+ private function setNewDatabaseConnection($dbName) {
+ self::$dbh = new PDO("pgsql:host=" . $this->host . ";dbname=" . $dbName . ";port=5432"
+ . ";user=" . $this->user . ";password=" . $this->pass);
+ $err = self::$dbh->errorInfo();
+ if ($err[1] != null) {
+ throw new PDOException();
+ }
+ }
+
+ /**
+ * Runs various database checks against the given settings. If a database with the given name already exists,
+ * we attempt to install the Airtime schema. If not, we first check if the user can create databases, then try
+ * to create the database. If we encounter errors, the offending fields are returned in an array to the browser.
+ * @return array associative array containing a display message and fields with errors
+ * @throws AirtimeDatabaseException
+ */
+ public function runSetup() {
+ try {
+ $this->setNewDatabaseConnection("postgres");
+ if ($this->checkDatabaseExists()) {
+ $this->installDatabaseTables();
+ } else {
+ $this->checkUserCanCreateDb();
+ $this->createDatabase();
+ $this->installDatabaseTables();
+ }
+ } catch (PDOException $e) {
+ throw new AirtimeDatabaseException("Couldn't establish a connection to the database! "
+ . "Please check your credentials and try again. "
+ . "PDO Exception: " . $e->getMessage(),
+ array(
+ self::DB_NAME,
+ self::DB_USER,
+ self::DB_PASS,
+ ));
+ }
+
+ $this->writeToTemp();
+
+ self::$dbh = null;
+ return array(
+ "message" => "Airtime database was created successfully!",
+ "errors" => array(),
+ );
+ }
+
+ protected function writeToTemp() {
+ parent::writeToTemp(self::SECTION, self::$properties);
+ }
+
+ private function installDatabaseTables() {
+ $this->checkDatabaseEncoding();
+ $this->setNewDatabaseConnection($this->name);
+ $this->checkSchemaExists();
+ $this->createDatabaseTables();
+ }
+
+ /**
+ * Check if the database settings and credentials given are valid
+ * @return boolean true if the database given exists and the user is valid and can access it
+ */
+ private function checkDatabaseExists() {
+ $statement = self::$dbh->prepare("SELECT datname FROM pg_database WHERE datname = :dbname");
+ $statement->execute(array(":dbname" => $this->name));
+ $result = $statement->fetch();
+ return isset($result[0]);
+ }
+
+ /**
+ * Check if the database schema has already been set up
+ * @throws AirtimeDatabaseException
+ */
+ private function checkSchemaExists() {
+ $statement = self::$dbh->prepare("SELECT EXISTS (SELECT relname FROM pg_class WHERE relname='cc_files')");
+ $statement->execute();
+ $result = $statement->fetch();
+ if (isset($result[0]) && $result[0] == "t") {
+ throw new AirtimeDatabaseException("Airtime is already installed in this database!", array());
+ }
+ }
+
+ /**
+ * Check if the given user has access on the given host to create a new database
+ * @throws AirtimeDatabaseException
+ */
+ private function checkUserCanCreateDb() {
+ $statement = self::$dbh->prepare("SELECT 1 FROM pg_roles WHERE rolname=:dbuser AND rolcreatedb='t'");
+ $statement->execute(array(":dbuser" => $this->user));
+ $result = $statement->fetch();
+ if (!isset($result[0])) {
+ throw new AirtimeDatabaseException("No database " . $this->name . " exists; user '" . $this->user
+ . "' does not have permission to create databases on " . $this->host,
+ array(
+ self::DB_NAME,
+ self::DB_USER,
+ self::DB_PASS,
+ ));
+ }
+ }
+
+ /**
+ * Creates the Airtime database using the given credentials
+ * @throws AirtimeDatabaseException
+ */
+ private function createDatabase() {
+ $statement = self::$dbh->prepare("CREATE DATABASE " . pg_escape_string($this->name)
+ . " WITH ENCODING 'UTF8' TEMPLATE template0"
+ . " OWNER " . pg_escape_string($this->user));
+ if (!$statement->execute()) {
+ throw new AirtimeDatabaseException("There was an error creating the database!",
+ array(self::DB_NAME,));
+ }
+ }
+
+ /**
+ * Creates the Airtime database schema using the given credentials
+ * @throws AirtimeDatabaseException
+ */
+ private function createDatabaseTables() {
+ $sqlDir = dirname(dirname(__DIR__)) . "/build/sql/";
+ $files = array("schema.sql", "sequences.sql", "views.sql", "triggers.sql", "defaultdata.sql");
+ foreach ($files as $f) {
+ try {
+ /*
+ * Unfortunately, we need to use exec here due to PDO's lack of support for importing
+ * multi-line .sql files. PDO->exec() almost works, but any SQL errors stop the import,
+ * so the necessary DROPs on non-existent tables make it unusable. Prepared statements
+ * have multiple issues; they similarly die on any SQL errors, fail to read in multi-line
+ * commands, and fail on any unescaped ? or $ characters.
+ */
+ exec("export PGPASSWORD=" . $this->pass . " && psql -U " . $this->user . " --dbname "
+ . $this->name . " -h " . $this->host . " -f $sqlDir$f 2>/dev/null", $out, $status);
+ } catch (Exception $e) {
+ throw new AirtimeDatabaseException("There was an error setting up the Airtime schema!",
+ array(self::DB_NAME,));
+ }
+ }
+ }
+
+ /**
+ * Checks whether the newly-created database's encoding was properly set to UTF8
+ * @throws AirtimeDatabaseException
+ */
+ private function checkDatabaseEncoding() {
+ $statement = self::$dbh->prepare("SELECT pg_encoding_to_char(encoding) "
+ . "FROM pg_database WHERE datname = :dbname");
+ $statement->execute(array(":dbname" => $this->name));
+ $encoding = $statement->fetch();
+ if (!($encoding && $encoding[0] == "UTF8")) {
+ throw new AirtimeDatabaseException("The database was installed with an incorrect encoding type!",
+ array(self::DB_NAME,));
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/airtime_mvc/public/setup/general-setup.php b/airtime_mvc/public/setup/general-setup.php
new file mode 100644
index 000000000..f63a84f90
--- /dev/null
+++ b/airtime_mvc/public/setup/general-setup.php
@@ -0,0 +1,61 @@
+value pairs for airtime.conf
+ static $properties;
+
+ // Message and error fields to return to the front-end
+ static $message = null;
+ static $errors = array();
+
+ function __construct($settings) {
+ self::$host = $settings[self::GENERAL_HOST];
+ self::$port = $settings[self::GENERAL_PORT];
+
+ self::$properties = array(
+ "api_key" => $this->generateRandomString(),
+ "base_url" => self::$host,
+ "base_port" => self::$port,
+ );
+ }
+
+ function writeToTemp() {
+ parent::writeToTemp(self::SECTION, self::$properties);
+ }
+
+ /**
+ * @return array associative array containing a display message and fields with errors
+ */
+ function runSetup() {
+ // TODO Do we need to validate these settings?
+
+ if (count(self::$errors) <= 0) {
+ $this->writeToTemp();
+ }
+
+ return array(
+ "message" => self::$message,
+ "errors" => self::$errors
+ );
+ }
+
+}
\ No newline at end of file
diff --git a/airtime_mvc/public/setup/media-setup.php b/airtime_mvc/public/setup/media-setup.php
new file mode 100644
index 000000000..d2cb99edc
--- /dev/null
+++ b/airtime_mvc/public/setup/media-setup.php
@@ -0,0 +1,141 @@
+setupMusicDirectory();
+ } else {
+ self::$message = "Invalid path!";
+ self::$errors[] = self::MEDIA_FOLDER;
+ }
+
+ // Finalize and move airtime.conf.temp
+ if (file_exists("/etc/airtime/")) {
+ if (!$this->moveAirtimeConfig()) {
+ $message = "Error moving airtime.conf or deleting /tmp/airtime.conf.temp!";
+ $errors[] = "ERR";
+ }
+
+ /*
+ * If we're upgrading from an old Airtime instance (pre-2.5.2) we rename their old
+ * airtime.conf to airtime.conf.tmp during the setup process. Now that we're done,
+ * we can rename it to airtime.conf.bak to avoid confusion.
+ */
+ if (file_exists(self::AIRTIME_CONF_PATH . ".tmp")) {
+ rename(self::AIRTIME_CONF_PATH . ".tmp", self::AIRTIME_CONF_PATH . ".bak");
+ }
+ } else {
+ $message = "Failed to move airtime.conf; /etc/airtime doesn't exist!";
+ $errors[] = "ERR";
+ }
+
+ return array(
+ "message" => self::$message,
+ "errors" => self::$errors
+ );
+ }
+
+ /**
+ * Moves /tmp/airtime.conf.temp to /etc/airtime.conf and then removes it to complete setup
+ * @return boolean false if either of the copy or removal operations fail
+ */
+ function moveAirtimeConfig() {
+ return copy(AIRTIME_CONF_TEMP_PATH, self::AIRTIME_CONF_PATH)
+ && unlink(AIRTIME_CONF_TEMP_PATH);
+ }
+
+ /**
+ * Add the given directory to cc_music_dirs
+ * TODO Should we check for an existing entry in cc_music_dirs?
+ */
+ function setupMusicDirectory() {
+ try {
+ $_SERVER['AIRTIME_CONF'] = AIRTIME_CONF_TEMP_PATH;
+ Propel::init(CONFIG_PATH . "airtime-conf-production.php");
+ $con = Propel::getConnection();
+ } catch(Exception $e) {
+ self::$message = "Failed to insert media folder; database isn't configured properly!";
+ self::$errors[] = self::MEDIA_FOLDER;
+ return;
+ }
+
+ $this->runMusicDirsQuery($con);
+ }
+
+ function runMusicDirsQuery($con) {
+ try {
+ if ($this->checkMusicDirectoryExists($con)) {
+ $dir = CcMusicDirsQuery::create()->findPk(1, $con);
+ } else {
+ $dir = new CcMusicDirs();
+ }
+
+ $dir->setDirectory(self::$path)
+ ->setType("stor")
+ ->save();
+ self::$message = "Successfully set up media folder!";
+ Propel::close();
+ unset($_SERVER['AIRTIME_CONF']);
+ } catch (Exception $e) {
+ self::$message = "Failed to insert " . self::$path . " into cc_music_dirs";
+ self::$errors[] = self::MEDIA_FOLDER;
+ }
+
+ }
+
+ function checkMusicDirectoryExists($con) {
+ $entry = CcMusicDirsQuery::create()->findPk(1, $con);
+ return isset($entry) && $entry;
+ }
+
+}
\ No newline at end of file
diff --git a/airtime_mvc/public/setup/rabbitmq-setup.php b/airtime_mvc/public/setup/rabbitmq-setup.php
new file mode 100644
index 000000000..817b51742
--- /dev/null
+++ b/airtime_mvc/public/setup/rabbitmq-setup.php
@@ -0,0 +1,100 @@
+value pairs for airtime.conf
+ static $properties;
+
+ // Message and error fields to return to the front-end
+ static $message = null;
+ static $errors = array();
+
+ function __construct($settings) {
+ self::$user = $settings[self::RMQ_USER];
+ self::$pass = $settings[self::RMQ_PASS];
+ self::$port = $settings[self::RMQ_PORT];
+ self::$host = $settings[self::RMQ_HOST];
+ self::$vhost = $settings[self::RMQ_VHOST];
+
+ self::$properties = array(
+ "host" => self::$host,
+ "port" => self::$port,
+ "user" => self::$user,
+ "password" => self::$pass,
+ "vhost" => self::$vhost,
+ );
+ }
+
+ /**
+ * @return array associative array containing a display message and fields with errors
+ */
+ function runSetup() {
+ try {
+ if ($this->checkRMQConnection()) {
+ self::$message = "Connection successful!";
+ } else {
+ $this->identifyRMQConnectionError();
+ }
+ } catch(Exception $e) {
+ $this->identifyRMQConnectionError();
+ }
+
+ if (count(self::$errors) <= 0) {
+ $this->writeToTemp();
+ }
+
+ return array(
+ "message" => self::$message,
+ "errors" => self::$errors
+ );
+ }
+
+ function writeToTemp() {
+ parent::writeToTemp(self::SECTION, self::$properties);
+ }
+
+ function checkRMQConnection() {
+ $conn = new AMQPConnection(self::$host,
+ self::$port,
+ self::$user,
+ self::$pass,
+ self::$vhost);
+ return isset($conn);
+ }
+
+ function identifyRMQConnectionError() {
+ // It's impossible to identify errors coming out of amqp.inc without a major
+ // rewrite, so for now just tell the user ALL THE THINGS went wrong
+ self::$message = "Couldn't connect to RabbitMQ server! Please check if the server "
+ . "is running and your credentials are correct.";
+ self::$errors[] = self::RMQ_USER;
+ self::$errors[] = self::RMQ_PASS;
+ self::$errors[] = self::RMQ_HOST;
+ self::$errors[] = self::RMQ_PORT;
+ self::$errors[] = self::RMQ_VHOST;
+ }
+
+}
\ No newline at end of file
diff --git a/airtime_mvc/public/setup/setup-functions.php b/airtime_mvc/public/setup/setup-functions.php
new file mode 100644
index 000000000..36d96265e
--- /dev/null
+++ b/airtime_mvc/public/setup/setup-functions.php
@@ -0,0 +1,126 @@
+errors = $errors;
+ }
+
+ public function getErrorFields() {
+ return $this->errors;
+ }
+
+}
+
+// Import Setup subclasses
+require_once ('database-setup.php');
+require_once ('rabbitmq-setup.php');
+require_once ('general-setup.php');
+require_once ('media-setup.php');
+
+// If airtime.conf exists, we shouldn't be here
+if (!file_exists("/etc/airtime/airtime.conf")) {
+ if (isset($_GET["obj"]) && $objType = $_GET["obj"]) {
+ $obj = new $objType($_POST);
+ if ($obj instanceof Setup) {
+ try {
+ $response = $obj->runSetup();
+ } catch (AirtimeDatabaseException $e) {
+ $response = array(
+ "message" => $e->getMessage(),
+ "errors" => $e->getErrorFields()
+ );
+ }
+
+ echo json_encode($response);
+ }
+ }
+}
diff --git a/airtime_mvc/tests/application/bootstrap.php b/airtime_mvc/tests/application/bootstrap.php
index 1de69efaa..ddd54f82d 100644
--- a/airtime_mvc/tests/application/bootstrap.php
+++ b/airtime_mvc/tests/application/bootstrap.php
@@ -3,7 +3,10 @@ error_reporting(E_ALL | E_STRICT);
// Define path to application directory
defined('APPLICATION_PATH')
- || define('APPLICATION_PATH', realpath(dirname(__FILE__) . '/../../application'));
+ || define('APPLICATION_PATH', realpath(dirname(__FILE__) . '/../../application/'));
+
+// Define path to configs directory
+define('CONFIG_PATH', APPLICATION_PATH . '/configs/');
// Define application environment
defined('APPLICATION_ENV')
diff --git a/install_minimal/include/AirtimeInstall.php b/airtime_mvc/tests/application/helpers/AirtimeInstall.php
similarity index 87%
rename from install_minimal/include/AirtimeInstall.php
rename to airtime_mvc/tests/application/helpers/AirtimeInstall.php
index 6e429d6ac..f3dafbecc 100644
--- a/install_minimal/include/AirtimeInstall.php
+++ b/airtime_mvc/tests/application/helpers/AirtimeInstall.php
@@ -5,25 +5,20 @@ if (file_exists('/usr/share/php/libzend-framework-php')){
set_include_path('/usr/share/php/libzend-framework-php' . PATH_SEPARATOR . get_include_path());
}
#require_once('Zend/Loader/Autoloader.php');
-
class AirtimeInstall
{
const CONF_DIR_BINARIES = "/usr/lib/airtime";
const CONF_DIR_WWW = "/usr/share/airtime";
const CONF_DIR_LOG = "/var/log/airtime";
-
public static $databaseTablesCreated = false;
-
public static function GetAirtimeSrcDir()
{
- return __DIR__."/../../airtime_mvc";
+ return __DIR__."/../../..";
}
-
public static function GetUtilsSrcDir()
{
- return __DIR__."/../../utils";
+ return __DIR__."/../../../../utils";
}
-
/**
* Ensures that the user is running this PHP script with root
* permissions. If not running with root permissions, causes the
@@ -37,7 +32,6 @@ class AirtimeInstall
exit(1);
}
}
-
/**
* Return the version of Airtime currently installed.
* If not installed, return null.
@@ -51,14 +45,12 @@ class AirtimeInstall
} catch (PropelException $e) {
return null;
}
-
if (file_exists('/etc/airtime/airtime.conf')) {
$values = parse_ini_file('/etc/airtime/airtime.conf', true);
}
else {
return null;
}
-
$sql = "SELECT valstr FROM cc_pref WHERE keystr = 'system_version' LIMIT 1";
try {
@@ -70,7 +62,6 @@ class AirtimeInstall
//the database because it was busy, so it just removed the tables instead.
return null;
}
-
//if version is empty string, then version is older than version 1.8.0
if ($version == '') {
try {
@@ -82,10 +73,8 @@ class AirtimeInstall
$version = null;
}
}
-
return $version;
}
-
public static function DbTableExists($p_name)
{
$con = Propel::getConnection();
@@ -97,7 +86,6 @@ class AirtimeInstall
}
return true;
}
-
public static function InstallQuery($sql, $verbose = true)
{
$con = Propel::getConnection();
@@ -112,7 +100,6 @@ class AirtimeInstall
echo " ".$sql."\n\n";
}
}
-
public static function DropSequence($p_sequenceName)
{
AirtimeInstall::InstallQuery("DROP SEQUENCE IF EXISTS $p_sequenceName", false);
@@ -142,20 +129,15 @@ class AirtimeInstall
}
return true;
}
-
-
/* TODO: This function should be moved to the media-monitor
* install script. */
public static function InstallStorageDirectory()
{
$CC_CONFIG = Config::getConfig();
echo "* Storage directory setup".PHP_EOL;
-
$ini = parse_ini_file(__DIR__."/airtime-install.ini");
$stor_dir = $ini["storage_dir"];
-
$dirs = array($stor_dir, $stor_dir."/organize");
-
foreach ($dirs as $dir){
if (!file_exists($dir)) {
if (mkdir($dir, 02775, true)){
@@ -175,24 +157,19 @@ class AirtimeInstall
echo "* Error: Directory already exists, but is not writable: $rp".PHP_EOL;
exit(1);
}
-
echo "* Giving Apache permission to access $rp".PHP_EOL;
$success = chown($rp, $CC_CONFIG["webServerUser"]);
$success = chgrp($rp, $CC_CONFIG["webServerUser"]);
$success = chmod($rp, 0775);
}
}
-
public static function CreateDatabaseUser()
{
$CC_CONFIG = Config::getConfig();
-
echo " * Creating Airtime database user".PHP_EOL;
-
$username = $CC_CONFIG['dsn']['username'];
$password = $CC_CONFIG['dsn']['password'];
$command = "echo \"CREATE USER $username ENCRYPTED PASSWORD '$password' LOGIN CREATEDB NOCREATEUSER;\" | su postgres -c psql 2>/dev/null";
-
@exec($command, $output, $results);
if ($results == 0) {
echo " * Database user '{$CC_CONFIG['dsn']['username']}' created.".PHP_EOL;
@@ -206,13 +183,9 @@ class AirtimeInstall
}
}
}
-
-
public static function CreateDatabase()
{
$CC_CONFIG = Config::getConfig();
-
-
$database = $CC_CONFIG['dsn']['database'];
$username = $CC_CONFIG['dsn']['username'];
#$command = "echo \"CREATE DATABASE $database OWNER $username\" | su postgres -c psql 2>/dev/null";
@@ -222,37 +195,30 @@ class AirtimeInstall
putenv("LC_ALL=en_CA.UTF-8"); //Squash warnings when running unit tests
$command = "su postgres -c \"psql -l | cut -f2 -d' ' | grep -w '{$database}'\";";
exec($command, $output, $rv);
-
if ($rv == 0) {
//database already exists
echo "Database already exists." . PHP_EOL;
return true;
}
-
$command = "sudo -i -u postgres psql postgres -c \"CREATE DATABASE ".$database." WITH ENCODING 'UTF8' TEMPLATE template0 OWNER ".$username."\"";
-
@exec($command, $output, $results);
if ($results == 0) {
- echo " * Database '{$CC_CONFIG['dsn']['database']}' created.".PHP_EOL;
+ echo " * Database $database created.".PHP_EOL;
} else {
if (count($output) > 0) {
- echo " * Could not create database '{$CC_CONFIG['dsn']['database']}': ".PHP_EOL;
+ echo " * Could not create database $database: ".PHP_EOL;
echo implode(PHP_EOL, $output);
}
else {
- echo " * Database '{$CC_CONFIG['dsn']['database']}' already exists.".PHP_EOL;
+ echo " * Database $database already exists.".PHP_EOL;
}
}
-
$databaseExisted = ($results != 0);
-
return $databaseExisted;
}
-
public static function InstallPostgresScriptingLanguage()
{
$con = Propel::getConnection();
-
// Install postgres scripting language
$sql = 'SELECT COUNT(*) FROM pg_language WHERE lanname = \'plpgsql\'';
$langIsInstalled = $con->query($sql)->fetchColumn(0);
@@ -264,25 +230,19 @@ class AirtimeInstall
echo " * Postgres scripting language already installed".PHP_EOL;
}
}
-
public static function CreateDatabaseTables($p_dbuser, $p_dbpasswd, $p_dbname, $p_dbhost)
{
echo " * Creating database tables".PHP_EOL;
-
// Put Propel sql files in Database
//$command = AirtimeInstall::CONF_DIR_WWW."/library/propel/generator/bin/propel-gen ".AirtimeInstall::CONF_DIR_WWW."/build/ insert-sql 2>/dev/null";
-
$dir = self::GetAirtimeSrcDir()."/build/sql/";
$files = array("schema.sql", "sequences.sql", "views.sql", "triggers.sql", "defaultdata.sql");
-
foreach ($files as $f){
- $command = "export PGPASSWORD=$p_dbpasswd && psql --username $p_dbuser --dbname $p_dbname --host $p_dbhost --file $dir$f 2>/dev/null";
+ $command = "export PGPASSWORD=$p_dbpasswd && psql --username $p_dbuser --dbname $p_dbname --host $p_dbhost --file $dir$f 2>&1";
@exec($command, $output, $results);
}
-
AirtimeInstall::$databaseTablesCreated = true;
}
-
public static function BypassMigrations($dir, $version)
{
$appDir = AirtimeInstall::GetAirtimeSrcDir();
@@ -292,7 +252,6 @@ class AirtimeInstall
"--no-interaction --add migrations:version $version";
system($command);
}
-
public static function MigrateTablesToVersion($dir, $version)
{
$appDir = AirtimeInstall::GetAirtimeSrcDir();
@@ -302,22 +261,18 @@ class AirtimeInstall
"--no-interaction migrations:migrate $version";
system($command);
}
-
public static function SetAirtimeVersion($p_version)
{
$con = Propel::getConnection();
$sql = "DELETE FROM cc_pref WHERE keystr = 'system_version'";
$con->exec($sql);
-
Application_Model_Preference::SetAirtimeVersion($p_version);
}
-
public static function SetUniqueId()
{
$uniqueId = md5(uniqid("", true));
Application_Model_Preference::SetUniqueId($uniqueId);
}
-
public static function GetAirtimeVersion()
{
$con = Propel::getConnection();
@@ -325,72 +280,23 @@ class AirtimeInstall
$version = $con->query($sql)->fetchColumn(0);
return $version;
}
-
public static function DeleteFilesRecursive($p_path)
{
$command = "rm -rf \"$p_path\"";
exec($command);
}
-
- public static function CreateSymlinksToUtils()
- {
- echo "* Creating /usr/bin symlinks".PHP_EOL;
- AirtimeInstall::RemoveSymlinks();
-
- echo "* Installing airtime-import".PHP_EOL;
- $dir = AirtimeInstall::CONF_DIR_BINARIES."/utils/airtime-import/airtime-import";
- exec("ln -s $dir /usr/bin/airtime-import");
-
- echo "* Installing airtime-check-system".PHP_EOL;
- $dir = AirtimeInstall::CONF_DIR_BINARIES."/utils/airtime-check-system";
- exec("ln -s $dir /usr/bin/airtime-check-system");
-
- echo "* Installing airtime-user".PHP_EOL;
- $dir = AirtimeInstall::CONF_DIR_BINARIES."/utils/airtime-user";
- exec("ln -s $dir /usr/bin/airtime-user");
-
- echo "* Installing airtime-log".PHP_EOL;
- $dir = AirtimeInstall::CONF_DIR_BINARIES."/utils/airtime-log";
- exec("ln -s $dir /usr/bin/airtime-log");
- }
-
- public static function RemoveSymlinks()
- {
- exec("rm -f /usr/bin/airtime-import");
- exec("rm -f /usr/bin/airtime-check-system");
- exec("rm -f /usr/bin/airtime-user");
- exec("rm -f /usr/bin/airtime-log");
- exec("rm -f /usr/bin/airtime-clean-storage");
- }
-
public static function InstallPhpCode()
{
$CC_CONFIG = Config::getConfig();
echo "* Installing PHP code to ".AirtimeInstall::CONF_DIR_WWW.PHP_EOL;
exec("mkdir -p ".AirtimeInstall::CONF_DIR_WWW);
exec("cp -R ".AirtimeInstall::GetAirtimeSrcDir()."/* ".AirtimeInstall::CONF_DIR_WWW);
-
}
-
public static function UninstallPhpCode()
{
echo "* Removing PHP code from ".AirtimeInstall::CONF_DIR_WWW.PHP_EOL;
exec('rm -rf "'.AirtimeInstall::CONF_DIR_WWW.'"');
}
-
- public static function InstallBinaries()
- {
- echo "* Installing binaries to ".AirtimeInstall::CONF_DIR_BINARIES.PHP_EOL;
- exec("mkdir -p ".AirtimeInstall::CONF_DIR_BINARIES);
- exec("cp -R ".AirtimeInstall::GetUtilsSrcDir()." ".AirtimeInstall::CONF_DIR_BINARIES);
- }
-
- public static function UninstallBinaries()
- {
- echo "* Removing Airtime binaries from ".AirtimeInstall::CONF_DIR_BINARIES.PHP_EOL;
- exec('rm -rf "'.AirtimeInstall::CONF_DIR_BINARIES.'"');
- }
-
public static function DirCheck()
{
echo "Legend: \"+\" means the dir/file exists, \"-\" means that it does not.".PHP_EOL;
@@ -412,54 +318,44 @@ class AirtimeInstall
}
}
}
-
public static function CreateZendPhpLogFile(){
$CC_CONFIG = Config::getConfig();
-
$path = AirtimeInstall::CONF_DIR_LOG;
$file = $path.'/zendphp.log';
if (!file_exists($path)){
mkdir($path, 0755, true);
}
-
touch($file);
chmod($file, 0644);
chown($file, $CC_CONFIG['webServerUser']);
chgrp($file, $CC_CONFIG['webServerUser']);
}
-
public static function RemoveLogDirectories(){
$path = AirtimeInstall::CONF_DIR_LOG;
echo "* Removing logs directory ".$path.PHP_EOL;
-
exec("rm -rf \"$path\"");
}
-
public static function CreateCronFile(){
echo "* Creating Cron File".PHP_EOL;
// Create CRON task to run every day. Time of day is initialized to a random time.
$hour = rand(0,23);
$minute = rand(0,59);
-
$fp = fopen('/etc/cron.d/airtime-crons','w');
fwrite($fp, "$minute $hour * * * root /usr/lib/airtime/utils/phone_home_stat\n");
fclose($fp);
}
-
public static function removeVirtualEnvDistributeFile(){
echo "* Removing distribute-0.6.10.tar.gz".PHP_EOL;
if(file_exists('/usr/share/python-virtualenv/distribute-0.6.10.tar.gz')){
exec("rm -f /usr/share/python-virtualenv/distribute-0.6.10.tar.gz");
}
}
-
public static function printUsage($opts)
{
$msg = $opts->getUsageMessage();
echo PHP_EOL."Usage: airtime-install [options]";
echo substr($msg, strpos($msg, "\n")).PHP_EOL;
}
-
public static function getOpts()
{
try {
@@ -482,7 +378,6 @@ class AirtimeInstall
}
return $opts;
}
-
public static function checkPHPVersion()
{
if (PHP_VERSION_ID < 50300)
diff --git a/airtime_mvc/tests/application/helpers/TestHelper.php b/airtime_mvc/tests/application/helpers/TestHelper.php
index 43ce6d151..c9a00d3a0 100644
--- a/airtime_mvc/tests/application/helpers/TestHelper.php
+++ b/airtime_mvc/tests/application/helpers/TestHelper.php
@@ -62,7 +62,7 @@ class TestHelper
// cc_subjs - Most of Airtime requires an admin account to work, which has id=1,
// so don't clear it.
// cc_music_dirs - Has foreign key constraints against cc_files, so we clear cc_files
- // first and ckear cc_music_dirs after
+ // first and clear cc_music_dirs after
$tablesToNotClear = array("cc_subjs", "cc_music_dirs");
$con->beginTransaction();
@@ -128,7 +128,7 @@ class TestHelper
public static function setupZendBootstrap()
{
- $application = new Zend_Application(APPLICATION_ENV, APPLICATION_PATH .'/configs/application.ini');
+ $application = new Zend_Application(APPLICATION_ENV, CONFIG_PATH . 'application.ini');
$application->bootstrap();
return $application;
}
diff --git a/airtime_mvc/tests/application/models/unit/PreferenceUnitTest.php b/airtime_mvc/tests/application/models/unit/PreferenceUnitTest.php
index 765079dec..44a466e69 100644
--- a/airtime_mvc/tests/application/models/unit/PreferenceUnitTest.php
+++ b/airtime_mvc/tests/application/models/unit/PreferenceUnitTest.php
@@ -17,7 +17,7 @@ class PreferenceUnitTest extends PHPUnit_Framework_TestCase
public function testSetHeadTitle()
{
$title = "unit test";
- //This function is confusing and doesn't really work so we're just gonna let it slide...
+ //This function is confusing and doesn't really work so we're just gonna let it formSlide...
Application_Model_Preference::SetHeadTitle($title);
$this->assertEquals(Application_Model_Preference::GetHeadTitle(), $title);
}
diff --git a/airtime_mvc/tests/runtests.sh b/airtime_mvc/tests/runtests.sh
index faf6628ef..abe2d2ba5 100755
--- a/airtime_mvc/tests/runtests.sh
+++ b/airtime_mvc/tests/runtests.sh
@@ -33,5 +33,5 @@ DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
cd $DIR
#Run the unit tests
-phpunit --log-junit test_results.xml
+phpunit --verbose --log-junit test_results.xml
diff --git a/dev_tools/compare_cc_files_to_fs.py b/dev_tools/compare_cc_files_to_fs.py
index 3f35fc033..fe842332b 100644
--- a/dev_tools/compare_cc_files_to_fs.py
+++ b/dev_tools/compare_cc_files_to_fs.py
@@ -25,7 +25,7 @@ class AirtimeMediaMonitorBootstrap():
api_clients -- reference of api_clients to communicate with airtime-server
"""
def __init__(self):
- config = ConfigObj('/etc/airtime/media-monitor.cfg')
+ config = ConfigObj('/etc/airtime/airtime.conf')
self.api_client = apc.api_client_factory(config)
"""
diff --git a/dev_tools/toggle-pypo-debug.sh b/dev_tools/toggle-pypo-debug.sh
index d8f6a3e96..6468066a1 100755
--- a/dev_tools/toggle-pypo-debug.sh
+++ b/dev_tools/toggle-pypo-debug.sh
@@ -18,7 +18,7 @@ if [ "$1" = "--enable" ]; then
echo "Changing ownership to user $1"
chmod -R a+rw /var/log/airtime/pypo
- chmod a+r /etc/airtime/pypo.cfg
+ chmod a+r /etc/airtime/airtime.conf
chown -Rv $user:$user /var/tmp/airtime/pypo/
chmod -v a+r /etc/airtime/api_client.cfg
elif [ "$1" = "--disable" ]; then
@@ -26,7 +26,7 @@ elif [ "$1" = "--disable" ]; then
user="pypo"
echo "Changing ownership to user $1"
- chmod 644 /etc/airtime/pypo.cfg
+ chmod 644 /etc/airtime/airtime.conf
chown -Rv $user:$user /var/tmp/airtime/pypo/
chmod -v a+r /etc/airtime/api_client.cfg
diff --git a/install b/install
new file mode 100755
index 000000000..714b01c0a
--- /dev/null
+++ b/install
@@ -0,0 +1,625 @@
+#!/bin/bash -e
+#-e Causes bash script to exit if any of the installers
+#return with a non-zero return value.
+
+if [[ $EUID -ne 0 ]]; then
+ echo "Please run as root user."
+ exit 1
+fi
+
+SCRIPT_DIR="$( cd "$( dirname "$0" )" && pwd )"
+AIRTIMEROOT=${SCRIPT_DIR}
+
+showhelp () {
+ echo "Usage: sudo bash install [options]
+ -h, --help, -?
+ Display usage information
+ -V, --version
+ Display version information
+ -v, --verbose
+ More output
+ -q, --quiet, --silent
+ No output except errors
+ -f, --force
+ Turn off interactive prompts
+ --distribution
+ Linux distribution the installation is being run on
+ --release
+ Distribution release
+ -d, --ignore-dependencies
+ Don't install binary dependencies
+ -w, --web-user=WEB_USER
+ Set the apache web user. Defaults to www-data. Only change
+ this setting if you've changed the default apache web user
+ -r, --web-root=WEB_ROOT
+ Set the web root for Airtime files
+ This will copy the Airtime application files, but you will need
+ to give your web user access to the given directory if it is
+ not accessible
+ -I, --in-place
+ Set the current Airtime directory as the web root
+ Note that you will need to give your web user permission to
+ access this directory if it is not accessible
+ -p, --postgres
+ Create a default postgres user named 'airtime' with password
+ 'airtime'
+ -a, --apache
+ Install apache and deploy a basic configuration for Airtime
+ -i, --icecast
+ Install Icecast 2 and deploy a basic configuration for Airtime"
+ exit 0
+}
+
+showversion () {
+ version=$(php -r 'require_once(__DIR__ . "/airtime_mvc/application/configs/constants.php"); echo AIRTIME_CODE_VERSION;')
+ echo "Airtime Version ${version}"
+ exit 0
+}
+
+web_user="www-data"
+web_root=""
+in_place="f"
+postgres="f"
+apache="f"
+icecast="f"
+ignore_dependencies="f"
+# Interactive
+_i=1
+# Verbose
+_v=0
+# Quiet
+_q=0
+upgrade="f"
+dist=""
+code=""
+
+function verbose() {
+ if [[ ${_v} -eq 1 ]]; then
+ echo -e "$@"
+ fi
+}
+
+function loud() {
+ if [[ ${_q} -eq 0 ]]; then
+ echo -e "$@"
+ fi
+}
+
+# Evaluate commands silently if quiet
+function loudCmd() {
+ if [[ ${_q} -eq 0 ]]; then
+ eval $@
+ else
+ eval $@ > /dev/null
+ fi
+}
+
+function checkCommandExists() {
+ set +e
+ command=$@
+ eval hash ${command} 2>/dev/null
+ commandFound=$?
+ if [[ ! ${commandFound} -eq 0 ]]; then
+ echo -e "Error: ${command} not found. Please ensure you have the corresponding dependency installed."
+ exit
+ fi
+ set -e
+}
+
+while :; do
+ case "$1" in
+ --help)
+ showhelp
+ ;;
+ --version)
+ showversion
+ ;;
+ --verbose)
+ _v=1
+ ;;
+ --quiet|--silent)
+ _q=1
+ ;;
+ --force)
+ _i=0
+ ;;
+ --distribution)
+ if [ "$2" ]; then
+ dist=$2
+ shift 2
+ continue
+ else
+ echo 'ERROR: Must specify a non-empty "--distribution DISTRIBUTION" argument.' >&2
+ exit 1
+ fi
+ ;;
+ --distribution=?*)
+ dist=${1#*=} # Delete everything up to "=" and assign the remainder.
+ ;;
+ --distribution=)
+ echo 'ERROR: Must specify a non-empty "--distribution DISTRIBUTION" argument.' >&2
+ exit 1
+ ;;
+ --release)
+ if [ "$2" ]; then
+ code=$2
+ shift 2
+ continue
+ else
+ echo 'ERROR: Must specify a non-empty "--release RELEASE" argument.' >&2
+ exit 1
+ fi
+ ;;
+ --release=?*)
+ code=${1#*=} # Delete everything up to "=" and assign the remainder.
+ ;;
+ --release=)
+ echo 'ERROR: Must specify a non-empty "--release RELEASE" argument.' >&2
+ exit 1
+ ;;
+ --ignore-dependencies)
+ ignore_dependencies="t"
+ ;;
+ --apache)
+ apache="t"
+ ;;
+ --icecast)
+ icecast="t"
+ ;;
+ --postgres)
+ postgres="t"
+ ;;
+ --in-place)
+ in_place="t"
+ ;;
+ --web-user)
+ if [ "$2" ]; then
+ web_user=$2
+ shift 2
+ continue
+ else
+ echo 'ERROR: Must specify a non-empty "--web-user WEB_USER" argument.' >&2
+ exit 1
+ fi
+ ;;
+ --web-user=?*)
+ web_user=${1#*=} # Delete everything up to "=" and assign the remainder.
+ ;;
+ --web-user=)
+ echo 'ERROR: Must specify a non-empty "--web-user=WEB_USER" argument.' >&2
+ exit 1
+ ;;
+ --web-root)
+ if [ "$2" ]; then
+ web_root=$(readlink -f $2)
+ shift 2
+ continue
+ else
+ echo 'ERROR: Must specify a non-empty "--web-root WEB_ROOT" argument.' >&2
+ exit 1
+ fi
+ ;;
+ --web-root=?*)
+ web_root=${1#*=} # Delete everything up to "=" and assign the remainder.
+ ;;
+ --web-root=)
+ echo 'ERROR: Must specify a non-empty "--web-root=WEB_ROOT" argument.' >&2
+ exit 1
+ ;;
+ --)
+ shift
+ break
+ ;;
+ -?*)
+ for ((i = 1; i < ${#1}; i++)); do
+ case "${1:$i:1}" in
+ h|\?)
+ showhelp
+ ;;
+ V)
+ showversion
+ ;;
+ v)
+ _v=1
+ ;;
+ q)
+ _q=1
+ ;;
+ f)
+ _i=0
+ ;;
+ d)
+ ignore_dependencies="t"
+ ;;
+ a)
+ apache="t"
+ ;;
+ i)
+ icecast="t"
+ ;;
+ p)
+ postgres="t"
+ ;;
+ I)
+ in_place="t"
+ ;;
+ w)
+ if [ "$2" ]; then
+ web_user=$2
+ continue
+ else
+ echo 'ERROR: Must specify a non-empty "-w WEB_USER" argument.' >&2
+ exit 1
+ fi
+ ;;
+ r)
+ if [ "$2" ]; then
+ web_root=$(readlink -f $2)
+ continue
+ else
+ echo 'ERROR: Must specify a non-empty "-d WEB_ROOT" argument.' >&2
+ exit 1
+ fi
+ ;;
+ *)
+ echo "$0: error - unrecognized option '${1:$i:1}'" >&2;
+ echo "Try 'install --help' for more information."
+ exit 1
+ esac
+ done
+ ;;
+ *)
+ break
+ esac
+ shift
+done
+
+if [ -z web_root -a ! -d web_root ]; then
+ echo "$web_root doesn't exist!"
+ exit 1
+fi
+
+echo -e "\n _____ .________________________.___ _____ ___________ "
+echo " / _ \ | \______ \__ ___/| | / \ \_ _____/ "
+echo " / /_\ \| || _/ | | | |/ \ / \ | __)_ "
+echo "/ | \ || | \ | | | / Y \| \ "
+echo "\____|__ /___||____|_ / |____| |___\____|__ /_______ / "
+echo -e " \/ \/ \/ \/ \n"
+
+if [ "$ignore_dependencies" = "f" ]; then
+ set +e
+ if [ -z "${dist}" ]; then
+ loudCmd "apt-get -y --force-yes install lsb-release"
+ dist=`lsb_release -ds | awk '{print tolower($1);}'`
+ code=`lsb_release -cs`
+ fi
+
+ loud "\n-----------------------------------------------------"
+ loud " * Installing External Dependencies * "
+ loud "-----------------------------------------------------"
+
+ verbose "\n * Reading requirements-${dist,,}-${code,,}.apt..."
+ loudCmd "apt-get update"
+ if [ -f ${SCRIPT_DIR}/installer/lib/requirements-${dist,,}-${code,,}.apt ]; then
+ loudCmd "DEBIAN_FRONTEND=noninteractive apt-get -y -m --force-yes install $(grep -vE '^\s*#' ${SCRIPT_DIR}/installer/lib/requirements-${dist,,}-${code,,}.apt | tr '\n' ' ')"
+ else
+ loudCmd "DEBIAN_FRONTEND=noninteractive apt-get -y -m --force-yes install $(grep -vE '^\s*#' ${SCRIPT_DIR}/installer/lib/requirements-ubuntu-trusty.apt | tr '\n' ' ')"
+ fi
+ set -e
+else
+ checkCommandExists "apache2"
+ checkCommandExists "rabbitmqctl"
+ checkCommandExists "psql"
+fi
+
+if [ -f /etc/airtime/airtime.conf ]; then
+ OLD_CONF=$(grep "[media-monitor]" /etc/airtime/airtime.conf)
+
+ if [ -n "${OLD_CONF}" ]; then
+ upgrade="t"
+
+ set +e
+ verbose "Stopping airtime services..."
+ loudCmd "service airtime-playout stop-with-monit"
+ loudCmd "service airtime-media-monitor stop-with-monit"
+ loudCmd "service airtime-liquidsoap stop-with-monit"
+ verbose "...Done"
+
+ echo "Looks like you have an old version of Airtime. Your current /etc/airtime/airtime.conf \
+will be moved to /etc/airtime/airtime.conf.tmp"
+ # If we don't remove the existing python files in /usr/lib and the
+ # /etc/init.d startup scripts, services won't work properly
+ if [ -d /usr/lib/airtime/ ]; then
+ rm -rf /usr/lib/airtime/
+ fi
+
+ rm /etc/init.d/airtime-*
+
+ if [ "$apache" = "t" ]; then
+ # If the user selects an "in-place" install or passes in a web root,
+ # we need to replace the old apache airtime.conf
+ rm /etc/apache2/sites-available/airtime.conf
+ fi
+
+ if [ -d /usr/share/airtime -a web_root = /usr/share/airtime ]; then
+ rm -rf /usr/share/airtime
+ fi
+
+ mv /etc/airtime/airtime.conf /etc/airtime/airtime.conf.tmp
+ set -e
+ fi
+fi
+
+if [ "$apache" = "f" -a ${_i} -eq 1 ]; then
+ echo -e "Install default Airtime apache configuration? (Y/n): \c"
+ read IN
+ if [ "$IN" = "y" -o "$IN" = "Y" ]; then
+ apache="t"
+ fi
+fi
+
+if [ "$in_place" = "t" ]; then
+ verbose "\n * Setting current Airtime directory as web root..."
+ web_root=${AIRTIMEROOT}/airtime_mvc/public
+elif [ -n "$web_root" ]; then
+ verbose "\n * Creating Apache web root directory..."
+ cp -R ${AIRTIMEROOT}/airtime_mvc/* ${web_root}
+ web_root=${web_root}/public/
+else
+ verbose "\n * Creating default Apache web root directory /usr/share/airtime/..."
+ web_root="/usr/share/airtime"
+ mkdir -p ${web_root}
+ cp -R ${AIRTIMEROOT}/airtime_mvc/* ${web_root}
+ web_root=${web_root}/public/
+fi
+verbose "...Done"
+
+if [ "$apache" = "t" ]; then
+ loud "\n-----------------------------------------------------"
+ loud " * Configuring Apache * "
+ loud "-----------------------------------------------------"
+
+ set +e
+ apache2 -v | grep "2\.4" > /dev/null
+ apacheversion=$?
+ set -e
+
+ if [ "$apacheversion" != "1" ]; then
+ airtimeconfigfile="airtime.conf"
+ oldconfigfile="airtime-vhost.conf"
+ else
+ airtimeconfigfile="airtime"
+ oldconfigfile="airtime-vhost"
+ fi
+
+ # If we're upgrading (installing over an existing Airtime install) and we've been told to
+ # install apache, we should overwrite any existing configuration. If we don't do this, doing
+ # an in-place installation over an old Airtime install (which installs to /usr/share by default)
+ # will fail
+ if [ "$upgrade" = "t" -o ! -f /etc/apache2/sites-available/${airtimeconfigfile} ]; then
+ verbose "\n * Creating Apache config for Airtime..."
+
+ if [ "$apacheversion" != "1" ]; then
+ sed -e "s@WEB_ROOT@${web_root}@g" ${SCRIPT_DIR}/installer/apache/airtime-vhost-2.4 > /etc/apache2/sites-available/${airtimeconfigfile}
+ else
+ sed -e "s@WEB_ROOT@${web_root}@g" ${SCRIPT_DIR}/installer/apache/airtime-vhost > /etc/apache2/sites-available/${airtimeconfigfile}
+ fi
+ loudCmd "a2dissite 000-default"
+ # If Airtime was previously installed with apt, the vhost file name is different,
+ # so we need to specifically disable it.
+ if [ -f "/etc/apache2/sites-available/${oldconfigfile}" ]; then
+ loudCmd "a2dissite airtime-vhost"
+ fi
+ loudCmd "a2ensite airtime"
+ else
+ verbose "\nApache config for Airtime already exists, skipping"
+ fi
+fi
+
+if [ "$icecast" = "f" -a ${_i} -eq 1 ]; then
+ echo -e "Install default Airtime Icecast configuration? (Y/n): \c"
+ read IN
+ if [ "$IN" = "y" -o "$IN" = "Y" ]; then
+ icecast="t"
+ fi
+fi
+
+if [ "$icecast" = "t" ]; then
+ loud "\n-----------------------------------------------------"
+ loud " * Configuring Icecast * "
+ loud "-----------------------------------------------------"
+
+ verbose "\n * Enabling Icecast 2..."
+ sed -i 's/ENABLE=false/ENABLE=true/g' /etc/default/icecast2
+ set +e
+ loudCmd "service icecast2 start"
+ set -e
+ verbose "...Done"
+fi
+
+loud "\n-----------------------------------------------------"
+loud " * Installing Airtime Services * "
+loud "-----------------------------------------------------"
+
+verbose "\n * Installing necessary python services..."
+loudCmd "pip install setuptools"
+verbose "...Done"
+
+verbose "\n * Creating /run/airtime..."
+mkdir -p /run/airtime
+chmod 755 /run/airtime
+chown -R ${web_user}:${web_user} /run/airtime
+verbose "...Done"
+
+verbose "\n * Installing log writer..."
+loudCmd "python ${AIRTIMEROOT}/python_apps/std_err_override/setup.py install --install-scripts=/usr/bin"
+verbose "...Done"
+
+verbose "\n * Installing API client..."
+loudCmd "python ${AIRTIMEROOT}/python_apps/api_clients/setup.py install --install-scripts=/usr/bin"
+verbose "...Done"
+
+verbose "\n * Installing media-monitor..."
+loudCmd "python ${AIRTIMEROOT}/python_apps/media-monitor/setup.py install --install-scripts=/usr/bin"
+verbose "...Done"
+
+verbose "\n * Installing pypo..."
+loudCmd "python ${AIRTIMEROOT}/python_apps/pypo/setup.py install --install-scripts=/usr/bin"
+verbose "...Done"
+
+for i in /etc/init/airtime*.template; do
+ chmod 644 $i
+ sed -i "s/WEB_USER/${web_user}/g" $i
+ mv $i ${i%.template}
+done
+
+set +e
+loudCmd "initctl reload-configuration"
+loudCmd "systemctl daemon-reload" #systemd hipsters
+loudCmd "update-rc.d airtime-playout defaults" # Start at bootup, on Debian
+loudCmd "update-rc.d airtime-media-monitor defaults" # Start at bootup, on Debian
+loudCmd "update-rc.d airtime-liquidsoap defaults" # Start at bootup, on Debian
+set -e
+
+if [ ! -d /var/log/airtime ]; then
+ loud "\n-----------------------------------------------------"
+ loud " * Installing Log Files * "
+ loud "-----------------------------------------------------"
+
+ verbose "\n * Creating /var/tmp/airtime..."
+ mkdir -p /var/tmp/airtime/show-recorder/
+
+ verbose "\n * Copying logrotate files..."
+ cp ${AIRTIMEROOT}/airtime_mvc/build/airtime-php.logrotate /etc/logrotate.d/airtime-php
+ cp ${AIRTIMEROOT}/python_apps/pypo/pypo/liquidsoap_scripts/airtime-liquidsoap.logrotate /etc/logrotate.d/airtime-liquidsoap
+fi
+
+verbose "\n * Setting permissions on /var/log/airtime..."
+chmod -R a+x /var/log/airtime
+chown -R ${web_user}:${web_user} /var/log/airtime/
+
+verbose "\n * Setting permissions on /var/tmp/airtime..."
+chmod -R a+x /var/tmp/airtime
+chown -R ${web_user}:${web_user} /var/tmp/airtime/
+
+# PHP Config File for Apache
+if [ ! -f "/etc/php5/apache2/conf.d/airtime.ini" ]; then
+ verbose "\n * Creating Airtime PHP config for Apache..."
+ cp ${SCRIPT_DIR}/installer/php/airtime.ini /etc/php5/apache2/conf.d/airtime.ini
+else
+ verbose "\nAirtime PHP config for Apache already exists, skipping"
+fi
+
+# Enable Apache modules
+loudCmd "a2enmod rewrite php5"
+
+loud "\n-----------------------------------------------------"
+loud " * Configuring PostgreSQL * "
+loud "-----------------------------------------------------"
+
+# Ensure postgres is running - It isn't after you install the postgres package on Ubuntu 15.04
+loudCmd "service postgresql start"
+
+setupAirtimePostgresUser() {
+ # here-doc to execute this block as postgres user
+ su postgres <<'EOF'
+ set +e
+ psql -d postgres -tAc "CREATE USER airtime WITH ENCRYPTED PASSWORD 'airtime'; ALTER USER airtime CREATEDB;"
+ set -e
+# don't indent this!
+EOF
+}
+
+if [ "$postgres" = "t" ]; then
+ setupAirtimePostgresUser
+elif [ ${_i} -eq 1 ]; then
+ echo -e "Create default airtime postgres user? (Y/n): \c"
+ read IN
+ if [ "$IN" = "y" -o "$IN" = "Y" ]; then
+ setupAirtimePostgresUser
+ fi
+fi
+
+loud "\n-----------------------------------------------------"
+loud " * Configuring RabbitMQ * "
+loud "-----------------------------------------------------"
+
+RABBITMQ_VHOST=/airtime
+RABBITMQ_USER=airtime
+RABBITMQ_PASSWORD=airtime
+EXCHANGES="airtime-pypo|pypo-fetch|airtime-media-monitor|media-monitor"
+
+# Ignore errors in this check to avoid dying when vhost isn't found
+set +e
+rabbitmqctl list_vhosts | grep -w ${RABBITMQ_VHOST} > /dev/null
+RESULT="$?"
+set -e
+
+# Only run these if the vhost doesn't exist
+if [ "$RESULT" != "0" ]; then
+ verbose "\n * Creating RabbitMQ user ${RABBITMQ_USER}..."
+
+ rabbitmqctl add_vhost ${RABBITMQ_VHOST}
+ rabbitmqctl add_user ${RABBITMQ_USER} ${RABBITMQ_PASSWORD}
+else
+ verbose "\nRabbitMQ user already exists, skipping creation"
+fi
+
+verbose "\n * Setting RabbitMQ user permissions..."
+loudCmd "rabbitmqctl set_permissions -p ${RABBITMQ_VHOST} ${RABBITMQ_USER} \"$EXCHANGES\" \"$EXCHANGES\" \"$EXCHANGES\""
+
+if [ ! -d "/etc/airtime" ]; then
+ loud "\n-----------------------------------------------------"
+ loud " * Installing Airtime * "
+ loud "-----------------------------------------------------"
+
+ verbose "\n * Creating /etc/airtime/ directory..."
+ mkdir /etc/airtime
+fi
+chown -R ${web_user}:${web_user} /etc/airtime
+
+if [ ! -d "/srv/airtime" ]; then
+ mkdir -p /srv/airtime
+fi
+chown -R ${web_user}:${web_user} /srv/airtime
+
+
+# We only generate the locales for Airtime if you're allowing us
+# to install our dependencies, so that we won't automatically do this
+# when this install script runs from our DEB package.
+if [ "$ignore_dependencies" = "f" ]; then
+ loud "\n-----------------------------------------------------"
+ loud " * Installing Locales * "
+ loud "-----------------------------------------------------"
+
+ set +e
+ verbose "\n * Generating locales"
+ for i in `ls ${web_root}/../locale | grep ".._.."`; do
+ if [ "$dist" = "debian" ]; then
+ grep -qi "^$i" /etc/locale.gen
+ if [ $? -ne 0 ]; then
+ verbose "$i.UTF-8 UTF-8" >> /etc/locale.gen
+ fi
+ else
+ loudCmd "locale-gen \"$i.utf8\""
+ fi
+ done
+ set -e
+
+ if [ "$dist" = "debian" ]; then
+ loudCmd "/usr/sbin/locale-gen"
+ fi
+fi
+
+verbose "\n * Reloading apache..."
+loudCmd "service apache2 reload 2>/dev/null"
+
+IP=$(ifconfig eth0 2>/dev/null|awk '/inet addr:/ {print $2}'|sed 's/addr://')
+
+echo -e "\n-----------------------------------------------------"
+echo " * Basic Setup DONE! * "
+echo " "
+echo " To get started with Airtime, visit ${IP} "
+echo " or, if you've set up your own web configuration, "
+echo " the Airtime webroot on your webserver "
+echo "-----------------------------------------------------"
diff --git a/install_full/debian/airtime-full-install b/install_full/debian/airtime-full-install
deleted file mode 100755
index 805f1ee7e..000000000
--- a/install_full/debian/airtime-full-install
+++ /dev/null
@@ -1,14 +0,0 @@
-#!/bin/bash
-#
-# Auto install script for airtime on Debian
-
-
-#Current dir
-# Absolute path to this script, e.g. /home/user/bin/foo.sh
-SCRIPT=`readlink -f $0`
-# Absolute path this script is in, thus /home/user/bin
-SCRIPTPATH=`dirname $SCRIPT`
-
-cd $SCRIPTPATH/../ubuntu
-./airtime-full-install
-
diff --git a/install_full/nginx/airtime-vhost b/install_full/nginx/airtime-vhost
deleted file mode 100644
index 069bf970a..000000000
--- a/install_full/nginx/airtime-vhost
+++ /dev/null
@@ -1,56 +0,0 @@
-# This file is contributed by Eugene MechanisM
-# Link to the post:
-# http://forum.sourcefabric.org/discussion/13563/first-step-to-run-airtime-via-nginx-based-on-airtime-2.0-beta-files
-
-upstream php5-fpm {
- ip_hash;
- server unix:/var/run/airtime.php.sock;
-}
-server {
- listen 80;
- server_name airtime; #change to your host
- include mime.types;
- root /usr/share/airtime/public;
- access_log /var/log/airtime.access.log;
- error_log /var/log/airtime.error.log;
- index index.php;
- include fastcgi_params;
- client_max_body_size 1G;
-
- location ~* ^.+\.(css|js|jpg|jpeg|gif|png|ico|gz|svg|svgz|ttf|otf|woff|eot|mp4|ogg|ogv|webm)$ {
- expires max;
- access_log off;
- add_header Pragma public;
- add_header Cache-Control "public, must-revalidate, proxy-revalidate";
- }
- location / {
- if (-e $request_filename){
- set $rule_0 1;
- }
- if ($request_filename ~ "-l"){
- set $rule_0 1;
- }
- if (-d $request_filename){
- set $rule_0 1;
- }
- rewrite ^/.*$ /index.php last;
- try_files $uri $uri/ index.php;
-
- }
- location ~ \.php$ {
- include fastcgi_params;
- fastcgi_pass php5-fpm;
- }
- location = /favicon.ico {
- log_not_found off;
- access_log off;
- }
- location = /robots.txt {
- allow all;
- log_not_found off;
- access_log off;
- }
- location ~ /\.ht {
- deny all;
- }
-}
diff --git a/install_full/php5-fpm/airtime.conf b/install_full/php5-fpm/airtime.conf
deleted file mode 100644
index cb0e2f335..000000000
--- a/install_full/php5-fpm/airtime.conf
+++ /dev/null
@@ -1,250 +0,0 @@
-# NGINX changes are contributed by Eugene MechanisM
-# Link to the post:
-# http://forum.sourcefabric.org/discussion/13563/first-step-to-run-airtime-via-nginx-based-on-airtime-2.0-beta-files
-
-; Start a new pool named 'airtime'.
-; the variable $pool can we used in any directive and will be replaced by the
-; pool name ('airtime' here)
-[airtime]
-
-; Per pool prefix
-; It only applies on the following directives:
-; - 'slowlog'
-; - 'listen' (unixsocket)
-; - 'chroot'
-; - 'chdir'
-; - 'php_values'
-; - 'php_admin_values'
-; When not set, the global prefix (or /usr) applies instead.
-; Note: This directive can also be relative to the global prefix.
-; Default Value: none
-;prefix = /path/to/pools/$pool
-
-; The address on which to accept FastCGI requests.
-; Valid syntaxes are:
-; 'ip.add.re.ss:port' - to listen on a TCP socket to a specific address on
-; a specific port;
-; 'port' - to listen on a TCP socket to all addresses on a
-; specific port;
-; '/path/to/unix/socket' - to listen on a unix socket.
-; Note: This value is mandatory.
-listen = '/var/run/airtime.php.sock'
-
-; Set listen(2) backlog. A value of '-1' means unlimited.
-; Default Value: 128 (-1 on FreeBSD and OpenBSD)
-;listen.backlog = -1
-
-; List of ipv4 addresses of FastCGI clients which are allowed to connect.
-; Equivalent to the FCGI_WEB_SERVER_ADDRS environment variable in the original
-; PHP FCGI (5.2.2+). Makes sense only with a tcp listening socket. Each address
-; must be separated by a comma. If this value is left blank, connections will be
-; accepted from any ip address.
-; Default Value: any
-;listen.allowed_clients = 127.0.0.1
-
-; Set permissions for unix socket, if one is used. In Linux, read/write
-; permissions must be set in order to allow connections from a web server. Many
-; BSD-derived systems allow connections regardless of permissions.
-; Default Values: user and group are set as the running user
-; mode is set to 0666
-;listen.owner = www-data
-;listen.group = www-data
-;listen.mode = 0666
-
-; Unix user/group of processes
-; Note: The user is mandatory. If the group is not set, the default user's group
-; will be used.
-user = www-data
-group = www-data
-
-; Choose how the process manager will control the number of child processes.
-; Possible Values:
-; static - a fixed number (pm.max_children) of child processes;
-; dynamic - the number of child processes are set dynamically based on the
-; following directives:
-; pm.max_children - the maximum number of children that can
-; be alive at the same time.
-; pm.start_servers - the number of children created on startup.
-; pm.min_spare_servers - the minimum number of children in 'idle'
-; state (waiting to process). If the number
-; of 'idle' processes is less than this
-; number then some children will be created.
-; pm.max_spare_servers - the maximum number of children in 'idle'
-; state (waiting to process). If the number
-; of 'idle' processes is greater than this
-; number then some children will be killed.
-; Note: This value is mandatory.
-pm = dynamic
-
-; The number of child processes to be created when pm is set to 'static' and the
-; maximum number of child processes to be created when pm is set to 'dynamic'.
-; This value sets the limit on the number of simultaneous requests that will be
-; served. Equivalent to the ApacheMaxClients directive with mpm_prefork.
-; Equivalent to the PHP_FCGI_CHILDREN environment variable in the original PHP
-; CGI.
-; Note: Used when pm is set to either 'static' or 'dynamic'
-; Note: This value is mandatory.
-pm.max_children = 10
-
-; The number of child processes created on startup.
-; Note: Used only when pm is set to 'dynamic'
-; Default Value: min_spare_servers + (max_spare_servers - min_spare_servers) / 2
-pm.start_servers = 4
-
-; The desired minimum number of idle server processes.
-; Note: Used only when pm is set to 'dynamic'
-; Note: Mandatory when pm is set to 'dynamic'
-pm.min_spare_servers = 2
-
-; The desired maximum number of idle server processes.
-; Note: Used only when pm is set to 'dynamic'
-; Note: Mandatory when pm is set to 'dynamic'
-pm.max_spare_servers = 6
-
-; The number of requests each child process should execute before respawning.
-; This can be useful to work around memory leaks in 3rd party libraries. For
-; endless request processing specify '0'. Equivalent to PHP_FCGI_MAX_REQUESTS.
-; Default Value: 0
-;pm.max_requests = 500
-
-; The URI to view the FPM status page. If this value is not set, no URI will be
-; recognized as a status page. By default, the status page shows the following
-; information:
-; accepted conn - the number of request accepted by the pool;
-; pool - the name of the pool;
-; process manager - static or dynamic;
-; idle processes - the number of idle processes;
-; active processes - the number of active processes;
-; total processes - the number of idle + active processes.
-; max children reached - number of times, the process limit has been reached,
-; when pm tries to start more children (works only for
-; pm 'dynamic')
-; The values of 'idle processes', 'active processes' and 'total processes' are
-; updated each second. The value of 'accepted conn' is updated in real time.
-; Example output:
-; accepted conn: 12073
-; pool: www
-; process manager: static
-; idle processes: 35
-; active processes: 65
-; total processes: 100
-; max children reached: 1
-; By default the status page output is formatted as text/plain. Passing either
-; 'html' or 'json' as a query string will return the corresponding output
-; syntax. Example:
-; http://www.foo.bar/status
-; http://www.foo.bar/status?json
-; http://www.foo.bar/status?html
-; Note: The value must start with a leading slash (/). The value can be
-; anything, but it may not be a good idea to use the .php extension or it
-; may conflict with a real PHP file.
-; Default Value: not set
-;pm.status_path = /status
-
-; The ping URI to call the monitoring page of FPM. If this value is not set, no
-; URI will be recognized as a ping page. This could be used to test from outside
-; that FPM is alive and responding, or to
-; - create a graph of FPM availability (rrd or such);
-; - remove a server from a group if it is not responding (load balancing);
-; - trigger alerts for the operating team (24/7).
-; Note: The value must start with a leading slash (/). The value can be
-; anything, but it may not be a good idea to use the .php extension or it
-; may conflict with a real PHP file.
-; Default Value: not set
-;ping.path = /ping
-
-; This directive may be used to customize the response of a ping request. The
-; response is formatted as text/plain with a 200 response code.
-; Default Value: pong
-;ping.response = pong
-
-; The timeout for serving a single request after which the worker process will
-; be killed. This option should be used when the 'max_execution_time' ini option
-; does not stop script execution for some reason. A value of '0' means 'off'.
-; Available units: s(econds)(default), m(inutes), h(ours), or d(ays)
-; Default Value: 0
-;request_terminate_timeout = 0
-
-; The timeout for serving a single request after which a PHP backtrace will be
-; dumped to the 'slowlog' file. A value of '0s' means 'off'.
-; Available units: s(econds)(default), m(inutes), h(ours), or d(ays)
-; Default Value: 0
-;request_slowlog_timeout = 0
-
-; The log file for slow requests
-; Default Value: not set
-; Note: slowlog is mandatory if request_slowlog_timeout is set
-;slowlog = log/$pool.log.slow
-
-; Set open file descriptor rlimit.
-; Default Value: system defined value
-;rlimit_files = 1024
-
-; Set max core size rlimit.
-; Possible Values: 'unlimited' or an integer greater or equal to 0
-; Default Value: system defined value
-;rlimit_core = 0
-
-; Chroot to this directory at the start. This value must be defined as an
-; absolute path. When this value is not set, chroot is not used.
-; Note: you can prefix with '$prefix' to chroot to the pool prefix or one
-; of its subdirectories. If the pool prefix is not set, the global prefix
-; will be used instead.
-; Note: chrooting is a great security feature and should be used whenever
-; possible. However, all PHP paths will be relative to the chroot
-; (error_log, sessions.save_path, ...).
-; Default Value: not set
-;chroot =
-
-; Chdir to this directory at the start.
-; Note: relative path can be used.
-; Default Value: current directory or / when chroot
-chdir = /
-
-; Redirect worker stdout and stderr into main error log. If not set, stdout and
-; stderr will be redirected to /dev/null according to FastCGI specs.
-; Note: on highloaded environement, this can cause some delay in the page
-; process time (several ms).
-; Default Value: no
-;catch_workers_output = yes
-
-; Pass environment variables like LD_LIBRARY_PATH. All $VARIABLEs are taken from
-; the current environment.
-; Default Value: clean env
-;env[HOSTNAME] = $HOSTNAME
-;env[PATH] = /usr/local/bin:/usr/bin:/bin
-;env[TMP] = /tmp
-;env[TMPDIR] = /tmp
-;env[TEMP] = /tmp
-
-; Additional php.ini defines, specific to this pool of workers. These settings
-; overwrite the values previously defined in the php.ini. The directives are the
-; same as the PHP SAPI:
-; php_value/php_flag - you can set classic ini defines which can
-; be overwritten from PHP call 'ini_set'.
-; php_admin_value/php_admin_flag - these directives won't be overwritten by
-; PHP call 'ini_set'
-; For php_*flag, valid values are on, off, 1, 0, true, false, yes or no.
-
-; Defining 'extension' will load the corresponding shared extension from
-; extension_dir. Defining 'disable_functions' or 'disable_classes' will not
-; overwrite previously defined php.ini values, but will append the new value
-; instead.
-
-; Note: path INI options can be relative and will be expanded with the prefix
-; (pool, global or /usr)
-
-; Default Value: nothing is defined by default except the values in php.ini and
-; specified at startup with the -d argument
-;php_admin_value[sendmail_path] = /usr/sbin/sendmail -t -i -f www@my.domain.com
-;php_flag[display_errors] = off
-;php_admin_value[error_log] = /var/log/fpm-php.www.log
-;php_admin_flag[log_errors] = on
-;php_admin_value[memory_limit] = 32M
-
-php_admin_value[error_log] = /var/log/airtime.php-fpm.error.log
-php_admin_value[post_max_size] = 500M
-php_admin_value[upload_max_filesize] = 500M
-php_admin_value[request_order] = GPC
-php_admin_value[session.gc_probability] = 0
-php_admin_value[upload_tmp_dir] = /tmp
diff --git a/install_full/ubuntu/airtime-full-install b/install_full/ubuntu/airtime-full-install
deleted file mode 100755
index 5bd4a6485..000000000
--- a/install_full/ubuntu/airtime-full-install
+++ /dev/null
@@ -1,216 +0,0 @@
-#!/bin/bash -e
-#
-# Auto install script for airtime on Ubuntu
-#
-# NGINX changes are contributed by Eugene MechanisM
-# Link to the post:
-# http://forum.sourcefabric.org/discussion/13563/first-step-to-run-airtime-via-nginx-based-on-airtime-2.0-beta-files
-
-exec > >(tee install_log.txt)
-exec 2>&1
-
-if [ "$(id -u)" != "0" ]; then
- echo "Please run as root user."
- exit 1
-fi
-
-server="$1"
-
-#Current dir
-# Absolute path to this script, e.g. /home/user/bin/foo.sh
-SCRIPT=`readlink -f $0`
-# Absolute path this script is in, thus /home/user/bin
-SCRIPTPATH=`dirname $SCRIPT`
-
-#Prerequisite
-echo "----------------------------------------------------"
-echo " 1. Install Packages"
-echo "----------------------------------------------------"
-
-dist=`lsb_release -is`
-code=`lsb_release -cs`
-
-#enable squeeze backports to get lame packages
-if [ "$dist" = "Debian" -a "$code" = "squeeze" ]; then
- set +e
- grep -E "deb http://backports.debian.org/debian-backports squeeze-backports main" /etc/apt/sources.list
- returncode=$?
- set -e
- if [ "$returncode" -ne "0" ]; then
- echo "deb http://backports.debian.org/debian-backports squeeze-backports main" >> /etc/apt/sources.list
- fi
-fi
-
-codename=`lsb_release -sc`
-set +e
-grep -E "deb +http://apt.sourcefabric.org/? +$codename +main" /etc/apt/sources.list
-returncode=$?
-set -e
-if [ "$returncode" != "0" ]; then
- echo "deb http://apt.sourcefabric.org/ $codename main" >> /etc/apt/sources.list
-fi
-
-apt-get update
-
-# Updated package list
-apt-get -y --force-yes install tar gzip curl php5-pgsql \
-php-pear php5-gd postgresql odbc-postgresql python libsoundtouch-ocaml \
-libtaglib-ocaml libao-ocaml libmad-ocaml ecasound \
-libesd0 libportaudio2 libsamplerate0 rabbitmq-server patch \
-php5-curl mpg123 monit python-virtualenv multitail libcamomile-ocaml-data \
-libpulse0 vorbis-tools lsb-release lsof sudo mp3gain vorbisgain flac vorbis-tools \
-pwgen libfaad2 php-apc
-
-
-#install packages with --force-yes option (this is useful in the case
-#of Debian, where these packages are unauthorized)
-apt-get -y --force-yes install libmp3lame-dev lame icecast2
-
-#Debian Squeeze only has zendframework package. Newer versions of Ubuntu have zend-framework package.
-#Ubuntu Lucid has both zendframework and zend-framework. Difference appears to be that zendframework is for
-#1.10 and zend-framework is 1.11
-if [ "$dist" = "Debian" ]; then
- apt-get -y --force-yes install zendframework
-else
- apt-get -y --force-yes install libzend-framework-php
-fi
-
-#get the "timeout" unix command
-if [ "$code" = "lucid" ]; then
- apt-get -y --force-yes install timeout
-else
- apt-get -y --force-yes install coreutils
-fi
-
-#install aac package only available in new distributions: (Debian Wheezy, Ubuntu Precise or newer)
-if [ "$code" != "squeeze" -a "$code" != "lucid" ]; then
- apt-get -y --force-yes install libvo-aacenc0
-fi
-
-#Install some plugin packages on Ubuntu Saucy.
-if [ "$dist" = "Ubuntu" -a "$code" = "saucy" ]; then
- apt-get -y --force-yes install php5-json
- apt-get -y --force-yes install liquidsoap-plugin-alsa liquidsoap-plugin-ao liquidsoap-plugin-faad liquidsoap-plugin-flac liquidsoap-plugin-icecast liquidsoap-plugin-lame liquidsoap-plugin-mad liquidsoap-plugin-ogg liquidsoap-plugin-opus liquidsoap-plugin-portaudio liquidsoap-plugin-pulseaudio liquidsoap-plugin-taglib liquidsoap-plugin-voaacenc liquidsoap-plugin-vorbis
-
-fi
-
-#Install packages back-ported by Sourcefabric
-apt-get -y --force-yes install sourcefabric-keyring
-apt-get -y --force-yes install liquidsoap
-apt-get -y --force-yes install silan
-apt-get -y --force-yes install libopus0
-
-if [ "$server" = "nginx" ]; then
- apt-get -y --force-yes install nginx php5-fpm
- # NGINX Config File
- echo "----------------------------------------------------"
- echo "2.1 NGINX Config File"
- echo "----------------------------------------------------"
- if [ ! -f /etc/nginx/sites-available/airtime ]; then
- cp $SCRIPTPATH/../nginx/airtime-vhost /etc/nginx/sites-available/airtime
- ln -s /etc/nginx/sites-available/airtime /etc/nginx/sites-enabled/airtime
- service nginx reload
- else
- echo "NGINX config for Airtime already exists..."
- fi
-
- # php-fpm Airtime pool file
- echo "----------------------------------------------------"
- echo "2.2 Airtime php pool file"
- echo "----------------------------------------------------"
- if [ ! -f /etc/php5/fpm/pool.d/airtime.conf ]; then
- cp $SCRIPTPATH/../php5-fpm/airtime.conf /etc/php5/fpm/pool.d/airtime.conf
- service php5-fpm reload
- else
- echo "Airtime php pool file already exists..."
- fi
-else
- apt-get -y --force-yes install apache2 libapache2-mod-php5
- set +e
- apache2 -v | grep "2\.4" > /dev/null
- apacheversion=$?
- set -e
-
-
- # Apache Config File
- echo "----------------------------------------------------"
- echo "2.1 Apache Config File"
- echo "----------------------------------------------------"
-
- if [ "$apacheversion" != "1" ]; then
- airtimeconfigfile="airtime.conf"
- else
- airtimeconfigfile="airtime"
- fi
-
- if [ ! -f /etc/apache2/sites-available/$airtimeconfigfile ]; then
- echo "Creating Apache config for Airtime..."
-
- cp $SCRIPTPATH/../apache/airtime-vhost /etc/apache2/sites-available/$airtimeconfigfile
- a2dissite 000-default
- a2ensite airtime
- else
- echo "Apache config for Airtime already exists..."
- fi
-
- if [ ! -d /usr/share/airtime/public ]; then
- echo "Creating Apache web root directory..."
- mkdir -p /usr/share/airtime/public/
- else
- echo "Airtime web root directory already exists..."
- fi
-
- # PHP Config File for Apache
- echo "----------------------------------------------------"
- echo "2.2 PHP Config File for Apache"
- echo "----------------------------------------------------"
- if [ ! -f /etc/php5/apache2/airtime.ini ]; then
- echo "Creating Airtime PHP config for Apache..."
- cp $SCRIPTPATH/../php5/airtime.ini /etc/php5/apache2/conf.d/airtime.ini
- else
- echo "Airtime PHP config for Apache already exists..."
- fi
-
- # Enable modules and restart Apache to enable any configuration changes
- echo "----------------------------------------------------"
- echo "2.3 Enable Apache Modules and Restart Apache"
- echo "----------------------------------------------------"
- a2enmod rewrite php5
- service apache2 restart
-fi
-
-# Enable Icecast
-echo "----------------------------------------------------"
-echo "3. Enable Icecast"
-echo "----------------------------------------------------"
-cd /etc/default/
-sed -i 's/ENABLE=false/ENABLE=true/g' icecast2
-set +e
-service icecast2 start
-set -e
-echo ""
-
-# Enable Monit
-echo "----------------------------------------------------"
-echo "4. Enable Monit"
-echo "----------------------------------------------------"
-cd /etc/default/
-sed -i 's/startup=0/startup=1/g' monit
-
-set +e
-grep -q "include /etc/monit/conf.d" /etc/monit/monitrc
-RETVAL=$?
-set -e
-if [ $RETVAL -ne 0 ] ; then
- mkdir -p /etc/monit/conf.d
- echo "include /etc/monit/conf.d/*" >> /etc/monit/monitrc
-fi
-
-# Run Airtime Install
-echo "----------------------------------------------------"
-echo "5. Run Airtime Install"
-echo "----------------------------------------------------"
-cd $SCRIPTPATH/../../install_minimal
-# Restart apache to clear php cache
-service apache2 restart
-./airtime-install
diff --git a/install_full/ubuntu/airtime-full-install-nginx b/install_full/ubuntu/airtime-full-install-nginx
deleted file mode 100755
index 7f55a3aa2..000000000
--- a/install_full/ubuntu/airtime-full-install-nginx
+++ /dev/null
@@ -1,10 +0,0 @@
-#!/bin/bash
-# Auto install script for airtime + nginx
-
-# Absolute path to this script, e.g. /home/user/bin/foo.sh
-SCRIPT=`readlink -f $0`
-# Absolute path this script is in, thus /home/user/bin
-SCRIPTPATH=`dirname $SCRIPT`
-
-$SCRIPTPATH/airtime-full-install nginx
-
diff --git a/install_minimal/DoctrineMigrations/Version20110312121200.php b/install_minimal/DoctrineMigrations/Version20110312121200.php
deleted file mode 100644
index 8bf20d856..000000000
--- a/install_minimal/DoctrineMigrations/Version20110312121200.php
+++ /dev/null
@@ -1,19 +0,0 @@
-dropTable("cc_backup");
- $schema->dropTable("cc_trans");
- }
-
- public function down(Schema $schema)
- {
- }
-}
diff --git a/install_minimal/DoctrineMigrations/Version20110331111708.php b/install_minimal/DoctrineMigrations/Version20110331111708.php
deleted file mode 100644
index d355566a9..000000000
--- a/install_minimal/DoctrineMigrations/Version20110331111708.php
+++ /dev/null
@@ -1,96 +0,0 @@
-getTable('cc_show_instances');
-
- $show_instances_table->addColumn('record', 'smallint', array('notnull' => 0, 'default' => 0));
- $show_instances_table->addColumn('rebroadcast', 'smallint', array('notnull' => 0, 'default' => 0));
- $show_instances_table->addColumn('instance_id', 'integer', array('notnull' => 0));
- $show_instances_table->addColumn('file_id', 'integer', array('notnull' => 0));
- $show_instances_table->addColumn('soundcloud_id', 'integer', array('notnull' => 0));
-
- $show_instances_table->addNamedForeignKeyConstraint('cc_original_show_instance_fkey', $show_instances_table, array('instance_id'), array('id'), array('onDelete' => 'CASCADE'));
-
- $files_table = $schema->getTable('cc_files');
- $show_instances_table->addNamedForeignKeyConstraint('cc_recorded_file_fkey', $files_table, array('file_id'), array('id'), array('onDelete' => 'CASCADE'));
- //end cc_show_instances modifications
-
- //start cc_show_days modifications
- $show_days_table = $schema->getTable('cc_show_days');
-
- $show_days_table->addColumn('record', 'smallint', array( 'notnull' => 0, 'default' => 0));
- //end cc_show_days modifications
-
- //start cc_show modifications
- $show_table = $schema->getTable('cc_show');
-
- $show_table->addColumn('url', 'string', array('notnull' => 0, 'length' => 255));
- //end cc_show modifications
-
- //start cc_schedule modifications
- $schedule_table = $schema->getTable('cc_schedule');
-
- $playlist_id_col = $schedule_table->getColumn('playlist_id');
- $playlist_id_col->setNotnull(false);
- //end cc_schedule modifications
-
- //create cc_show_rebroadcast table
- $cc_show_rebroadcast_table = $schema->createTable('cc_show_rebroadcast');
-
- $cc_show_rebroadcast_table->addColumn('id', 'integer', array('unsigned' => true, 'autoincrement' => true));
- $cc_show_rebroadcast_table->addColumn('day_offset', 'string', array('length' => 255));
- $cc_show_rebroadcast_table->addColumn('start_time', 'datetime', array('notnull' => 1));
- $cc_show_rebroadcast_table->addColumn('show_id', 'integer', array('notnull' => 1));
-
- $cc_show_rebroadcast_table->setPrimaryKey(array('id'));
- //end create cc_show_rebroadcast table
- }
-
- public function down(Schema $schema)
- {
- //start cc_show_instances modifications
- $show_instances_table = $schema->getTable('cc_show_instances');
-
- $show_instances_table->dropColumn('record');
- $show_instances_table->dropColumn('rebroadcast');
- $show_instances_table->dropColumn('instance_id');
- $show_instances_table->dropColumn('file_id');
- $show_instances_table->dropColumn('soundcloud_id');
- //end cc_show_instances modifications
-
- //start cc_show_days modifications
- $show_days_table = $schema->getTable('cc_show_days');
-
- $show_days_table->dropColumn('record');
- //end cc_show_days modifications
-
- //start cc_show modifications
- $show_table = $schema->getTable('cc_show');
-
- $show_table->dropColumn('url');
- //end cc_show modifications
-
- //start cc_schedule modifications
- $schedule_table = $schema->getTable('cc_schedule');
-
- $playlist_id_col = $schedule_table->getColumn('playlist_id');
- $playlist_id_col->setNotnull(true);
- //end cc_schedule modifications
-
- //drop cc_show_rebroadcast table
- $schema->dropTable('cc_show_rebroadcast');
- //end drop cc_show_rebroadcast table
- }
-}
diff --git a/install_minimal/DoctrineMigrations/Version20110402164819.php b/install_minimal/DoctrineMigrations/Version20110402164819.php
deleted file mode 100644
index d4e84145c..000000000
--- a/install_minimal/DoctrineMigrations/Version20110402164819.php
+++ /dev/null
@@ -1,28 +0,0 @@
-getTable('cc_show');
-
- $show_table->addColumn('genre', 'string', array('notnull' => 0, 'length' => 255, 'default' => ""));
- //end cc_show modifications
-
- }
-
- public function down(Schema $schema)
- {
- //start cc_show modifications
- $show_table = $schema->getTable('cc_show');
-
- $show_table->dropColumn('genre');
- //end cc_show modifications
- }
-}
diff --git a/install_minimal/DoctrineMigrations/Version20110406182005.php b/install_minimal/DoctrineMigrations/Version20110406182005.php
deleted file mode 100644
index 671b32c17..000000000
--- a/install_minimal/DoctrineMigrations/Version20110406182005.php
+++ /dev/null
@@ -1,47 +0,0 @@
-getTable('cc_show_instances');
-
- $cc_show_instances->addColumn('time_filled', 'time', array('notnull' => false));
- //end cc_show_instances modifications
-
- //start cc_show_rebroadcast modifications
- $cc_show_rebroadcast = $schema->getTable('cc_show_rebroadcast');
-
- $type = $cc_show_rebroadcast->getColumn('start_time')->getType()->getName();
- if($type == 'datetime') {
- $cc_show_rebroadcast->dropColumn('start_time');
- $cc_show_rebroadcast->addColumn('start_time', 'time', array('notnull' => true));
- }
- //end cc_show_rebroadcast modifications
- }
-
- public function down(Schema $schema)
- {
- //start cc_show_instances modifications
- $cc_show_instances = $schema->getTable('cc_show_instances');
-
- $cc_show_instances->dropColumn('time_filled');
- //end cc_show_instances modifications
-
- //start cc_show_rebroadcast modifications
- $cc_show_rebroadcast = $schema->getTable('cc_show_rebroadcast');
-
- $type = $cc_show_rebroadcast->getColumn('start_time')->getType()->getName();
- if($type == 'datetime') {
- $cc_show_rebroadcast->dropColumn('start_time');
- $cc_show_rebroadcast->addColumn('start_time', 'datetime', array('notnull' => 1));
- }
- //end cc_show_rebroadcast modifications
- }
-}
diff --git a/install_minimal/DoctrineMigrations/Version20110629143017.php b/install_minimal/DoctrineMigrations/Version20110629143017.php
deleted file mode 100644
index 162a1772b..000000000
--- a/install_minimal/DoctrineMigrations/Version20110629143017.php
+++ /dev/null
@@ -1,30 +0,0 @@
-createTable('cc_music_dirs');
-
- $cc_music_dirs->addColumn('id', 'integer', array('unsigned' => true, 'autoincrement' => true));
- $cc_music_dirs->addColumn('type', 'string', array('length' => 255));
- $cc_music_dirs->addColumn('directory', 'text', array('unique' => true));
-
- $cc_music_dirs->setPrimaryKey(array('id'));
-
- //end create cc_music_dirs table
- }
-
-
-
- public function down(Schema $schema)
- {
- $schema->dropTable('cc_music_dirs');
- }
-}
diff --git a/install_minimal/DoctrineMigrations/Version20110711161043.php b/install_minimal/DoctrineMigrations/Version20110711161043.php
deleted file mode 100644
index 388d31772..000000000
--- a/install_minimal/DoctrineMigrations/Version20110711161043.php
+++ /dev/null
@@ -1,51 +0,0 @@
-_addSql("INSERT INTO cc_music_dirs (type, directory) VALUES ('stor', $stor_dir);");
-
- $this->_addSql("INSERT INTO cc_music_dirs (type, directory) VALUES ('link', '');");
-
- $cc_music_dirs = $schema->getTable('cc_music_dirs');
-
- /* 2) create a foreign key relationship from cc_files to cc_music_dirs */
- $cc_files = $schema->getTable('cc_files');
- $cc_files->addColumn('directory', 'integer', array('notnull' => 0, 'default'=> NULL));
-
- $cc_files->addNamedForeignKeyConstraint('cc_music_dirs_folder_fkey', $cc_music_dirs, array('directory'), array('id'), array('onDelete' => 'CASCADE'));
-
- // before 3) we have to delete all entries in cc_schedule with file_id that are not in cc_file table
- $this->_addSql("DELETE FROM cc_schedule WHERE cc_schedule.id IN(
- SELECT cc_schedule.id
- FROM cc_schedule
- LEFT JOIN cc_files
- ON cc_schedule.file_id = cc_files.id
- WHERE cc_files.id IS NULL)");
-
- /* 3) create a foreign key relationship from cc_schedule to cc_files */
- $cc_schedule = $schema->getTable('cc_schedule');
- $cc_schedule->addNamedForeignKeyConstraint('cc_files_folder_fkey', $cc_files, array('file_id'), array('id'), array('onDelete' => 'CASCADE'));
- }
-
- public function down(Schema $schema)
- {
-
- }
-}
diff --git a/install_minimal/DoctrineMigrations/Version20110713161043.php b/install_minimal/DoctrineMigrations/Version20110713161043.php
deleted file mode 100644
index db44a0270..000000000
--- a/install_minimal/DoctrineMigrations/Version20110713161043.php
+++ /dev/null
@@ -1,26 +0,0 @@
-createTable('cc_country');
-
- $cc_country->addColumn('isocode', 'string', array('length' => 3));
- $cc_country->addColumn('name', 'string', array('length' => 255));
-
- $cc_country->setPrimaryKey(array('isocode'));
- //end create cc_country table
- }
-
- public function down(Schema $schema)
- {
- $schema->dropTable('cc_country');
- }
-}
\ No newline at end of file
diff --git a/install_minimal/DoctrineMigrations/Version20110829143306.php b/install_minimal/DoctrineMigrations/Version20110829143306.php
deleted file mode 100644
index 477df6a39..000000000
--- a/install_minimal/DoctrineMigrations/Version20110829143306.php
+++ /dev/null
@@ -1,27 +0,0 @@
-createTable('cc_stream_setting');
-
- $cc_stream_setting->addColumn('keyname', 'string', array('length' => 64));
- $cc_stream_setting->addColumn('value', 'string', array('length' => 255));
- $cc_stream_setting->addColumn('type', 'string', array('length' => 16));
-
- $cc_stream_setting->setPrimaryKey(array('keyname'));
- //end create cc_stream_setting table
- }
-
- public function down(Schema $schema)
- {
- $schema->dropTable('cc_stream_setting');
- }
-}
\ No newline at end of file
diff --git a/install_minimal/DoctrineMigrations/Version20110922153933.php b/install_minimal/DoctrineMigrations/Version20110922153933.php
deleted file mode 100644
index 42e10ad19..000000000
--- a/install_minimal/DoctrineMigrations/Version20110922153933.php
+++ /dev/null
@@ -1,23 +0,0 @@
-getTable('cc_files');
- $cc_files->addColumn('soundcloud_id', 'integer', array('notnull' => 0, 'default'=> NULL));
- $cc_files->addColumn('soundcloud_error_code', 'integer', array('notnull' => 0, 'default'=> NULL));
- $cc_files->addColumn('soundcloud_error_msg', 'string', array('length' => 255, 'notnull' => 0, 'default'=> NULL));
- }
-
- public function down(Schema $schema)
- {
-
- }
-}
\ No newline at end of file
diff --git a/install_minimal/DoctrineMigrations/Version20110925171051.php b/install_minimal/DoctrineMigrations/Version20110925171051.php
deleted file mode 100644
index d4aa77cff..000000000
--- a/install_minimal/DoctrineMigrations/Version20110925171051.php
+++ /dev/null
@@ -1,26 +0,0 @@
-_addSql("update cc_files as cf set soundcloud_id = csi.soundcloud_id
- from cc_show_instances as csi
- where csi.file_id = cf.id and file_id is not NULL");
-
- // remove soundcloud_id from cc_show_instance table
- $cc_show_instances = $schema->getTable('cc_show_instances');
- $cc_show_instances->dropColumn('soundcloud_id');
- }
-
- public function down(Schema $schema)
- {
-
- }
-}
\ No newline at end of file
diff --git a/install_minimal/DoctrineMigrations/Version20110925171256.php b/install_minimal/DoctrineMigrations/Version20110925171256.php
deleted file mode 100644
index b10c0a421..000000000
--- a/install_minimal/DoctrineMigrations/Version20110925171256.php
+++ /dev/null
@@ -1,29 +0,0 @@
-createTable('cc_login_attempts');
-
- $cc_login->addColumn('ip', 'string', array('length' => 32));
- $cc_login->addColumn('attempts', 'integer', array('notnull' => 0, 'default'=> 0));
-
- $cc_login->setPrimaryKey(array('ip'));
-
- // add login_attempts column to cc_subjs table
- $cc_subjs = $schema->getTable('cc_subjs');
- $cc_subjs->addColumn('login_attempts', 'integer', array('notnull' => 0, 'default'=> 0));
- }
-
- public function down(Schema $schema)
- {
-
- }
-}
\ No newline at end of file
diff --git a/install_minimal/DoctrineMigrations/Version20110929184401.php b/install_minimal/DoctrineMigrations/Version20110929184401.php
deleted file mode 100644
index 22828b054..000000000
--- a/install_minimal/DoctrineMigrations/Version20110929184401.php
+++ /dev/null
@@ -1,23 +0,0 @@
-createTable('cc_service_register');
- $cc_component->addColumn('name', 'string', array('length' => 32));
- $cc_component->addColumn('ip', 'string', array('length' => 18));
-
- $cc_component->setPrimaryKey(array('name'));
- }
-
- public function down(Schema $schema)
- {
-
- }
-}
diff --git a/install_minimal/DoctrineMigrations/Version20111102142811.php b/install_minimal/DoctrineMigrations/Version20111102142811.php
deleted file mode 100644
index d0a80da84..000000000
--- a/install_minimal/DoctrineMigrations/Version20111102142811.php
+++ /dev/null
@@ -1,25 +0,0 @@
- 'soundcloud_auto_upload_recorded_show' CC-2928
- $this->_addSql("UPDATE cc_pref SET keystr = 'soundcloud_auto_upload_recorded_show'
- WHERE keystr = 'soundcloud_upload'");
-
- // add soundcloud_link_to_file
- $cc_files = $schema->getTable('cc_files');
- $cc_files->addColumn('soundcloud_link_to_file', 'string', array('length' => 4096, 'notnull' => 0, 'default'=> NULL));
- }
-
- public function down(Schema $schema)
- {
-
- }
-}
\ No newline at end of file
diff --git a/install_minimal/DoctrineMigrations/Version20111103141311.php b/install_minimal/DoctrineMigrations/Version20111103141311.php
deleted file mode 100644
index 9be485e29..000000000
--- a/install_minimal/DoctrineMigrations/Version20111103141311.php
+++ /dev/null
@@ -1,21 +0,0 @@
-getTable('cc_show_days');
- $cc_subjs->addColumn('timezone', 'string', array('required' => true, 'default'=> ''));
- }
-
- public function down(Schema $schema)
- {
-
- }
-}
diff --git a/install_minimal/DoctrineMigrations/Version20111114222927.php b/install_minimal/DoctrineMigrations/Version20111114222927.php
deleted file mode 100644
index b0cf33379..000000000
--- a/install_minimal/DoctrineMigrations/Version20111114222927.php
+++ /dev/null
@@ -1,20 +0,0 @@
-getTable('cc_show_instances');
- $cc_show_instances->addColumn('modified_instance', 'boolean', array('notnull' => true, 'default'=> '0'));
- }
-
- public function down(Schema $schema)
- {
-
- }
-}
diff --git a/install_minimal/DoctrineMigrations/Version20120613123039.php b/install_minimal/DoctrineMigrations/Version20120613123039.php
deleted file mode 100644
index 74145ade7..000000000
--- a/install_minimal/DoctrineMigrations/Version20120613123039.php
+++ /dev/null
@@ -1,20 +0,0 @@
-getTable("cc_subjs");
- $table->addColumn("cell_phone", "string");
- }
-
- public function down(Schema $schema)
- {
-
- }
-}
diff --git a/install_minimal/DoctrineMigrations/migrations.xml b/install_minimal/DoctrineMigrations/migrations.xml
deleted file mode 100644
index c78b0c499..000000000
--- a/install_minimal/DoctrineMigrations/migrations.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
- Airtime 2.0.0 Database Upgrade
-
- DoctrineMigrations
-
-
-
- ./
-
-
diff --git a/install_minimal/airtime-dircheck.php b/install_minimal/airtime-dircheck.php
deleted file mode 100644
index d689af689..000000000
--- a/install_minimal/airtime-dircheck.php
+++ /dev/null
@@ -1,5 +0,0 @@
-&2; exit 1;;
- (*) break;;
- esac
- shift
-done
-
-if [ "$mediamonitor" = "f" -a "$pypo" = "f" -a "$web" = "f" -a "$airtime_analyzer" = "f" ]; then
- #none of these install parameters were specified, so by default we install all of them
- mediamonitor="f" # FIXME: Remove media_monitor! -- Albert
- pypo="t"
- showrecorder="t"
- airtime_analyzer="t"
- web="t"
-fi
-
-if [ "$disable_deb_check" == "f" ]; then
- set +e
- DEB=$(dpkg -s airtime 2> /dev/null | grep Status)
- set -e
- if [[ "$DEB" = "Status: install ok installed" ]]; then
- echo -e "\nDebian package of Airtime detected. Please use the debian package to upgrade.\n"
- exit 1
- fi
-fi
-
-
-#Update apt sources.list to point to the new deb-multimedia domain.
-sed -i s/www.debian-multimedia.org/www.deb-multimedia.org/g /etc/apt/sources.list
-
-# Absolute path to this script, e.g. /home/user/bin/foo.sh
-SCRIPT=`readlink -f $0`
-# Absolute path this script is in, thus /home/user/bin
-SCRIPTPATH=`dirname $SCRIPT`
-AIRTIMEROOT=$SCRIPTPATH/../
-
-echo "* Making sure /etc/default/locale is set properly"
-set +e
-update-locale
-cat /etc/default/locale | grep -i "LANG=.*UTF-\?8"
-if [ "$?" != "0" ]; then
- echo -e " * Fail\n"
- echo "A non UTF-8 default locale found in /etc/default/locale. Airtime requires
-a UTF-8 locale to run. To fix this please do the following:
-
-Ubuntu:
-Put line 'en_US.UTF-8 UTF-8' (or similar) without quotes to '/var/lib/locales/supported.d/local',
-replacing any existing lines.
-A list of supported locales is available in '/usr/share/i18n/SUPPORTED'
-Then run 'sudo dpkg-reconfigure locales'
-
-Debian:
-Run 'sudo dpkg-reconfigure locales' and use the interface to select 'en_US.UTF-8 UTF-8' (or similar).
-On the second page select this new locale as the default.
-
-After these changes have been made simply run install again.
-
-Now exiting install...
-"
- exit 1
-fi
-set -e
-
-# Check if airtime exists already
-set +e
-php --php-ini ${SCRIPTPATH}/airtime-php.ini ${SCRIPTPATH}/include/airtime-installed-check.php
-result=$?
-set -e
-
-DO_UPGRADE="0"
-if [ "$result" -eq "0" ]; then
- echo " * None found."
-
- #Make sure any straggler config files are removed. Reason for this is that they may be from
- #an older version of Airtime, but since there no database installed, we have no idea how to
- #handle these (what version are they from?).
- rm -f "/etc/airtime/airtime.conf"
- rm -f "/etc/airtime/api_client.cfg"
- rm -f "/etc/airtime/liquidsoap.cfg"
- rm -f "/etc/airtime/media-monitor.cfg"
- rm -f "/etc/airtime/pypo.cfg"
-elif [ "$result" -eq "1" -a "$reinstall" = "f" ]; then
- echo " * Same version of Airtime already installed! Reusing database."
- nodb='t'
- overwrite='f'
-elif [ "$result" -eq "2" ]; then
- echo " * Previous version of Airtime already installed..will perform upgrade."
- DO_UPGRADE="1"
-elif [ "$result" -eq "3" ]; then
- echo " * You require at least Airtime 1.8.0 installed for upgrade."
- exit 1
-fi
-
-#We don't want any of our python services running if we are doing an upgrade/reinstall.
-#They will be automatically restarted later on.
-echo "* Temporarily stopping any previous running services"
-set +e
-monit unmonitor airtime-media-monitor >/dev/null 2>&1
-monit unmonitor airtime-liquidsoap >/dev/null 2>&1
-monit unmonitor airtime-playout >/dev/null 2>&1
-set -e
-if [ -e /etc/init.d/airtime-media-monitor ]; then
- invoke-rc.d airtime-media-monitor stop > /dev/null 2>&1
-fi
-if [ -e /etc/init.d/airtime-playout ]; then
- invoke-rc.d airtime-playout stop > /dev/null 2>&1
-fi
-if [ -e /etc/init.d/airtime-liquidsoap ]; then
- invoke-rc.d airtime-liquidsoap stop > /dev/null 2>&1
-fi
-
-#export these variables to make them available in sub bash scripts
-export DO_UPGRADE
-export mediamonitor
-export airtime_analyzer
-export pypo
-export showrecorder
-export web
-export reinstall
-export nodb
-export overwrite
-export preserve
-
-set +e
-test "$mediamonitor" = "t" -o "$pypo" = "t"
-export python_service=$?
-set -e
-
-echo -e "\n******************************** Install Begin *********************************"
-rm -rf "/usr/lib/airtime"
-mkdir -p /usr/lib/airtime
-
-if [ "$python_service" -eq "0" ]; then
- $AIRTIMEROOT/python_apps/python-virtualenv/virtualenv-install.sh
-
- virtualenv_bin="/usr/lib/airtime/airtime_virtualenv/bin/"
- . ${virtualenv_bin}activate
- python $AIRTIMEROOT/python_apps/create-pypo-user.py
-fi
-
-if [ "$DO_UPGRADE" -eq "1" ]; then
- #do upgrade
- php --php-ini ${SCRIPTPATH}/airtime-php.ini ${SCRIPTPATH}/include/airtime-upgrade.php $@
-fi
-
-set +e
-if [ "$DO_UPGRADE" -eq "0" ]; then
- php --php-ini ${SCRIPTPATH}/airtime-php.ini ${SCRIPTPATH}/include/airtime-install.php $@
- result=$?
-
- if [ "$result" -ne "0" ]; then
- #There was an error, exit with error code.
- echo "There was an error during install. Exit code $result"
- exit 1
- fi
-fi
-
-rabbitmq_install
-set -e
-
-
-export airtime_service_start='t'
-$SCRIPTPATH/include/airtime-copy-files.sh
-$SCRIPTPATH/include/airtime-initialize.sh $@
-
-if [ "$mediamonitor" = "t" -o "$pypo" = "t" ]; then
- #deactivate virtualenv
- deactivate
-fi
-
-# Restart airtime_analyzer (or start it)
-service airtime_analyzer restart
-
-
-#An attempt to force apache to realize that files are updated on upgrade...
-touch /usr/share/airtime/public/index.php
-
-if [ "$python_service" -eq "0" ]; then
- #only run airtime-check-system if all components were installed
- echo -e "\n*** Verifying your system environment, running airtime-check-system ***"
- sleep 10
-
- set +e
- airtime-check-system --no-color
- set -e
-fi
-
-echo -e "\n******************************* Install Complete *******************************"
diff --git a/install_minimal/airtime-php.ini b/install_minimal/airtime-php.ini
deleted file mode 100644
index 3a12449ab..000000000
--- a/install_minimal/airtime-php.ini
+++ /dev/null
@@ -1,1854 +0,0 @@
-[PHP]
-suhosin.executor.include.whitelist="phar"
-
-;;;;;;;;;;;;;;;;;;;
-; About php.ini ;
-;;;;;;;;;;;;;;;;;;;
-; PHP's initialization file, generally called php.ini, is responsible for
-; configuring many of the aspects of PHP's behavior.
-
-; PHP attempts to find and load this configuration from a number of locations.
-; The following is a summary of its search order:
-; 1. SAPI module specific location.
-; 2. The PHPRC environment variable. (As of PHP 5.2.0)
-; 3. A number of predefined registry keys on Windows (As of PHP 5.2.0)
-; 4. Current working directory (except CLI)
-; 5. The web server's directory (for SAPI modules), or directory of PHP
-; (otherwise in Windows)
-; 6. The directory from the --with-config-file-path compile time option, or the
-; Windows directory (C:\windows or C:\winnt)
-; See the PHP docs for more specific information.
-; http://php.net/configuration.file
-
-; The syntax of the file is extremely simple. Whitespace and Lines
-; beginning with a semicolon are silently ignored (as you probably guessed).
-; Section headers (e.g. [Foo]) are also silently ignored, even though
-; they might mean something in the future.
-
-; Directives following the section heading [PATH=/www/mysite] only
-; apply to PHP files in the /www/mysite directory. Directives
-; following the section heading [HOST=www.example.com] only apply to
-; PHP files served from www.example.com. Directives set in these
-; special sections cannot be overridden by user-defined INI files or
-; at runtime. Currently, [PATH=] and [HOST=] sections only work under
-; CGI/FastCGI.
-; http://php.net/ini.sections
-
-; Directives are specified using the following syntax:
-; directive = value
-; Directive names are *case sensitive* - foo=bar is different from FOO=bar.
-; Directives are variables used to configure PHP or PHP extensions.
-; There is no name validation. If PHP can't find an expected
-; directive because it is not set or is mistyped, a default value will be used.
-
-; The value can be a string, a number, a PHP constant (e.g. E_ALL or M_PI), one
-; of the INI constants (On, Off, True, False, Yes, No and None) or an expression
-; (e.g. E_ALL & ~E_NOTICE), a quoted string ("bar"), or a reference to a
-; previously set variable or directive (e.g. ${foo})
-
-; Expressions in the INI file are limited to bitwise operators and parentheses:
-; | bitwise OR
-; ^ bitwise XOR
-; & bitwise AND
-; ~ bitwise NOT
-; ! boolean NOT
-
-; Boolean flags can be turned on using the values 1, On, True or Yes.
-; They can be turned off using the values 0, Off, False or No.
-
-; An empty string can be denoted by simply not writing anything after the equal
-; sign, or by using the None keyword:
-
-; foo = ; sets foo to an empty string
-; foo = None ; sets foo to an empty string
-; foo = "None" ; sets foo to the string 'None'
-
-; If you use constants in your value, and these constants belong to a
-; dynamically loaded extension (either a PHP extension or a Zend extension),
-; you may only use these constants *after* the line that loads the extension.
-
-;;;;;;;;;;;;;;;;;;;
-; About this file ;
-;;;;;;;;;;;;;;;;;;;
-; PHP comes packaged with two INI files. One that is recommended to be used
-; in production environments and one that is recommended to be used in
-; development environments.
-
-; php.ini-production contains settings which hold security, performance and
-; best practices at its core. But please be aware, these settings may break
-; compatibility with older or less security conscience applications. We
-; recommending using the production ini in production and testing environments.
-
-; php.ini-development is very similar to its production variant, except it's
-; much more verbose when it comes to errors. We recommending using the
-; development version only in development environments as errors shown to
-; application users can inadvertently leak otherwise secure information.
-
-;;;;;;;;;;;;;;;;;;;
-; Quick Reference ;
-;;;;;;;;;;;;;;;;;;;
-; The following are all the settings which are different in either the production
-; or development versions of the INIs with respect to PHP's default behavior.
-; Please see the actual settings later in the document for more details as to why
-; we recommend these changes in PHP's behavior.
-
-; allow_call_time_pass_reference
-; Default Value: On
-; Development Value: Off
-; Production Value: Off
-
-; display_errors
-; Default Value: On
-; Development Value: On
-; Production Value: Off
-
-; display_startup_errors
-; Default Value: Off
-; Development Value: On
-; Production Value: Off
-
-; error_reporting
-; Default Value: E_ALL & ~E_NOTICE
-; Development Value: E_ALL | E_STRICT
-; Production Value: E_ALL & ~E_DEPRECATED
-
-; html_errors
-; Default Value: On
-; Development Value: On
-; Production value: Off
-
-; log_errors
-; Default Value: Off
-; Development Value: On
-; Production Value: On
-
-; magic_quotes_gpc
-; Default Value: On
-; Development Value: Off
-; Production Value: Off
-
-; max_input_time
-; Default Value: -1 (Unlimited)
-; Development Value: 60 (60 seconds)
-; Production Value: 60 (60 seconds)
-
-; output_buffering
-; Default Value: Off
-; Development Value: 4096
-; Production Value: 4096
-
-; register_argc_argv
-; Default Value: On
-; Development Value: Off
-; Production Value: Off
-
-; register_long_arrays
-; Default Value: On
-; Development Value: Off
-; Production Value: Off
-
-; request_order
-; Default Value: None
-; Development Value: "GP"
-; Production Value: "GP"
-
-; session.bug_compat_42
-; Default Value: On
-; Development Value: On
-; Production Value: Off
-
-; session.bug_compat_warn
-; Default Value: On
-; Development Value: On
-; Production Value: Off
-
-; session.gc_divisor
-; Default Value: 100
-; Development Value: 1000
-; Production Value: 1000
-
-; session.hash_bits_per_character
-; Default Value: 4
-; Development Value: 5
-; Production Value: 5
-
-; short_open_tag
-; Default Value: On
-; Development Value: Off
-; Production Value: Off
-
-; track_errors
-; Default Value: Off
-; Development Value: On
-; Production Value: Off
-
-; url_rewriter.tags
-; Default Value: "a=href,area=href,frame=src,form=,fieldset="
-; Development Value: "a=href,area=href,frame=src,input=src,form=fakeentry"
-; Production Value: "a=href,area=href,frame=src,input=src,form=fakeentry"
-
-; variables_order
-; Default Value: "EGPCS"
-; Development Value: "GPCS"
-; Production Value: "GPCS"
-
-;;;;;;;;;;;;;;;;;;;;
-; php.ini Options ;
-;;;;;;;;;;;;;;;;;;;;
-; Name for user-defined php.ini (.htaccess) files. Default is ".user.ini"
-;user_ini.filename = ".user.ini"
-
-; To disable this feature set this option to empty value
-;user_ini.filename =
-
-; TTL for user-defined php.ini files (time-to-live) in seconds. Default is 300 seconds (5 minutes)
-;user_ini.cache_ttl = 300
-
-;;;;;;;;;;;;;;;;;;;;
-; Language Options ;
-;;;;;;;;;;;;;;;;;;;;
-
-; Enable the PHP scripting language engine under Apache.
-; http://php.net/engine
-engine = On
-
-; This directive determines whether or not PHP will recognize code between
-; and ?> tags as PHP source which should be processed as such. It's been
-; recommended for several years that you not use the short tag "short cut" and
-; instead to use the full tag combination. With the wide spread use
-; of XML and use of these tags by other languages, the server can become easily
-; confused and end up parsing the wrong code in the wrong context. But because
-; this short cut has been a feature for such a long time, it's currently still
-; supported for backwards compatibility, but we recommend you don't use them.
-; Default Value: On
-; Development Value: Off
-; Production Value: Off
-; http://php.net/short-open-tag
-short_open_tag = On
-
-; Allow ASP-style <% %> tags.
-; http://php.net/asp-tags
-asp_tags = Off
-
-; The number of significant digits displayed in floating point numbers.
-; http://php.net/precision
-precision = 14
-
-; Enforce year 2000 compliance (will cause problems with non-compliant browsers)
-; http://php.net/y2k-compliance
-y2k_compliance = On
-
-; Output buffering is a mechanism for controlling how much output data
-; (excluding headers and cookies) PHP should keep internally before pushing that
-; data to the client. If your application's output exceeds this setting, PHP
-; will send that data in chunks of roughly the size you specify.
-; Turning on this setting and managing its maximum buffer size can yield some
-; interesting side-effects depending on your application and web server.
-; You may be able to send headers and cookies after you've already sent output
-; through print or echo. You also may see performance benefits if your server is
-; emitting less packets due to buffered output versus PHP streaming the output
-; as it gets it. On production servers, 4096 bytes is a good setting for performance
-; reasons.
-; Note: Output buffering can also be controlled via Output Buffering Control
-; functions.
-; Possible Values:
-; On = Enabled and buffer is unlimited. (Use with caution)
-; Off = Disabled
-; Integer = Enables the buffer and sets its maximum size in bytes.
-; Note: This directive is hardcoded to Off for the CLI SAPI
-; Default Value: Off
-; Development Value: 4096
-; Production Value: 4096
-; http://php.net/output-buffering
-output_buffering = 4096
-
-; You can redirect all of the output of your scripts to a function. For
-; example, if you set output_handler to "mb_output_handler", character
-; encoding will be transparently converted to the specified encoding.
-; Setting any output handler automatically turns on output buffering.
-; Note: People who wrote portable scripts should not depend on this ini
-; directive. Instead, explicitly set the output handler using ob_start().
-; Using this ini directive may cause problems unless you know what script
-; is doing.
-; Note: You cannot use both "mb_output_handler" with "ob_iconv_handler"
-; and you cannot use both "ob_gzhandler" and "zlib.output_compression".
-; Note: output_handler must be empty if this is set 'On' !!!!
-; Instead you must use zlib.output_handler.
-; http://php.net/output-handler
-;output_handler =
-
-; Transparent output compression using the zlib library
-; Valid values for this option are 'off', 'on', or a specific buffer size
-; to be used for compression (default is 4KB)
-; Note: Resulting chunk size may vary due to nature of compression. PHP
-; outputs chunks that are few hundreds bytes each as a result of
-; compression. If you prefer a larger chunk size for better
-; performance, enable output_buffering in addition.
-; Note: You need to use zlib.output_handler instead of the standard
-; output_handler, or otherwise the output will be corrupted.
-; http://php.net/zlib.output-compression
-zlib.output_compression = Off
-
-; http://php.net/zlib.output-compression-level
-;zlib.output_compression_level = -1
-
-; You cannot specify additional output handlers if zlib.output_compression
-; is activated here. This setting does the same as output_handler but in
-; a different order.
-; http://php.net/zlib.output-handler
-;zlib.output_handler =
-
-; Implicit flush tells PHP to tell the output layer to flush itself
-; automatically after every output block. This is equivalent to calling the
-; PHP function flush() after each and every call to print() or echo() and each
-; and every HTML block. Turning this option on has serious performance
-; implications and is generally recommended for debugging purposes only.
-; http://php.net/implicit-flush
-; Note: This directive is hardcoded to On for the CLI SAPI
-implicit_flush = Off
-
-; The unserialize callback function will be called (with the undefined class'
-; name as parameter), if the unserializer finds an undefined class
-; which should be instantiated. A warning appears if the specified function is
-; not defined, or if the function doesn't include/implement the missing class.
-; So only set this entry, if you really want to implement such a
-; callback-function.
-unserialize_callback_func =
-
-; When floats & doubles are serialized store serialize_precision significant
-; digits after the floating point. The default value ensures that when floats
-; are decoded with unserialize, the data will remain the same.
-serialize_precision = 100
-
-; This directive allows you to enable and disable warnings which PHP will issue
-; if you pass a value by reference at function call time. Passing values by
-; reference at function call time is a deprecated feature which will be removed
-; from PHP at some point in the near future. The acceptable method for passing a
-; value by reference to a function is by declaring the reference in the functions
-; definition, not at call time. This directive does not disable this feature, it
-; only determines whether PHP will warn you about it or not. These warnings
-; should enabled in development environments only.
-; Default Value: On (Suppress warnings)
-; Development Value: Off (Issue warnings)
-; Production Value: Off (Issue warnings)
-; http://php.net/allow-call-time-pass-reference
-allow_call_time_pass_reference = Off
-
-; Safe Mode
-; http://php.net/safe-mode
-safe_mode = Off
-
-; By default, Safe Mode does a UID compare check when
-; opening files. If you want to relax this to a GID compare,
-; then turn on safe_mode_gid.
-; http://php.net/safe-mode-gid
-safe_mode_gid = Off
-
-; When safe_mode is on, UID/GID checks are bypassed when
-; including files from this directory and its subdirectories.
-; (directory must also be in include_path or full path must
-; be used when including)
-; http://php.net/safe-mode-include-dir
-safe_mode_include_dir =
-
-; When safe_mode is on, only executables located in the safe_mode_exec_dir
-; will be allowed to be executed via the exec family of functions.
-; http://php.net/safe-mode-exec-dir
-safe_mode_exec_dir =
-
-; Setting certain environment variables may be a potential security breach.
-; This directive contains a comma-delimited list of prefixes. In Safe Mode,
-; the user may only alter environment variables whose names begin with the
-; prefixes supplied here. By default, users will only be able to set
-; environment variables that begin with PHP_ (e.g. PHP_FOO=BAR).
-; Note: If this directive is empty, PHP will let the user modify ANY
-; environment variable!
-; http://php.net/safe-mode-allowed-env-vars
-safe_mode_allowed_env_vars = PHP_
-
-; This directive contains a comma-delimited list of environment variables that
-; the end user won't be able to change using putenv(). These variables will be
-; protected even if safe_mode_allowed_env_vars is set to allow to change them.
-; http://php.net/safe-mode-protected-env-vars
-safe_mode_protected_env_vars = LD_LIBRARY_PATH
-
-; open_basedir, if set, limits all file operations to the defined directory
-; and below. This directive makes most sense if used in a per-directory
-; or per-virtualhost web server configuration file. This directive is
-; *NOT* affected by whether Safe Mode is turned On or Off.
-; http://php.net/open-basedir
-;open_basedir =
-
-; This directive allows you to disable certain functions for security reasons.
-; It receives a comma-delimited list of function names. This directive is
-; *NOT* affected by whether Safe Mode is turned On or Off.
-; http://php.net/disable-functions
-disable_functions =
-
-; This directive allows you to disable certain classes for security reasons.
-; It receives a comma-delimited list of class names. This directive is
-; *NOT* affected by whether Safe Mode is turned On or Off.
-; http://php.net/disable-classes
-disable_classes =
-
-; Colors for Syntax Highlighting mode. Anything that's acceptable in
-; would work.
-; http://php.net/syntax-highlighting
-;highlight.string = #DD0000
-;highlight.comment = #FF9900
-;highlight.keyword = #007700
-;highlight.bg = #FFFFFF
-;highlight.default = #0000BB
-;highlight.html = #000000
-
-; If enabled, the request will be allowed to complete even if the user aborts
-; the request. Consider enabling it if executing long requests, which may end up
-; being interrupted by the user or a browser timing out. PHP's default behavior
-; is to disable this feature.
-; http://php.net/ignore-user-abort
-;ignore_user_abort = On
-
-; Determines the size of the realpath cache to be used by PHP. This value should
-; be increased on systems where PHP opens many files to reflect the quantity of
-; the file operations performed.
-; http://php.net/realpath-cache-size
-;realpath_cache_size = 16k
-
-; Duration of time, in seconds for which to cache realpath information for a given
-; file or directory. For systems with rarely changing files, consider increasing this
-; value.
-; http://php.net/realpath-cache-ttl
-;realpath_cache_ttl = 120
-
-;;;;;;;;;;;;;;;;;
-; Miscellaneous ;
-;;;;;;;;;;;;;;;;;
-
-; Decides whether PHP may expose the fact that it is installed on the server
-; (e.g. by adding its signature to the Web server header). It is no security
-; threat in any way, but it makes it possible to determine whether you use PHP
-; on your server or not.
-; http://php.net/expose-php
-expose_php = On
-
-;;;;;;;;;;;;;;;;;;;
-; Resource Limits ;
-;;;;;;;;;;;;;;;;;;;
-
-; Maximum execution time of each script, in seconds
-; http://php.net/max-execution-time
-; Note: This directive is hardcoded to 0 for the CLI SAPI
-max_execution_time = 30
-
-; Maximum amount of time each script may spend parsing request data. It's a good
-; idea to limit this time on productions servers in order to eliminate unexpectedly
-; long running scripts.
-; Note: This directive is hardcoded to -1 for the CLI SAPI
-; Default Value: -1 (Unlimited)
-; Development Value: 60 (60 seconds)
-; Production Value: 60 (60 seconds)
-; http://php.net/max-input-time
-max_input_time = 60
-
-; Maximum input variable nesting level
-; http://php.net/max-input-nesting-level
-;max_input_nesting_level = 64
-
-; Maximum amount of memory a script may consume (128MB)
-; http://php.net/memory-limit
-memory_limit = -1
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-; Error handling and logging ;
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
-; This directive informs PHP of which errors, warnings and notices you would like
-; it to take action for. The recommended way of setting values for this
-; directive is through the use of the error level constants and bitwise
-; operators. The error level constants are below here for convenience as well as
-; some common settings and their meanings.
-; By default, PHP is set to take action on all errors, notices and warnings EXCEPT
-; those related to E_NOTICE and E_STRICT, which together cover best practices and
-; recommended coding standards in PHP. For performance reasons, this is the
-; recommend error reporting setting. Your production server shouldn't be wasting
-; resources complaining about best practices and coding standards. That's what
-; development servers and development settings are for.
-; Note: The php.ini-development file has this setting as E_ALL | E_STRICT. This
-; means it pretty much reports everything which is exactly what you want during
-; development and early testing.
-;
-; Error Level Constants:
-; E_ALL - All errors and warnings (includes E_STRICT as of PHP 6.0.0)
-; E_ERROR - fatal run-time errors
-; E_RECOVERABLE_ERROR - almost fatal run-time errors
-; E_WARNING - run-time warnings (non-fatal errors)
-; E_PARSE - compile-time parse errors
-; E_NOTICE - run-time notices (these are warnings which often result
-; from a bug in your code, but it's possible that it was
-; intentional (e.g., using an uninitialized variable and
-; relying on the fact it's automatically initialized to an
-; empty string)
-; E_STRICT - run-time notices, enable to have PHP suggest changes
-; to your code which will ensure the best interoperability
-; and forward compatibility of your code
-; E_CORE_ERROR - fatal errors that occur during PHP's initial startup
-; E_CORE_WARNING - warnings (non-fatal errors) that occur during PHP's
-; initial startup
-; E_COMPILE_ERROR - fatal compile-time errors
-; E_COMPILE_WARNING - compile-time warnings (non-fatal errors)
-; E_USER_ERROR - user-generated error message
-; E_USER_WARNING - user-generated warning message
-; E_USER_NOTICE - user-generated notice message
-; E_DEPRECATED - warn about code that will not work in future versions
-; of PHP
-; E_USER_DEPRECATED - user-generated deprecation warnings
-;
-; Common Values:
-; E_ALL & ~E_NOTICE (Show all errors, except for notices and coding standards warnings.)
-; E_ALL & ~E_NOTICE | E_STRICT (Show all errors, except for notices)
-; E_COMPILE_ERROR|E_RECOVERABLE_ERROR|E_ERROR|E_CORE_ERROR (Show only errors)
-; E_ALL | E_STRICT (Show all errors, warnings and notices including coding standards.)
-; Default Value: E_ALL & ~E_NOTICE
-; Development Value: E_ALL | E_STRICT
-; Production Value: E_ALL & ~E_DEPRECATED
-; http://php.net/error-reporting
-error_reporting = E_ALL & ~E_DEPRECATED
-
-; This directive controls whether or not and where PHP will output errors,
-; notices and warnings too. Error output is very useful during development, but
-; it could be very dangerous in production environments. Depending on the code
-; which is triggering the error, sensitive information could potentially leak
-; out of your application such as database usernames and passwords or worse.
-; It's recommended that errors be logged on production servers rather than
-; having the errors sent to STDOUT.
-; Possible Values:
-; Off = Do not display any errors
-; stderr = Display errors to STDERR (affects only CGI/CLI binaries!)
-; On or stdout = Display errors to STDOUT
-; Default Value: On
-; Development Value: On
-; Production Value: Off
-; http://php.net/display-errors
-display_errors = Off
-
-; The display of errors which occur during PHP's startup sequence are handled
-; separately from display_errors. PHP's default behavior is to suppress those
-; errors from clients. Turning the display of startup errors on can be useful in
-; debugging configuration problems. But, it's strongly recommended that you
-; leave this setting off on production servers.
-; Default Value: Off
-; Development Value: On
-; Production Value: Off
-; http://php.net/display-startup-errors
-display_startup_errors = Off
-
-; Besides displaying errors, PHP can also log errors to locations such as a
-; server-specific log, STDERR, or a location specified by the error_log
-; directive found below. While errors should not be displayed on productions
-; servers they should still be monitored and logging is a great way to do that.
-; Default Value: Off
-; Development Value: On
-; Production Value: On
-; http://php.net/log-errors
-log_errors = On
-
-; Set maximum length of log_errors. In error_log information about the source is
-; added. The default is 1024 and 0 allows to not apply any maximum length at all.
-; http://php.net/log-errors-max-len
-log_errors_max_len = 1024
-
-; Do not log repeated messages. Repeated errors must occur in same file on same
-; line unless ignore_repeated_source is set true.
-; http://php.net/ignore-repeated-errors
-ignore_repeated_errors = Off
-
-; Ignore source of message when ignoring repeated messages. When this setting
-; is On you will not log errors with repeated messages from different files or
-; source lines.
-; http://php.net/ignore-repeated-source
-ignore_repeated_source = Off
-
-; If this parameter is set to Off, then memory leaks will not be shown (on
-; stdout or in the log). This has only effect in a debug compile, and if
-; error reporting includes E_WARNING in the allowed list
-; http://php.net/report-memleaks
-report_memleaks = On
-
-; This setting is on by default.
-;report_zend_debug = 0
-
-; Store the last error/warning message in $php_errormsg (boolean). Setting this value
-; to On can assist in debugging and is appropriate for development servers. It should
-; however be disabled on production servers.
-; Default Value: Off
-; Development Value: On
-; Production Value: Off
-; http://php.net/track-errors
-track_errors = Off
-
-; Turn off normal error reporting and emit XML-RPC error XML
-; http://php.net/xmlrpc-errors
-;xmlrpc_errors = 0
-
-; An XML-RPC faultCode
-;xmlrpc_error_number = 0
-
-; When PHP displays or logs an error, it has the capability of inserting html
-; links to documentation related to that error. This directive controls whether
-; those HTML links appear in error messages or not. For performance and security
-; reasons, it's recommended you disable this on production servers.
-; Note: This directive is hardcoded to Off for the CLI SAPI
-; Default Value: On
-; Development Value: On
-; Production value: Off
-; http://php.net/html-errors
-html_errors = Off
-
-; If html_errors is set On PHP produces clickable error messages that direct
-; to a page describing the error or function causing the error in detail.
-; You can download a copy of the PHP manual from http://php.net/docs
-; and change docref_root to the base URL of your local copy including the
-; leading '/'. You must also specify the file extension being used including
-; the dot. PHP's default behavior is to leave these settings empty.
-; Note: Never use this feature for production boxes.
-; http://php.net/docref-root
-; Examples
-;docref_root = "/phpmanual/"
-
-; http://php.net/docref-ext
-;docref_ext = .html
-
-; String to output before an error message. PHP's default behavior is to leave
-; this setting blank.
-; http://php.net/error-prepend-string
-; Example:
-;error_prepend_string = ""
-
-; String to output after an error message. PHP's default behavior is to leave
-; this setting blank.
-; http://php.net/error-append-string
-; Example:
-;error_append_string = ""
-
-; Log errors to specified file. PHP's default behavior is to leave this value
-; empty.
-; http://php.net/error-log
-; Example:
-;error_log = php_errors.log
-; Log errors to syslog (Event Log on NT, not valid in Windows 95).
-;error_log = syslog
-
-;;;;;;;;;;;;;;;;;
-; Data Handling ;
-;;;;;;;;;;;;;;;;;
-
-; The separator used in PHP generated URLs to separate arguments.
-; PHP's default setting is "&".
-; http://php.net/arg-separator.output
-; Example:
-;arg_separator.output = "&"
-
-; List of separator(s) used by PHP to parse input URLs into variables.
-; PHP's default setting is "&".
-; NOTE: Every character in this directive is considered as separator!
-; http://php.net/arg-separator.input
-; Example:
-;arg_separator.input = ";&"
-
-; This directive determines which super global arrays are registered when PHP
-; starts up. If the register_globals directive is enabled, it also determines
-; what order variables are populated into the global space. G,P,C,E & S are
-; abbreviations for the following respective super globals: GET, POST, COOKIE,
-; ENV and SERVER. There is a performance penalty paid for the registration of
-; these arrays and because ENV is not as commonly used as the others, ENV is
-; is not recommended on productions servers. You can still get access to
-; the environment variables through getenv() should you need to.
-; Default Value: "EGPCS"
-; Development Value: "GPCS"
-; Production Value: "GPCS";
-; http://php.net/variables-order
-variables_order = "GPCS"
-
-; This directive determines which super global data (G,P,C,E & S) should
-; be registered into the super global array REQUEST. If so, it also determines
-; the order in which that data is registered. The values for this directive are
-; specified in the same manner as the variables_order directive, EXCEPT one.
-; Leaving this value empty will cause PHP to use the value set in the
-; variables_order directive. It does not mean it will leave the super globals
-; array REQUEST empty.
-; Default Value: None
-; Development Value: "GP"
-; Production Value: "GP"
-; http://php.net/request-order
-request_order = "GP"
-
-; Whether or not to register the EGPCS variables as global variables. You may
-; want to turn this off if you don't want to clutter your scripts' global scope
-; with user data.
-; You should do your best to write your scripts so that they do not require
-; register_globals to be on; Using form variables as globals can easily lead
-; to possible security problems, if the code is not very well thought of.
-; http://php.net/register-globals
-register_globals = Off
-
-; Determines whether the deprecated long $HTTP_*_VARS type predefined variables
-; are registered by PHP or not. As they are deprecated, we obviously don't
-; recommend you use them. They are on by default for compatibility reasons but
-; they are not recommended on production servers.
-; Default Value: On
-; Development Value: Off
-; Production Value: Off
-; http://php.net/register-long-arrays
-register_long_arrays = Off
-
-; This directive determines whether PHP registers $argv & $argc each time it
-; runs. $argv contains an array of all the arguments passed to PHP when a script
-; is invoked. $argc contains an integer representing the number of arguments
-; that were passed when the script was invoked. These arrays are extremely
-; useful when running scripts from the command line. When this directive is
-; enabled, registering these variables consumes CPU cycles and memory each time
-; a script is executed. For performance reasons, this feature should be disabled
-; on production servers.
-; Note: This directive is hardcoded to On for the CLI SAPI
-; Default Value: On
-; Development Value: Off
-; Production Value: Off
-; http://php.net/register-argc-argv
-register_argc_argv = Off
-
-; When enabled, the SERVER and ENV variables are created when they're first
-; used (Just In Time) instead of when the script starts. If these variables
-; are not used within a script, having this directive on will result in a
-; performance gain. The PHP directives register_globals, register_long_arrays,
-; and register_argc_argv must be disabled for this directive to have any affect.
-; http://php.net/auto-globals-jit
-auto_globals_jit = On
-
-; Maximum size of POST data that PHP will accept.
-; http://php.net/post-max-size
-post_max_size = 8M
-
-; Magic quotes are a preprocessing feature of PHP where PHP will attempt to
-; escape any character sequences in GET, POST, COOKIE and ENV data which might
-; otherwise corrupt data being placed in resources such as databases before
-; making that data available to you. Because of character encoding issues and
-; non-standard SQL implementations across many databases, it's not currently
-; possible for this feature to be 100% accurate. PHP's default behavior is to
-; enable the feature. We strongly recommend you use the escaping mechanisms
-; designed specifically for the database your using instead of relying on this
-; feature. Also note, this feature has been deprecated as of PHP 5.3.0 and is
-; scheduled for removal in PHP 6.
-; Default Value: On
-; Development Value: Off
-; Production Value: Off
-; http://php.net/magic-quotes-gpc
-magic_quotes_gpc = Off
-
-; Magic quotes for runtime-generated data, e.g. data from SQL, from exec(), etc.
-; http://php.net/magic-quotes-runtime
-magic_quotes_runtime = Off
-
-; Use Sybase-style magic quotes (escape ' with '' instead of \').
-; http://php.net/magic-quotes-sybase
-magic_quotes_sybase = Off
-
-; Automatically add files before PHP document.
-; http://php.net/auto-prepend-file
-auto_prepend_file =
-
-; Automatically add files after PHP document.
-; http://php.net/auto-append-file
-auto_append_file =
-
-; By default, PHP will output a character encoding using
-; the Content-type: header. To disable sending of the charset, simply
-; set it to be empty.
-;
-; PHP's built-in default is text/html
-; http://php.net/default-mimetype
-default_mimetype = "text/html"
-
-; PHP's default character set is set to empty.
-; http://php.net/default-charset
-;default_charset = "iso-8859-1"
-
-; Always populate the $HTTP_RAW_POST_DATA variable. PHP's default behavior is
-; to disable this feature.
-; http://php.net/always-populate-raw-post-data
-;always_populate_raw_post_data = On
-
-;;;;;;;;;;;;;;;;;;;;;;;;;
-; Paths and Directories ;
-;;;;;;;;;;;;;;;;;;;;;;;;;
-
-; UNIX: "/path1:/path2"
-;include_path = ".:/usr/share/php"
-;
-; Windows: "\path1;\path2"
-;include_path = ".;c:\php\includes"
-;
-; PHP's default setting for include_path is ".;/path/to/php/pear"
-; http://php.net/include-path
-
-; The root of the PHP pages, used only if nonempty.
-; if PHP was not compiled with FORCE_REDIRECT, you SHOULD set doc_root
-; if you are running php as a CGI under any web server (other than IIS)
-; see documentation for security issues. The alternate is to use the
-; cgi.force_redirect configuration below
-; http://php.net/doc-root
-doc_root =
-
-; The directory under which PHP opens the script using /~username used only
-; if nonempty.
-; http://php.net/user-dir
-user_dir =
-
-; Directory in which the loadable extensions (modules) reside.
-; http://php.net/extension-dir
-; extension_dir = "./"
-; On windows:
-; extension_dir = "ext"
-
-; Whether or not to enable the dl() function. The dl() function does NOT work
-; properly in multithreaded servers, such as IIS or Zeus, and is automatically
-; disabled on them.
-; http://php.net/enable-dl
-enable_dl = Off
-
-; cgi.force_redirect is necessary to provide security running PHP as a CGI under
-; most web servers. Left undefined, PHP turns this on by default. You can
-; turn it off here AT YOUR OWN RISK
-; **You CAN safely turn this off for IIS, in fact, you MUST.**
-; http://php.net/cgi.force-redirect
-;cgi.force_redirect = 1
-
-; if cgi.nph is enabled it will force cgi to always sent Status: 200 with
-; every request. PHP's default behavior is to disable this feature.
-;cgi.nph = 1
-
-; if cgi.force_redirect is turned on, and you are not running under Apache or Netscape
-; (iPlanet) web servers, you MAY need to set an environment variable name that PHP
-; will look for to know it is OK to continue execution. Setting this variable MAY
-; cause security issues, KNOW WHAT YOU ARE DOING FIRST.
-; http://php.net/cgi.redirect-status-env
-;cgi.redirect_status_env = ;
-
-; cgi.fix_pathinfo provides *real* PATH_INFO/PATH_TRANSLATED support for CGI. PHP's
-; previous behaviour was to set PATH_TRANSLATED to SCRIPT_FILENAME, and to not grok
-; what PATH_INFO is. For more information on PATH_INFO, see the cgi specs. Setting
-; this to 1 will cause PHP CGI to fix its paths to conform to the spec. A setting
-; of zero causes PHP to behave as before. Default is 1. You should fix your scripts
-; to use SCRIPT_FILENAME rather than PATH_TRANSLATED.
-; http://php.net/cgi.fix-pathinfo
-;cgi.fix_pathinfo=1
-
-; FastCGI under IIS (on WINNT based OS) supports the ability to impersonate
-; security tokens of the calling client. This allows IIS to define the
-; security context that the request runs under. mod_fastcgi under Apache
-; does not currently support this feature (03/17/2002)
-; Set to 1 if running under IIS. Default is zero.
-; http://php.net/fastcgi.impersonate
-;fastcgi.impersonate = 1;
-
-; Disable logging through FastCGI connection. PHP's default behavior is to enable
-; this feature.
-;fastcgi.logging = 0
-
-; cgi.rfc2616_headers configuration option tells PHP what type of headers to
-; use when sending HTTP response code. If it's set 0 PHP sends Status: header that
-; is supported by Apache. When this option is set to 1 PHP will send
-; RFC2616 compliant header.
-; Default is zero.
-; http://php.net/cgi.rfc2616-headers
-;cgi.rfc2616_headers = 0
-
-;;;;;;;;;;;;;;;;
-; File Uploads ;
-;;;;;;;;;;;;;;;;
-
-; Whether to allow HTTP file uploads.
-; http://php.net/file-uploads
-file_uploads = On
-
-; Temporary directory for HTTP uploaded files (will use system default if not
-; specified).
-; http://php.net/upload-tmp-dir
-;upload_tmp_dir =
-
-; Maximum allowed size for uploaded files.
-; http://php.net/upload-max-filesize
-upload_max_filesize = 2M
-
-; Maximum number of files that can be uploaded via a single request
-max_file_uploads = 20
-
-;;;;;;;;;;;;;;;;;;
-; Fopen wrappers ;
-;;;;;;;;;;;;;;;;;;
-
-; Whether to allow the treatment of URLs (like http:// or ftp://) as files.
-; http://php.net/allow-url-fopen
-allow_url_fopen = On
-
-; Whether to allow include/require to open URLs (like http:// or ftp://) as files.
-; http://php.net/allow-url-include
-allow_url_include = Off
-
-; Define the anonymous ftp password (your email address). PHP's default setting
-; for this is empty.
-; http://php.net/from
-;from="john@doe.com"
-
-; Define the User-Agent string. PHP's default setting for this is empty.
-; http://php.net/user-agent
-;user_agent="PHP"
-
-; Default timeout for socket based streams (seconds)
-; http://php.net/default-socket-timeout
-default_socket_timeout = 60
-
-; If your scripts have to deal with files from Macintosh systems,
-; or you are running on a Mac and need to deal with files from
-; unix or win32 systems, setting this flag will cause PHP to
-; automatically detect the EOL character in those files so that
-; fgets() and file() will work regardless of the source of the file.
-; http://php.net/auto-detect-line-endings
-;auto_detect_line_endings = Off
-
-;;;;;;;;;;;;;;;;;;;;;;
-; Dynamic Extensions ;
-;;;;;;;;;;;;;;;;;;;;;;
-
-; If you wish to have an extension loaded automatically, use the following
-; syntax:
-;
-; extension=modulename.extension
-;
-; For example, on Windows:
-;
-; extension=msql.dll
-;
-; ... or under UNIX:
-;
-; extension=msql.so
-;
-; ... or with a path:
-;
-; extension=/path/to/extension/msql.so
-;
-; If you only provide the name of the extension, PHP will look for it in its
-; default extension directory.
-;
-
-;;;;;;;;;;;;;;;;;;;
-; Module Settings ;
-;;;;;;;;;;;;;;;;;;;
-
-[Date]
-; Defines the default timezone used by the date functions
-; http://php.net/date.timezone
-;date.timezone =
-
-; http://php.net/date.default-latitude
-;date.default_latitude = 31.7667
-
-; http://php.net/date.default-longitude
-;date.default_longitude = 35.2333
-
-; http://php.net/date.sunrise-zenith
-;date.sunrise_zenith = 90.583333
-
-; http://php.net/date.sunset-zenith
-;date.sunset_zenith = 90.583333
-
-[filter]
-; http://php.net/filter.default
-;filter.default = unsafe_raw
-
-; http://php.net/filter.default-flags
-;filter.default_flags =
-
-[iconv]
-;iconv.input_encoding = ISO-8859-1
-;iconv.internal_encoding = ISO-8859-1
-;iconv.output_encoding = ISO-8859-1
-
-[intl]
-;intl.default_locale =
-; This directive allows you to produce PHP errors when some error
-; happens within intl functions. The value is the level of the error produced.
-; Default is 0, which does not produce any errors.
-;intl.error_level = E_WARNING
-
-[sqlite]
-; http://php.net/sqlite.assoc-case
-;sqlite.assoc_case = 0
-
-[sqlite3]
-;sqlite3.extension_dir =
-
-[Pcre]
-;PCRE library backtracking limit.
-; http://php.net/pcre.backtrack-limit
-;pcre.backtrack_limit=100000
-
-;PCRE library recursion limit.
-;Please note that if you set this value to a high number you may consume all
-;the available process stack and eventually crash PHP (due to reaching the
-;stack size limit imposed by the Operating System).
-; http://php.net/pcre.recursion-limit
-;pcre.recursion_limit=100000
-
-[Pdo]
-; Whether to pool ODBC connections. Can be one of "strict", "relaxed" or "off"
-; http://php.net/pdo-odbc.connection-pooling
-;pdo_odbc.connection_pooling=strict
-
-;pdo_odbc.db2_instance_name
-
-[Pdo_mysql]
-; If mysqlnd is used: Number of cache slots for the internal result set cache
-; http://php.net/pdo_mysql.cache_size
-pdo_mysql.cache_size = 2000
-
-; Default socket name for local MySQL connects. If empty, uses the built-in
-; MySQL defaults.
-; http://php.net/pdo_mysql.default-socket
-pdo_mysql.default_socket=
-
-[Phar]
-; http://php.net/phar.readonly
-phar.readonly = Off
-
-; http://php.net/phar.require-hash
-;phar.require_hash = On
-
-;phar.cache_list =
-
-[Syslog]
-; Whether or not to define the various syslog variables (e.g. $LOG_PID,
-; $LOG_CRON, etc.). Turning it off is a good idea performance-wise. In
-; runtime, you can define these variables by calling define_syslog_variables().
-; http://php.net/define-syslog-variables
-define_syslog_variables = Off
-
-[mail function]
-; For Win32 only.
-; http://php.net/smtp
-SMTP = localhost
-; http://php.net/smtp-port
-smtp_port = 25
-
-; For Win32 only.
-; http://php.net/sendmail-from
-;sendmail_from = me@example.com
-
-; For Unix only. You may supply arguments as well (default: "sendmail -t -i").
-; http://php.net/sendmail-path
-;sendmail_path =
-
-; Force the addition of the specified parameters to be passed as extra parameters
-; to the sendmail binary. These parameters will always replace the value of
-; the 5th parameter to mail(), even in safe mode.
-;mail.force_extra_parameters =
-
-; Add X-PHP-Originating-Script: that will include uid of the script followed by the filename
-mail.add_x_header = On
-
-; Log all mail() calls including the full path of the script, line #, to address and headers
-;mail.log =
-
-[SQL]
-; http://php.net/sql.safe-mode
-sql.safe_mode = Off
-
-[ODBC]
-; http://php.net/odbc.default-db
-;odbc.default_db = Not yet implemented
-
-; http://php.net/odbc.default-user
-;odbc.default_user = Not yet implemented
-
-; http://php.net/odbc.default-pw
-;odbc.default_pw = Not yet implemented
-
-; Controls the ODBC cursor model.
-; Default: SQL_CURSOR_STATIC (default).
-;odbc.default_cursortype
-
-; Allow or prevent persistent links.
-; http://php.net/odbc.allow-persistent
-odbc.allow_persistent = On
-
-; Check that a connection is still valid before reuse.
-; http://php.net/odbc.check-persistent
-odbc.check_persistent = On
-
-; Maximum number of persistent links. -1 means no limit.
-; http://php.net/odbc.max-persistent
-odbc.max_persistent = -1
-
-; Maximum number of links (persistent + non-persistent). -1 means no limit.
-; http://php.net/odbc.max-links
-odbc.max_links = -1
-
-; Handling of LONG fields. Returns number of bytes to variables. 0 means
-; passthru.
-; http://php.net/odbc.defaultlrl
-odbc.defaultlrl = 4096
-
-; Handling of binary data. 0 means passthru, 1 return as is, 2 convert to char.
-; See the documentation on odbc_binmode and odbc_longreadlen for an explanation
-; of odbc.defaultlrl and odbc.defaultbinmode
-; http://php.net/odbc.defaultbinmode
-odbc.defaultbinmode = 1
-
-;birdstep.max_links = -1
-
-[Interbase]
-; Allow or prevent persistent links.
-ibase.allow_persistent = 1
-
-; Maximum number of persistent links. -1 means no limit.
-ibase.max_persistent = -1
-
-; Maximum number of links (persistent + non-persistent). -1 means no limit.
-ibase.max_links = -1
-
-; Default database name for ibase_connect().
-;ibase.default_db =
-
-; Default username for ibase_connect().
-;ibase.default_user =
-
-; Default password for ibase_connect().
-;ibase.default_password =
-
-; Default charset for ibase_connect().
-;ibase.default_charset =
-
-; Default timestamp format.
-ibase.timestampformat = "%Y-%m-%d %H:%M:%S"
-
-; Default date format.
-ibase.dateformat = "%Y-%m-%d"
-
-; Default time format.
-ibase.timeformat = "%H:%M:%S"
-
-[MySQL]
-; Allow accessing, from PHP's perspective, local files with LOAD DATA statements
-; http://php.net/mysql.allow_local_infile
-mysql.allow_local_infile = On
-
-; Allow or prevent persistent links.
-; http://php.net/mysql.allow-persistent
-mysql.allow_persistent = On
-
-; If mysqlnd is used: Number of cache slots for the internal result set cache
-; http://php.net/mysql.cache_size
-mysql.cache_size = 2000
-
-; Maximum number of persistent links. -1 means no limit.
-; http://php.net/mysql.max-persistent
-mysql.max_persistent = -1
-
-; Maximum number of links (persistent + non-persistent). -1 means no limit.
-; http://php.net/mysql.max-links
-mysql.max_links = -1
-
-; Default port number for mysql_connect(). If unset, mysql_connect() will use
-; the $MYSQL_TCP_PORT or the mysql-tcp entry in /etc/services or the
-; compile-time value defined MYSQL_PORT (in that order). Win32 will only look
-; at MYSQL_PORT.
-; http://php.net/mysql.default-port
-mysql.default_port =
-
-; Default socket name for local MySQL connects. If empty, uses the built-in
-; MySQL defaults.
-; http://php.net/mysql.default-socket
-mysql.default_socket =
-
-; Default host for mysql_connect() (doesn't apply in safe mode).
-; http://php.net/mysql.default-host
-mysql.default_host =
-
-; Default user for mysql_connect() (doesn't apply in safe mode).
-; http://php.net/mysql.default-user
-mysql.default_user =
-
-; Default password for mysql_connect() (doesn't apply in safe mode).
-; Note that this is generally a *bad* idea to store passwords in this file.
-; *Any* user with PHP access can run 'echo get_cfg_var("mysql.default_password")
-; and reveal this password! And of course, any users with read access to this
-; file will be able to reveal the password as well.
-; http://php.net/mysql.default-password
-mysql.default_password =
-
-; Maximum time (in seconds) for connect timeout. -1 means no limit
-; http://php.net/mysql.connect-timeout
-mysql.connect_timeout = 60
-
-; Trace mode. When trace_mode is active (=On), warnings for table/index scans and
-; SQL-Errors will be displayed.
-; http://php.net/mysql.trace-mode
-mysql.trace_mode = Off
-
-[MySQLi]
-
-; Maximum number of persistent links. -1 means no limit.
-; http://php.net/mysqli.max-persistent
-mysqli.max_persistent = -1
-
-; Allow accessing, from PHP's perspective, local files with LOAD DATA statements
-; http://php.net/mysqli.allow_local_infile
-;mysqli.allow_local_infile = On
-
-; Allow or prevent persistent links.
-; http://php.net/mysqli.allow-persistent
-mysqli.allow_persistent = On
-
-; Maximum number of links. -1 means no limit.
-; http://php.net/mysqli.max-links
-mysqli.max_links = -1
-
-; If mysqlnd is used: Number of cache slots for the internal result set cache
-; http://php.net/mysqli.cache_size
-mysqli.cache_size = 2000
-
-; Default port number for mysqli_connect(). If unset, mysqli_connect() will use
-; the $MYSQL_TCP_PORT or the mysql-tcp entry in /etc/services or the
-; compile-time value defined MYSQL_PORT (in that order). Win32 will only look
-; at MYSQL_PORT.
-; http://php.net/mysqli.default-port
-mysqli.default_port = 3306
-
-; Default socket name for local MySQL connects. If empty, uses the built-in
-; MySQL defaults.
-; http://php.net/mysqli.default-socket
-mysqli.default_socket =
-
-; Default host for mysql_connect() (doesn't apply in safe mode).
-; http://php.net/mysqli.default-host
-mysqli.default_host =
-
-; Default user for mysql_connect() (doesn't apply in safe mode).
-; http://php.net/mysqli.default-user
-mysqli.default_user =
-
-; Default password for mysqli_connect() (doesn't apply in safe mode).
-; Note that this is generally a *bad* idea to store passwords in this file.
-; *Any* user with PHP access can run 'echo get_cfg_var("mysqli.default_pw")
-; and reveal this password! And of course, any users with read access to this
-; file will be able to reveal the password as well.
-; http://php.net/mysqli.default-pw
-mysqli.default_pw =
-
-; Allow or prevent reconnect
-mysqli.reconnect = Off
-
-[mysqlnd]
-; Enable / Disable collection of general statstics by mysqlnd which can be
-; used to tune and monitor MySQL operations.
-; http://php.net/mysqlnd.collect_statistics
-mysqlnd.collect_statistics = On
-
-; Enable / Disable collection of memory usage statstics by mysqlnd which can be
-; used to tune and monitor MySQL operations.
-; http://php.net/mysqlnd.collect_memory_statistics
-mysqlnd.collect_memory_statistics = Off
-
-; Size of a pre-allocated buffer used when sending commands to MySQL in bytes.
-; http://php.net/mysqlnd.net_cmd_buffer_size
-;mysqlnd.net_cmd_buffer_size = 2048
-
-; Size of a pre-allocated buffer used for reading data sent by the server in
-; bytes.
-; http://php.net/mysqlnd.net_read_buffer_size
-;mysqlnd.net_read_buffer_size = 32768
-
-[OCI8]
-
-; Connection: Enables privileged connections using external
-; credentials (OCI_SYSOPER, OCI_SYSDBA)
-; http://php.net/oci8.privileged-connect
-;oci8.privileged_connect = Off
-
-; Connection: The maximum number of persistent OCI8 connections per
-; process. Using -1 means no limit.
-; http://php.net/oci8.max-persistent
-;oci8.max_persistent = -1
-
-; Connection: The maximum number of seconds a process is allowed to
-; maintain an idle persistent connection. Using -1 means idle
-; persistent connections will be maintained forever.
-; http://php.net/oci8.persistent-timeout
-;oci8.persistent_timeout = -1
-
-; Connection: The number of seconds that must pass before issuing a
-; ping during oci_pconnect() to check the connection validity. When
-; set to 0, each oci_pconnect() will cause a ping. Using -1 disables
-; pings completely.
-; http://php.net/oci8.ping-interval
-;oci8.ping_interval = 60
-
-; Connection: Set this to a user chosen connection class to be used
-; for all pooled server requests with Oracle 11g Database Resident
-; Connection Pooling (DRCP). To use DRCP, this value should be set to
-; the same string for all web servers running the same application,
-; the database pool must be configured, and the connection string must
-; specify to use a pooled server.
-;oci8.connection_class =
-
-; High Availability: Using On lets PHP receive Fast Application
-; Notification (FAN) events generated when a database node fails. The
-; database must also be configured to post FAN events.
-;oci8.events = Off
-
-; Tuning: This option enables statement caching, and specifies how
-; many statements to cache. Using 0 disables statement caching.
-; http://php.net/oci8.statement-cache-size
-;oci8.statement_cache_size = 20
-
-; Tuning: Enables statement prefetching and sets the default number of
-; rows that will be fetched automatically after statement execution.
-; http://php.net/oci8.default-prefetch
-;oci8.default_prefetch = 100
-
-; Compatibility. Using On means oci_close() will not close
-; oci_connect() and oci_new_connect() connections.
-; http://php.net/oci8.old-oci-close-semantics
-;oci8.old_oci_close_semantics = Off
-
-[PostgresSQL]
-; Allow or prevent persistent links.
-; http://php.net/pgsql.allow-persistent
-pgsql.allow_persistent = On
-
-; Detect broken persistent links always with pg_pconnect().
-; Auto reset feature requires a little overheads.
-; http://php.net/pgsql.auto-reset-persistent
-pgsql.auto_reset_persistent = Off
-
-; Maximum number of persistent links. -1 means no limit.
-; http://php.net/pgsql.max-persistent
-pgsql.max_persistent = -1
-
-; Maximum number of links (persistent+non persistent). -1 means no limit.
-; http://php.net/pgsql.max-links
-pgsql.max_links = -1
-
-; Ignore PostgreSQL backends Notice message or not.
-; Notice message logging require a little overheads.
-; http://php.net/pgsql.ignore-notice
-pgsql.ignore_notice = 0
-
-; Log PostgreSQL backends Notice message or not.
-; Unless pgsql.ignore_notice=0, module cannot log notice message.
-; http://php.net/pgsql.log-notice
-pgsql.log_notice = 0
-
-[Sybase-CT]
-; Allow or prevent persistent links.
-; http://php.net/sybct.allow-persistent
-sybct.allow_persistent = On
-
-; Maximum number of persistent links. -1 means no limit.
-; http://php.net/sybct.max-persistent
-sybct.max_persistent = -1
-
-; Maximum number of links (persistent + non-persistent). -1 means no limit.
-; http://php.net/sybct.max-links
-sybct.max_links = -1
-
-; Minimum server message severity to display.
-; http://php.net/sybct.min-server-severity
-sybct.min_server_severity = 10
-
-; Minimum client message severity to display.
-; http://php.net/sybct.min-client-severity
-sybct.min_client_severity = 10
-
-; Set per-context timeout
-; http://php.net/sybct.timeout
-;sybct.timeout=
-
-;sybct.packet_size
-
-; The maximum time in seconds to wait for a connection attempt to succeed before returning failure.
-; Default: one minute
-;sybct.login_timeout=
-
-; The name of the host you claim to be connecting from, for display by sp_who.
-; Default: none
-;sybct.hostname=
-
-; Allows you to define how often deadlocks are to be retried. -1 means "forever".
-; Default: 0
-;sybct.deadlock_retry_count=
-
-[bcmath]
-; Number of decimal digits for all bcmath functions.
-; http://php.net/bcmath.scale
-bcmath.scale = 0
-
-[browscap]
-; http://php.net/browscap
-;browscap = extra/browscap.ini
-
-[Session]
-; Handler used to store/retrieve data.
-; http://php.net/session.save-handler
-session.save_handler = files
-
-; Argument passed to save_handler. In the case of files, this is the path
-; where data files are stored. Note: Windows users have to change this
-; variable in order to use PHP's session functions.
-;
-; The path can be defined as:
-;
-; session.save_path = "N;/path"
-;
-; where N is an integer. Instead of storing all the session files in
-; /path, what this will do is use subdirectories N-levels deep, and
-; store the session data in those directories. This is useful if you
-; or your OS have problems with lots of files in one directory, and is
-; a more efficient layout for servers that handle lots of sessions.
-;
-; NOTE 1: PHP will not create this directory structure automatically.
-; You can use the script in the ext/session dir for that purpose.
-; NOTE 2: See the section on garbage collection below if you choose to
-; use subdirectories for session storage
-;
-; The file storage module creates files using mode 600 by default.
-; You can change that by using
-;
-; session.save_path = "N;MODE;/path"
-;
-; where MODE is the octal representation of the mode. Note that this
-; does not overwrite the process's umask.
-; http://php.net/session.save-path
-;session.save_path = "/tmp"
-
-; Whether to use cookies.
-; http://php.net/session.use-cookies
-session.use_cookies = 1
-
-; http://php.net/session.cookie-secure
-;session.cookie_secure =
-
-; This option forces PHP to fetch and use a cookie for storing and maintaining
-; the session id. We encourage this operation as it's very helpful in combatting
-; session hijacking when not specifying and managing your own session id. It is
-; not the end all be all of session hijacking defense, but it's a good start.
-; http://php.net/session.use-only-cookies
-session.use_only_cookies = 1
-
-; Name of the session (used as cookie name).
-; http://php.net/session.name
-session.name = PHPSESSID
-
-; Initialize session on request startup.
-; http://php.net/session.auto-start
-session.auto_start = 0
-
-; Lifetime in seconds of cookie or, if 0, until browser is restarted.
-; http://php.net/session.cookie-lifetime
-session.cookie_lifetime = 0
-
-; The path for which the cookie is valid.
-; http://php.net/session.cookie-path
-session.cookie_path = /
-
-; The domain for which the cookie is valid.
-; http://php.net/session.cookie-domain
-session.cookie_domain =
-
-; Whether or not to add the httpOnly flag to the cookie, which makes it inaccessible to browser scripting languages such as JavaScript.
-; http://php.net/session.cookie-httponly
-session.cookie_httponly =
-
-; Handler used to serialize data. php is the standard serializer of PHP.
-; http://php.net/session.serialize-handler
-session.serialize_handler = php
-
-; Defines the probability that the 'garbage collection' process is started
-; on every session initialization. The probability is calculated by using
-; gc_probability/gc_divisor. Where session.gc_probability is the numerator
-; and gc_divisor is the denominator in the equation. Setting this value to 1
-; when the session.gc_divisor value is 100 will give you approximately a 1% chance
-; the gc will run on any give request.
-; Default Value: 1
-; Development Value: 1
-; Production Value: 1
-; http://php.net/session.gc-probability
-session.gc_probability = 0
-
-; Defines the probability that the 'garbage collection' process is started on every
-; session initialization. The probability is calculated by using the following equation:
-; gc_probability/gc_divisor. Where session.gc_probability is the numerator and
-; session.gc_divisor is the denominator in the equation. Setting this value to 1
-; when the session.gc_divisor value is 100 will give you approximately a 1% chance
-; the gc will run on any give request. Increasing this value to 1000 will give you
-; a 0.1% chance the gc will run on any give request. For high volume production servers,
-; this is a more efficient approach.
-; Default Value: 100
-; Development Value: 1000
-; Production Value: 1000
-; http://php.net/session.gc-divisor
-session.gc_divisor = 1000
-
-; After this number of seconds, stored data will be seen as 'garbage' and
-; cleaned up by the garbage collection process.
-; http://php.net/session.gc-maxlifetime
-session.gc_maxlifetime = 1440
-
-; NOTE: If you are using the subdirectory option for storing session files
-; (see session.save_path above), then garbage collection does *not*
-; happen automatically. You will need to do your own garbage
-; collection through a shell script, cron entry, or some other method.
-; For example, the following script would is the equivalent of
-; setting session.gc_maxlifetime to 1440 (1440 seconds = 24 minutes):
-; cd /path/to/sessions; find -cmin +24 | xargs rm
-
-; PHP 4.2 and less have an undocumented feature/bug that allows you to
-; to initialize a session variable in the global scope, even when register_globals
-; is disabled. PHP 4.3 and later will warn you, if this feature is used.
-; You can disable the feature and the warning separately. At this time,
-; the warning is only displayed, if bug_compat_42 is enabled. This feature
-; introduces some serious security problems if not handled correctly. It's
-; recommended that you do not use this feature on production servers. But you
-; should enable this on development servers and enable the warning as well. If you
-; do not enable the feature on development servers, you won't be warned when it's
-; used and debugging errors caused by this can be difficult to track down.
-; Default Value: On
-; Development Value: On
-; Production Value: Off
-; http://php.net/session.bug-compat-42
-session.bug_compat_42 = Off
-
-; This setting controls whether or not you are warned by PHP when initializing a
-; session value into the global space. session.bug_compat_42 must be enabled before
-; these warnings can be issued by PHP. See the directive above for more information.
-; Default Value: On
-; Development Value: On
-; Production Value: Off
-; http://php.net/session.bug-compat-warn
-session.bug_compat_warn = Off
-
-; Check HTTP Referer to invalidate externally stored URLs containing ids.
-; HTTP_REFERER has to contain this substring for the session to be
-; considered as valid.
-; http://php.net/session.referer-check
-session.referer_check =
-
-; How many bytes to read from the file.
-; http://php.net/session.entropy-length
-session.entropy_length = 0
-
-; Specified here to create the session id.
-; http://php.net/session.entropy-file
-; On systems that don't have /dev/urandom /dev/arandom can be used
-; On windows, setting the entropy_length setting will activate the
-; Windows random source (using the CryptoAPI)
-;session.entropy_file = /dev/urandom
-
-; Set to {nocache,private,public,} to determine HTTP caching aspects
-; or leave this empty to avoid sending anti-caching headers.
-; http://php.net/session.cache-limiter
-session.cache_limiter = nocache
-
-; Document expires after n minutes.
-; http://php.net/session.cache-expire
-session.cache_expire = 180
-
-; trans sid support is disabled by default.
-; Use of trans sid may risk your users security.
-; Use this option with caution.
-; - User may send URL contains active session ID
-; to other person via. email/irc/etc.
-; - URL that contains active session ID may be stored
-; in publically accessible computer.
-; - User may access your site with the same session ID
-; always using URL stored in browser's history or bookmarks.
-; http://php.net/session.use-trans-sid
-session.use_trans_sid = 0
-
-; Select a hash function for use in generating session ids.
-; Possible Values
-; 0 (MD5 128 bits)
-; 1 (SHA-1 160 bits)
-; This option may also be set to the name of any hash function supported by
-; the hash extension. A list of available hashes is returned by the hash_algos()
-; function.
-; http://php.net/session.hash-function
-session.hash_function = 0
-
-; Define how many bits are stored in each character when converting
-; the binary hash data to something readable.
-; Possible values:
-; 4 (4 bits: 0-9, a-f)
-; 5 (5 bits: 0-9, a-v)
-; 6 (6 bits: 0-9, a-z, A-Z, "-", ",")
-; Default Value: 4
-; Development Value: 5
-; Production Value: 5
-; http://php.net/session.hash-bits-per-character
-session.hash_bits_per_character = 5
-
-; The URL rewriter will look for URLs in a defined set of HTML tags.
-; form/fieldset are special; if you include them here, the rewriter will
-; add a hidden field with the info which is otherwise appended
-; to URLs. If you want XHTML conformity, remove the form entry.
-; Note that all valid entries require a "=", even if no value follows.
-; Default Value: "a=href,area=href,frame=src,form=,fieldset="
-; Development Value: "a=href,area=href,frame=src,input=src,form=fakeentry"
-; Production Value: "a=href,area=href,frame=src,input=src,form=fakeentry"
-; http://php.net/url-rewriter.tags
-url_rewriter.tags = "a=href,area=href,frame=src,input=src,form=fakeentry"
-
-[MSSQL]
-; Allow or prevent persistent links.
-mssql.allow_persistent = On
-
-; Maximum number of persistent links. -1 means no limit.
-mssql.max_persistent = -1
-
-; Maximum number of links (persistent+non persistent). -1 means no limit.
-mssql.max_links = -1
-
-; Minimum error severity to display.
-mssql.min_error_severity = 10
-
-; Minimum message severity to display.
-mssql.min_message_severity = 10
-
-; Compatibility mode with old versions of PHP 3.0.
-mssql.compatability_mode = Off
-
-; Connect timeout
-;mssql.connect_timeout = 5
-
-; Query timeout
-;mssql.timeout = 60
-
-; Valid range 0 - 2147483647. Default = 4096.
-;mssql.textlimit = 4096
-
-; Valid range 0 - 2147483647. Default = 4096.
-;mssql.textsize = 4096
-
-; Limits the number of records in each batch. 0 = all records in one batch.
-;mssql.batchsize = 0
-
-; Specify how datetime and datetim4 columns are returned
-; On => Returns data converted to SQL server settings
-; Off => Returns values as YYYY-MM-DD hh:mm:ss
-;mssql.datetimeconvert = On
-
-; Use NT authentication when connecting to the server
-mssql.secure_connection = Off
-
-; Specify max number of processes. -1 = library default
-; msdlib defaults to 25
-; FreeTDS defaults to 4096
-;mssql.max_procs = -1
-
-; Specify client character set.
-; If empty or not set the client charset from freetds.comf is used
-; This is only used when compiled with FreeTDS
-;mssql.charset = "ISO-8859-1"
-
-[Assertion]
-; Assert(expr); active by default.
-; http://php.net/assert.active
-;assert.active = On
-
-; Issue a PHP warning for each failed assertion.
-; http://php.net/assert.warning
-;assert.warning = On
-
-; Don't bail out by default.
-; http://php.net/assert.bail
-;assert.bail = Off
-
-; User-function to be called if an assertion fails.
-; http://php.net/assert.callback
-;assert.callback = 0
-
-; Eval the expression with current error_reporting(). Set to true if you want
-; error_reporting(0) around the eval().
-; http://php.net/assert.quiet-eval
-;assert.quiet_eval = 0
-
-[COM]
-; path to a file containing GUIDs, IIDs or filenames of files with TypeLibs
-; http://php.net/com.typelib-file
-;com.typelib_file =
-
-; allow Distributed-COM calls
-; http://php.net/com.allow-dcom
-;com.allow_dcom = true
-
-; autoregister constants of a components typlib on com_load()
-; http://php.net/com.autoregister-typelib
-;com.autoregister_typelib = true
-
-; register constants casesensitive
-; http://php.net/com.autoregister-casesensitive
-;com.autoregister_casesensitive = false
-
-; show warnings on duplicate constant registrations
-; http://php.net/com.autoregister-verbose
-;com.autoregister_verbose = true
-
-; The default character set code-page to use when passing strings to and from COM objects.
-; Default: system ANSI code page
-;com.code_page=
-
-[mbstring]
-; language for internal character representation.
-; http://php.net/mbstring.language
-;mbstring.language = Japanese
-
-; internal/script encoding.
-; Some encoding cannot work as internal encoding.
-; (e.g. SJIS, BIG5, ISO-2022-*)
-; http://php.net/mbstring.internal-encoding
-;mbstring.internal_encoding = EUC-JP
-
-; http input encoding.
-; http://php.net/mbstring.http-input
-;mbstring.http_input = auto
-
-; http output encoding. mb_output_handler must be
-; registered as output buffer to function
-; http://php.net/mbstring.http-output
-;mbstring.http_output = SJIS
-
-; enable automatic encoding translation according to
-; mbstring.internal_encoding setting. Input chars are
-; converted to internal encoding by setting this to On.
-; Note: Do _not_ use automatic encoding translation for
-; portable libs/applications.
-; http://php.net/mbstring.encoding-translation
-;mbstring.encoding_translation = Off
-
-; automatic encoding detection order.
-; auto means
-; http://php.net/mbstring.detect-order
-;mbstring.detect_order = auto
-
-; substitute_character used when character cannot be converted
-; one from another
-; http://php.net/mbstring.substitute-character
-;mbstring.substitute_character = none;
-
-; overload(replace) single byte functions by mbstring functions.
-; mail(), ereg(), etc are overloaded by mb_send_mail(), mb_ereg(),
-; etc. Possible values are 0,1,2,4 or combination of them.
-; For example, 7 for overload everything.
-; 0: No overload
-; 1: Overload mail() function
-; 2: Overload str*() functions
-; 4: Overload ereg*() functions
-; http://php.net/mbstring.func-overload
-;mbstring.func_overload = 0
-
-; enable strict encoding detection.
-;mbstring.strict_detection = Off
-
-; This directive specifies the regex pattern of content types for which mb_output_handler()
-; is activated.
-; Default: mbstring.http_output_conv_mimetype=^(text/|application/xhtml\+xml)
-;mbstring.http_output_conv_mimetype=
-
-; Allows to set script encoding. Only affects if PHP is compiled with --enable-zend-multibyte
-; Default: ""
-;mbstring.script_encoding=
-
-[gd]
-; Tell the jpeg decode to ignore warnings and try to create
-; a gd image. The warning will then be displayed as notices
-; disabled by default
-; http://php.net/gd.jpeg-ignore-warning
-;gd.jpeg_ignore_warning = 0
-
-[exif]
-; Exif UNICODE user comments are handled as UCS-2BE/UCS-2LE and JIS as JIS.
-; With mbstring support this will automatically be converted into the encoding
-; given by corresponding encode setting. When empty mbstring.internal_encoding
-; is used. For the decode settings you can distinguish between motorola and
-; intel byte order. A decode setting cannot be empty.
-; http://php.net/exif.encode-unicode
-;exif.encode_unicode = ISO-8859-15
-
-; http://php.net/exif.decode-unicode-motorola
-;exif.decode_unicode_motorola = UCS-2BE
-
-; http://php.net/exif.decode-unicode-intel
-;exif.decode_unicode_intel = UCS-2LE
-
-; http://php.net/exif.encode-jis
-;exif.encode_jis =
-
-; http://php.net/exif.decode-jis-motorola
-;exif.decode_jis_motorola = JIS
-
-; http://php.net/exif.decode-jis-intel
-;exif.decode_jis_intel = JIS
-
-[Tidy]
-; The path to a default tidy configuration file to use when using tidy
-; http://php.net/tidy.default-config
-;tidy.default_config = /usr/local/lib/php/default.tcfg
-
-; Should tidy clean and repair output automatically?
-; WARNING: Do not use this option if you are generating non-html content
-; such as dynamic images
-; http://php.net/tidy.clean-output
-tidy.clean_output = Off
-
-[soap]
-; Enables or disables WSDL caching feature.
-; http://php.net/soap.wsdl-cache-enabled
-soap.wsdl_cache_enabled=1
-
-; Sets the directory name where SOAP extension will put cache files.
-; http://php.net/soap.wsdl-cache-dir
-soap.wsdl_cache_dir="/tmp"
-
-; (time to live) Sets the number of second while cached file will be used
-; instead of original one.
-; http://php.net/soap.wsdl-cache-ttl
-soap.wsdl_cache_ttl=86400
-
-; Sets the size of the cache limit. (Max. number of WSDL files to cache)
-soap.wsdl_cache_limit = 5
-
-[sysvshm]
-; A default size of the shared memory segment
-;sysvshm.init_mem = 10000
-
-[ldap]
-; Sets the maximum number of open links or -1 for unlimited.
-ldap.max_links = -1
-
-[mcrypt]
-; For more information about mcrypt settings see http://php.net/mcrypt-module-open
-
-; Directory where to load mcrypt algorithms
-; Default: Compiled in into libmcrypt (usually /usr/local/lib/libmcrypt)
-;mcrypt.algorithms_dir=
-
-; Directory where to load mcrypt modes
-; Default: Compiled in into libmcrypt (usually /usr/local/lib/libmcrypt)
-;mcrypt.modes_dir=
-
-[dba]
-;dba.default_handler=
-
-; Local Variables:
-; tab-width: 4
-; End:
-
diff --git a/install_minimal/airtime-uninstall b/install_minimal/airtime-uninstall
deleted file mode 100755
index bc12a4403..000000000
--- a/install_minimal/airtime-uninstall
+++ /dev/null
@@ -1,66 +0,0 @@
-#!/bin/bash
-
-#Check if root user
-if [[ $EUID -ne 0 ]]; then
- echo "Please run as root user."
- exit 1
-fi
-
-
-options=$(getopt -o p -l purge -- "$@")
-if [ $? -ne 0 ]; then
- echo "only -p or --purge parameter allowed"
- exit 1
-fi
-eval set -- "$options"
-
-purge='f'
-
-while true
-do
- case "$1" in
- -p|--purge) purge='t'; shift;;
- --) shift 1; break ;;
- *) break ;;
- esac
-done
-
-#Make 'purge' env variable available to sub bash script
-export purge
-
-rabbitmq_uninstall () {
- RABBITMQ_VHOST="/airtime"
- RABBITMQ_USER="airtime"
-
- rabbitmqctl delete_vhost $RABBITMQ_VHOST
- rabbitmqctl delete_user $RABBITMQ_USER
-}
-
-echo -e "\n******************************* Uninstall Begin ********************************"
-
-# Absolute path to this script, e.g. /home/user/bin/foo.sh
-SCRIPT=`readlink -f $0`
-# Absolute path this script is in, thus /home/user/bin
-SCRIPTPATH=`dirname $SCRIPT`
-
-rabbitmq_uninstall
-
-virtualenv_bin="/usr/lib/airtime/airtime_virtualenv/bin/"
-. ${virtualenv_bin}activate
-
-#Uninitialize Airtime
-$SCRIPTPATH/include/airtime-uninitialize.sh
-
-#Remove Airtime files
-$SCRIPTPATH/include/airtime-remove-files.sh
-
-#Remove pypo user
-python $SCRIPTPATH/../python_apps/remove-pypo-user.py
-
-#deactivate virtualenv
-deactivate
-
-echo -e "\n****************************** Uninstall Complete *******************************\n"
-echo "NOTE: To fully remove all Airtime files, you will also have to manually delete"
-echo " the directories '/srv/airtime'(default storage location of media files)"
-echo -e " and '/etc/airtime'(where the config files are stored).\n"
diff --git a/install_minimal/include/AirtimeIni.php b/install_minimal/include/AirtimeIni.php
deleted file mode 100644
index 2ca53850f..000000000
--- a/install_minimal/include/AirtimeIni.php
+++ /dev/null
@@ -1,349 +0,0 @@
-$elem) {
- if ($first_line) {
- $content .= "[".$key."]\n";
- $first_line = false;
- } else {
- $content .= "\n[".$key."]\n";
- }
- foreach ($elem as $key2=>$elem2) {
- if(is_array($elem2))
- {
- for($i=0;$i$elem) {
- if(is_array($elem))
- {
- for($i=0;$i /etc/cron.d/airtime-crons
-
-echo "* Creating /usr/lib/airtime"
-if [ "$python_service" -eq "0" ]; then
- python $AIRTIMEROOT/python_apps/api_clients/install/api_client_install.py
-
- if [ "$airtime_analyzer" = "t" ]; then
- pushd $AIRTIMEROOT/python_apps/airtime_analyzer/
- python setup.py install
- popd
- fi
- if [ "$pypo" = "t" ]; then
- python $AIRTIMEROOT/python_apps/pypo/install/pypo-copy-files.py
- fi
-fi
-
-cp -R $AIRTIMEROOT/utils /usr/lib/airtime
-cp -R $AIRTIMEROOT/python_apps/std_err_override /usr/lib/airtime
-
-echo "* Creating symbolic links in /usr/bin"
-#create symbolic links
-ln -sf /usr/lib/airtime/utils/airtime-import/airtime-import /usr/bin/airtime-import
-ln -sf /usr/lib/airtime/utils/airtime-check-system /usr/bin/airtime-check-system
-ln -sf /usr/lib/airtime/utils/airtime-log /usr/bin/airtime-log
-ln -sf /usr/lib/airtime/utils/airtime-test-soundcard /usr/bin/airtime-test-soundcard
-ln -sf /usr/lib/airtime/utils/airtime-test-stream /usr/bin/airtime-test-stream
-ln -sf /usr/lib/airtime/utils/airtime-silan /usr/bin/airtime-silan
-
-echo "* Creating /var/log/airtime"
-mkdir -p /var/log/airtime
-chmod a+x /var/log/airtime
-chown www-data:www-data /var/log/airtime/
-chown pypo:pypo /var/log/airtime/pypo
-chown pypo:pypo /var/log/airtime/pypo-liquidsoap
-
-
-if [ "$web" = "t" ]; then
- echo "* Creating /usr/share/airtime"
- rm -rf "/usr/share/airtime"
- mkdir -p /usr/share/airtime
- cp -R $AIRTIMEROOT/airtime_mvc/* /usr/share/airtime/
- rm -f /etc/logrotate.d/airtime-php
- cp $AIRTIMEROOT/airtime_mvc/build/airtime-php.logrotate /etc/logrotate.d/airtime-php
-fi
-
-echo "* Creating /var/log/airtime"
-mkdir -p /var/log/airtime
-
-echo "* Creating /var/tmp/airtime"
-mkdir -p /var/tmp/airtime
-
-#Finished copying files
diff --git a/install_minimal/include/airtime-db-install.php b/install_minimal/include/airtime-db-install.php
deleted file mode 100644
index ae49fec40..000000000
--- a/install_minimal/include/airtime-db-install.php
+++ /dev/null
@@ -1,84 +0,0 @@
-exec($sql);
- } catch (Exception $e) {
- echo " * Failed inserting {$stor_dir} in cc_music_dirs".PHP_EOL;
- echo " * Message {$e->getMessage()}".PHP_EOL;
- exit(1);
- }
-}
diff --git a/install_minimal/include/airtime-initialize.sh b/install_minimal/include/airtime-initialize.sh
deleted file mode 100755
index 05978955f..000000000
--- a/install_minimal/include/airtime-initialize.sh
+++ /dev/null
@@ -1,69 +0,0 @@
-#!/bin/bash -e
-#-e Causes bash script to exit if any of the installers
-#return with a non-zero return value.
-
-if [[ $EUID -ne 0 ]]; then
- echo "Please run as root user."
- exit 1
-fi
-
-set +e
-dist=`lsb_release -is`
-echo "Generating locales"
-for i in `ls /usr/share/airtime/locale | grep ".._.."`; do
- if [ "$dist" = "Debian" ]; then
- grep -qi "^$i" /etc/locale.gen
- if [ $? -ne 0 ]; then
- echo "$i.UTF-8 UTF-8" >> /etc/locale.gen
- fi
- else
- locale-gen "$i.utf8"
- fi
-done
-set -e
-
-if [ "$dist" = "Debian" ]; then
- /usr/sbin/locale-gen
-fi
-
-# Absolute path to this script, e.g. /home/user/bin/foo.sh
-SCRIPT=`readlink -f $0`
-# Absolute path this script is in, thus /home/user/bin
-SCRIPTPATH=`dirname $SCRIPT`
-
-AIRTIMEROOT=$SCRIPTPATH/../../
-
-if [ "$mediamonitor" = "t" ]; then
- python $AIRTIMEROOT/python_apps/media-monitor/install/media-monitor-initialize.py
-fi
-if [ "$pypo" = "t" ]; then
- python $AIRTIMEROOT/python_apps/pypo/install/pypo-initialize.py
-fi
-
-chmod 600 /etc/monit/conf.d/monit-airtime-generic.cfg
-chmod 600 /etc/monit/conf.d/monit-airtime-liquidsoap.cfg
-if [ "$mediamonitor" = "t" ]; then
- chmod 600 /etc/monit/conf.d/monit-airtime-media-monitor.cfg
-fi
-chmod 600 /etc/monit/conf.d/monit-airtime-playout.cfg
-chmod 600 /etc/monit/conf.d/monit-airtime-liquidsoap.cfg
-
-# Start monit if it is not running, or restart if it is.
-# Need to ensure monit is running before Airtime daemons are run. This is
-# so we can ensure they can register with monit to monitor them when they start.
-# If monit is already running, this step is still useful as we need monit to
-# reload its config files.
-invoke-rc.d monit restart
-
-#give monit some time to boot-up before issuing commands
-sleep 1
-
-set +e
-if [ "$mediamonitor" = "t" ]; then
- monit monitor airtime-media-monitor
-fi
-if [ "$pypo" = "t" ]; then
- monit monitor airtime-playout
- monit monitor airtime-liquidsoap
-fi
-set -e
diff --git a/install_minimal/include/airtime-install.ini b/install_minimal/include/airtime-install.ini
deleted file mode 100644
index 01d938f3a..000000000
--- a/install_minimal/include/airtime-install.ini
+++ /dev/null
@@ -1 +0,0 @@
-storage_dir = /srv/airtime/stor/
diff --git a/install_minimal/include/airtime-install.php b/install_minimal/include/airtime-install.php
deleted file mode 100644
index 481983a0f..000000000
--- a/install_minimal/include/airtime-install.php
+++ /dev/null
@@ -1,88 +0,0 @@
-/dev/null 2>&1
-monit unmonitor airtime-liquidsoap >/dev/null 2>&1
-monit unmonitor airtime-playout >/dev/null 2>&1
-set -e
-
-#uninitialize Airtime services
-python $AIRTIMEROOT/python_apps/pypo/install/pypo-uninitialize.py
-python $AIRTIMEROOT/python_apps/media-monitor/install/media-monitor-uninitialize.py
-
-if [ "$purge" = "t" ]; then
-#call Airtime uninstall script
-php --php-ini ${SCRIPTPATH}/../airtime-php.ini ${SCRIPTPATH}/airtime-uninstall.php
-fi
diff --git a/install_minimal/include/airtime-uninstall.php b/install_minimal/include/airtime-uninstall.php
deleted file mode 100644
index 20d323daf..000000000
--- a/install_minimal/include/airtime-uninstall.php
+++ /dev/null
@@ -1,107 +0,0 @@
-query($sql)->fetchAll();
- } catch (Exception $e) {
- $rows = array();
- }
-
- foreach ($rows as $row) {
- $tablename = $row["tablename"];
- echo " * Removing database table $tablename...";
-
- $sql = "DROP TABLE $tablename CASCADE";
- AirtimeInstall::InstallQuery($sql, false);
- AirtimeInstall::DropSequence($tablename."_id");
- echo "done.".PHP_EOL;
- }
-
-
- echo " * Deleting database sequences...".PHP_EOL;
- $sql = "SELECT c.relname FROM pg_class c WHERE c.relkind = 'S';";
- try {
- $rows = $con->query($sql)->fetchAll();
- } catch (Exception $e) {
- $rows = array();
- }
-
- foreach ($rows as $row) {
- $sequence = $row["relname"];
- echo " * Removing database sequence $sequence...";
-
- $sql = "DROP SEQUENCE $sequence CASCADE";
- AirtimeInstall::InstallQuery($sql, false);
- echo "done.".PHP_EOL;
- }
- }
-}
-
-//------------------------------------------------------------------------
-// Delete the user
-//------------------------------------------------------------------------
-echo " * Deleting database user '{$CC_CONFIG['dsn']['username']}'...".PHP_EOL;
-$command = "echo \"DROP USER IF EXISTS {$CC_CONFIG['dsn']['username']}\" | su postgres -c psql >/dev/null 2>&1";
-@exec($command, $output, $results);
-if ($results == 0) {
- echo " * User '{$CC_CONFIG['dsn']['username']}' deleted.".PHP_EOL;
-} else {
- echo " * Nothing to delete.".PHP_EOL;
-}
-
diff --git a/install_minimal/include/airtime-upgrade.php b/install_minimal/include/airtime-upgrade.php
deleted file mode 100644
index 563dcce5e..000000000
--- a/install_minimal/include/airtime-upgrade.php
+++ /dev/null
@@ -1,114 +0,0 @@
-&1 | grep -v \"will create implicit index\"");
- }
-}
diff --git a/install_minimal/upgrades/airtime-2.2.0/TODO b/install_minimal/upgrades/airtime-2.2.0/TODO
deleted file mode 100644
index 037b6cd5f..000000000
--- a/install_minimal/upgrades/airtime-2.2.0/TODO
+++ /dev/null
@@ -1,9 +0,0 @@
-need to install the following packages:
-
-mp3gain
-vorbisgain
-flac
-vorbis-tools
-
-
-calculate Replay Gain dB on upgrade: the default value should be NULL.
diff --git a/install_minimal/upgrades/airtime-2.2.0/airtime-upgrade.php b/install_minimal/upgrades/airtime-2.2.0/airtime-upgrade.php
deleted file mode 100644
index 924babbdb..000000000
--- a/install_minimal/upgrades/airtime-2.2.0/airtime-upgrade.php
+++ /dev/null
@@ -1,11 +0,0 @@
-fetchColumn();
-
- date_default_timezone_set($timezone);
- }
-
- public static function connectToDatabase($p_exitOnError = true)
- {
- try {
- $con = Propel::getConnection();
- } catch (Exception $e) {
- echo $e->getMessage().PHP_EOL;
- echo "Database connection problem.".PHP_EOL;
- echo "Check if database exists with corresponding permissions.".PHP_EOL;
- if ($p_exitOnError) {
- exit(1);
- }
- return false;
- }
- return true;
- }
-
-
- public static function DbTableExists($p_name)
- {
- $con = Propel::getConnection();
- try {
- $sql = "SELECT * FROM ".$p_name." LIMIT 1";
- $con->query($sql);
- } catch (PDOException $e){
- return false;
- }
- return true;
- }
-
- private static function GetAirtimeSrcDir()
- {
- return __DIR__."/../../../../airtime_mvc";
- }
-
- public static function MigrateTablesToVersion($dir, $version)
- {
- echo "Upgrading database, may take several minutes, please wait".PHP_EOL;
-
- $appDir = self::GetAirtimeSrcDir();
- $command = "php --php-ini $dir/../../airtime-php.ini ".
- "$appDir/library/doctrine/migrations/doctrine-migrations.phar ".
- "--configuration=$dir/common/migrations.xml ".
- "--db-configuration=$appDir/library/doctrine/migrations/migrations-db.php ".
- "--no-interaction migrations:migrate $version";
- system($command);
- }
-
- public static function BypassMigrations($dir, $version)
- {
- $appDir = self::GetAirtimeSrcDir();
- $command = "php --php-ini $dir/../../airtime-php.ini ".
- "$appDir/library/doctrine/migrations/doctrine-migrations.phar ".
- "--configuration=$dir/common/migrations.xml ".
- "--db-configuration=$appDir/library/doctrine/migrations/migrations-db.php ".
- "--no-interaction --add migrations:version $version";
- system($command);
- }
-
- public static function upgradeConfigFiles(){
-
- $configFiles = array(UpgradeCommon::CONF_FILE_AIRTIME,
- UpgradeCommon::CONF_FILE_PYPO,
- //this is not necessary because liquidsoap configs
- //are automatically generated
- //UpgradeCommon::CONF_FILE_LIQUIDSOAP,
- UpgradeCommon::CONF_FILE_MEDIAMONITOR,
- UpgradeCommon::CONF_FILE_API_CLIENT);
-
- // Backup the config files
- $suffix = date("Ymdhis")."-".UpgradeCommon::VERSION_NUMBER;
- foreach ($configFiles as $conf) {
- // do not back up monit cfg -- ok?? not being done anyway
- if (file_exists($conf)) {
- echo "Backing up $conf to $conf$suffix.bak".PHP_EOL;
- //copy($conf, $conf.$suffix.".bak");
- exec("cp -p $conf $conf$suffix.bak"); //use cli version to preserve file attributes
- }
- }
-
- self::CreateIniFiles(UpgradeCommon::CONF_BACKUP_SUFFIX);
- self::MergeConfigFiles($configFiles, $suffix);
-
- //HACK: This will fix a last minute bug we discovered with our upgrade scripts.
- //Will be fixed properly in 2.3.0
- $old = "list_all_db_files = 'list-all-files/format/json/api_key/%%api_key%%/dir_id/%%dir_id%%'";
- $new = "list_all_db_files = 'list-all-files/format/json/api_key/%%api_key%%/dir_id/%%dir_id%%/all/%%all%%'";
- exec("sed -i \"s#$old#$new#g\" /etc/airtime/api_client.cfg");
-
- $old = "update_start_playing_url = 'notify-media-item-start-play/api_key/%%api_key%%/media_id/%%media_id%%/schedule_id/%%schedule_id%%'";
- $new = "update_start_playing_url = 'notify-media-item-start-play/api_key/%%api_key%%/media_id/%%media_id%%/'";
- exec("sed -i \"s#$old#$new#g\" /etc/airtime/api_client.cfg");
- }
-
- /**
- * This function creates the /etc/airtime configuration folder
- * and copies the default config files to it.
- */
- public static function CreateIniFiles($suffix)
- {
- if (!file_exists("/etc/airtime/")){
- if (!mkdir("/etc/airtime/", 0755, true)){
- echo "Could not create /etc/airtime/ directory. Exiting.";
- exit(1);
- }
- }
-
- $config_copy = array(
- "../etc/airtime.conf" => self::CONF_FILE_AIRTIME,
- "../etc/pypo.cfg" => self::CONF_FILE_PYPO,
- "../etc/media-monitor.cfg" => self::CONF_FILE_MEDIAMONITOR,
- "../etc/api_client.cfg" => self::CONF_FILE_API_CLIENT
- );
-
- echo "Copying configs:\n";
- foreach ($config_copy as $path_part => $destination) {
- $full_path = OsPath::normpath(OsPath::join(__DIR__,
- "$path_part.$suffix"));
- echo "'$full_path' --> '$destination'\n";
- if(!copy($full_path, $destination)) {
- echo "Failed on the copying operation above\n";
- exit(1);
- }
- }
- }
-
- private static function MergeConfigFiles(array $configFiles, $suffix) {
- foreach ($configFiles as $conf) {
- if (file_exists("$conf$suffix.bak")) {
-
- if($conf === self::CONF_FILE_AIRTIME) {
- // Parse with sections
- $newSettings = parse_ini_file($conf, true);
- $oldSettings = parse_ini_file("$conf$suffix.bak", true);
- }
- else {
- $newSettings = self::ReadPythonConfig($conf);
- $oldSettings = self::ReadPythonConfig("$conf$suffix.bak");
- }
-
- $settings = array_keys($newSettings);
-
- foreach($settings as $section) {
- if(isset($oldSettings[$section])) {
- if(is_array($oldSettings[$section])) {
- $sectionKeys = array_keys($newSettings[$section]);
- foreach($sectionKeys as $sectionKey) {
-
- if(isset($oldSettings[$section][$sectionKey])) {
- self::UpdateIniValue($conf, $sectionKey,
- $oldSettings[$section][$sectionKey]);
- }
- }
- } else {
- self::UpdateIniValue($conf, $section,
- $oldSettings[$section]);
- }
- }
- }
- }
- }
- }
-
- private static function ReadPythonConfig($p_filename)
- {
- $values = array();
-
- $fh = fopen($p_filename, 'r');
-
- while(!feof($fh)){
- $line = fgets($fh);
- if(substr(trim($line), 0, 1) == '#' || trim($line) == ""){
- continue;
- }else{
- $info = explode('=', $line, 2);
- $values[trim($info[0])] = trim($info[1]);
- }
- }
-
- return $values;
- }
-
- /**
- * This function updates an INI style config file.
- *
- * A property and the value the property should be changed to are
- * supplied. If the property is not found, then no changes are made.
- *
- * @param string $p_filename
- * The path the to the file.
- * @param string $p_property
- * The property to look for in order to change its value.
- * @param string $p_value
- * The value the property should be changed to.
- *
- */
- private static function UpdateIniValue($p_filename, $p_property, $p_value)
- {
- $lines = file($p_filename);
- $n = count($lines);
- foreach ($lines as &$line) {
- if ($line[0] != "#"){
- $key_value = explode("=", $line);
- $key = trim($key_value[0]);
-
- if ($key == $p_property){
- $line = "$p_property = $p_value".PHP_EOL;
- }
- }
- }
-
- $fp=fopen($p_filename, 'w');
- for($i=0; $i<$n; $i++){
- fwrite($fp, $lines[$i]);
- }
- fclose($fp);
- }
-
- public static function queryDb($p_sql){
- $con = Propel::getConnection();
-
- try {
- $result = $con->query($p_sql);
- } catch (Exception $e) {
- echo "Error executing $p_sql. Exiting.";
- exit(1);
- }
-
- return $result;
- }
-}
-
-class OsPath {
- // this function is from http://stackoverflow.com/questions/2670299/is-there-a-php-equivalent-function-to-the-python-os-path-normpath
- public static function normpath($path)
- {
- if (empty($path))
- return '.';
-
- if (strpos($path, '/') === 0)
- $initial_slashes = true;
- else
- $initial_slashes = false;
- if (
- ($initial_slashes) &&
- (strpos($path, '//') === 0) &&
- (strpos($path, '///') === false)
- )
- $initial_slashes = 2;
- $initial_slashes = (int) $initial_slashes;
-
- $comps = explode('/', $path);
- $new_comps = array();
- foreach ($comps as $comp)
- {
- if (in_array($comp, array('', '.')))
- continue;
- if (
- ($comp != '..') ||
- (!$initial_slashes && !$new_comps) ||
- ($new_comps && (end($new_comps) == '..'))
- )
- array_push($new_comps, $comp);
- elseif ($new_comps)
- array_pop($new_comps);
- }
- $comps = $new_comps;
- $path = implode('/', $comps);
- if ($initial_slashes)
- $path = str_repeat('/', $initial_slashes) . $path;
- if ($path)
- return $path;
- else
- return '.';
- }
-
- /* Similar to the os.path.join python method
- * http://stackoverflow.com/a/1782990/276949 */
- public static function join() {
- $args = func_get_args();
- $paths = array();
-
- foreach($args as $arg) {
- $paths = array_merge($paths, (array)$arg);
- }
-
- foreach($paths as &$path) {
- $path = trim($path, DIRECTORY_SEPARATOR);
- }
-
- if (substr($args[0], 0, 1) == DIRECTORY_SEPARATOR) {
- $paths[0] = DIRECTORY_SEPARATOR . $paths[0];
- }
-
- return join(DIRECTORY_SEPARATOR, $paths);
- }
-}
diff --git a/install_minimal/upgrades/airtime-2.2.0/data/upgrade.sql b/install_minimal/upgrades/airtime-2.2.0/data/upgrade.sql
deleted file mode 100644
index 95e621874..000000000
--- a/install_minimal/upgrades/airtime-2.2.0/data/upgrade.sql
+++ /dev/null
@@ -1,227 +0,0 @@
-DELETE FROM cc_pref WHERE keystr = 'system_version';
-INSERT INTO cc_pref (keystr, valstr) VALUES ('system_version', '2.2.0');
-
---DELETE user column order prefs, since the number of columns has increased in 2.2
-DELETE FROM cc_pref where keystr = 'library_datatable';
-DELETE FROM cc_pref where keystr = 'timeline_datatable';
-
-INSERT INTO cc_stream_setting (keyname, value, type) VALUES ('s1_name', 'Airtime!', 'string');
-INSERT INTO cc_stream_setting (keyname, value, type) VALUES ('s2_name', '', 'string');
-INSERT INTO cc_stream_setting (keyname, value, type) VALUES ('s3_name', '', 'string');
-
-INSERT INTO cc_stream_setting (keyname, value, type) VALUES ('s1_channels', 'stereo', 'string');
-INSERT INTO cc_stream_setting (keyname, value, type) VALUES ('s2_channels', 'stereo', 'string');
-INSERT INTO cc_stream_setting (keyname, value, type) VALUES ('s3_channels', 'stereo', 'string');
-
-
-CREATE FUNCTION airtime_to_int(chartoconvert character varying) RETURNS integer
- AS
- 'SELECT CASE WHEN trim($1) SIMILAR TO ''[0-9]+'' THEN CAST(trim($1) AS integer) ELSE NULL END;'
- LANGUAGE SQL
- IMMUTABLE
- RETURNS NULL ON NULL INPUT;
-
---clean up database of scheduled items that weren't properly deleted in 2.1.x
---due to a bug
-DELETE
-FROM cc_schedule
-WHERE id IN
- (SELECT s.id
- FROM cc_schedule s
- LEFT JOIN cc_show_instances si ON s.instance_id = si.id
- WHERE si.modified_instance = 't');
-
-ALTER TABLE cc_files
- DROP CONSTRAINT cc_files_gunid_idx;
-
-DROP INDEX cc_files_file_exists_idx;
-
-DROP TABLE cc_access;
-
-CREATE SEQUENCE cc_block_id_seq
- START WITH 1
- INCREMENT BY 1
- NO MAXVALUE
- NO MINVALUE
- CACHE 1;
-
-CREATE SEQUENCE cc_blockcontents_id_seq
- START WITH 1
- INCREMENT BY 1
- NO MAXVALUE
- NO MINVALUE
- CACHE 1;
-
-CREATE SEQUENCE cc_blockcriteria_id_seq
- START WITH 1
- INCREMENT BY 1
- NO MAXVALUE
- NO MINVALUE
- CACHE 1;
-
-CREATE SEQUENCE cc_webstream_id_seq
- START WITH 1
- INCREMENT BY 1
- NO MAXVALUE
- NO MINVALUE
- CACHE 1;
-
-CREATE SEQUENCE cc_webstream_metadata_id_seq
- START WITH 1
- INCREMENT BY 1
- NO MAXVALUE
- NO MINVALUE
- CACHE 1;
-
-CREATE TABLE cc_block (
- id integer DEFAULT nextval('cc_block_id_seq'::regclass) NOT NULL,
- name character varying(255) DEFAULT ''::character varying NOT NULL,
- mtime timestamp(6) without time zone,
- utime timestamp(6) without time zone,
- creator_id integer,
- description character varying(512),
- length interval DEFAULT '00:00:00'::interval,
- type character varying(7) DEFAULT 'static'::character varying
-);
-
-CREATE TABLE cc_blockcontents (
- id integer DEFAULT nextval('cc_blockcontents_id_seq'::regclass) NOT NULL,
- block_id integer,
- file_id integer,
- "position" integer,
- cliplength interval DEFAULT '00:00:00'::interval,
- cuein interval DEFAULT '00:00:00'::interval,
- cueout interval DEFAULT '00:00:00'::interval,
- fadein time without time zone DEFAULT '00:00:00'::time without time zone,
- fadeout time without time zone DEFAULT '00:00:00'::time without time zone
-);
-
-CREATE TABLE cc_blockcriteria (
- id integer DEFAULT nextval('cc_blockcriteria_id_seq'::regclass) NOT NULL,
- criteria character varying(32) NOT NULL,
- modifier character varying(16) NOT NULL,
- "value" character varying(512) NOT NULL,
- extra character varying(512),
- block_id integer NOT NULL
-);
-
-CREATE TABLE cc_webstream (
- id integer DEFAULT nextval('cc_webstream_id_seq'::regclass) NOT NULL,
- name character varying(255) NOT NULL,
- description character varying(255) NOT NULL,
- url character varying(512) NOT NULL,
- length interval DEFAULT '00:00:00'::interval NOT NULL,
- creator_id integer NOT NULL,
- mtime timestamp(6) without time zone NOT NULL,
- utime timestamp(6) without time zone NOT NULL,
- lptime timestamp(6) without time zone,
- mime character varying(255)
-);
-
-CREATE TABLE cc_webstream_metadata (
- id integer DEFAULT nextval('cc_webstream_metadata_id_seq'::regclass) NOT NULL,
- instance_id integer NOT NULL,
- start_time timestamp without time zone NOT NULL,
- liquidsoap_data character varying(1024) NOT NULL
-);
-
-ALTER TABLE cc_files
- DROP COLUMN gunid,
- ADD COLUMN replay_gain numeric,
- ADD COLUMN owner_id integer,
- ALTER COLUMN bpm TYPE integer using airtime_to_int(bpm) /* TYPE change - table: cc_files original: character varying(8) new: integer */;
-
-ALTER TABLE cc_files
- ADD CONSTRAINT cc_files_owner_fkey FOREIGN KEY (owner_id) REFERENCES cc_subjs(id);
-
-ALTER TABLE cc_playlistcontents
- ADD COLUMN block_id integer,
- ADD COLUMN stream_id integer,
- ADD COLUMN type smallint DEFAULT 0 NOT NULL;
-
-ALTER TABLE cc_schedule
- ADD COLUMN stream_id integer;
-
-CREATE INDEX cc_schedule_instance_id_idx
- ON cc_schedule
- USING btree
- (instance_id);
-
-
-ALTER TABLE cc_subjs
- ADD COLUMN cell_phone character varying(255);
-
-ALTER TABLE cc_block
- ADD CONSTRAINT cc_block_pkey PRIMARY KEY (id);
-
-ALTER TABLE cc_blockcontents
- ADD CONSTRAINT cc_blockcontents_pkey PRIMARY KEY (id);
-
-ALTER TABLE cc_blockcriteria
- ADD CONSTRAINT cc_blockcriteria_pkey PRIMARY KEY (id);
-
-ALTER TABLE cc_webstream
- ADD CONSTRAINT cc_webstream_pkey PRIMARY KEY (id);
-
-ALTER TABLE cc_webstream_metadata
- ADD CONSTRAINT cc_webstream_metadata_pkey PRIMARY KEY (id);
-
-ALTER TABLE cc_block
- ADD CONSTRAINT cc_block_createdby_fkey FOREIGN KEY (creator_id) REFERENCES cc_subjs(id);
-
-ALTER TABLE cc_blockcontents
- ADD CONSTRAINT cc_blockcontents_block_id_fkey FOREIGN KEY (block_id) REFERENCES cc_block(id) ON DELETE CASCADE;
-
-ALTER TABLE cc_blockcontents
- ADD CONSTRAINT cc_blockcontents_file_id_fkey FOREIGN KEY (file_id) REFERENCES cc_files(id) ON DELETE CASCADE;
-
-ALTER TABLE cc_blockcriteria
- ADD CONSTRAINT cc_blockcontents_block_id_fkey FOREIGN KEY (block_id) REFERENCES cc_block(id) ON DELETE CASCADE;
-
-ALTER TABLE cc_playlistcontents
- ADD CONSTRAINT cc_playlistcontents_block_id_fkey FOREIGN KEY (block_id) REFERENCES cc_block(id) ON DELETE CASCADE;
-
-ALTER TABLE cc_schedule
- ADD CONSTRAINT cc_show_stream_fkey FOREIGN KEY (stream_id) REFERENCES cc_webstream(id) ON DELETE CASCADE;
-
-ALTER TABLE cc_webstream_metadata
- ADD CONSTRAINT cc_schedule_inst_fkey FOREIGN KEY (instance_id) REFERENCES cc_schedule(id) ON DELETE CASCADE;
-
-
-
-
-ALTER TABLE cc_playlist
- DROP CONSTRAINT cc_playlist_createdby_fkey;
-
-ALTER SEQUENCE cc_block_id_seq
- OWNED BY cc_block.id;
-
-ALTER SEQUENCE cc_blockcontents_id_seq
- OWNED BY cc_blockcontents.id;
-
-ALTER SEQUENCE cc_blockcriteria_id_seq
- OWNED BY cc_blockcriteria.id;
-
-ALTER SEQUENCE cc_webstream_id_seq
- OWNED BY cc_webstream.id;
-
-ALTER SEQUENCE cc_webstream_metadata_id_seq
- OWNED BY cc_webstream_metadata.id;
-
-ALTER TABLE cc_playlist
- ADD CONSTRAINT cc_playlist_createdby_fkey FOREIGN KEY (creator_id) REFERENCES cc_subjs(id) ON DELETE CASCADE;
-
-
-
-
-DROP FUNCTION airtime_to_int(chartoconvert character varying);
-
-UPDATE cc_files
-SET owner_id=(SELECT id FROM cc_subjs WHERE type='A' LIMIT 1)
-WHERE owner_id is NULL;
-
-UPDATE cc_files
-SET mime='audio/ogg'
-WHERE mime='audio/vorbis';
-
-
diff --git a/install_minimal/upgrades/airtime-2.2.0/etc/airtime.conf.220 b/install_minimal/upgrades/airtime-2.2.0/etc/airtime.conf.220
deleted file mode 100644
index 0853cedc9..000000000
--- a/install_minimal/upgrades/airtime-2.2.0/etc/airtime.conf.220
+++ /dev/null
@@ -1,31 +0,0 @@
-[database]
-host = localhost
-dbname = airtime
-dbuser = airtime
-dbpass = airtime
-
-[rabbitmq]
-host = 127.0.0.1
-port = 5672
-user = guest
-password = guest
-vhost = /
-
-[general]
-api_key = AAA
-web_server_user = www-data
-airtime_dir = x
-base_url = localhost
-base_port = 80
-
-;How many hours ahead of time should Airtime playout engine (PYPO)
-;cache scheduled media files.
-cache_ahead_hours = 1
-
-[monit]
-monit_user = guest
-monit_password = airtime
-
-[soundcloud]
-connection_retries = 3
-time_between_retries = 60
diff --git a/install_minimal/upgrades/airtime-2.2.0/etc/api_client.cfg.220 b/install_minimal/upgrades/airtime-2.2.0/etc/api_client.cfg.220
deleted file mode 100644
index 06e92edb2..000000000
--- a/install_minimal/upgrades/airtime-2.2.0/etc/api_client.cfg.220
+++ /dev/null
@@ -1,121 +0,0 @@
-bin_dir = "/usr/lib/airtime/api_clients"
-
-#############################
-## Common
-#############################
-
-# Value needed to access the API
-api_key = 'AAA'
-
-# Path to the base of the API
-api_base = 'api'
-
-# URL to get the version number of the server API
-version_url = 'version/api_key/%%api_key%%'
-
-#URL to register a components IP Address with the central web server
-register_component = 'register-component/format/json/api_key/%%api_key%%/component/%%component%%'
-
-# Hostname
-base_url = 'localhost'
-base_port = 80
-
-#############################
-## Config for Media Monitor
-#############################
-
-# URL to setup the media monitor
-media_setup_url = 'media-monitor-setup/format/json/api_key/%%api_key%%'
-
-# Tell Airtime the file id associated with a show instance.
-upload_recorded = 'upload-recorded/format/json/api_key/%%api_key%%/fileid/%%fileid%%/showinstanceid/%%showinstanceid%%'
-
-# URL to tell Airtime to update file's meta data
-update_media_url = 'reload-metadata/format/json/api_key/%%api_key%%/mode/%%mode%%'
-
-# URL to tell Airtime we want a listing of all files it knows about
-list_all_db_files = 'list-all-files/format/json/api_key/%%api_key%%/dir_id/%%dir_id%%'
-
-# URL to tell Airtime we want a listing of all dirs its watching (including the stor dir)
-list_all_watched_dirs = 'list-all-watched-dirs/format/json/api_key/%%api_key%%'
-
-# URL to tell Airtime we want to add watched directory
-add_watched_dir = 'add-watched-dir/format/json/api_key/%%api_key%%/path/%%path%%'
-
-# URL to tell Airtime we want to add watched directory
-remove_watched_dir = 'remove-watched-dir/format/json/api_key/%%api_key%%/path/%%path%%'
-
-# URL to tell Airtime we want to add watched directory
-set_storage_dir = 'set-storage-dir/format/json/api_key/%%api_key%%/path/%%path%%'
-
-# URL to tell Airtime about file system mount change
-update_fs_mount = 'update-file-system-mount/format/json/api_key/%%api_key%%'
-
-# URL to commit multiple updates from media monitor at the same time
-
-reload_metadata_group = 'reload-metadata-group/format/json/api_key/%%api_key%%'
-
-# URL to tell Airtime about file system mount change
-handle_watched_dir_missing = 'handle-watched-dir-missing/format/json/api_key/%%api_key%%/dir/%%dir%%'
-
-#############################
-## Config for Recorder
-#############################
-
-# URL to get the schedule of shows set to record
-show_schedule_url = 'recorded-shows/format/json/api_key/%%api_key%%'
-
-# URL to upload the recorded show's file to Airtime
-upload_file_url = 'upload-file/format/json/api_key/%%api_key%%'
-
-# URL to commit multiple updates from media monitor at the same time
-
-#number of retries to upload file if connection problem
-upload_retries = 3
-
-#time to wait between attempts to upload file if connection problem (in seconds)
-upload_wait = 60
-
-################################################################################
-# Uncomment *one of the sets* of values from the API clients below, and comment
-# out all the others.
-################################################################################
-
-#############################
-## Config for Pypo
-#############################
-
-# Schedule export path.
-# %%from%% - starting date/time in the form YYYY-MM-DD-hh-mm
-# %%to%% - starting date/time in the form YYYY-MM-DD-hh-mm
-export_url = 'schedule/api_key/%%api_key%%'
-
-get_media_url = 'get-media/file/%%file%%/api_key/%%api_key%%'
-
-# Update whether a schedule group has begun playing.
-update_item_url = 'notify-schedule-group-play/api_key/%%api_key%%/schedule_id/%%schedule_id%%'
-
-# Update whether an audio clip is currently playing.
-update_start_playing_url = 'notify-media-item-start-play/api_key/%%api_key%%/media_id/%%media_id%%/schedule_id/%%schedule_id%%'
-
-# URL to tell Airtime we want to get stream setting
-get_stream_setting = 'get-stream-setting/format/json/api_key/%%api_key%%/'
-
-#URL to update liquidsoap status
-update_liquidsoap_status = 'update-liquidsoap-status/format/json/api_key/%%api_key%%/msg/%%msg%%/stream_id/%%stream_id%%/boot_time/%%boot_time%%'
-
-#URL to check live stream auth
-check_live_stream_auth = 'check-live-stream-auth/format/json/api_key/%%api_key%%/username/%%username%%/password/%%password%%/djtype/%%djtype%%'
-
-#URL to update source status
-update_source_status = 'update-source-status/format/json/api_key/%%api_key%%/sourcename/%%sourcename%%/status/%%status%%'
-
-get_bootstrap_info = 'get-bootstrap-info/format/json/api_key/%%api_key%%'
-
-get_files_without_replay_gain = 'get-files-without-replay-gain/api_key/%%api_key%%/dir_id/%%dir_id%%'
-
-update_replay_gain_value = 'update-replay-gain-value/api_key/%%api_key%%'
-
-notify_webstream_data = 'notify-webstream-data/api_key/%%api_key%%/media_id/%%media_id%%/format/json'
-
-notify_liquidsoap_started = 'rabbitmq-do-push/api_key/%%api_key%%/format/json'
diff --git a/install_minimal/upgrades/airtime-2.2.0/etc/media-monitor.cfg.220 b/install_minimal/upgrades/airtime-2.2.0/etc/media-monitor.cfg.220
deleted file mode 100644
index b1167f56b..000000000
--- a/install_minimal/upgrades/airtime-2.2.0/etc/media-monitor.cfg.220
+++ /dev/null
@@ -1,31 +0,0 @@
-api_client = "airtime"
-
-# where the binary files live
-bin_dir = '/usr/lib/airtime/media-monitor'
-
-# where the logging files live
-log_dir = '/var/log/airtime/media-monitor'
-
-
-############################################
-# RabbitMQ settings #
-############################################
-rabbitmq_host = 'localhost'
-rabbitmq_user = 'guest'
-rabbitmq_password = 'guest'
-rabbitmq_vhost = '/'
-
-############################################
-# Media-Monitor preferences #
-############################################
-check_filesystem_events = 5 #how long to queue up events performed on the files themselves.
-check_airtime_events = 30 #how long to queue metadata input from airtime.
-
-# MM2 only:
-touch_interval = 5
-chunking_number = 450
-request_max_wait = 3.0
-rmq_event_wait = 0.1
-logpath = '/var/log/airtime/media-monitor/media-monitor.log'
-index_path = '/var/tmp/airtime/media-monitor/last_index'
-
diff --git a/install_minimal/upgrades/airtime-2.2.0/etc/pypo.cfg.220 b/install_minimal/upgrades/airtime-2.2.0/etc/pypo.cfg.220
deleted file mode 100644
index 9ffc390e4..000000000
--- a/install_minimal/upgrades/airtime-2.2.0/etc/pypo.cfg.220
+++ /dev/null
@@ -1,85 +0,0 @@
-############################################
-# pypo - configuration #
-############################################
-
-# Set the type of client you are using.
-# Currently supported types:
-# 1) "obp" = Open Broadcast Platform
-# 2) "airtime"
-#
-api_client = "airtime"
-
-############################################
-# Cache Directories #
-# *include* trailing slash !! #
-############################################
-cache_dir = '/var/tmp/airtime/pypo/cache/'
-file_dir = '/var/tmp/airtime/pypo/files/'
-tmp_dir = '/var/tmp/airtime/pypo/tmp/'
-
-############################################
-# Setup Directories #
-# Do *not* include trailing slash !! #
-############################################
-cache_base_dir = '/var/tmp/airtime/pypo'
-bin_dir = '/usr/lib/airtime/pypo'
-log_base_dir = '/var/log/airtime'
-pypo_log_dir = '/var/log/airtime/pypo'
-liquidsoap_log_dir = '/var/log/airtime/pypo-liquidsoap'
-
-############################################
-# Liquidsoap settings #
-############################################
-ls_host = '127.0.0.1'
-ls_port = '1234'
-
-############################################
-# RabbitMQ settings #
-############################################
-rabbitmq_host = 'localhost'
-rabbitmq_user = 'guest'
-rabbitmq_password = 'guest'
-rabbitmq_vhost = '/'
-
-############################################
-# pypo preferences #
-############################################
-
-# Poll interval in seconds.
-#
-# This will rarely need to be changed because any schedule changes are
-# automatically sent to pypo immediately.
-#
-# This is how often the poll script downloads new schedules and files from the
-# server in the event that no changes are made to the schedule.
-#
-poll_interval = 3600 # in seconds.
-
-
-# Push interval in seconds.
-#
-# This is how often the push script checks whether it has something new to
-# push to liquidsoap.
-#
-# It's hard to imagine a situation where this should be more than 1 second.
-#
-push_interval = 1 # in seconds
-
-# 'pre' or 'otf'. 'pre' cues while playlist preparation
-# while 'otf' (on the fly) cues while loading into ls
-# (needs the post_processor patch)
-cue_style = 'pre'
-
-############################################
-# Recorded Audio settings #
-############################################
-record_bitrate = 256
-record_samplerate = 44100
-record_channels = 2
-record_sample_size = 16
-
-#can be either ogg|mp3, mp3 recording requires installation of the package "lame"
-record_file_type = 'ogg'
-
-# base path to store recordered shows at
-base_recorded_files = '/var/tmp/airtime/show-recorder/'
diff --git a/install_minimal/upgrades/airtime-2.2.1/DbUpgrade.php b/install_minimal/upgrades/airtime-2.2.1/DbUpgrade.php
deleted file mode 100644
index bda71b900..000000000
--- a/install_minimal/upgrades/airtime-2.2.1/DbUpgrade.php
+++ /dev/null
@@ -1,24 +0,0 @@
-&1 | grep -v \"will create implicit index\"");
- }
-}
diff --git a/install_minimal/upgrades/airtime-2.2.1/airtime-upgrade.php b/install_minimal/upgrades/airtime-2.2.1/airtime-upgrade.php
deleted file mode 100644
index 042b92d05..000000000
--- a/install_minimal/upgrades/airtime-2.2.1/airtime-upgrade.php
+++ /dev/null
@@ -1,8 +0,0 @@
-&1 | grep -v \"will create implicit index\"");
- passthru("export PGPASSWORD=$password && psql -h $host -U $username -q -f $dir/data/upgrade.sql $database 2>&1 | grep -v \"will create implicit index\"");
- }
-}
diff --git a/install_minimal/upgrades/airtime-2.3.0/airtime-upgrade.php b/install_minimal/upgrades/airtime-2.3.0/airtime-upgrade.php
deleted file mode 100644
index 924babbdb..000000000
--- a/install_minimal/upgrades/airtime-2.3.0/airtime-upgrade.php
+++ /dev/null
@@ -1,11 +0,0 @@
-fetchColumn();
-
- date_default_timezone_set($timezone);
- }
-
- public static function connectToDatabase($p_exitOnError = true)
- {
- try {
- $con = Propel::getConnection();
- } catch (Exception $e) {
- echo $e->getMessage().PHP_EOL;
- echo "Database connection problem.".PHP_EOL;
- echo "Check if database exists with corresponding permissions.".PHP_EOL;
- if ($p_exitOnError) {
- exit(1);
- }
- return false;
- }
- return true;
- }
-
-
- public static function DbTableExists($p_name)
- {
- $con = Propel::getConnection();
- try {
- $sql = "SELECT * FROM ".$p_name." LIMIT 1";
- $con->query($sql);
- } catch (PDOException $e){
- return false;
- }
- return true;
- }
-
- private static function GetAirtimeSrcDir()
- {
- return __DIR__."/../../../../airtime_mvc";
- }
-
- public static function MigrateTablesToVersion($dir, $version)
- {
- echo "Upgrading database, may take several minutes, please wait".PHP_EOL;
-
- $appDir = self::GetAirtimeSrcDir();
- $command = "php --php-ini $dir/../../airtime-php.ini ".
- "$appDir/library/doctrine/migrations/doctrine-migrations.phar ".
- "--configuration=$dir/common/migrations.xml ".
- "--db-configuration=$appDir/library/doctrine/migrations/migrations-db.php ".
- "--no-interaction migrations:migrate $version";
- system($command);
- }
-
- public static function BypassMigrations($dir, $version)
- {
- $appDir = self::GetAirtimeSrcDir();
- $command = "php --php-ini $dir/../../airtime-php.ini ".
- "$appDir/library/doctrine/migrations/doctrine-migrations.phar ".
- "--configuration=$dir/common/migrations.xml ".
- "--db-configuration=$appDir/library/doctrine/migrations/migrations-db.php ".
- "--no-interaction --add migrations:version $version";
- system($command);
- }
-
- public static function upgradeConfigFiles(){
-
- $configFiles = array(UpgradeCommon::CONF_FILE_AIRTIME,
- UpgradeCommon::CONF_FILE_PYPO,
- //this is not necessary because liquidsoap configs
- //are automatically generated
- //UpgradeCommon::CONF_FILE_LIQUIDSOAP,
- UpgradeCommon::CONF_FILE_MEDIAMONITOR,
- UpgradeCommon::CONF_FILE_API_CLIENT);
-
- // Backup the config files
- $suffix = date("Ymdhis")."-".UpgradeCommon::VERSION_NUMBER;
- foreach ($configFiles as $conf) {
- // do not back up monit cfg -- ok?? not being done anyway
- if (file_exists($conf)) {
- echo "Backing up $conf to $conf$suffix.bak".PHP_EOL;
- //copy($conf, $conf.$suffix.".bak");
- exec("cp -p $conf $conf$suffix.bak"); //use cli version to preserve file attributes
- }
- }
-
- self::CreateIniFiles(UpgradeCommon::CONF_BACKUP_SUFFIX);
- self::MergeConfigFiles($configFiles, $suffix);
-
- //HACK: This will fix a last minute bug we discovered with our upgrade scripts.
- //Will be fixed properly in 2.3.0
- $old = "list_all_db_files = 'list-all-files/format/json/api_key/%%api_key%%/dir_id/%%dir_id%%'";
- $new = "list_all_db_files = 'list-all-files/format/json/api_key/%%api_key%%/dir_id/%%dir_id%%/all/%%all%%'";
- exec("sed -i \"s#$old#$new#g\" /etc/airtime/api_client.cfg");
-
- $old = "update_start_playing_url = 'notify-media-item-start-play/api_key/%%api_key%%/media_id/%%media_id%%/schedule_id/%%schedule_id%%'";
- $new = "update_start_playing_url = 'notify-media-item-start-play/api_key/%%api_key%%/media_id/%%media_id%%/'";
- exec("sed -i \"s#$old#$new#g\" /etc/airtime/api_client.cfg");
- }
-
- /**
- * This function creates the /etc/airtime configuration folder
- * and copies the default config files to it.
- */
- public static function CreateIniFiles($suffix)
- {
- if (!file_exists("/etc/airtime/")){
- if (!mkdir("/etc/airtime/", 0755, true)){
- echo "Could not create /etc/airtime/ directory. Exiting.";
- exit(1);
- }
- }
-
- $config_copy = array(
- "../etc/airtime.conf" => self::CONF_FILE_AIRTIME,
- "../etc/pypo.cfg" => self::CONF_FILE_PYPO,
- "../etc/media-monitor.cfg" => self::CONF_FILE_MEDIAMONITOR,
- "../etc/api_client.cfg" => self::CONF_FILE_API_CLIENT
- );
-
- echo "Copying configs:\n";
- foreach ($config_copy as $path_part => $destination) {
- $full_path = OsPath::normpath(OsPath::join(__DIR__,
- "$path_part.$suffix"));
- echo "'$full_path' --> '$destination'\n";
- if(!copy($full_path, $destination)) {
- echo "Failed on the copying operation above\n";
- exit(1);
- }
- }
- }
-
- private static function MergeConfigFiles(array $configFiles, $suffix) {
- foreach ($configFiles as $conf) {
- if (file_exists("$conf$suffix.bak")) {
-
- if($conf === self::CONF_FILE_AIRTIME) {
- // Parse with sections
- $newSettings = parse_ini_file($conf, true);
- $oldSettings = parse_ini_file("$conf$suffix.bak", true);
- }
- else {
- $newSettings = self::ReadPythonConfig($conf);
- $oldSettings = self::ReadPythonConfig("$conf$suffix.bak");
- }
-
- $settings = array_keys($newSettings);
-
- foreach($settings as $section) {
- if(isset($oldSettings[$section])) {
- if(is_array($oldSettings[$section])) {
- $sectionKeys = array_keys($newSettings[$section]);
- foreach($sectionKeys as $sectionKey) {
-
- if(isset($oldSettings[$section][$sectionKey])) {
- self::UpdateIniValue($conf, $sectionKey,
- $oldSettings[$section][$sectionKey]);
- }
- }
- } else {
- self::UpdateIniValue($conf, $section,
- $oldSettings[$section]);
- }
- }
- }
- }
- }
- }
-
- private static function ReadPythonConfig($p_filename)
- {
- $values = array();
-
- $fh = fopen($p_filename, 'r');
-
- while(!feof($fh)){
- $line = fgets($fh);
- if(substr(trim($line), 0, 1) == '#' || trim($line) == ""){
- continue;
- }else{
- $info = explode('=', $line, 2);
- $values[trim($info[0])] = trim($info[1]);
- }
- }
-
- return $values;
- }
-
- /**
- * This function updates an INI style config file.
- *
- * A property and the value the property should be changed to are
- * supplied. If the property is not found, then no changes are made.
- *
- * @param string $p_filename
- * The path the to the file.
- * @param string $p_property
- * The property to look for in order to change its value.
- * @param string $p_value
- * The value the property should be changed to.
- *
- */
- private static function UpdateIniValue($p_filename, $p_property, $p_value)
- {
- $lines = file($p_filename);
- $n = count($lines);
- foreach ($lines as &$line) {
- if ($line[0] != "#"){
- $key_value = explode("=", $line);
- $key = trim($key_value[0]);
-
- if ($key == $p_property){
- $line = "$p_property = $p_value".PHP_EOL;
- }
- }
- }
-
- $fp=fopen($p_filename, 'w');
- for($i=0; $i<$n; $i++){
- fwrite($fp, $lines[$i]);
- }
- fclose($fp);
- }
-
- public static function queryDb($p_sql){
- $con = Propel::getConnection();
-
- try {
- $result = $con->query($p_sql);
- } catch (Exception $e) {
- echo "Error executing $p_sql. Exiting.";
- exit(1);
- }
-
- return $result;
- }
-}
-
-class OsPath {
- // this function is from http://stackoverflow.com/questions/2670299/is-there-a-php-equivalent-function-to-the-python-os-path-normpath
- public static function normpath($path)
- {
- if (empty($path))
- return '.';
-
- if (strpos($path, '/') === 0)
- $initial_slashes = true;
- else
- $initial_slashes = false;
- if (
- ($initial_slashes) &&
- (strpos($path, '//') === 0) &&
- (strpos($path, '///') === false)
- )
- $initial_slashes = 2;
- $initial_slashes = (int) $initial_slashes;
-
- $comps = explode('/', $path);
- $new_comps = array();
- foreach ($comps as $comp)
- {
- if (in_array($comp, array('', '.')))
- continue;
- if (
- ($comp != '..') ||
- (!$initial_slashes && !$new_comps) ||
- ($new_comps && (end($new_comps) == '..'))
- )
- array_push($new_comps, $comp);
- elseif ($new_comps)
- array_pop($new_comps);
- }
- $comps = $new_comps;
- $path = implode('/', $comps);
- if ($initial_slashes)
- $path = str_repeat('/', $initial_slashes) . $path;
- if ($path)
- return $path;
- else
- return '.';
- }
-
- /* Similar to the os.path.join python method
- * http://stackoverflow.com/a/1782990/276949 */
- public static function join() {
- $args = func_get_args();
- $paths = array();
-
- foreach($args as $arg) {
- $paths = array_merge($paths, (array)$arg);
- }
-
- foreach($paths as &$path) {
- $path = trim($path, DIRECTORY_SEPARATOR);
- }
-
- if (substr($args[0], 0, 1) == DIRECTORY_SEPARATOR) {
- $paths[0] = DIRECTORY_SEPARATOR . $paths[0];
- }
-
- return join(DIRECTORY_SEPARATOR, $paths);
- }
-}
diff --git a/install_minimal/upgrades/airtime-2.3.0/data/schema.sql b/install_minimal/upgrades/airtime-2.3.0/data/schema.sql
deleted file mode 100644
index b742303f0..000000000
--- a/install_minimal/upgrades/airtime-2.3.0/data/schema.sql
+++ /dev/null
@@ -1,93 +0,0 @@
-
-CREATE SEQUENCE cc_listener_count_id_seq
- START WITH 1
- INCREMENT BY 1
- NO MAXVALUE
- NO MINVALUE
- CACHE 1;
-
-CREATE SEQUENCE cc_locale_id_seq
- START WITH 1
- INCREMENT BY 1
- NO MAXVALUE
- NO MINVALUE
- CACHE 1;
-
-CREATE SEQUENCE cc_mount_name_id_seq
- START WITH 1
- INCREMENT BY 1
- NO MAXVALUE
- NO MINVALUE
- CACHE 1;
-
-CREATE SEQUENCE cc_timestamp_id_seq
- START WITH 1
- INCREMENT BY 1
- NO MAXVALUE
- NO MINVALUE
- CACHE 1;
-
-CREATE TABLE cc_listener_count (
- id integer DEFAULT nextval('cc_listener_count_id_seq'::regclass) NOT NULL,
- timestamp_id integer NOT NULL,
- mount_name_id integer NOT NULL,
- listener_count integer NOT NULL
-);
-
-CREATE TABLE cc_locale (
- id integer DEFAULT nextval('cc_locale_id_seq'::regclass) NOT NULL,
- locale_code character varying(16) NOT NULL,
- locale_lang character varying(128) NOT NULL
-);
-
-CREATE TABLE cc_mount_name (
- id integer DEFAULT nextval('cc_mount_name_id_seq'::regclass) NOT NULL,
- mount_name character varying(255) NOT NULL
-);
-
-CREATE TABLE cc_timestamp (
- id integer DEFAULT nextval('cc_timestamp_id_seq'::regclass) NOT NULL,
- "timestamp" timestamp without time zone NOT NULL
-);
-
-ALTER TABLE cc_files
- ADD COLUMN cuein interval DEFAULT '00:00:00'::interval,
- ADD COLUMN cueout interval DEFAULT '00:00:00'::interval,
- ADD COLUMN silan_check boolean DEFAULT false,
- ADD COLUMN hidden boolean DEFAULT false;
-
-ALTER TABLE cc_schedule
- ALTER COLUMN cue_in DROP DEFAULT,
- ALTER COLUMN cue_in SET NOT NULL,
- ALTER COLUMN cue_out DROP DEFAULT,
- ALTER COLUMN cue_out SET NOT NULL;
-
-ALTER SEQUENCE cc_listener_count_id_seq
- OWNED BY cc_listener_count.id;
-
-ALTER SEQUENCE cc_locale_id_seq
- OWNED BY cc_locale.id;
-
-ALTER SEQUENCE cc_mount_name_id_seq
- OWNED BY cc_mount_name.id;
-
-ALTER SEQUENCE cc_timestamp_id_seq
- OWNED BY cc_timestamp.id;
-
-ALTER TABLE cc_listener_count
- ADD CONSTRAINT cc_listener_count_pkey PRIMARY KEY (id);
-
-ALTER TABLE cc_locale
- ADD CONSTRAINT cc_locale_pkey PRIMARY KEY (id);
-
-ALTER TABLE cc_mount_name
- ADD CONSTRAINT cc_mount_name_pkey PRIMARY KEY (id);
-
-ALTER TABLE cc_timestamp
- ADD CONSTRAINT cc_timestamp_pkey PRIMARY KEY (id);
-
-ALTER TABLE cc_listener_count
- ADD CONSTRAINT cc_mount_name_inst_fkey FOREIGN KEY (mount_name_id) REFERENCES cc_mount_name(id) ON DELETE CASCADE;
-
-ALTER TABLE cc_listener_count
- ADD CONSTRAINT cc_timestamp_inst_fkey FOREIGN KEY (timestamp_id) REFERENCES cc_timestamp(id) ON DELETE CASCADE;
diff --git a/install_minimal/upgrades/airtime-2.3.0/data/upgrade.sql b/install_minimal/upgrades/airtime-2.3.0/data/upgrade.sql
deleted file mode 100644
index ef768206e..000000000
--- a/install_minimal/upgrades/airtime-2.3.0/data/upgrade.sql
+++ /dev/null
@@ -1,47 +0,0 @@
-DELETE FROM cc_pref WHERE keystr = 'system_version';
-INSERT INTO cc_pref (keystr, valstr) VALUES ('system_version', '2.3.0');
-
-INSERT INTO cc_stream_setting ("keyname", "value", "type") VALUES ('off_air_meta', 'Airtime - offline', 'string');
-INSERT INTO cc_pref("keystr", "valstr") VALUES('enable_replay_gain', 1);
-
-INSERT INTO cc_stream_setting ("keyname", "value", "type") VALUES ('s1_admin_user', '', 'string');
-INSERT INTO cc_stream_setting ("keyname", "value", "type") VALUES ('s1_admin_pass', '', 'string');
-INSERT INTO cc_stream_setting ("keyname", "value", "type") VALUES ('s2_admin_user', '', 'string');
-INSERT INTO cc_stream_setting ("keyname", "value", "type") VALUES ('s2_admin_pass', '', 'string');
-INSERT INTO cc_stream_setting ("keyname", "value", "type") VALUES ('s3_admin_user', '', 'string');
-INSERT INTO cc_stream_setting ("keyname", "value", "type") VALUES ('s3_admin_pass', '', 'string');
-
---Make sure that cc_music_dir has a trailing '/' and cc_files does not have a leading '/'
-UPDATE cc_music_dirs SET directory = directory || '/' where id in (select id from cc_music_dirs where substr(directory, length(directory)) != '/');
-UPDATE cc_files SET filepath = substring(filepath from 2) where id in (select id from cc_files where substring(filepath from 1 for 1) = '/');
-
-UPDATE cc_files SET cueout = length where cueout = '00:00:00';
-
-UPDATE cc_schedule SET cue_out = clip_length WHERE cue_out = '00:00:00';
-
-UPDATE cc_schedule SET fade_out = '00:00:59.9' WHERE fade_out > '00:00:59.9';
-UPDATE cc_schedule SET fade_in = '00:00:59.9' WHERE fade_in > '00:00:59.9';
-UPDATE cc_playlistcontents SET fadeout = '00:00:59.9' WHERE fadeout > '00:00:59.9';
-UPDATE cc_playlistcontents SET fadein = '00:00:59.9' WHERE fadein > '00:00:59.9';
-UPDATE cc_blockcontents SET fadeout = '00:00:59.9' WHERE fadeout > '00:00:59.9';
-UPDATE cc_blockcontents SET fadein = '00:00:59.9' WHERE fadein > '00:00:59.9';
-
-INSERT INTO cc_pref("keystr", "valstr") VALUES('locale', 'en_CA');
-
-INSERT INTO cc_pref("subjid", "keystr", "valstr") VALUES(1, 'user_locale', 'en_CA');
-
-INSERT INTO cc_locale (locale_code, locale_lang) VALUES ('en_CA', 'English (Canada)');
-INSERT INTO cc_locale (locale_code, locale_lang) VALUES ('en_GB', 'English (Britain)');
-INSERT INTO cc_locale (locale_code, locale_lang) VALUES ('en_US', 'English (USA)');
-INSERT INTO cc_locale (locale_code, locale_lang) VALUES ('cs_CZ', 'Český');
-INSERT INTO cc_locale (locale_code, locale_lang) VALUES ('de_DE', 'Deutsch');
-INSERT INTO cc_locale (locale_code, locale_lang) VALUES ('de_AT', 'Österreichisches Deutsch');
-INSERT INTO cc_locale (locale_code, locale_lang) VALUES ('es_ES', 'Español');
-INSERT INTO cc_locale (locale_code, locale_lang) VALUES ('fr_FR', 'Français');
-INSERT INTO cc_locale (locale_code, locale_lang) VALUES ('it_IT', 'Italiano');
-INSERT INTO cc_locale (locale_code, locale_lang) VALUES ('ko_KR', '한국어');
-INSERT INTO cc_locale (locale_code, locale_lang) VALUES ('pl_PL', 'Polski');
-INSERT INTO cc_locale (locale_code, locale_lang) VALUES ('pt_BR', 'Português Brasileiro');
-INSERT INTO cc_locale (locale_code, locale_lang) VALUES ('ru_RU', 'Русский');
-INSERT INTO cc_locale (locale_code, locale_lang) VALUES ('zh_CN', '简体中文');
-INSERT INTO cc_locale (locale_code, locale_lang) VALUES ('el_GR', 'Ελληνικά');
diff --git a/install_minimal/upgrades/airtime-2.3.0/etc/airtime.conf.230 b/install_minimal/upgrades/airtime-2.3.0/etc/airtime.conf.230
deleted file mode 100644
index 7495bd9f3..000000000
--- a/install_minimal/upgrades/airtime-2.3.0/etc/airtime.conf.230
+++ /dev/null
@@ -1,32 +0,0 @@
-[database]
-host = localhost
-dbname = airtime
-dbuser = airtime
-dbpass = airtime
-
-[rabbitmq]
-host = 127.0.0.1
-port = 5672
-user = guest
-password = guest
-vhost = /
-
-[general]
-api_key = AAA
-web_server_user = www-data
-airtime_dir = x
-base_url = localhost
-base_port = 80
-base_dir = '/'
-
-;How many hours ahead of time should Airtime playout engine (PYPO)
-;cache scheduled media files.
-cache_ahead_hours = 1
-
-[monit]
-monit_user = guest
-monit_password = airtime
-
-[soundcloud]
-connection_retries = 3
-time_between_retries = 60
diff --git a/install_minimal/upgrades/airtime-2.3.0/etc/api_client.cfg.230 b/install_minimal/upgrades/airtime-2.3.0/etc/api_client.cfg.230
deleted file mode 100644
index 10d091b77..000000000
--- a/install_minimal/upgrades/airtime-2.3.0/etc/api_client.cfg.230
+++ /dev/null
@@ -1,128 +0,0 @@
-bin_dir = "/usr/lib/airtime/api_clients"
-
-#############################
-## Common
-#############################
-
-# Value needed to access the API
-api_key = 'AAA'
-
-# Path to the base of the API
-api_base = 'api'
-
-# URL to get the version number of the server API
-version_url = 'version/api_key/%%api_key%%'
-
-#URL to register a components IP Address with the central web server
-register_component = 'register-component/format/json/api_key/%%api_key%%/component/%%component%%'
-
-# Hostname
-host = 'localhost'
-base_port = 80
-base_dir = '/'
-
-#############################
-## Config for Media Monitor
-#############################
-
-# URL to setup the media monitor
-media_setup_url = 'media-monitor-setup/format/json/api_key/%%api_key%%'
-
-# Tell Airtime the file id associated with a show instance.
-upload_recorded = 'upload-recorded/format/json/api_key/%%api_key%%/fileid/%%fileid%%/showinstanceid/%%showinstanceid%%'
-
-# URL to tell Airtime to update file's meta data
-update_media_url = 'reload-metadata/format/json/api_key/%%api_key%%/mode/%%mode%%'
-
-# URL to tell Airtime we want a listing of all files it knows about
-list_all_db_files = 'list-all-files/format/json/api_key/%%api_key%%/dir_id/%%dir_id%%/all/%%all%%'
-
-# URL to tell Airtime we want a listing of all dirs its watching (including the stor dir)
-list_all_watched_dirs = 'list-all-watched-dirs/format/json/api_key/%%api_key%%'
-
-# URL to tell Airtime we want to add watched directory
-add_watched_dir = 'add-watched-dir/format/json/api_key/%%api_key%%/path/%%path%%'
-
-# URL to tell Airtime we want to add watched directory
-remove_watched_dir = 'remove-watched-dir/format/json/api_key/%%api_key%%/path/%%path%%'
-
-# URL to tell Airtime we want to add watched directory
-set_storage_dir = 'set-storage-dir/format/json/api_key/%%api_key%%/path/%%path%%'
-
-# URL to tell Airtime about file system mount change
-update_fs_mount = 'update-file-system-mount/format/json/api_key/%%api_key%%'
-
-# URL to commit multiple updates from media monitor at the same time
-
-reload_metadata_group = 'reload-metadata-group/format/json/api_key/%%api_key%%'
-
-# URL to tell Airtime about file system mount change
-handle_watched_dir_missing = 'handle-watched-dir-missing/format/json/api_key/%%api_key%%/dir/%%dir%%'
-
-#############################
-## Config for Recorder
-#############################
-
-# URL to get the schedule of shows set to record
-show_schedule_url = 'recorded-shows/format/json/api_key/%%api_key%%'
-
-# URL to upload the recorded show's file to Airtime
-upload_file_url = 'upload-file/format/json/api_key/%%api_key%%'
-
-# URL to commit multiple updates from media monitor at the same time
-
-#number of retries to upload file if connection problem
-upload_retries = 3
-
-#time to wait between attempts to upload file if connection problem (in seconds)
-upload_wait = 60
-
-################################################################################
-# Uncomment *one of the sets* of values from the API clients below, and comment
-# out all the others.
-################################################################################
-
-#############################
-## Config for Pypo
-#############################
-
-# Schedule export path.
-# %%from%% - starting date/time in the form YYYY-MM-DD-hh-mm
-# %%to%% - starting date/time in the form YYYY-MM-DD-hh-mm
-export_url = 'schedule/api_key/%%api_key%%'
-
-get_media_url = 'get-media/file/%%file%%/api_key/%%api_key%%'
-
-# Update whether a schedule group has begun playing.
-update_item_url = 'notify-schedule-group-play/api_key/%%api_key%%/schedule_id/%%schedule_id%%'
-
-# Update whether an audio clip is currently playing.
-update_start_playing_url = 'notify-media-item-start-play/api_key/%%api_key%%/media_id/%%media_id%%/'
-
-# URL to tell Airtime we want to get stream setting
-get_stream_setting = 'get-stream-setting/format/json/api_key/%%api_key%%/'
-
-#URL to update liquidsoap status
-update_liquidsoap_status = 'update-liquidsoap-status/format/json/api_key/%%api_key%%/msg/%%msg%%/stream_id/%%stream_id%%/boot_time/%%boot_time%%'
-
-#URL to check live stream auth
-check_live_stream_auth = 'check-live-stream-auth/format/json/api_key/%%api_key%%/username/%%username%%/password/%%password%%/djtype/%%djtype%%'
-
-#URL to update source status
-update_source_status = 'update-source-status/format/json/api_key/%%api_key%%/sourcename/%%sourcename%%/status/%%status%%'
-
-get_bootstrap_info = 'get-bootstrap-info/format/json/api_key/%%api_key%%'
-
-get_files_without_replay_gain = 'get-files-without-replay-gain/api_key/%%api_key%%/dir_id/%%dir_id%%'
-
-update_replay_gain_value = 'update-replay-gain-value/api_key/%%api_key%%'
-
-notify_webstream_data = 'notify-webstream-data/api_key/%%api_key%%/media_id/%%media_id%%/format/json'
-
-notify_liquidsoap_started = 'rabbitmq-do-push/api_key/%%api_key%%/format/json'
-
-get_stream_parameters = 'get-stream-parameters/api_key/%%api_key%%/format/json'
-
-push_stream_stats = 'push-stream-stats/api_key/%%api_key%%/format/json'
-
-update_stream_setting_table = 'update-stream-setting-table/api_key/%%api_key%%/format/json'
diff --git a/install_minimal/upgrades/airtime-2.3.0/etc/media-monitor.cfg.230 b/install_minimal/upgrades/airtime-2.3.0/etc/media-monitor.cfg.230
deleted file mode 100644
index b1167f56b..000000000
--- a/install_minimal/upgrades/airtime-2.3.0/etc/media-monitor.cfg.230
+++ /dev/null
@@ -1,31 +0,0 @@
-api_client = "airtime"
-
-# where the binary files live
-bin_dir = '/usr/lib/airtime/media-monitor'
-
-# where the logging files live
-log_dir = '/var/log/airtime/media-monitor'
-
-
-############################################
-# RabbitMQ settings #
-############################################
-rabbitmq_host = 'localhost'
-rabbitmq_user = 'guest'
-rabbitmq_password = 'guest'
-rabbitmq_vhost = '/'
-
-############################################
-# Media-Monitor preferences #
-############################################
-check_filesystem_events = 5 #how long to queue up events performed on the files themselves.
-check_airtime_events = 30 #how long to queue metadata input from airtime.
-
-# MM2 only:
-touch_interval = 5
-chunking_number = 450
-request_max_wait = 3.0
-rmq_event_wait = 0.1
-logpath = '/var/log/airtime/media-monitor/media-monitor.log'
-index_path = '/var/tmp/airtime/media-monitor/last_index'
-
diff --git a/install_minimal/upgrades/airtime-2.3.0/etc/pypo.cfg.230 b/install_minimal/upgrades/airtime-2.3.0/etc/pypo.cfg.230
deleted file mode 100644
index 9ffc390e4..000000000
--- a/install_minimal/upgrades/airtime-2.3.0/etc/pypo.cfg.230
+++ /dev/null
@@ -1,85 +0,0 @@
-############################################
-# pypo - configuration #
-############################################
-
-# Set the type of client you are using.
-# Currently supported types:
-# 1) "obp" = Open Broadcast Platform
-# 2) "airtime"
-#
-api_client = "airtime"
-
-############################################
-# Cache Directories #
-# *include* trailing slash !! #
-############################################
-cache_dir = '/var/tmp/airtime/pypo/cache/'
-file_dir = '/var/tmp/airtime/pypo/files/'
-tmp_dir = '/var/tmp/airtime/pypo/tmp/'
-
-############################################
-# Setup Directories #
-# Do *not* include trailing slash !! #
-############################################
-cache_base_dir = '/var/tmp/airtime/pypo'
-bin_dir = '/usr/lib/airtime/pypo'
-log_base_dir = '/var/log/airtime'
-pypo_log_dir = '/var/log/airtime/pypo'
-liquidsoap_log_dir = '/var/log/airtime/pypo-liquidsoap'
-
-############################################
-# Liquidsoap settings #
-############################################
-ls_host = '127.0.0.1'
-ls_port = '1234'
-
-############################################
-# RabbitMQ settings #
-############################################
-rabbitmq_host = 'localhost'
-rabbitmq_user = 'guest'
-rabbitmq_password = 'guest'
-rabbitmq_vhost = '/'
-
-############################################
-# pypo preferences #
-############################################
-
-# Poll interval in seconds.
-#
-# This will rarely need to be changed because any schedule changes are
-# automatically sent to pypo immediately.
-#
-# This is how often the poll script downloads new schedules and files from the
-# server in the event that no changes are made to the schedule.
-#
-poll_interval = 3600 # in seconds.
-
-
-# Push interval in seconds.
-#
-# This is how often the push script checks whether it has something new to
-# push to liquidsoap.
-#
-# It's hard to imagine a situation where this should be more than 1 second.
-#
-push_interval = 1 # in seconds
-
-# 'pre' or 'otf'. 'pre' cues while playlist preparation
-# while 'otf' (on the fly) cues while loading into ls
-# (needs the post_processor patch)
-cue_style = 'pre'
-
-############################################
-# Recorded Audio settings #
-############################################
-record_bitrate = 256
-record_samplerate = 44100
-record_channels = 2
-record_sample_size = 16
-
-#can be either ogg|mp3, mp3 recording requires installation of the package "lame"
-record_file_type = 'ogg'
-
-# base path to store recordered shows at
-base_recorded_files = '/var/tmp/airtime/show-recorder/'
diff --git a/install_minimal/upgrades/airtime-2.3.1/DbUpgrade.php b/install_minimal/upgrades/airtime-2.3.1/DbUpgrade.php
deleted file mode 100644
index 363b5776a..000000000
--- a/install_minimal/upgrades/airtime-2.3.1/DbUpgrade.php
+++ /dev/null
@@ -1,25 +0,0 @@
-&1 | grep -v \"will create implicit index\"");
- passthru("export PGPASSWORD=$password && psql -h $host -U $username -q -f $dir/data/upgrade.sql $database 2>&1 | grep -v \"will create implicit index\"");
- }
-}
diff --git a/install_minimal/upgrades/airtime-2.3.1/airtime-upgrade.php b/install_minimal/upgrades/airtime-2.3.1/airtime-upgrade.php
deleted file mode 100644
index 53470a0df..000000000
--- a/install_minimal/upgrades/airtime-2.3.1/airtime-upgrade.php
+++ /dev/null
@@ -1,15 +0,0 @@
-fetchColumn();
-
- date_default_timezone_set($timezone);
- }
-
- public static function connectToDatabase($p_exitOnError = true)
- {
- try {
- $con = Propel::getConnection();
- } catch (Exception $e) {
- echo $e->getMessage().PHP_EOL;
- echo "Database connection problem.".PHP_EOL;
- echo "Check if database exists with corresponding permissions.".PHP_EOL;
- if ($p_exitOnError) {
- exit(1);
- }
- return false;
- }
- return true;
- }
-
-
- public static function DbTableExists($p_name)
- {
- $con = Propel::getConnection();
- try {
- $sql = "SELECT * FROM ".$p_name." LIMIT 1";
- $con->query($sql);
- } catch (PDOException $e){
- return false;
- }
- return true;
- }
-
- private static function GetAirtimeSrcDir()
- {
- return __DIR__."/../../../../airtime_mvc";
- }
-
- public static function MigrateTablesToVersion($dir, $version)
- {
- echo "Upgrading database, may take several minutes, please wait".PHP_EOL;
-
- $appDir = self::GetAirtimeSrcDir();
- $command = "php --php-ini $dir/../../airtime-php.ini ".
- "$appDir/library/doctrine/migrations/doctrine-migrations.phar ".
- "--configuration=$dir/common/migrations.xml ".
- "--db-configuration=$appDir/library/doctrine/migrations/migrations-db.php ".
- "--no-interaction migrations:migrate $version";
- system($command);
- }
-
- public static function BypassMigrations($dir, $version)
- {
- $appDir = self::GetAirtimeSrcDir();
- $command = "php --php-ini $dir/../../airtime-php.ini ".
- "$appDir/library/doctrine/migrations/doctrine-migrations.phar ".
- "--configuration=$dir/common/migrations.xml ".
- "--db-configuration=$appDir/library/doctrine/migrations/migrations-db.php ".
- "--no-interaction --add migrations:version $version";
- system($command);
- }
-
- public static function upgradeConfigFiles(){
-
- $configFiles = array(UpgradeCommon::CONF_FILE_AIRTIME,
- UpgradeCommon::CONF_FILE_PYPO,
- //this is not necessary because liquidsoap configs
- //are automatically generated
- //UpgradeCommon::CONF_FILE_LIQUIDSOAP,
- UpgradeCommon::CONF_FILE_MEDIAMONITOR,
- UpgradeCommon::CONF_FILE_API_CLIENT);
-
- // Backup the config files
- $suffix = date("Ymdhis")."-".UpgradeCommon::VERSION_NUMBER;
- foreach ($configFiles as $conf) {
- // do not back up monit cfg -- ok?? not being done anyway
- if (file_exists($conf)) {
- echo "Backing up $conf to $conf$suffix.bak".PHP_EOL;
- //copy($conf, $conf.$suffix.".bak");
- exec("cp -p $conf $conf$suffix.bak"); //use cli version to preserve file attributes
- }
- }
-
- self::CreateIniFiles(UpgradeCommon::CONF_BACKUP_SUFFIX);
- self::MergeConfigFiles($configFiles, $suffix);
- }
-
- /**
- * This function creates the /etc/airtime configuration folder
- * and copies the default config files to it.
- */
- public static function CreateIniFiles($suffix)
- {
- if (!file_exists("/etc/airtime/")){
- if (!mkdir("/etc/airtime/", 0755, true)){
- echo "Could not create /etc/airtime/ directory. Exiting.";
- exit(1);
- }
- }
-
- $config_copy = array(
- "../etc/airtime.conf" => self::CONF_FILE_AIRTIME,
- "../etc/pypo.cfg" => self::CONF_FILE_PYPO,
- "../etc/media-monitor.cfg" => self::CONF_FILE_MEDIAMONITOR,
- "../etc/api_client.cfg" => self::CONF_FILE_API_CLIENT
- );
-
- echo "Copying configs:\n";
- foreach ($config_copy as $path_part => $destination) {
- $full_path = OsPath::normpath(OsPath::join(__DIR__,
- "$path_part.$suffix"));
- echo "'$full_path' --> '$destination'\n";
- if(!copy($full_path, $destination)) {
- echo "Failed on the copying operation above\n";
- exit(1);
- }
- }
- }
-
- private static function MergeConfigFiles(array $configFiles, $suffix) {
- foreach ($configFiles as $conf) {
- if (file_exists("$conf$suffix.bak")) {
-
- if($conf === self::CONF_FILE_AIRTIME) {
- // Parse with sections
- $newSettings = parse_ini_file($conf, true);
- $oldSettings = parse_ini_file("$conf$suffix.bak", true);
- }
- else {
- $newSettings = self::ReadPythonConfig($conf);
- $oldSettings = self::ReadPythonConfig("$conf$suffix.bak");
- }
-
- $settings = array_keys($newSettings);
-
- foreach($settings as $section) {
- if(isset($oldSettings[$section])) {
- if(is_array($oldSettings[$section])) {
- $sectionKeys = array_keys($newSettings[$section]);
- foreach($sectionKeys as $sectionKey) {
-
- if(isset($oldSettings[$section][$sectionKey])) {
- self::UpdateIniValue($conf, $sectionKey,
- $oldSettings[$section][$sectionKey]);
- }
- }
- } else {
- self::UpdateIniValue($conf, $section,
- $oldSettings[$section]);
- }
- }
- }
- }
- }
- }
-
- private static function ReadPythonConfig($p_filename)
- {
- $values = array();
-
- $fh = fopen($p_filename, 'r');
-
- while(!feof($fh)){
- $line = fgets($fh);
- if(substr(trim($line), 0, 1) == '#' || trim($line) == ""){
- continue;
- }else{
- $info = explode('=', $line, 2);
- $values[trim($info[0])] = trim($info[1]);
- }
- }
-
- return $values;
- }
-
- /**
- * This function updates an INI style config file.
- *
- * A property and the value the property should be changed to are
- * supplied. If the property is not found, then no changes are made.
- *
- * @param string $p_filename
- * The path the to the file.
- * @param string $p_property
- * The property to look for in order to change its value.
- * @param string $p_value
- * The value the property should be changed to.
- *
- */
- private static function UpdateIniValue($p_filename, $p_property, $p_value)
- {
- $lines = file($p_filename);
- $n = count($lines);
- foreach ($lines as &$line) {
- if ($line[0] != "#"){
- $key_value = explode("=", $line);
- $key = trim($key_value[0]);
-
- if ($key == $p_property){
- $line = "$p_property = $p_value".PHP_EOL;
- }
- }
- }
-
- $fp=fopen($p_filename, 'w');
- for($i=0; $i<$n; $i++){
- fwrite($fp, $lines[$i]);
- }
- fclose($fp);
- }
-
- public static function queryDb($p_sql){
- $con = Propel::getConnection();
-
- try {
- $result = $con->query($p_sql);
- } catch (Exception $e) {
- echo "Error executing $p_sql. Exiting.";
- exit(1);
- }
-
- return $result;
- }
-}
-
-class OsPath {
- // this function is from http://stackoverflow.com/questions/2670299/is-there-a-php-equivalent-function-to-the-python-os-path-normpath
- public static function normpath($path)
- {
- if (empty($path))
- return '.';
-
- if (strpos($path, '/') === 0)
- $initial_slashes = true;
- else
- $initial_slashes = false;
- if (
- ($initial_slashes) &&
- (strpos($path, '//') === 0) &&
- (strpos($path, '///') === false)
- )
- $initial_slashes = 2;
- $initial_slashes = (int) $initial_slashes;
-
- $comps = explode('/', $path);
- $new_comps = array();
- foreach ($comps as $comp)
- {
- if (in_array($comp, array('', '.')))
- continue;
- if (
- ($comp != '..') ||
- (!$initial_slashes && !$new_comps) ||
- ($new_comps && (end($new_comps) == '..'))
- )
- array_push($new_comps, $comp);
- elseif ($new_comps)
- array_pop($new_comps);
- }
- $comps = $new_comps;
- $path = implode('/', $comps);
- if ($initial_slashes)
- $path = str_repeat('/', $initial_slashes) . $path;
- if ($path)
- return $path;
- else
- return '.';
- }
-
- /* Similar to the os.path.join python method
- * http://stackoverflow.com/a/1782990/276949 */
- public static function join() {
- $args = func_get_args();
- $paths = array();
-
- foreach($args as $arg) {
- $paths = array_merge($paths, (array)$arg);
- }
-
- foreach($paths as &$path) {
- $path = trim($path, DIRECTORY_SEPARATOR);
- }
-
- if (substr($args[0], 0, 1) == DIRECTORY_SEPARATOR) {
- $paths[0] = DIRECTORY_SEPARATOR . $paths[0];
- }
-
- return join(DIRECTORY_SEPARATOR, $paths);
- }
-}
diff --git a/install_minimal/upgrades/airtime-2.3.1/data/upgrade.sql b/install_minimal/upgrades/airtime-2.3.1/data/upgrade.sql
deleted file mode 100644
index 6b3bb0a42..000000000
--- a/install_minimal/upgrades/airtime-2.3.1/data/upgrade.sql
+++ /dev/null
@@ -1,2 +0,0 @@
-DELETE FROM cc_pref WHERE keystr = 'system_version';
-INSERT INTO cc_pref (keystr, valstr) VALUES ('system_version', '2.3.1');
diff --git a/install_minimal/upgrades/airtime-2.4.0/ConfFileUpgrade.php b/install_minimal/upgrades/airtime-2.4.0/ConfFileUpgrade.php
deleted file mode 100644
index 4daae0e5a..000000000
--- a/install_minimal/upgrades/airtime-2.4.0/ConfFileUpgrade.php
+++ /dev/null
@@ -1,28 +0,0 @@
-&1 | grep -v \"will create implicit index\"");
- passthru("export PGPASSWORD=$password && psql -h $host -U $username -q -f $dir/data/upgrade.sql $database 2>&1 | grep -v \"will create implicit index\"");
- }
-}
diff --git a/install_minimal/upgrades/airtime-2.4.0/airtime-upgrade.php b/install_minimal/upgrades/airtime-2.4.0/airtime-upgrade.php
deleted file mode 100644
index 924babbdb..000000000
--- a/install_minimal/upgrades/airtime-2.4.0/airtime-upgrade.php
+++ /dev/null
@@ -1,11 +0,0 @@
-$elem) {
- if ($first_line) {
- $content .= "[".$key."]\n";
- $first_line = false;
- } else {
- $content .= "\n[".$key."]\n";
- }
- foreach ($elem as $key2=>$elem2) {
- if(is_array($elem2))
- {
- for($i=0;$i$elem) {
- if(is_array($elem))
- {
- for($i=0;$i&1 | grep -v \"will create implicit index\"");
- }
-}
diff --git a/install_minimal/upgrades/airtime-2.4.1/airtime-upgrade.php b/install_minimal/upgrades/airtime-2.4.1/airtime-upgrade.php
deleted file mode 100644
index 042b92d05..000000000
--- a/install_minimal/upgrades/airtime-2.4.1/airtime-upgrade.php
+++ /dev/null
@@ -1,8 +0,0 @@
-&1 | grep -v \"will create implicit index\"");
- passthru("export PGPASSWORD=$password && psql -h $host -U $username -q -f $dir/data/upgrade.sql $database 2>&1 | grep -v \"will create implicit index\"");
- }
-}
diff --git a/install_minimal/upgrades/airtime-2.5.0/airtime-upgrade.php b/install_minimal/upgrades/airtime-2.5.0/airtime-upgrade.php
deleted file mode 100644
index 042b92d05..000000000
--- a/install_minimal/upgrades/airtime-2.5.0/airtime-upgrade.php
+++ /dev/null
@@ -1,8 +0,0 @@
-1 )
-AND ins.id NOT IN (SELECT min(id) FROM cc_show_instances GROUP BY starts,ends,show_id HAVING count(*) >1 );
-
-
-DELETE FROM cc_schedule
-WHERE id
-IN (SELECT sc.id FROM cc_schedule AS sc LEFT JOIN cc_show_instances AS i ON sc.instance_id=i.id LEFT JOIN cc_show AS s ON i.show_id=s.id WHERE sc.starts&1 | grep -v \"will create implicit index\"");
- }
-}
diff --git a/install_minimal/upgrades/airtime-2.5.1/airtime-upgrade.php b/install_minimal/upgrades/airtime-2.5.1/airtime-upgrade.php
deleted file mode 100644
index 042b92d05..000000000
--- a/install_minimal/upgrades/airtime-2.5.1/airtime-upgrade.php
+++ /dev/null
@@ -1,8 +0,0 @@
-&1 | grep -v \"will create implicit index\"");
- }
-}
diff --git a/install_minimal/upgrades/airtime-2.5.3/StorageQuotaUpgrade.php b/install_minimal/upgrades/airtime-2.5.3/StorageQuotaUpgrade.php
deleted file mode 100644
index 595861087..000000000
--- a/install_minimal/upgrades/airtime-2.5.3/StorageQuotaUpgrade.php
+++ /dev/null
@@ -1,27 +0,0 @@
-filterByType('stor')
- ->filterByExists(true)
- ->findOne();
- $storPath = $musicDir->getDirectory();
-
- $f = $storPath;
- $io = popen('/usr/bin/du -bs ' . $f, 'r');
- $size = fgets($io, 4096);
- $size = substr($size, 0, strpos($size, "\t"));
- pclose($io);
-
- Application_Model_Preference::setDiskUsage($size);
- }
-}
diff --git a/install_minimal/upgrades/airtime-2.5.3/airtime-upgrade.php b/install_minimal/upgrades/airtime-2.5.3/airtime-upgrade.php
deleted file mode 100644
index 31792eb7a..000000000
--- a/install_minimal/upgrades/airtime-2.5.3/airtime-upgrade.php
+++ /dev/null
@@ -1,10 +0,0 @@
-getMessage().PHP_EOL;
- echo "Database connection problem.".PHP_EOL;
- echo "Check if database exists with corresponding permissions.".PHP_EOL;
- if ($p_exitOnError) {
- exit(1);
- }
- return false;
- }
- return true;
- }
-
-
- public static function DbTableExists($p_name)
- {
- $con = Propel::getConnection();
- try {
- $sql = "SELECT * FROM ".$p_name." LIMIT 1";
- $con->query($sql);
- } catch (PDOException $e){
- return false;
- }
- return true;
- }
-
- private static function GetAirtimeSrcDir()
- {
- return __DIR__."/../../../airtime_mvc";
- }
-
- public static function MigrateTablesToVersion($dir, $version)
- {
- $appDir = self::GetAirtimeSrcDir();
- $command = "php --php-ini $dir/../../airtime-php.ini ".
- "$appDir/library/doctrine/migrations/doctrine-migrations.phar ".
- "--configuration=$dir/../../DoctrineMigrations/migrations.xml ".
- "--db-configuration=$appDir/library/doctrine/migrations/migrations-db.php ".
- "--no-interaction migrations:migrate $version";
- system($command);
- }
-
- public static function BypassMigrations($dir, $version)
- {
- $appDir = self::GetAirtimeSrcDir();
- $command = "php --php-ini $dir/../../airtime-php.ini ".
- "$appDir/library/doctrine/migrations/doctrine-migrations.phar ".
- "--configuration=$dir/../../DoctrineMigrations/migrations.xml ".
- "--db-configuration=$appDir/library/doctrine/migrations/migrations-db.php ".
- "--no-interaction --add migrations:version $version";
- system($command);
- }
-
- public static function upgradeConfigFiles(){
-
- $configFiles = array(UpgradeCommon::CONF_FILE_AIRTIME,
- UpgradeCommon::CONF_FILE_PYPO,
- UpgradeCommon::CONF_FILE_RECORDER,
- UpgradeCommon::CONF_FILE_LIQUIDSOAP,
- UpgradeCommon::CONF_FILE_MEDIAMONITOR,
- UpgradeCommon::CONF_FILE_API_CLIENT);
-
- // Backup the config files
- $suffix = date("Ymdhis")."-".UpgradeCommon::VERSION_NUMBER;
- foreach ($configFiles as $conf) {
- // do not back up monit cfg
- if (file_exists($conf)) {
- echo "Backing up $conf to $conf$suffix.bak".PHP_EOL;
- //copy($conf, $conf.$suffix.".bak");
- exec("cp -p $conf $conf$suffix.bak"); //use cli version to preserve file attributes
- }
- }
-
- self::CreateIniFiles(UpgradeCommon::CONF_BACKUP_SUFFIX);
- self::MergeConfigFiles($configFiles, $suffix);
- }
-
- /**
- * This function creates the /etc/airtime configuration folder
- * and copies the default config files to it.
- */
- public static function CreateIniFiles($suffix)
- {
- if (!file_exists("/etc/airtime/")){
- if (!mkdir("/etc/airtime/", 0755, true)){
- echo "Could not create /etc/airtime/ directory. Exiting.";
- exit(1);
- }
- }
-
- if (!copy(__DIR__."/airtime.conf.$suffix", self::CONF_FILE_AIRTIME)){
- echo "Could not copy airtime.conf to /etc/airtime/. Exiting.";
- exit(1);
- }
- if (!copy(__DIR__."/pypo.cfg.$suffix", self::CONF_FILE_PYPO)){
- echo "Could not copy pypo.cfg to /etc/airtime/. Exiting.";
- exit(1);
- }
- if (!copy(__DIR__."/recorder.cfg.$suffix", self::CONF_FILE_RECORDER)){
- echo "Could not copy recorder.cfg to /etc/airtime/. Exiting.";
- exit(1);
- }
- if (!copy(__DIR__."/api_client.cfg.$suffix", self::CONF_FILE_API_CLIENT)){
- echo "Could not copy airtime-monit.cfg to /etc/monit/conf.d/. Exiting.";
- exit(1);
- }
- }
-
- private static function MergeConfigFiles($configFiles, $suffix) {
- foreach ($configFiles as $conf) {
- // we want to use new liquidsoap.cfg so don't merge
- // also for monit
- if( $conf == self::CONF_FILE_LIQUIDSOAP){
- continue;
- }
- if (file_exists("$conf$suffix.bak")) {
-
- if($conf === self::CONF_FILE_AIRTIME) {
- // Parse with sections
- $newSettings = parse_ini_file($conf, true);
- $oldSettings = parse_ini_file("$conf$suffix.bak", true);
- }
- else {
- $newSettings = self::ReadPythonConfig($conf);
- $oldSettings = self::ReadPythonConfig("$conf$suffix.bak");
- }
-
- $settings = array_keys($newSettings);
-
- foreach($settings as $section) {
- if(isset($oldSettings[$section])) {
- if(is_array($oldSettings[$section])) {
- $sectionKeys = array_keys($newSettings[$section]);
- foreach($sectionKeys as $sectionKey) {
- // skip airtim_dir as we want to use new value
- if($sectionKey != "airtime_dir"){
- if(isset($oldSettings[$section][$sectionKey])) {
- self::UpdateIniValue($conf, $sectionKey, $oldSettings[$section][$sectionKey]);
- }
- }
- }
- }
- else {
- self::UpdateIniValue($conf, $section, $oldSettings[$section]);
- }
- }
- }
- }
- }
- }
-
- private static function ReadPythonConfig($p_filename)
- {
- $values = array();
-
- $fh = fopen($p_filename, 'r');
-
- while(!feof($fh)){
- $line = fgets($fh);
- if(substr(trim($line), 0, 1) == '#' || trim($line) == ""){
- continue;
- }else{
- $info = explode('=', $line, 2);
- $values[trim($info[0])] = trim($info[1]);
- }
- }
-
- return $values;
- }
-
- /**
- * This function updates an INI style config file.
- *
- * A property and the value the property should be changed to are
- * supplied. If the property is not found, then no changes are made.
- *
- * @param string $p_filename
- * The path the to the file.
- * @param string $p_property
- * The property to look for in order to change its value.
- * @param string $p_value
- * The value the property should be changed to.
- *
- */
- private static function UpdateIniValue($p_filename, $p_property, $p_value)
- {
- $lines = file($p_filename);
- $n=count($lines);
- foreach ($lines as &$line) {
- if ($line[0] != "#"){
- $key_value = explode("=", $line);
- $key = trim($key_value[0]);
-
- if ($key == $p_property){
- $line = "$p_property = $p_value".PHP_EOL;
- }
- }
- }
-
- $fp=fopen($p_filename, 'w');
- for($i=0; $i<$n; $i++){
- fwrite($fp, $lines[$i]);
- }
- fclose($fp);
- }
-}
diff --git a/install_minimal/upgrades/upgrade-template/airtime-upgrade.php b/install_minimal/upgrades/upgrade-template/airtime-upgrade.php
deleted file mode 100644
index dbe5c7589..000000000
--- a/install_minimal/upgrades/upgrade-template/airtime-upgrade.php
+++ /dev/null
@@ -1,82 +0,0 @@
-
ServerAdmin foo@bar.org
- DocumentRoot /usr/share/airtime/public
+ DocumentRoot WEB_ROOT
php_admin_value upload_tmp_dir /tmp
-
+
DirectoryIndex index.php
AllowOverride all
Order allow,deny
diff --git a/installer/apache/airtime-vhost-2.4 b/installer/apache/airtime-vhost-2.4
new file mode 100644
index 000000000..a1060d875
--- /dev/null
+++ b/installer/apache/airtime-vhost-2.4
@@ -0,0 +1,14 @@
+
+ ServerAdmin foo@bar.org
+ DocumentRoot WEB_ROOT
+ php_admin_value upload_tmp_dir /tmp
+
+
+ DirectoryIndex index.php
+ AllowOverride all
+ Order allow,deny
+ Allow from all
+
+ Require all granted
+
+
diff --git a/installer/lib/requirements-debian-jessie.apt b/installer/lib/requirements-debian-jessie.apt
new file mode 100644
index 000000000..1d0b076b2
--- /dev/null
+++ b/installer/lib/requirements-debian-jessie.apt
@@ -0,0 +1,57 @@
+apache2
+libapache2-mod-php5
+php5
+zendframework
+php-pear
+php5-gd
+
+lsb-release
+
+rabbitmq-server
+
+postgresql
+postgresql-client
+php5-pgsql
+
+python
+python-virtualenv
+python-pip
+
+libsoundtouch-ocaml
+libtaglib-ocaml
+libao-ocaml
+libmad-ocaml
+ecasound
+libportaudio2
+libsamplerate0
+libvo-aacenc0
+
+patch
+
+icecast2
+
+php5-curl
+mpg123
+
+libcamomile-ocaml-data
+libpulse0
+vorbis-tools
+lsb-release
+lsof
+vorbisgain
+flac
+vorbis-tools
+pwgen
+libfaad2
+php-apc
+
+lame
+
+coreutils
+
+liquidsoap
+
+libopus0
+
+sysvinit
+sysvinit-utils
\ No newline at end of file
diff --git a/installer/lib/requirements-debian-wheezy.apt b/installer/lib/requirements-debian-wheezy.apt
new file mode 100644
index 000000000..61de957c6
--- /dev/null
+++ b/installer/lib/requirements-debian-wheezy.apt
@@ -0,0 +1,58 @@
+apache2
+libapache2-mod-php5
+php5
+zendframework
+php-pear
+php5-gd
+
+lsb-release
+
+rabbitmq-server
+
+postgresql
+postgresql-client
+php5-pgsql
+
+python
+python-virtualenv
+python-pip
+
+libsoundtouch-ocaml
+libtaglib-ocaml
+libao-ocaml
+libmad-ocaml
+ecasound
+libportaudio2
+libsamplerate0
+libvo-aacenc0
+
+patch
+
+icecast2
+
+php5-curl
+mpg123
+
+libcamomile-ocaml-data
+libpulse0
+vorbis-tools
+lsb-release
+lsof
+mp3gain
+vorbisgain
+flac
+vorbis-tools
+pwgen
+libfaad2
+php-apc
+
+lame
+
+coreutils
+
+liquidsoap
+
+libopus0
+
+sysvinit
+sysvinit-utils
\ No newline at end of file
diff --git a/installer/lib/requirements-ubuntu-precise.apt b/installer/lib/requirements-ubuntu-precise.apt
new file mode 100644
index 000000000..88e948473
--- /dev/null
+++ b/installer/lib/requirements-ubuntu-precise.apt
@@ -0,0 +1,66 @@
+apache2
+libapache2-mod-php5
+php5
+libzend-framework-php
+php-pear
+php5-gd
+
+lsb-release
+
+rabbitmq-server
+
+postgresql
+postgresql-client
+php5-pgsql
+
+python
+python-virtualenv
+python-pip
+
+libsoundtouch-ocaml
+libtaglib-ocaml
+libao-ocaml
+libmad-ocaml
+ecasound
+libportaudio2
+libsamplerate0
+
+patch
+
+php5-curl
+mpg123
+
+icecast2
+
+libcamomile-ocaml-data
+libpulse0
+vorbis-tools
+lsb-release
+lsof
+mp3gain
+vorbisgain
+flac
+vorbis-tools
+pwgen
+libfaad2
+php-apc
+dbus
+
+lame
+
+coreutils
+
+liquidsoap
+liquidsoap-plugin-alsa
+liquidsoap-plugin-ao
+liquidsoap-plugin-faad
+liquidsoap-plugin-flac
+liquidsoap-plugin-icecast
+liquidsoap-plugin-lame
+liquidsoap-plugin-mad
+liquidsoap-plugin-ogg
+liquidsoap-plugin-portaudio
+liquidsoap-plugin-pulseaudio
+liquidsoap-plugin-taglib
+liquidsoap-plugin-voaacenc
+liquidsoap-plugin-vorbis
\ No newline at end of file
diff --git a/installer/lib/requirements-ubuntu-saucy.apt b/installer/lib/requirements-ubuntu-saucy.apt
new file mode 100644
index 000000000..5d410413d
--- /dev/null
+++ b/installer/lib/requirements-ubuntu-saucy.apt
@@ -0,0 +1,69 @@
+apache2
+libapache2-mod-php5
+php5
+libzend-framework-php
+php-pear
+php5-gd
+php5-json
+
+lsb-release
+
+rabbitmq-server
+
+postgresql
+postgresql-client
+php5-pgsql
+
+python
+python-virtualenv
+python-pip
+
+libsoundtouch-ocaml
+libtaglib-ocaml
+libao-ocaml
+libmad-ocaml
+ecasound
+libportaudio2
+libsamplerate0
+
+patch
+
+php5-curl
+mpg123
+
+icecast2
+
+libcamomile-ocaml-data
+libpulse0
+vorbis-tools
+lsb-release
+lsof
+mp3gain
+vorbisgain
+flac
+vorbis-tools
+pwgen
+libfaad2
+php-apc
+
+lame
+
+coreutils
+
+liquidsoap
+liquidsoap-plugin-alsa
+liquidsoap-plugin-ao
+liquidsoap-plugin-faad
+liquidsoap-plugin-flac
+liquidsoap-plugin-icecast
+liquidsoap-plugin-lame
+liquidsoap-plugin-mad
+liquidsoap-plugin-ogg
+liquidsoap-plugin-portaudio
+liquidsoap-plugin-pulseaudio
+liquidsoap-plugin-taglib
+liquidsoap-plugin-voaacenc
+liquidsoap-plugin-vorbis
+
+silan
+libopus0
\ No newline at end of file
diff --git a/installer/lib/requirements-ubuntu-trusty.apt b/installer/lib/requirements-ubuntu-trusty.apt
new file mode 100644
index 000000000..939b8f1d1
--- /dev/null
+++ b/installer/lib/requirements-ubuntu-trusty.apt
@@ -0,0 +1,70 @@
+apache2
+libapache2-mod-php5
+php5
+libzend-framework-php
+php-pear
+php5-gd
+
+lsb-release
+
+rabbitmq-server
+
+postgresql
+postgresql-client
+php5-pgsql
+
+python
+python-virtualenv
+python-pip
+
+libsoundtouch-ocaml
+libtaglib-ocaml
+libao-ocaml
+libmad-ocaml
+ecasound
+libportaudio2
+libsamplerate0
+
+patch
+
+php5-curl
+mpg123
+
+icecast2
+
+libcamomile-ocaml-data
+libpulse0
+vorbis-tools
+lsb-release
+lsof
+mp3gain
+vorbisgain
+flac
+vorbis-tools
+pwgen
+libfaad2
+php-apc
+
+lame
+
+coreutils
+
+liquidsoap
+liquidsoap-plugin-alsa
+liquidsoap-plugin-ao
+liquidsoap-plugin-faad
+liquidsoap-plugin-flac
+liquidsoap-plugin-icecast
+liquidsoap-plugin-lame
+liquidsoap-plugin-mad
+liquidsoap-plugin-ogg
+liquidsoap-plugin-portaudio
+liquidsoap-plugin-pulseaudio
+liquidsoap-plugin-taglib
+liquidsoap-plugin-voaacenc
+liquidsoap-plugin-vorbis
+
+silan
+libopus0
+
+sysvinit-utils
\ No newline at end of file
diff --git a/installer/lib/requirements-ubuntu-vivid.apt b/installer/lib/requirements-ubuntu-vivid.apt
new file mode 100644
index 000000000..795e1d05e
--- /dev/null
+++ b/installer/lib/requirements-ubuntu-vivid.apt
@@ -0,0 +1,69 @@
+apache2
+libapache2-mod-php5
+php5
+libzend-framework-php
+php-pear
+php5-gd
+
+lsb-release
+
+rabbitmq-server
+
+postgresql
+postgresql-client
+php5-pgsql
+
+python
+python-virtualenv
+python-pip
+
+libsoundtouch-ocaml
+libtaglib-ocaml
+libao-ocaml
+libmad-ocaml
+ecasound
+libportaudio2
+libsamplerate0
+
+patch
+
+php5-curl
+mpg123
+
+icecast2
+
+libcamomile-ocaml-data
+libpulse0
+vorbis-tools
+lsb-release
+lsof
+vorbisgain
+flac
+vorbis-tools
+pwgen
+libfaad2
+php-apc
+
+lame
+
+coreutils
+
+liquidsoap
+liquidsoap-plugin-alsa
+liquidsoap-plugin-ao
+liquidsoap-plugin-faad
+liquidsoap-plugin-flac
+liquidsoap-plugin-icecast
+liquidsoap-plugin-lame
+liquidsoap-plugin-mad
+liquidsoap-plugin-ogg
+liquidsoap-plugin-portaudio
+liquidsoap-plugin-pulseaudio
+liquidsoap-plugin-taglib
+liquidsoap-plugin-voaacenc
+liquidsoap-plugin-vorbis
+
+silan
+libopus0
+
+sysvinit-utils
diff --git a/installer/lxc-bootstrap b/installer/lxc-bootstrap
new file mode 100755
index 000000000..c361d46b5
--- /dev/null
+++ b/installer/lxc-bootstrap
@@ -0,0 +1,60 @@
+#!/bin/bash -e
+#-e Causes bash script to exit if any of the installers
+#return with a non-zero return value.
+
+if [[ $EUID -ne 0 ]]; then
+ echo "Please run as root user."
+ exit 1
+fi
+
+dist=$1
+release=$2
+name=airtime-install
+
+set +e
+echo -e "\n * Stopping ${name}..."
+lxc-stop -n airtime-install
+echo "...Done"
+
+echo -e "\n * Destroying ${name}..."
+lxc-destroy -n airtime-install
+echo "...Done"
+set -e
+
+###
+# ! NOTE: If you run into errors resolving the archives when running apt-get update,
+# clear your /var/cache/lxc directory and retry.
+###
+
+echo -e "\n * Creating ${name} with dist ${dist} and release ${release}..."
+lxc-create -t ${dist} -n ${name} -- --release ${release}
+echo "...Done"
+
+echo -e "\n * Starting ${name}..."
+lxc-start -n ${name} -d
+echo "...Done"
+
+echo -e "\n * Running apt update..."
+lxc-attach -n ${name} -- apt-get update
+echo "...Done"
+
+echo -e "\n * Installing git..."
+lxc-attach -n ${name} -- apt-get -y --force-yes install git
+echo "...Done"
+
+echo -e "\n * Cloning Airtime..."
+lxc-attach -n ${name} -- git clone https://github.com/sourcefabric/Airtime.git /usr/share/Airtime --branch 2.5.x-installer-monitless --depth 1
+echo "...Done"
+
+echo -e "\n * Running installer..."
+lxc-attach -n ${name} -e -- /usr/share/Airtime/install -ifapdIv
+echo "...Done"
+
+IP=$(lxc-info -i -n ${name} -H)
+echo -e "\n * Opening ${name} in your browser..."
+if hash xdg-open 2>/dev/null; then
+ xdg-open "http://${IP}/"
+elif hash gnome-open 2>/dev/null; then
+ gnome-open "http://${IP}/"
+fi
+echo "...Done"
diff --git a/install_full/php5/airtime.ini b/installer/php/airtime.ini
similarity index 100%
rename from install_full/php5/airtime.ini
rename to installer/php/airtime.ini
diff --git a/python_apps/api_clients/api_client.cfg b/python_apps/api_clients/api_client.cfg
deleted file mode 100644
index 5bcce0bfa..000000000
--- a/python_apps/api_clients/api_client.cfg
+++ /dev/null
@@ -1,12 +0,0 @@
-bin_dir = "/usr/lib/airtime/api_clients"
-
-# Value needed to access the API
-api_key = 'AAA'
-
-# Path to the base of the API
-api_base = 'api'
-
-# Hostname
-host = 'localhost'
-base_port = 80
-base_dir = '/'
diff --git a/python_apps/api_clients/__init__.py b/python_apps/api_clients/api_clients/__init__.py
similarity index 100%
rename from python_apps/api_clients/__init__.py
rename to python_apps/api_clients/api_clients/__init__.py
diff --git a/python_apps/api_clients/api_client.py b/python_apps/api_clients/api_clients/api_client.py
similarity index 95%
rename from python_apps/api_clients/api_client.py
rename to python_apps/api_clients/api_clients/api_client.py
index 6c12e6fb6..6710c959b 100644
--- a/python_apps/api_clients/api_client.py
+++ b/python_apps/api_clients/api_clients/api_client.py
@@ -83,6 +83,8 @@ api_config['push_stream_stats'] = 'push-stream-stats/api_key/%%api_key%%/format/
api_config['update_stream_setting_table'] = 'update-stream-setting-table/api_key/%%api_key%%/format/json'
api_config['get_files_without_silan_value'] = 'get-files-without-silan-value/api_key/%%api_key%%'
api_config['update_cue_values_by_silan'] = 'update-cue-values-by-silan/api_key/%%api_key%%'
+api_config['api_base'] = 'api'
+api_config['bin_dir'] = '/usr/lib/airtime/api_clients/'
@@ -181,17 +183,17 @@ class RequestProvider(object):
def __init__(self, cfg):
self.config = cfg
self.requests = {}
- if self.config["base_dir"].startswith("/"):
- self.config["base_dir"] = self.config["base_dir"][1:]
+ if self.config["general"]["base_dir"].startswith("/"):
+ self.config["general"]["base_dir"] = self.config["general"]["base_dir"][1:]
self.url = ApcUrl("http://%s:%s/%s%s/%s" \
- % (self.config["host"], str(self.config["base_port"]),
- self.config["base_dir"], self.config["api_base"],
+ % (self.config["general"]["base_url"], str(self.config["general"]["base_port"]),
+ self.config["general"]["base_dir"], self.config["api_base"],
'%%action%%'))
# Now we must discover the possible actions
actions = dict( (k,v) for k,v in cfg.iteritems() if '%%api_key%%' in v)
for action_name, action_value in actions.iteritems():
new_url = self.url.params(action=action_value).params(
- api_key=self.config['api_key'])
+ api_key=self.config["general"]['api_key'])
self.requests[action_name] = ApiRequest(action_name, new_url)
def available_requests(self) : return self.requests.keys()
@@ -203,7 +205,7 @@ class RequestProvider(object):
class AirtimeApiClient(object):
- def __init__(self, logger=None,config_path='/etc/airtime/api_client.cfg'):
+ def __init__(self, logger=None,config_path='/etc/airtime/airtime.conf'):
if logger is None: self.logger = logging
else: self.logger = logger
@@ -318,13 +320,13 @@ class AirtimeApiClient(object):
def construct_url(self,config_action_key):
"""Constructs the base url for every request"""
# TODO : Make other methods in this class use this this method.
- if self.config["base_dir"].startswith("/"):
- self.config["base_dir"] = self.config["base_dir"][1:]
+ if self.config["general"]["base_dir"].startswith("/"):
+ self.config["general"]["base_dir"] = self.config["general"]["base_dir"][1:]
url = "http://%s:%s/%s%s/%s" % \
- (self.config["host"], str(self.config["base_port"]),
- self.config["base_dir"], self.config["api_base"],
+ (self.config["general"]["base_url"], str(self.config["general"]["base_port"]),
+ self.config["general"]["base_dir"], self.config["api_base"],
self.config[config_action_key])
- url = url.replace("%%api_key%%", self.config["api_key"])
+ url = url.replace("%%api_key%%", self.config["general"]["api_key"])
return url
"""
diff --git a/python_apps/api_clients/install/api_client_install.py b/python_apps/api_clients/install/api_client_install.py
deleted file mode 100644
index abc1d07de..000000000
--- a/python_apps/api_clients/install/api_client_install.py
+++ /dev/null
@@ -1,31 +0,0 @@
-import os
-import shutil
-import sys
-from configobj import ConfigObj
-
-def get_current_script_dir():
- return os.path.dirname(os.path.realpath(__file__))
-
-def copy_dir(src_dir, dest_dir):
- if (os.path.exists(dest_dir)) and (dest_dir != "/"):
- shutil.rmtree(dest_dir)
- if not (os.path.exists(dest_dir)):
- #print "Copying directory "+os.path.realpath(src_dir)+" to "+os.path.realpath(dest_dir)
- shutil.copytree(src_dir, dest_dir)
-
-PATH_INI_FILE = '/etc/airtime/api_client.cfg'
-
-current_script_dir = get_current_script_dir()
-
-if not os.path.exists(PATH_INI_FILE):
- shutil.copy('%s/../api_client.cfg'%current_script_dir, PATH_INI_FILE)
-
-"""load config file"""
-try:
- config = ConfigObj("%s/../api_client.cfg" % current_script_dir)
-except Exception, e:
- print 'Error loading config file: ', e
- sys.exit(1)
-
-#copy python files
-copy_dir("%s/../../api_clients"%current_script_dir, config["bin_dir"])
diff --git a/python_apps/api_clients/install/api_client_uninstall.py b/python_apps/api_clients/install/api_client_uninstall.py
deleted file mode 100644
index 5ecb2b036..000000000
--- a/python_apps/api_clients/install/api_client_uninstall.py
+++ /dev/null
@@ -1,21 +0,0 @@
-import os
-import sys
-from configobj import ConfigObj
-
-def remove_path(path):
- os.system('rm -rf "%s"' % path)
-
-def get_current_script_dir():
- return os.path.dirname(os.path.realpath(__file__))
-
-current_script_dir = get_current_script_dir()
-
-"""load config file"""
-try:
- config = ConfigObj("%s/../api_client.cfg" % current_script_dir)
-except Exception, e:
- print 'Error loading config file: ', e
- sys.exit(1)
-
-print " * Removing API Client files"
-remove_path(config["bin_dir"])
diff --git a/python_apps/api_clients/setup.py b/python_apps/api_clients/setup.py
new file mode 100644
index 000000000..b71f509a2
--- /dev/null
+++ b/python_apps/api_clients/setup.py
@@ -0,0 +1,33 @@
+from setuptools import setup
+from subprocess import call
+import sys
+import os
+
+script_path = os.path.dirname(os.path.realpath(__file__))
+print script_path
+os.chdir(script_path)
+
+setup(name='api_clients',
+ version='1.0',
+ description='Airtime API Client',
+ url='http://github.com/sourcefabric/Airtime',
+ author='sourcefabric',
+ license='AGPLv3',
+ packages=['api_clients'],
+ scripts=[],
+ install_requires=[
+# 'amqplib',
+# 'anyjson',
+# 'argparse',
+ 'configobj'
+# 'docopt',
+# 'kombu',
+# 'mutagen',
+# 'poster',
+# 'PyDispatcher',
+# 'pyinotify',
+# 'pytz',
+# 'wsgiref'
+ ],
+ zip_safe=False,
+ data_files=[])
\ No newline at end of file
diff --git a/python_apps/create-pypo-user.py b/python_apps/create-pypo-user.py
deleted file mode 100644
index 94e07d7dc..000000000
--- a/python_apps/create-pypo-user.py
+++ /dev/null
@@ -1,32 +0,0 @@
-import os
-import sys
-from subprocess import Popen, PIPE, STDOUT
-
-def create_user(username):
- print "* Checking for user "+username
-
- p = Popen('id '+username, shell=True, stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True)
- output = p.stdout.read()
-
- if (output[0:3] != "uid"):
- # Make the pypo user
- print " * Creating user "+username
- os.system("adduser --system --quiet --group "+username)
- else:
- print "User already exists."
- #add pypo to audio group
- os.system("adduser " + username + " audio 1>/dev/null 2>&1")
- #add pypo to www-data group
- os.system("adduser " + username + " www-data 1>/dev/null 2>&1")
- #add pypo to pulse group
- os.system("adduser " + username + " pulse 1>/dev/null 2>&1")
- #add pypo to pulse-access group
- os.system("adduser " + username + " pulse-access 1>/dev/null 2>&1")
-
-
-if __name__ == "__main__":
- if os.geteuid() != 0:
- print "Please run this as root."
- sys.exit(1)
-
- create_user("pypo")
diff --git a/python_apps/media-monitor/airtime-media-monitor b/python_apps/media-monitor/airtime-media-monitor
deleted file mode 100755
index 5997e8db4..000000000
--- a/python_apps/media-monitor/airtime-media-monitor
+++ /dev/null
@@ -1,30 +0,0 @@
-#!/bin/bash
-
-# Location of pypo_cli.py Python script
-
-virtualenv_bin="/usr/lib/airtime/airtime_virtualenv/bin/"
-. ${virtualenv_bin}activate
-
-media_monitor_path="/usr/lib/airtime/media-monitor/"
-media_monitor_script="media_monitor.py"
-
-api_client_path="/usr/lib/airtime/:/usr/lib/airtime/media-monitor/mm2/"
-
-cd ${media_monitor_path}
-
-exec 2>&1
-
-set +e
-cat /etc/default/locale | grep -i "LANG=.*UTF-\?8"
-set -e
-if [ "$?" != "0" ]; then
- echo "non UTF-8 default locale found in /etc/default/locale." > /var/log/airtime/media-monitor/error.log
- exit 1
-fi
-
-export PYTHONPATH=${api_client_path}
-export LC_ALL=`cat /etc/default/locale | grep "LANG=" | cut -d= -f2 | tr -d "\n\""`
-
-exec python ${media_monitor_path}${media_monitor_script} > /var/log/airtime/media-monitor/py-interpreter.log 2>&1
-
-# EOF
diff --git a/python_apps/media-monitor/bin/airtime-media-monitor b/python_apps/media-monitor/bin/airtime-media-monitor
new file mode 100755
index 000000000..3b05cb304
--- /dev/null
+++ b/python_apps/media-monitor/bin/airtime-media-monitor
@@ -0,0 +1,17 @@
+#!/usr/bin/python
+import logging
+import locale
+import time
+import sys
+import os
+import mm2.mm2 as mm2
+from std_err_override import LogWriter
+locale.setlocale(locale.LC_ALL, '')
+
+def run():
+ global_cfg = '/etc/airtime/airtime.conf'
+ logging_cfg = '/etc/airtime/media_monitor_logging.cfg'
+
+ mm2.main( global_cfg, logging_cfg )
+
+run()
diff --git a/python_apps/media-monitor/install/media-monitor-copy-files.py b/python_apps/media-monitor/install/media-monitor-copy-files.py
deleted file mode 100644
index 5f3b5d0f0..000000000
--- a/python_apps/media-monitor/install/media-monitor-copy-files.py
+++ /dev/null
@@ -1,70 +0,0 @@
-import os
-import shutil
-import sys
-import subprocess
-import random
-import string
-from configobj import ConfigObj
-
-if os.geteuid() != 0:
- print "Please run this as root."
- sys.exit(1)
-
-def get_current_script_dir():
- current_script_dir = os.path.realpath(__file__)
- index = current_script_dir.rindex('/')
- return current_script_dir[0:index]
-
-def copy_dir(src_dir, dest_dir):
- if (os.path.exists(dest_dir)) and (dest_dir != "/"):
- shutil.rmtree(dest_dir)
- if not (os.path.exists(dest_dir)):
- #print "Copying directory "+os.path.realpath(src_dir)+" to "+os.path.realpath(dest_dir)
- shutil.copytree(src_dir, dest_dir)
-
-def create_dir(path):
- try:
- os.makedirs(path)
- # TODO : fix this, at least print the error
- except Exception, e:
- pass
-
-def get_rand_string(length=10):
- return ''.join(random.choice(string.ascii_uppercase + string.digits) for x in range(length))
-
-PATH_INI_FILE = '/etc/airtime/media-monitor.cfg'
-
-try:
- # Absolute path this script is in
- current_script_dir = get_current_script_dir()
-
- if not os.path.exists(PATH_INI_FILE):
- shutil.copy('%s/../media-monitor.cfg'%current_script_dir, PATH_INI_FILE)
-
- # load config file
- try:
- config = ConfigObj(PATH_INI_FILE)
- except Exception, e:
- print 'Error loading config file: ', e
- sys.exit(1)
-
- #copy monit files
- shutil.copy('%s/../../monit/monit-airtime-generic.cfg'%current_script_dir, '/etc/monit/conf.d/')
- subprocess.call('sed -i "s/\$admin_pass/%s/g" /etc/monit/conf.d/monit-airtime-generic.cfg' % get_rand_string(), shell=True)
- shutil.copy('%s/../monit-airtime-media-monitor.cfg'%current_script_dir, '/etc/monit/conf.d/')
-
- #create log dir
- create_dir(config['log_dir'])
-
- #copy python files
- copy_dir("%s/.."%current_script_dir, config["bin_dir"])
- # mm2
- mm2_source = os.path.realpath(os.path.join(current_script_dir,
- "../../media-monitor2"))
- copy_dir(mm2_source, os.path.join( config["bin_dir"], "mm2" ))
-
- #copy init.d script
- shutil.copy(config["bin_dir"]+"/airtime-media-monitor-init-d", "/etc/init.d/airtime-media-monitor")
-
-except Exception, e:
- print e
diff --git a/python_apps/media-monitor/install/media-monitor-initialize.py b/python_apps/media-monitor/install/media-monitor-initialize.py
deleted file mode 100644
index 8cc7b6149..000000000
--- a/python_apps/media-monitor/install/media-monitor-initialize.py
+++ /dev/null
@@ -1,21 +0,0 @@
-import subprocess
-import os
-
-if os.geteuid() != 0:
- print "Please run this as root."
- sys.exit(1)
-
-try:
- #create media-monitor dir under /var/tmp/airtime
- if not os.path.exists("/var/tmp/airtime/media-monitor"):
- os.makedirs("/var/tmp/airtime/media-monitor")
-
- #update-rc.d init script
- subprocess.call("update-rc.d airtime-media-monitor defaults >/dev/null 2>&1", shell=True)
-
- #Start media-monitor daemon
- if "airtime_service_start" in os.environ and os.environ["airtime_service_start"] == "t":
- print "* Waiting for media-monitor processes to start..."
- subprocess.call("invoke-rc.d airtime-media-monitor start", shell=True)
-except Exception, e:
- print e
diff --git a/python_apps/media-monitor/install/media-monitor-remove-files.py b/python_apps/media-monitor/install/media-monitor-remove-files.py
deleted file mode 100644
index cf2e2729e..000000000
--- a/python_apps/media-monitor/install/media-monitor-remove-files.py
+++ /dev/null
@@ -1,44 +0,0 @@
-import os
-import shutil
-import sys
-from configobj import ConfigObj
-
-if os.geteuid() != 0:
- print "Please run this as root."
- sys.exit(1)
-
-def remove_file(path):
- try:
- os.remove(path)
- except Exception, e:
- pass
-
-PATH_INI_FILE = '/etc/airtime/media-monitor.cfg'
-
-# load config file
-try:
- config = ConfigObj(PATH_INI_FILE)
-except Exception, e:
- print 'Error loading config file: ', e
- sys.exit(1)
-
-try:
- #remove init.d script
- print " * Removing Media-Monitor init.d Script"
- remove_file("/etc/init.d/airtime-media-monitor")
-
- #remove bin dir
- print " * Removing Media-Monitor Program Directory"
- shutil.rmtree(config['bin_dir'], ignore_errors=True)
-
- #remove log dir
- print " * Removing Media-Monitor Log Directory"
- shutil.rmtree(config['log_dir'], ignore_errors=True)
-
- #remove monit files
- print " * Removing Media-Monitor Monit Files"
- remove_file("/etc/monit/conf.d/monit-airtime-media-monitor.cfg")
- remove_file("/etc/monit/conf.d/monit-airtime-generic.cfg")
-
-except Exception, e:
- print e
diff --git a/python_apps/media-monitor/install/media-monitor-uninitialize.py b/python_apps/media-monitor/install/media-monitor-uninitialize.py
deleted file mode 100644
index c73801b46..000000000
--- a/python_apps/media-monitor/install/media-monitor-uninitialize.py
+++ /dev/null
@@ -1,19 +0,0 @@
-import subprocess
-import os
-import sys
-
-if os.geteuid() != 0:
- print "Please run this as root."
- sys.exit(1)
-
-try:
- print "Waiting for media-monitor processes to stop...",
- if (os.path.exists('/etc/init.d/airtime-media-monitor')):
- subprocess.call("invoke-rc.d airtime-media-monitor stop", shell=True)
- print "OK"
- else:
- print "Wasn't running"
-
- subprocess.call("update-rc.d -f airtime-media-monitor remove".split(" "))
-except Exception, e:
- print e
diff --git a/python_apps/media-monitor/install/media-monitor-uninstall.py b/python_apps/media-monitor/install/media-monitor-uninstall.py
deleted file mode 100644
index d2a201316..000000000
--- a/python_apps/media-monitor/install/media-monitor-uninstall.py
+++ /dev/null
@@ -1,50 +0,0 @@
-# -*- coding: utf-8 -*-
-
-import os
-import sys
-from configobj import ConfigObj
-
-if os.geteuid() != 0:
- print "Please run this as root."
- sys.exit(1)
-
-PATH_INI_FILE = '/etc/airtime/media-monitor.cfg'
-
-def remove_path(path):
- os.system('rm -rf "%s"' % path)
-
-def get_current_script_dir():
- current_script_dir = os.path.realpath(__file__)
- index = current_script_dir.rindex('/')
- return current_script_dir[0:index]
-
-def remove_monit_file():
- os.system("rm -f /etc/monit/conf.d/monit-airtime-media-monitor.cfg")
-
-try:
- # load config file
- try:
- config = ConfigObj(PATH_INI_FILE)
- except Exception, e:
- print 'Error loading config file: ', e
- sys.exit(1)
-
- os.system("invoke-rc.d airtime-media-monitor stop")
- os.system("rm -f /etc/init.d/airtime-media-monitor")
- os.system("update-rc.d -f airtime-media-monitor remove >/dev/null 2>&1")
-
- print "Removing monit file"
- remove_monit_file()
-
- print "Removing log directories"
- remove_path(config["log_dir"])
-
- print "Removing symlinks"
- os.system("rm -f /usr/bin/airtime-media-monitor")
-
- print "Removing application files"
- remove_path(config["bin_dir"])
-
- print "Uninstall complete."
-except Exception, e:
- print "exception:" + str(e)
diff --git a/python_apps/media-monitor/logging.cfg b/python_apps/media-monitor/install/media_monitor_logging.cfg
similarity index 100%
rename from python_apps/media-monitor/logging.cfg
rename to python_apps/media-monitor/install/media_monitor_logging.cfg
diff --git a/python_apps/media-monitor/airtime-media-monitor-init-d b/python_apps/media-monitor/install/sysvinit/airtime-media-monitor
similarity index 66%
rename from python_apps/media-monitor/airtime-media-monitor-init-d
rename to python_apps/media-monitor/install/sysvinit/airtime-media-monitor
index d059e9389..0ff7fd1df 100755
--- a/python_apps/media-monitor/airtime-media-monitor-init-d
+++ b/python_apps/media-monitor/install/sysvinit/airtime-media-monitor
@@ -9,12 +9,26 @@
# Short-Description: Manage airtime-media-monitor daemon
### END INIT INFO
-USERID=root
+USERID=www-data
GROUPID=www-data
-NAME=Airtime\ Media\ Monitor
+NAME=airtime-media-monitor
-DAEMON=/usr/lib/airtime/media-monitor/airtime-media-monitor
-PIDFILE=/var/run/airtime-media-monitor.pid
+DAEMON=/usr/bin/$NAME
+PIDFILE=/var/run/$NAME.pid
+
+# Exit if the package is not installed
+[ -x "$DAEMON" ] || exit 0
+
+# Read configuration variable file if it is present
+[ -r /etc/default/$NAME ] && . /etc/default/$NAME
+
+# Load the VERBOSE setting and other rcS variables
+. /lib/init/vars.sh
+
+# Define LSB log_* functions.
+# Depend on lsb-base (>= 3.2-14) to ensure that this file is present
+# and status_of_proc is working.
+. /lib/lsb/init-functions
start () {
start-stop-daemon --start --background --quiet --chuid $USERID:$GROUPID \
@@ -27,17 +41,6 @@ stop () {
rm -f $PIDFILE
}
-start_with_monit() {
- start
- monit monitor airtime-media-monitor >/dev/null 2>&1
-}
-
-stop_with_monit() {
- monit unmonitor airtime-media-monitor >/dev/null 2>&1
- stop
-}
-
-
case "${1:-''}" in
'start')
# start commands here
@@ -58,21 +61,15 @@ case "${1:-''}" in
start
echo "Done."
;;
- 'start-with-monit')
- # restart commands here
- echo -n "Starting $NAME: "
- start_with_monit
- echo "Done."
- ;;
- 'stop-with-monit')
- # restart commands here
- echo -n "Stopping $NAME: "
- stop_with_monit
+ 'force-reload')
+ # reload commands here
+ echo -n "Reloading $NAME: "
+ stop
+ start
echo "Done."
;;
'status')
- # status commands here
- /usr/bin/airtime-check-system
+ status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $?
;;
*) # no parameter specified
echo "Usage: $SELF start|stop|restart|status"
diff --git a/python_apps/media-monitor/install/upstart/airtime-media-monitor.conf.template b/python_apps/media-monitor/install/upstart/airtime-media-monitor.conf.template
new file mode 100644
index 000000000..0afe7ebc8
--- /dev/null
+++ b/python_apps/media-monitor/install/upstart/airtime-media-monitor.conf.template
@@ -0,0 +1,15 @@
+description "Airtime Media Monitor"
+author "help@sourcefabric.org"
+
+start on runlevel [2345]
+stop on runlevel [!2345]
+
+respawn
+
+setuid WEB_USER
+setgid WEB_USER
+
+env LANG='en_US.UTF-8'
+env LC_ALL='en_US.UTF-8'
+
+exec airtime-media-monitor
\ No newline at end of file
diff --git a/python_apps/media-monitor/media-monitor.cfg b/python_apps/media-monitor/media-monitor.cfg
deleted file mode 100644
index b1167f56b..000000000
--- a/python_apps/media-monitor/media-monitor.cfg
+++ /dev/null
@@ -1,31 +0,0 @@
-api_client = "airtime"
-
-# where the binary files live
-bin_dir = '/usr/lib/airtime/media-monitor'
-
-# where the logging files live
-log_dir = '/var/log/airtime/media-monitor'
-
-
-############################################
-# RabbitMQ settings #
-############################################
-rabbitmq_host = 'localhost'
-rabbitmq_user = 'guest'
-rabbitmq_password = 'guest'
-rabbitmq_vhost = '/'
-
-############################################
-# Media-Monitor preferences #
-############################################
-check_filesystem_events = 5 #how long to queue up events performed on the files themselves.
-check_airtime_events = 30 #how long to queue metadata input from airtime.
-
-# MM2 only:
-touch_interval = 5
-chunking_number = 450
-request_max_wait = 3.0
-rmq_event_wait = 0.1
-logpath = '/var/log/airtime/media-monitor/media-monitor.log'
-index_path = '/var/tmp/airtime/media-monitor/last_index'
-
diff --git a/python_apps/media-monitor/media_monitor.py b/python_apps/media-monitor/media_monitor.py
deleted file mode 100644
index d41bbac93..000000000
--- a/python_apps/media-monitor/media_monitor.py
+++ /dev/null
@@ -1,11 +0,0 @@
-import logging
-import time
-import sys
-import mm2.mm2 as mm2
-from std_err_override import LogWriter
-
-global_cfg = '/etc/airtime/media-monitor.cfg'
-api_client_cfg = '/etc/airtime/api_client.cfg'
-logging_cfg = '/usr/lib/airtime/media-monitor/logging.cfg'
-
-mm2.main( global_cfg, api_client_cfg, logging_cfg )
diff --git a/python_apps/media-monitor/airtimefilemonitor/__init__.py b/python_apps/media-monitor/media_monitor/__init__.py
similarity index 100%
rename from python_apps/media-monitor/airtimefilemonitor/__init__.py
rename to python_apps/media-monitor/media_monitor/__init__.py
diff --git a/python_apps/media-monitor/media_monitor/__main__.py b/python_apps/media-monitor/media_monitor/__main__.py
new file mode 100644
index 000000000..057eef53f
--- /dev/null
+++ b/python_apps/media-monitor/media_monitor/__main__.py
@@ -0,0 +1,16 @@
+import logging
+import locale
+import time
+import sys
+import os
+import mm2.mm2 as mm2
+from std_err_override import LogWriter
+locale.setlocale(locale.LC_ALL, '')
+
+def run():
+ global_cfg = '/etc/airtime/airtime.conf'
+ logging_cfg = os.path.join(os.path.dirname(__file__), 'logging.cfg')
+
+ mm2.main( global_cfg, logging_cfg )
+
+run()
\ No newline at end of file
diff --git a/python_apps/media-monitor2/media/__init__.py b/python_apps/media-monitor/media_monitor/airtimefilemonitor/__init__.py
similarity index 100%
rename from python_apps/media-monitor2/media/__init__.py
rename to python_apps/media-monitor/media_monitor/airtimefilemonitor/__init__.py
diff --git a/python_apps/media-monitor/airtimefilemonitor/airtimemediamonitorbootstrap.py b/python_apps/media-monitor/media_monitor/airtimefilemonitor/airtimemediamonitorbootstrap.py
similarity index 100%
rename from python_apps/media-monitor/airtimefilemonitor/airtimemediamonitorbootstrap.py
rename to python_apps/media-monitor/media_monitor/airtimefilemonitor/airtimemediamonitorbootstrap.py
diff --git a/python_apps/media-monitor/airtimefilemonitor/airtimemetadata.py b/python_apps/media-monitor/media_monitor/airtimefilemonitor/airtimemetadata.py
similarity index 100%
rename from python_apps/media-monitor/airtimefilemonitor/airtimemetadata.py
rename to python_apps/media-monitor/media_monitor/airtimefilemonitor/airtimemetadata.py
diff --git a/python_apps/media-monitor/airtimefilemonitor/airtimenotifier.py b/python_apps/media-monitor/media_monitor/airtimefilemonitor/airtimenotifier.py
similarity index 98%
rename from python_apps/media-monitor/airtimefilemonitor/airtimenotifier.py
rename to python_apps/media-monitor/media_monitor/airtimefilemonitor/airtimenotifier.py
index 1077f5abb..dc27a36ec 100644
--- a/python_apps/media-monitor/airtimefilemonitor/airtimenotifier.py
+++ b/python_apps/media-monitor/media_monitor/airtimefilemonitor/airtimenotifier.py
@@ -45,7 +45,7 @@ class AirtimeNotifier(Notifier):
try:
schedule_exchange = Exchange("airtime-media-monitor", "direct", durable=True, auto_delete=True)
schedule_queue = Queue("media-monitor", exchange=schedule_exchange, key="filesystem")
- self.connection = BrokerConnection(self.config.cfg["rabbitmq_host"], self.config.cfg["rabbitmq_user"], self.config.cfg["rabbitmq_password"], self.config.cfg["rabbitmq_vhost"])
+ self.connection = BrokerConnection(self.config.cfg["rabbitmq"]["rabbitmq_host"], self.config.cfg["rabbitmq"]["rabbitmq_user"], self.config.cfg["rabbitmq"]["rabbitmq_password"], self.config.cfg["rabbitmq"]["rabbitmq_vhost"])
channel = self.connection.channel()
consumer = Consumer(channel, schedule_queue)
consumer.register_callback(self.handle_message)
diff --git a/python_apps/media-monitor/airtimefilemonitor/airtimeprocessevent.py b/python_apps/media-monitor/media_monitor/airtimefilemonitor/airtimeprocessevent.py
similarity index 100%
rename from python_apps/media-monitor/airtimefilemonitor/airtimeprocessevent.py
rename to python_apps/media-monitor/media_monitor/airtimefilemonitor/airtimeprocessevent.py
diff --git a/python_apps/media-monitor/airtimefilemonitor/mediaconfig.py b/python_apps/media-monitor/media_monitor/airtimefilemonitor/mediaconfig.py
similarity index 88%
rename from python_apps/media-monitor/airtimefilemonitor/mediaconfig.py
rename to python_apps/media-monitor/media_monitor/airtimefilemonitor/mediaconfig.py
index f51b23506..5f3865829 100644
--- a/python_apps/media-monitor/airtimefilemonitor/mediaconfig.py
+++ b/python_apps/media-monitor/media_monitor/airtimefilemonitor/mediaconfig.py
@@ -16,7 +16,7 @@ class AirtimeMediaConfig:
# loading config file
try:
- config = ConfigObj('/etc/airtime/media-monitor.cfg')
+ config = ConfigObj('/etc/airtime/airtime.conf')
self.cfg = config
except Exception, e:
logger.info('Error loading config: ', e)
diff --git a/python_apps/media-monitor/airtimefilemonitor/mediamonitorcommon.py b/python_apps/media-monitor/media_monitor/airtimefilemonitor/mediamonitorcommon.py
similarity index 100%
rename from python_apps/media-monitor/airtimefilemonitor/mediamonitorcommon.py
rename to python_apps/media-monitor/media_monitor/airtimefilemonitor/mediamonitorcommon.py
diff --git a/python_apps/media-monitor/airtimefilemonitor/replaygain.py b/python_apps/media-monitor/media_monitor/airtimefilemonitor/replaygain.py
similarity index 100%
rename from python_apps/media-monitor/airtimefilemonitor/replaygain.py
rename to python_apps/media-monitor/media_monitor/airtimefilemonitor/replaygain.py
diff --git a/python_apps/media-monitor/airtimefilemonitor/workerprocess.py b/python_apps/media-monitor/media_monitor/airtimefilemonitor/workerprocess.py
similarity index 100%
rename from python_apps/media-monitor/airtimefilemonitor/workerprocess.py
rename to python_apps/media-monitor/media_monitor/airtimefilemonitor/workerprocess.py
diff --git a/python_apps/media-monitor/mm1.py b/python_apps/media-monitor/media_monitor/mm1.py
similarity index 98%
rename from python_apps/media-monitor/mm1.py
rename to python_apps/media-monitor/media_monitor/mm1.py
index de286994a..615b1c7d1 100644
--- a/python_apps/media-monitor/mm1.py
+++ b/python_apps/media-monitor/media_monitor/mm1.py
@@ -61,7 +61,7 @@ def configure_locale():
# configure logging
try:
- logging.config.fileConfig("logging.cfg")
+ logging.config.fileConfig("%s/logging.cfg" % os.path.dirname(os.path.realpath(__file__)))
#need to wait for Python 2.7 for this..
#logging.captureWarnings(True)
diff --git a/python_apps/media-monitor2/__init__.py b/python_apps/media-monitor/mm2/__init__.py
similarity index 100%
rename from python_apps/media-monitor2/__init__.py
rename to python_apps/media-monitor/mm2/__init__.py
diff --git a/python_apps/media-monitor2/baby.py b/python_apps/media-monitor/mm2/baby.py
similarity index 100%
rename from python_apps/media-monitor2/baby.py
rename to python_apps/media-monitor/mm2/baby.py
diff --git a/python_apps/media-monitor2/media/monitor/__init__.py b/python_apps/media-monitor/mm2/configs/__init__.py
similarity index 100%
rename from python_apps/media-monitor2/media/monitor/__init__.py
rename to python_apps/media-monitor/mm2/configs/__init__.py
diff --git a/python_apps/media-monitor2/configs/logging.cfg b/python_apps/media-monitor/mm2/configs/logging.cfg
similarity index 100%
rename from python_apps/media-monitor2/configs/logging.cfg
rename to python_apps/media-monitor/mm2/configs/logging.cfg
diff --git a/python_apps/media-monitor2/media/saas/__init__.py b/python_apps/media-monitor/mm2/media/__init__.py
similarity index 100%
rename from python_apps/media-monitor2/media/saas/__init__.py
rename to python_apps/media-monitor/mm2/media/__init__.py
diff --git a/python_apps/media-monitor2/media/metadata/__init__.py b/python_apps/media-monitor/mm2/media/metadata/__init__.py
similarity index 100%
rename from python_apps/media-monitor2/media/metadata/__init__.py
rename to python_apps/media-monitor/mm2/media/metadata/__init__.py
diff --git a/python_apps/media-monitor2/media/metadata/definitions.py b/python_apps/media-monitor/mm2/media/metadata/definitions.py
similarity index 97%
rename from python_apps/media-monitor2/media/metadata/definitions.py
rename to python_apps/media-monitor/mm2/media/metadata/definitions.py
index 621449dd6..883a20acb 100644
--- a/python_apps/media-monitor2/media/metadata/definitions.py
+++ b/python_apps/media-monitor/mm2/media/metadata/definitions.py
@@ -1,8 +1,8 @@
# -*- coding: utf-8 -*-
-import media.metadata.process as md
+import process as md
import re
from os.path import normpath
-from media.monitor.pure import format_length, file_md5, is_airtime_recorded, \
+from ..monitor.pure import format_length, file_md5, is_airtime_recorded, \
no_extension_basename
defs_loaded = False
diff --git a/python_apps/media-monitor2/media/metadata/process.py b/python_apps/media-monitor/mm2/media/metadata/process.py
similarity index 95%
rename from python_apps/media-monitor2/media/metadata/process.py
rename to python_apps/media-monitor/mm2/media/metadata/process.py
index be6b81e20..178681cd8 100644
--- a/python_apps/media-monitor2/media/metadata/process.py
+++ b/python_apps/media-monitor/mm2/media/metadata/process.py
@@ -1,11 +1,11 @@
# -*- coding: utf-8 -*-
-from contextlib import contextmanager
-from media.monitor.pure import truncate_to_value, truncate_to_length, toposort
-from os.path import normpath
-from media.monitor.exceptions import BadSongFile
-from media.monitor.log import Loggable
-import media.monitor.pure as mmp
-from collections import namedtuple
+from contextlib import contextmanager
+from ..monitor.pure import truncate_to_value, truncate_to_length, toposort
+from os.path import normpath
+from ..monitor.exceptions import BadSongFile
+from ..monitor.log import Loggable
+from ..monitor import pure as mmp
+from collections import namedtuple
import mutagen
import subprocess
import json
diff --git a/python_apps/pypo/__init__.py b/python_apps/media-monitor/mm2/media/monitor/__init__.py
similarity index 100%
rename from python_apps/pypo/__init__.py
rename to python_apps/media-monitor/mm2/media/monitor/__init__.py
diff --git a/python_apps/media-monitor2/media/monitor/airtime.py b/python_apps/media-monitor/mm2/media/monitor/airtime.py
similarity index 92%
rename from python_apps/media-monitor2/media/monitor/airtime.py
rename to python_apps/media-monitor/mm2/media/monitor/airtime.py
index d1124449a..ce0e581d9 100644
--- a/python_apps/media-monitor2/media/monitor/airtime.py
+++ b/python_apps/media-monitor/mm2/media/monitor/airtime.py
@@ -1,22 +1,21 @@
# -*- coding: utf-8 -*-
-from kombu.messaging import Exchange, Queue, Consumer
-from kombu.connection import BrokerConnection
-from kombu.simple import SimpleQueue
-from os.path import normpath
+from kombu.messaging import Exchange, Queue, Consumer
+from kombu.connection import BrokerConnection
+from kombu.simple import SimpleQueue
+from os.path import normpath
import json
import os
import copy
import time
-from media.monitor.exceptions import BadSongFile, InvalidMetadataElement
-from media.monitor.metadata import Metadata
-from media.monitor.log import Loggable
-from media.monitor.syncdb import AirtimeDB
-from media.monitor.exceptions import DirectoryIsNotListed
-from media.monitor.bootstrap import Bootstrapper
+from exceptions import BadSongFile, InvalidMetadataElement, DirectoryIsNotListed
+from metadata import Metadata
+from log import Loggable
+from syncdb import AirtimeDB
+from bootstrap import Bootstrapper
-from media.saas.thread import apc, user
+from ..saas.thread import apc, user
class AirtimeNotifier(Loggable):
"""
@@ -38,9 +37,9 @@ class AirtimeNotifier(Loggable):
durable=True, auto_delete=True)
schedule_queue = Queue("media-monitor", exchange=schedule_exchange,
key="filesystem")
- self.connection = BrokerConnection(self.cfg["rabbitmq_host"],
- self.cfg["rabbitmq_user"], self.cfg["rabbitmq_password"],
- self.cfg["rabbitmq_vhost"])
+ self.connection = BrokerConnection(self.cfg["rabbitmq"]["host"],
+ self.cfg["rabbitmq"]["user"], self.cfg["rabbitmq"]["password"],
+ self.cfg["rabbitmq"]["vhost"])
channel = self.connection.channel()
self.simple_queue = SimpleQueue(channel, schedule_queue)
diff --git a/python_apps/media-monitor2/media/monitor/bootstrap.py b/python_apps/media-monitor/mm2/media/monitor/bootstrap.py
similarity index 92%
rename from python_apps/media-monitor2/media/monitor/bootstrap.py
rename to python_apps/media-monitor/mm2/media/monitor/bootstrap.py
index 6e685c964..4ae6d0140 100644
--- a/python_apps/media-monitor2/media/monitor/bootstrap.py
+++ b/python_apps/media-monitor/mm2/media/monitor/bootstrap.py
@@ -1,9 +1,9 @@
import os
-from pydispatch import dispatcher
-from media.monitor.events import NewFile, DeleteFile, ModifyFile
-from media.monitor.log import Loggable
-from media.saas.thread import getsig
-import media.monitor.pure as mmp
+from pydispatch import dispatcher
+from events import NewFile, DeleteFile, ModifyFile
+from log import Loggable
+from ..saas.thread import getsig
+import pure as mmp
class Bootstrapper(Loggable):
"""
diff --git a/python_apps/media-monitor2/media/monitor/config.py b/python_apps/media-monitor/mm2/media/monitor/config.py
similarity index 84%
rename from python_apps/media-monitor2/media/monitor/config.py
rename to python_apps/media-monitor/mm2/media/monitor/config.py
index b06e00a84..4e6f955df 100644
--- a/python_apps/media-monitor2/media/monitor/config.py
+++ b/python_apps/media-monitor/mm2/media/monitor/config.py
@@ -3,8 +3,8 @@ import os
import copy
from configobj import ConfigObj
-from media.monitor.exceptions import NoConfigFile, ConfigAccessViolation
-import media.monitor.pure as mmp
+from exceptions import NoConfigFile, ConfigAccessViolation
+import pure as mmp
class MMConfig(object):
def __init__(self, path):
@@ -28,5 +28,5 @@ class MMConfig(object):
def last_ran(self):
""" Returns the last time media monitor was ran by looking at
the time when the file at 'index_path' was modified """
- return mmp.last_modified(self.cfg['index_path'])
+ return mmp.last_modified(self.cfg['media-monitor']['index_path'])
diff --git a/python_apps/media-monitor2/media/monitor/eventcontractor.py b/python_apps/media-monitor/mm2/media/monitor/eventcontractor.py
similarity index 93%
rename from python_apps/media-monitor2/media/monitor/eventcontractor.py
rename to python_apps/media-monitor/mm2/media/monitor/eventcontractor.py
index f832f6c62..bd0bd295d 100644
--- a/python_apps/media-monitor2/media/monitor/eventcontractor.py
+++ b/python_apps/media-monitor/mm2/media/monitor/eventcontractor.py
@@ -1,5 +1,5 @@
-from media.monitor.log import Loggable
-from media.monitor.events import DeleteFile
+from log import Loggable
+from events import DeleteFile
class EventContractor(Loggable):
def __init__(self):
diff --git a/python_apps/media-monitor2/media/monitor/eventdrainer.py b/python_apps/media-monitor/mm2/media/monitor/eventdrainer.py
similarity index 91%
rename from python_apps/media-monitor2/media/monitor/eventdrainer.py
rename to python_apps/media-monitor/mm2/media/monitor/eventdrainer.py
index b551fae8e..85eb0d673 100644
--- a/python_apps/media-monitor2/media/monitor/eventdrainer.py
+++ b/python_apps/media-monitor/mm2/media/monitor/eventdrainer.py
@@ -1,7 +1,7 @@
import socket
import time
-from media.monitor.log import Loggable
-from media.monitor.toucher import RepeatTimer
+from log import Loggable
+from toucher import RepeatTimer
from amqplib.client_0_8.exceptions import AMQPConnectionException
class EventDrainer(Loggable):
diff --git a/python_apps/media-monitor2/media/monitor/events.py b/python_apps/media-monitor/mm2/media/monitor/events.py
similarity index 97%
rename from python_apps/media-monitor2/media/monitor/events.py
rename to python_apps/media-monitor/mm2/media/monitor/events.py
index 4389bf27e..52f0662d0 100644
--- a/python_apps/media-monitor2/media/monitor/events.py
+++ b/python_apps/media-monitor/mm2/media/monitor/events.py
@@ -2,12 +2,12 @@
import os
import abc
import re
-import media.monitor.pure as mmp
-from media.monitor.pure import LazyProperty
-from media.monitor.metadata import Metadata
-from media.monitor.log import Loggable
-from media.monitor.exceptions import BadSongFile
-from media.saas.thread import getsig, user
+import pure as mmp
+from pure import LazyProperty
+from metadata import Metadata
+from log import Loggable
+from exceptions import BadSongFile
+from ..saas.thread import getsig, user
class PathChannel(object):
""" Simple struct to hold a 'signal' string and a related 'path'.
diff --git a/python_apps/media-monitor2/media/monitor/exceptions.py b/python_apps/media-monitor/mm2/media/monitor/exceptions.py
similarity index 100%
rename from python_apps/media-monitor2/media/monitor/exceptions.py
rename to python_apps/media-monitor/mm2/media/monitor/exceptions.py
diff --git a/python_apps/media-monitor2/media/monitor/handler.py b/python_apps/media-monitor/mm2/media/monitor/handler.py
similarity index 95%
rename from python_apps/media-monitor2/media/monitor/handler.py
rename to python_apps/media-monitor/mm2/media/monitor/handler.py
index c67a437ef..7e00bfde9 100644
--- a/python_apps/media-monitor2/media/monitor/handler.py
+++ b/python_apps/media-monitor/mm2/media/monitor/handler.py
@@ -2,9 +2,9 @@
from pydispatch import dispatcher
import abc
-from media.monitor.log import Loggable
-from media.saas.thread import getsig
-import media.monitor.pure as mmp
+from log import Loggable
+from ..saas.thread import getsig
+import pure as mmp
# Defines the handle interface
class Handles(object):
diff --git a/python_apps/media-monitor2/media/monitor/listeners.py b/python_apps/media-monitor/mm2/media/monitor/listeners.py
similarity index 95%
rename from python_apps/media-monitor2/media/monitor/listeners.py
rename to python_apps/media-monitor/mm2/media/monitor/listeners.py
index 86b74bcea..0437a7964 100644
--- a/python_apps/media-monitor2/media/monitor/listeners.py
+++ b/python_apps/media-monitor/mm2/media/monitor/listeners.py
@@ -3,13 +3,13 @@ import pyinotify
from pydispatch import dispatcher
from functools import wraps
-import media.monitor.pure as mmp
-from media.monitor.pure import IncludeOnly
-from media.monitor.events import OrganizeFile, NewFile, MoveFile, DeleteFile, \
+import pure as mmp
+from pure import IncludeOnly
+from events import OrganizeFile, NewFile, MoveFile, DeleteFile, \
DeleteDir, MoveDir,\
DeleteDirWatch
-from media.monitor.log import Loggable
-from media.saas.thread import getsig, user
+from log import Loggable
+from ..saas.thread import getsig, user
# Note: Because of the way classes that inherit from pyinotify.ProcessEvent
# interact with constructors. you should only instantiate objects from them
# using keyword arguments. For example:
diff --git a/python_apps/media-monitor2/media/monitor/log.py b/python_apps/media-monitor/mm2/media/monitor/log.py
similarity index 96%
rename from python_apps/media-monitor2/media/monitor/log.py
rename to python_apps/media-monitor/mm2/media/monitor/log.py
index 7e75c719d..ec9523d7f 100644
--- a/python_apps/media-monitor2/media/monitor/log.py
+++ b/python_apps/media-monitor/mm2/media/monitor/log.py
@@ -1,7 +1,7 @@
import logging
import abc
import traceback
-from media.monitor.pure import LazyProperty
+from pure import LazyProperty
appname = 'root'
diff --git a/python_apps/media-monitor2/media/monitor/manager.py b/python_apps/media-monitor/mm2/media/monitor/manager.py
similarity index 95%
rename from python_apps/media-monitor2/media/monitor/manager.py
rename to python_apps/media-monitor/mm2/media/monitor/manager.py
index 6617ae416..c457b39b7 100644
--- a/python_apps/media-monitor2/media/monitor/manager.py
+++ b/python_apps/media-monitor/mm2/media/monitor/manager.py
@@ -1,16 +1,16 @@
import pyinotify
import time
import os
-from pydispatch import dispatcher
+from pydispatch import dispatcher
-from os.path import normpath
-from media.monitor.events import PathChannel
-from media.monitor.log import Loggable
-from media.monitor.listeners import StoreWatchListener, OrganizeListener
-from media.monitor.handler import ProblemFileHandler
-from media.monitor.organizer import Organizer
-from media.saas.thread import InstanceInheritingThread, getsig
-import media.monitor.pure as mmp
+from os.path import normpath
+from events import PathChannel
+from log import Loggable
+from listeners import StoreWatchListener, OrganizeListener
+from handler import ProblemFileHandler
+from organizer import Organizer
+from ..saas.thread import InstanceInheritingThread, getsig
+import pure as mmp
class ManagerTimeout(InstanceInheritingThread,Loggable):
diff --git a/python_apps/media-monitor2/media/monitor/metadata.py b/python_apps/media-monitor/mm2/media/monitor/metadata.py
similarity index 93%
rename from python_apps/media-monitor2/media/monitor/metadata.py
rename to python_apps/media-monitor/mm2/media/monitor/metadata.py
index de70b0a99..2c0988257 100644
--- a/python_apps/media-monitor2/media/monitor/metadata.py
+++ b/python_apps/media-monitor/mm2/media/monitor/metadata.py
@@ -2,17 +2,17 @@
import mutagen
import os
import copy
-from mutagen.easymp4 import EasyMP4KeyError
-from mutagen.easyid3 import EasyID3KeyError
+from mutagen.easymp4 import EasyMP4KeyError
+from mutagen.easyid3 import EasyID3KeyError
-from media.monitor.exceptions import BadSongFile, InvalidMetadataElement
-from media.monitor.log import Loggable
-from media.monitor.pure import format_length
-import media.monitor.pure as mmp
+from exceptions import BadSongFile, InvalidMetadataElement
+from log import Loggable
+from pure import format_length
+import pure as mmp
# emf related stuff
-from media.metadata.process import global_reader
-import media.metadata.definitions as defs
+from ..metadata.process import global_reader
+from ..metadata import definitions as defs
defs.load_definitions()
"""
diff --git a/python_apps/media-monitor2/media/monitor/organizer.py b/python_apps/media-monitor/mm2/media/monitor/organizer.py
similarity index 90%
rename from python_apps/media-monitor2/media/monitor/organizer.py
rename to python_apps/media-monitor/mm2/media/monitor/organizer.py
index 2407889f5..c4550bdfb 100644
--- a/python_apps/media-monitor2/media/monitor/organizer.py
+++ b/python_apps/media-monitor/mm2/media/monitor/organizer.py
@@ -1,12 +1,12 @@
# -*- coding: utf-8 -*-
-import media.monitor.pure as mmp
-from media.monitor.handler import ReportHandler
-from media.monitor.log import Loggable
-from media.monitor.exceptions import BadSongFile
-from media.monitor.events import OrganizeFile
-from pydispatch import dispatcher
-from os.path import dirname
-from media.saas.thread import getsig, user
+import pure as mmp
+from handler import ReportHandler
+from log import Loggable
+from exceptions import BadSongFile
+from events import OrganizeFile
+from pydispatch import dispatcher
+from os.path import dirname
+from ..saas.thread import getsig, user
import os.path
class Organizer(ReportHandler,Loggable):
diff --git a/python_apps/media-monitor2/media/monitor/owners.py b/python_apps/media-monitor/mm2/media/monitor/owners.py
similarity index 97%
rename from python_apps/media-monitor2/media/monitor/owners.py
rename to python_apps/media-monitor/mm2/media/monitor/owners.py
index 48898c9aa..5fc3ad831 100644
--- a/python_apps/media-monitor2/media/monitor/owners.py
+++ b/python_apps/media-monitor/mm2/media/monitor/owners.py
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
-from media.monitor.log import Loggable
+from log import Loggable
class Owner(Loggable):
def __init__(self):
diff --git a/python_apps/media-monitor2/media/monitor/pure.py b/python_apps/media-monitor/mm2/media/monitor/pure.py
similarity index 99%
rename from python_apps/media-monitor2/media/monitor/pure.py
rename to python_apps/media-monitor/mm2/media/monitor/pure.py
index 61ecaebeb..fc6692ba8 100644
--- a/python_apps/media-monitor2/media/monitor/pure.py
+++ b/python_apps/media-monitor/mm2/media/monitor/pure.py
@@ -21,7 +21,7 @@ try: from functools import reduce
except: pass
from configobj import ConfigObj
-from media.monitor.exceptions import FailedToSetLocale, FailedToCreateDir
+from exceptions import FailedToSetLocale, FailedToCreateDir
supported_extensions = [u"mp3", u"ogg", u"oga", u"flac", u"wav",
u'm4a', u'mp4', 'opus']
diff --git a/python_apps/media-monitor2/media/monitor/request.py b/python_apps/media-monitor/mm2/media/monitor/request.py
similarity index 93%
rename from python_apps/media-monitor2/media/monitor/request.py
rename to python_apps/media-monitor/mm2/media/monitor/request.py
index e2c5fb5ef..71c0c1b54 100644
--- a/python_apps/media-monitor2/media/monitor/request.py
+++ b/python_apps/media-monitor/mm2/media/monitor/request.py
@@ -1,8 +1,8 @@
# -*- coding: utf-8 -*-
-from media.monitor.exceptions import BadSongFile
-from media.monitor.log import Loggable
-from media.saas.thread import apc, InstanceInheritingThread
+from exceptions import BadSongFile
+from log import Loggable
+from ..saas.thread import apc, InstanceInheritingThread
class ThreadedRequestSync(InstanceInheritingThread, Loggable):
def __init__(self, rs):
diff --git a/python_apps/media-monitor2/media/monitor/syncdb.py b/python_apps/media-monitor/mm2/media/monitor/syncdb.py
similarity index 94%
rename from python_apps/media-monitor2/media/monitor/syncdb.py
rename to python_apps/media-monitor/mm2/media/monitor/syncdb.py
index dd837b2a1..047e13b78 100644
--- a/python_apps/media-monitor2/media/monitor/syncdb.py
+++ b/python_apps/media-monitor/mm2/media/monitor/syncdb.py
@@ -1,10 +1,10 @@
# -*- coding: utf-8 -*-
import os
-from media.monitor.log import Loggable
-from media.monitor.exceptions import NoDirectoryInAirtime
-from media.saas.thread import user
-from os.path import normpath, join
-import media.monitor.pure as mmp
+from log import Loggable
+from exceptions import NoDirectoryInAirtime
+from ..saas.thread import user
+from os.path import normpath, join
+import pure as mmp
class AirtimeDB(Loggable):
def __init__(self, apc, reload_now=True):
diff --git a/python_apps/media-monitor2/media/monitor/toucher.py b/python_apps/media-monitor/mm2/media/monitor/toucher.py
similarity index 87%
rename from python_apps/media-monitor2/media/monitor/toucher.py
rename to python_apps/media-monitor/mm2/media/monitor/toucher.py
index d94fd34f8..eb7a9df76 100644
--- a/python_apps/media-monitor2/media/monitor/toucher.py
+++ b/python_apps/media-monitor/mm2/media/monitor/toucher.py
@@ -1,9 +1,9 @@
# -*- coding: utf-8 -*-
-import media.monitor.pure as mmp
+import pure as mmp
import os
-from media.monitor.log import Loggable
-from media.monitor.exceptions import CouldNotCreateIndexFile
-from media.saas.thread import InstanceInheritingThread
+from log import Loggable
+from exceptions import CouldNotCreateIndexFile
+from ..saas.thread import InstanceInheritingThread
class Toucher(Loggable):
"""
diff --git a/python_apps/media-monitor2/media/monitor/watchersyncer.py b/python_apps/media-monitor/mm2/media/monitor/watchersyncer.py
similarity index 93%
rename from python_apps/media-monitor2/media/monitor/watchersyncer.py
rename to python_apps/media-monitor/mm2/media/monitor/watchersyncer.py
index 558759c89..dde859c05 100644
--- a/python_apps/media-monitor2/media/monitor/watchersyncer.py
+++ b/python_apps/media-monitor/mm2/media/monitor/watchersyncer.py
@@ -2,13 +2,13 @@
import time
import copy
-from media.monitor.handler import ReportHandler
-from media.monitor.log import Loggable
-from media.monitor.exceptions import BadSongFile
-from media.monitor.eventcontractor import EventContractor
-from media.monitor.events import EventProxy
-from media.monitor.request import ThreadedRequestSync, RequestSync
-from media.saas.thread import InstanceInheritingThread, getsig
+from handler import ReportHandler
+from log import Loggable
+from exceptions import BadSongFile
+from eventcontractor import EventContractor
+from events import EventProxy
+from request import ThreadedRequestSync, RequestSync
+from ..saas.thread import InstanceInheritingThread, getsig
class TimeoutWatcher(InstanceInheritingThread,Loggable):
"""
diff --git a/python_apps/std_err_override/__init__.py b/python_apps/media-monitor/mm2/media/saas/__init__.py
similarity index 100%
rename from python_apps/std_err_override/__init__.py
rename to python_apps/media-monitor/mm2/media/saas/__init__.py
diff --git a/python_apps/media-monitor2/media/saas/airtimeinstance.py b/python_apps/media-monitor/mm2/media/saas/airtimeinstance.py
similarity index 84%
rename from python_apps/media-monitor2/media/saas/airtimeinstance.py
rename to python_apps/media-monitor/mm2/media/saas/airtimeinstance.py
index c808a0620..4eeb8094e 100644
--- a/python_apps/media-monitor2/media/saas/airtimeinstance.py
+++ b/python_apps/media-monitor/mm2/media/saas/airtimeinstance.py
@@ -1,12 +1,12 @@
import os
from os.path import join, basename, dirname
-from media.monitor.exceptions import NoConfigFile
-from media.monitor.pure import LazyProperty
-from media.monitor.config import MMConfig
-from media.monitor.owners import Owner
-from media.monitor.events import EventRegistry
-from media.monitor.listeners import FileMediator
+from ..monitor.exceptions import NoConfigFile
+from ..monitor.pure import LazyProperty
+from ..monitor.config import MMConfig
+from ..monitor.owners import Owner
+from ..monitor.events import EventRegistry
+from ..monitor.listeners import FileMediator
from api_clients.api_client import AirtimeApiClient
# poor man's phantom types...
@@ -21,7 +21,7 @@ class AirtimeInstance(object):
def root_make(cls, name, root):
cfg = {
'api_client' : join(root, 'etc/airtime/api_client.cfg'),
- 'media_monitor' : join(root, 'etc/airtime/media-monitor.cfg'),
+ 'media_monitor' : join(root, 'etc/airtime/airtime.conf'),
}
return cls(name, root, cfg)
@@ -41,7 +41,7 @@ class AirtimeInstance(object):
def touch_file_path(self):
""" Get the path of the touch file for every instance """
- touch_base_path = self.mm_config['index_path']
+ touch_base_path = self.mm_config['media-monitor']['index_path']
touch_base_name = basename(touch_base_path)
new_base_name = self.name + touch_base_name
return join(dirname(touch_base_path), new_base_name)
diff --git a/python_apps/media-monitor2/media/saas/launcher.py b/python_apps/media-monitor/mm2/media/saas/launcher.py
similarity index 73%
rename from python_apps/media-monitor2/media/saas/launcher.py
rename to python_apps/media-monitor/mm2/media/saas/launcher.py
index c561464e3..a2bd95d5c 100644
--- a/python_apps/media-monitor2/media/saas/launcher.py
+++ b/python_apps/media-monitor/mm2/media/saas/launcher.py
@@ -2,31 +2,31 @@ import os, sys
import logging
import logging.config
-import media.monitor.pure as mmp
+from ..monitor import pure as mmp
-from media.monitor.exceptions import FailedToObtainLocale, FailedToSetLocale
-from media.monitor.log import get_logger, setup_logging
+from ..monitor.exceptions import FailedToObtainLocale, FailedToSetLocale
+from ..monitor.log import get_logger, setup_logging
from std_err_override import LogWriter
-from media.saas.thread import InstanceThread, user, apc, getsig
-from media.monitor.log import Loggable
-from media.monitor.exceptions import CouldNotCreateIndexFile
-from media.monitor.toucher import ToucherThread
-from media.monitor.airtime import AirtimeNotifier, AirtimeMessageReceiver
-from media.monitor.watchersyncer import WatchSyncer
-from media.monitor.eventdrainer import EventDrainer
-from media.monitor.manager import Manager
-from media.monitor.syncdb import AirtimeDB
-from media.saas.airtimeinstance import AirtimeInstance
+from ..saas.thread import InstanceThread, user, apc, getsig
+from ..monitor.log import Loggable
+from ..monitor.exceptions import CouldNotCreateIndexFile
+from ..monitor.toucher import ToucherThread
+from ..monitor.airtime import AirtimeNotifier, AirtimeMessageReceiver
+from ..monitor.watchersyncer import WatchSyncer
+from ..monitor.eventdrainer import EventDrainer
+from ..monitor.manager import Manager
+from ..monitor.syncdb import AirtimeDB
+from airtimeinstance import AirtimeInstance
class MM2(InstanceThread, Loggable):
def index_create(self, index_create_attempt=False):
config = user().mm_config
if not index_create_attempt:
- if not os.path.exists(config['index_path']):
+ if not os.path.exists(config['media-monitor']['index_path']):
self.logger.info("Attempting to create index file:...")
try:
- with open(config['index_path'], 'w') as f: f.write(" ")
+ with open(config['media-monitor']['index_path'], 'w') as f: f.write(" ")
except Exception as e:
self.logger.info("Failed to create index file with exception: %s" \
% str(e))
@@ -36,8 +36,8 @@ class MM2(InstanceThread, Loggable):
else:
self.logger.info("Already tried to create index. Will not try again ")
- if not os.path.exists(config['index_path']):
- raise CouldNotCreateIndexFile(config['index_path'])
+ if not os.path.exists(config['media-monitor']['index_path']):
+ raise CouldNotCreateIndexFile(config['media-monitor']['index_path'])
def run(self):
self.index_create()
@@ -45,8 +45,8 @@ class MM2(InstanceThread, Loggable):
apiclient = apc()
config = user().mm_config
WatchSyncer(signal=getsig('watch'),
- chunking_number=config['chunking_number'],
- timeout=config['request_max_wait'])
+ chunking_number=config['media-monitor']['chunking_number'],
+ timeout=config['media-monitor']['request_max_wait'])
airtime_receiver = AirtimeMessageReceiver(config,manager)
airtime_notifier = AirtimeNotifier(config, airtime_receiver)
@@ -76,14 +76,14 @@ class MM2(InstanceThread, Loggable):
else: self.logger.info("Failed to add watch on %s" % str(watch_dir))
EventDrainer(airtime_notifier,
- interval=float(config['rmq_event_wait']))
+ interval=float(config['media-monitor']['rmq_event_wait']))
# Launch the toucher that updates the last time when the script was
# ran every n seconds.
# TODO : verify that this does not interfere with bootstrapping because the
# toucher thread might update the last_ran variable too fast
ToucherThread(path=user().touch_file_path(),
- interval=int(config['touch_interval']))
+ interval=int(config['media-monitor']['touch_interval']))
success = False
while not success:
@@ -97,9 +97,9 @@ class MM2(InstanceThread, Loggable):
manager.loop()
-def launch_instance(name, root, global_cfg, apc_cfg):
+def launch_instance(name, root, global_cfg):
cfg = {
- 'api_client' : apc_cfg,
+ 'api_client' : global_cfg,
'media_monitor' : global_cfg,
}
ai = AirtimeInstance(name, root, cfg)
diff --git a/python_apps/media-monitor2/media/saas/thread.py b/python_apps/media-monitor/mm2/media/saas/thread.py
similarity index 100%
rename from python_apps/media-monitor2/media/saas/thread.py
rename to python_apps/media-monitor/mm2/media/saas/thread.py
diff --git a/python_apps/media-monitor2/mm2.py b/python_apps/media-monitor/mm2/mm2.py
similarity index 82%
rename from python_apps/media-monitor2/mm2.py
rename to python_apps/media-monitor/mm2/mm2.py
index 7c447c060..0f14909e8 100644
--- a/python_apps/media-monitor2/mm2.py
+++ b/python_apps/media-monitor/mm2/mm2.py
@@ -4,12 +4,12 @@ import os
from media.saas.launcher import setup_global, launch_instance, setup_logger
from media.monitor.config import MMConfig
-def main(global_config, api_client_config, log_config):
+def main(global_config, log_config):
""" function to run hosted install """
mm_config = MMConfig(global_config)
- log = setup_logger( log_config, mm_config['logpath'] )
+ log = setup_logger( log_config, mm_config['media-monitor']['logpath'] )
setup_global(log)
- launch_instance('hosted_install', '/', global_config, api_client_config)
+ launch_instance('hosted_install', '/', global_config)
__doc__ = """
Usage:
diff --git a/python_apps/media-monitor2/pyitest.py b/python_apps/media-monitor/mm2/pyitest.py
similarity index 100%
rename from python_apps/media-monitor2/pyitest.py
rename to python_apps/media-monitor/mm2/pyitest.py
diff --git a/python_apps/media-monitor2/tests/__init__.py b/python_apps/media-monitor/mm2/tests/__init__.py
similarity index 100%
rename from python_apps/media-monitor2/tests/__init__.py
rename to python_apps/media-monitor/mm2/tests/__init__.py
diff --git a/python_apps/media-monitor2/tests/api_client.cfg b/python_apps/media-monitor/mm2/tests/api_client.cfg
similarity index 100%
rename from python_apps/media-monitor2/tests/api_client.cfg
rename to python_apps/media-monitor/mm2/tests/api_client.cfg
diff --git a/python_apps/media-monitor2/tests/live_client.cfg b/python_apps/media-monitor/mm2/tests/live_client.cfg
similarity index 100%
rename from python_apps/media-monitor2/tests/live_client.cfg
rename to python_apps/media-monitor/mm2/tests/live_client.cfg
diff --git a/python_apps/media-monitor2/tests/prepare_tests.py b/python_apps/media-monitor/mm2/tests/prepare_tests.py
similarity index 92%
rename from python_apps/media-monitor2/tests/prepare_tests.py
rename to python_apps/media-monitor/mm2/tests/prepare_tests.py
index ebbce89b8..e145c9fa5 100644
--- a/python_apps/media-monitor2/tests/prepare_tests.py
+++ b/python_apps/media-monitor/mm2/tests/prepare_tests.py
@@ -8,7 +8,7 @@ real_path1 = u'/home/rudi/throwaway/watch/unknown/unknown/ACDC_-_Back_In_Black-s
opath = u"/home/rudi/Airtime/python_apps/media-monitor2/tests/"
ppath = u"/home/rudi/Airtime/python_apps/media-monitor2/media/"
-api_client_path = '/etc/airtime/api_client.cfg'
+api_client_path = '/etc/airtime/airtime.conf'
# holdover from the time we had a special config for testing
sample_config = api_client_path
real_config = api_client_path
diff --git a/python_apps/media-monitor2/tests/run_tests.pl b/python_apps/media-monitor/mm2/tests/run_tests.pl
similarity index 100%
rename from python_apps/media-monitor2/tests/run_tests.pl
rename to python_apps/media-monitor/mm2/tests/run_tests.pl
diff --git a/python_apps/media-monitor2/tests/test_api_client.py b/python_apps/media-monitor/mm2/tests/test_api_client.py
similarity index 100%
rename from python_apps/media-monitor2/tests/test_api_client.py
rename to python_apps/media-monitor/mm2/tests/test_api_client.py
diff --git a/python_apps/media-monitor2/tests/test_config.cfg b/python_apps/media-monitor/mm2/tests/test_config.cfg
similarity index 100%
rename from python_apps/media-monitor2/tests/test_config.cfg
rename to python_apps/media-monitor/mm2/tests/test_config.cfg
diff --git a/python_apps/media-monitor2/tests/test_config.py b/python_apps/media-monitor/mm2/tests/test_config.py
similarity index 100%
rename from python_apps/media-monitor2/tests/test_config.py
rename to python_apps/media-monitor/mm2/tests/test_config.py
diff --git a/python_apps/media-monitor2/tests/test_emf.py b/python_apps/media-monitor/mm2/tests/test_emf.py
similarity index 100%
rename from python_apps/media-monitor2/tests/test_emf.py
rename to python_apps/media-monitor/mm2/tests/test_emf.py
diff --git a/python_apps/media-monitor2/tests/test_eventcontractor.py b/python_apps/media-monitor/mm2/tests/test_eventcontractor.py
similarity index 100%
rename from python_apps/media-monitor2/tests/test_eventcontractor.py
rename to python_apps/media-monitor/mm2/tests/test_eventcontractor.py
diff --git a/python_apps/media-monitor2/tests/test_instance.py b/python_apps/media-monitor/mm2/tests/test_instance.py
similarity index 100%
rename from python_apps/media-monitor2/tests/test_instance.py
rename to python_apps/media-monitor/mm2/tests/test_instance.py
diff --git a/python_apps/media-monitor2/tests/test_listeners.py b/python_apps/media-monitor/mm2/tests/test_listeners.py
similarity index 100%
rename from python_apps/media-monitor2/tests/test_listeners.py
rename to python_apps/media-monitor/mm2/tests/test_listeners.py
diff --git a/python_apps/media-monitor2/tests/test_manager.py b/python_apps/media-monitor/mm2/tests/test_manager.py
similarity index 100%
rename from python_apps/media-monitor2/tests/test_manager.py
rename to python_apps/media-monitor/mm2/tests/test_manager.py
diff --git a/python_apps/media-monitor2/tests/test_metadata.py b/python_apps/media-monitor/mm2/tests/test_metadata.py
similarity index 100%
rename from python_apps/media-monitor2/tests/test_metadata.py
rename to python_apps/media-monitor/mm2/tests/test_metadata.py
diff --git a/python_apps/media-monitor2/tests/test_metadata_def.py b/python_apps/media-monitor/mm2/tests/test_metadata_def.py
similarity index 100%
rename from python_apps/media-monitor2/tests/test_metadata_def.py
rename to python_apps/media-monitor/mm2/tests/test_metadata_def.py
diff --git a/python_apps/media-monitor2/tests/test_notifier.py b/python_apps/media-monitor/mm2/tests/test_notifier.py
similarity index 100%
rename from python_apps/media-monitor2/tests/test_notifier.py
rename to python_apps/media-monitor/mm2/tests/test_notifier.py
diff --git a/python_apps/media-monitor2/tests/test_owners.py b/python_apps/media-monitor/mm2/tests/test_owners.py
similarity index 100%
rename from python_apps/media-monitor2/tests/test_owners.py
rename to python_apps/media-monitor/mm2/tests/test_owners.py
diff --git a/python_apps/media-monitor2/tests/test_pure.py b/python_apps/media-monitor/mm2/tests/test_pure.py
similarity index 100%
rename from python_apps/media-monitor2/tests/test_pure.py
rename to python_apps/media-monitor/mm2/tests/test_pure.py
diff --git a/python_apps/media-monitor2/tests/test_requestsync.py b/python_apps/media-monitor/mm2/tests/test_requestsync.py
similarity index 100%
rename from python_apps/media-monitor2/tests/test_requestsync.py
rename to python_apps/media-monitor/mm2/tests/test_requestsync.py
diff --git a/python_apps/media-monitor2/tests/test_syncdb.py b/python_apps/media-monitor/mm2/tests/test_syncdb.py
similarity index 100%
rename from python_apps/media-monitor2/tests/test_syncdb.py
rename to python_apps/media-monitor/mm2/tests/test_syncdb.py
diff --git a/python_apps/media-monitor2/tests/test_thread.py b/python_apps/media-monitor/mm2/tests/test_thread.py
similarity index 100%
rename from python_apps/media-monitor2/tests/test_thread.py
rename to python_apps/media-monitor/mm2/tests/test_thread.py
diff --git a/python_apps/media-monitor2/tests/test_toucher.py b/python_apps/media-monitor/mm2/tests/test_toucher.py
similarity index 100%
rename from python_apps/media-monitor2/tests/test_toucher.py
rename to python_apps/media-monitor/mm2/tests/test_toucher.py
diff --git a/python_apps/media-monitor/monit-airtime-media-monitor.cfg b/python_apps/media-monitor/monit-airtime-media-monitor.cfg
deleted file mode 100644
index 7001a3f5a..000000000
--- a/python_apps/media-monitor/monit-airtime-media-monitor.cfg
+++ /dev/null
@@ -1,9 +0,0 @@
- set daemon 10 # Poll at 5 second intervals
- set logfile /var/log/monit.log
-
- set httpd port 2812
-
- check process airtime-media-monitor
- with pidfile "/var/run/airtime-media-monitor.pid"
- start program = "/etc/init.d/airtime-media-monitor start" with timeout 10 seconds
- stop program = "/etc/init.d/airtime-media-monitor stop"
diff --git a/python_apps/media-monitor/setup.py b/python_apps/media-monitor/setup.py
new file mode 100644
index 000000000..3031b14aa
--- /dev/null
+++ b/python_apps/media-monitor/setup.py
@@ -0,0 +1,66 @@
+from setuptools import setup
+from subprocess import call
+import sys
+import os
+
+script_path = os.path.dirname(os.path.realpath(__file__))
+print script_path
+os.chdir(script_path)
+
+# Allows us to avoid installing the upstart init script when deploying on Airtime Pro:
+if '--no-init-script' in sys.argv:
+ data_files = []
+ sys.argv.remove('--no-init-script') # super hax
+else:
+ media_monitor_files = []
+ mm2_files = []
+ for root, dirnames, filenames in os.walk('media-monitor'):
+ for filename in filenames:
+ media_monitor_files.append(os.path.join(root, filename))
+ for root, dirnames, filenames in os.walk('media-monitor2'):
+ for filename in filenames:
+ mm2_files.append(os.path.join(root, filename))
+
+ data_files = [
+ ('/etc/init', ['install/upstart/airtime-media-monitor.conf.template']),
+ ('/etc/init.d', ['install/sysvinit/airtime-media-monitor']),
+ ('/etc/airtime', ['install/media_monitor_logging.cfg']),
+ ('/var/log/airtime/media-monitor', []),
+ ('/var/tmp/airtime/media-monitor', []),
+ ]
+ print data_files
+
+setup(name='airtime-media-monitor',
+ version='1.0',
+ description='Airtime Media Monitor',
+ url='http://github.com/sourcefabric/Airtime',
+ author='sourcefabric',
+ license='AGPLv3',
+ packages=['media_monitor', 'mm2', 'mm2.configs',
+ 'mm2.media', 'mm2.media.monitor',
+ 'mm2.media.metadata', 'mm2.media.saas'
+ ],
+ package_data={'': ['*.cfg']},
+ scripts=['bin/airtime-media-monitor'],
+ install_requires=[
+ 'amqplib',
+ 'anyjson',
+ 'argparse',
+ 'configobj',
+ 'docopt',
+ 'kombu',
+ 'mutagen',
+ 'poster',
+ 'PyDispatcher',
+ 'pyinotify',
+ 'pytz',
+ 'wsgiref'
+ ],
+ zip_safe=False,
+ data_files=data_files)
+
+# Reload the initctl config so that the media-monitor service works
+if data_files:
+ print "Reloading initctl configuration"
+ #call(['initctl', 'reload-configuration'])
+ print "Run \"sudo service airtime-media-monitor start\""
diff --git a/python_apps/media-monitor2/configs/airtime.conf b/python_apps/media-monitor2/configs/airtime.conf
deleted file mode 100644
index 525aa1ed7..000000000
--- a/python_apps/media-monitor2/configs/airtime.conf
+++ /dev/null
@@ -1,32 +0,0 @@
-[database]
-host = localhost
-dbname = airtime
-dbuser = airtime
-dbpass = airtime
-
-[rabbitmq]
-host = 127.0.0.1
-port = 5672
-user = guest
-password = guest
-vhost = /
-
-[general]
-api_key = I6EUOJM0D1EIGSMZ9T70
-web_server_user = www-data
-airtime_dir = /usr/share/airtime
-base_url = localhost
-base_port = 80
-base_dir = '/'
-
-;How many hours ahead of time should Airtime playout engine (PYPO)
-;cache scheduled media files.
-cache_ahead_hours = 1
-
-[monit]
-monit_user = guest
-monit_password = airtime
-
-[soundcloud]
-connection_retries = 3
-time_between_retries = 60
diff --git a/python_apps/media-monitor2/configs/api_client.cfg b/python_apps/media-monitor2/configs/api_client.cfg
deleted file mode 100644
index f62287e08..000000000
--- a/python_apps/media-monitor2/configs/api_client.cfg
+++ /dev/null
@@ -1,126 +0,0 @@
-bin_dir = "/usr/lib/airtime/api_clients"
-
-#############################
-## Common
-#############################
-
-# Value needed to access the API
-api_key = 'I6EUOJM0D1EIGSMZ9T70'
-
-# Path to the base of the API
-api_base = 'api'
-
-# URL to get the version number of the server API
-version_url = 'version/api_key/%%api_key%%'
-
-#URL to register a components IP Address with the central web server
-register_component = 'register-component/format/json/api_key/%%api_key%%/component/%%component%%'
-
-# Hostname
-host = 'localhost'
-base_port = 80
-base_dir = '/'
-
-#############################
-## Config for Media Monitor
-#############################
-
-# URL to setup the media monitor
-media_setup_url = 'media-monitor-setup/format/json/api_key/%%api_key%%'
-
-# Tell Airtime the file id associated with a show instance.
-upload_recorded = 'upload-recorded/format/json/api_key/%%api_key%%/fileid/%%fileid%%/showinstanceid/%%showinstanceid%%'
-
-# URL to tell Airtime to update file's meta data
-update_media_url = 'reload-metadata/format/json/api_key/%%api_key%%/mode/%%mode%%'
-
-# URL to tell Airtime we want a listing of all files it knows about
-list_all_db_files = 'list-all-files/format/json/api_key/%%api_key%%/dir_id/%%dir_id%%/all/%%all%%'
-
-# URL to tell Airtime we want a listing of all dirs its watching (including the stor dir)
-list_all_watched_dirs = 'list-all-watched-dirs/format/json/api_key/%%api_key%%'
-
-# URL to tell Airtime we want to add watched directory
-add_watched_dir = 'add-watched-dir/format/json/api_key/%%api_key%%/path/%%path%%'
-
-# URL to tell Airtime we want to add watched directory
-remove_watched_dir = 'remove-watched-dir/format/json/api_key/%%api_key%%/path/%%path%%'
-
-# URL to tell Airtime we want to add watched directory
-set_storage_dir = 'set-storage-dir/format/json/api_key/%%api_key%%/path/%%path%%'
-
-# URL to tell Airtime about file system mount change
-update_fs_mount = 'update-file-system-mount/format/json/api_key/%%api_key%%'
-
-# URL to commit multiple updates from media monitor at the same time
-
-reload_metadata_group = 'reload-metadata-group/format/json/api_key/%%api_key%%'
-
-# URL to tell Airtime about file system mount change
-handle_watched_dir_missing = 'handle-watched-dir-missing/format/json/api_key/%%api_key%%/dir/%%dir%%'
-
-#############################
-## Config for Recorder
-#############################
-
-# URL to get the schedule of shows set to record
-show_schedule_url = 'recorded-shows/format/json/api_key/%%api_key%%'
-
-# URL to upload the recorded show's file to Airtime
-upload_file_url = 'upload-file/format/json/api_key/%%api_key%%'
-
-# URL to commit multiple updates from media monitor at the same time
-
-#number of retries to upload file if connection problem
-upload_retries = 3
-
-#time to wait between attempts to upload file if connection problem (in seconds)
-upload_wait = 60
-
-################################################################################
-# Uncomment *one of the sets* of values from the API clients below, and comment
-# out all the others.
-################################################################################
-
-#############################
-## Config for Pypo
-#############################
-
-# Schedule export path.
-# %%from%% - starting date/time in the form YYYY-MM-DD-hh-mm
-# %%to%% - starting date/time in the form YYYY-MM-DD-hh-mm
-export_url = 'schedule/api_key/%%api_key%%'
-
-get_media_url = 'get-media/file/%%file%%/api_key/%%api_key%%'
-
-# Update whether a schedule group has begun playing.
-update_item_url = 'notify-schedule-group-play/api_key/%%api_key%%/schedule_id/%%schedule_id%%'
-
-# Update whether an audio clip is currently playing.
-update_start_playing_url = 'notify-media-item-start-play/api_key/%%api_key%%/media_id/%%media_id%%/'
-
-# URL to tell Airtime we want to get stream setting
-get_stream_setting = 'get-stream-setting/format/json/api_key/%%api_key%%/'
-
-#URL to update liquidsoap status
-update_liquidsoap_status = 'update-liquidsoap-status/format/json/api_key/%%api_key%%/msg/%%msg%%/stream_id/%%stream_id%%/boot_time/%%boot_time%%'
-
-#URL to check live stream auth
-check_live_stream_auth = 'check-live-stream-auth/format/json/api_key/%%api_key%%/username/%%username%%/password/%%password%%/djtype/%%djtype%%'
-
-#URL to update source status
-update_source_status = 'update-source-status/format/json/api_key/%%api_key%%/sourcename/%%sourcename%%/status/%%status%%'
-
-get_bootstrap_info = 'get-bootstrap-info/format/json/api_key/%%api_key%%'
-
-get_files_without_replay_gain = 'get-files-without-replay-gain/api_key/%%api_key%%/dir_id/%%dir_id%%'
-
-update_replay_gain_value = 'update-replay-gain-value/api_key/%%api_key%%'
-
-notify_webstream_data = 'notify-webstream-data/api_key/%%api_key%%/media_id/%%media_id%%/format/json'
-
-notify_liquidsoap_started = 'rabbitmq-do-push/api_key/%%api_key%%/format/json'
-
-get_stream_parameters = 'get-stream-parameters/api_key/%%api_key%%/format/json'
-
-push_stream_stats = 'push-stream-stats/api_key/%%api_key%%/format/json'
diff --git a/python_apps/media-monitor2/configs/media-monitor.cfg b/python_apps/media-monitor2/configs/media-monitor.cfg
deleted file mode 100644
index b1167f56b..000000000
--- a/python_apps/media-monitor2/configs/media-monitor.cfg
+++ /dev/null
@@ -1,31 +0,0 @@
-api_client = "airtime"
-
-# where the binary files live
-bin_dir = '/usr/lib/airtime/media-monitor'
-
-# where the logging files live
-log_dir = '/var/log/airtime/media-monitor'
-
-
-############################################
-# RabbitMQ settings #
-############################################
-rabbitmq_host = 'localhost'
-rabbitmq_user = 'guest'
-rabbitmq_password = 'guest'
-rabbitmq_vhost = '/'
-
-############################################
-# Media-Monitor preferences #
-############################################
-check_filesystem_events = 5 #how long to queue up events performed on the files themselves.
-check_airtime_events = 30 #how long to queue metadata input from airtime.
-
-# MM2 only:
-touch_interval = 5
-chunking_number = 450
-request_max_wait = 3.0
-rmq_event_wait = 0.1
-logpath = '/var/log/airtime/media-monitor/media-monitor.log'
-index_path = '/var/tmp/airtime/media-monitor/last_index'
-
diff --git a/python_apps/monit/monit-airtime-generic.cfg b/python_apps/monit/monit-airtime-generic.cfg
deleted file mode 100644
index 46e752972..000000000
--- a/python_apps/monit/monit-airtime-generic.cfg
+++ /dev/null
@@ -1,18 +0,0 @@
- set daemon 10 # Poll at 10 second intervals
- set logfile /var/log/monit.log
-
-# set mailserver %%mail_server%% port 25
-# set alert support@airtime.pro
-
-# set mail-format {
-# from: lxc%%instance_id%%@airtime.pro
-# subject: $ACTION $SERVICE (%%mail_server%%)
-# message:
-# Monit: $ACTION $SERVICE
-# Date: $DATE
-# Description: $DESCRIPTION.
-# }
-
- set httpd port 2812
- allow admin:$admin_pass
- allow guest:airtime read-only
diff --git a/python_apps/monit/monit-airtime-rabbitmq-server.cfg b/python_apps/monit/monit-airtime-rabbitmq-server.cfg
deleted file mode 100644
index dac2463c8..000000000
--- a/python_apps/monit/monit-airtime-rabbitmq-server.cfg
+++ /dev/null
@@ -1,7 +0,0 @@
- set daemon 10 # Poll at 5 second intervals
- set logfile /var/log/monit.log
-
- check process rabbitmq-server
- with pidfile "/var/run/rabbitmq.pid"
- start program = "/bin/bash -c '/etc/init.d/rabbitmq-server start; /usr/lib/airtime/utils/rabbitmq-update-pid.sh'"
- stop program = "/etc/init.d/rabbitmq-server stop"
diff --git a/python_apps/pypo/airtime-liquidsoap b/python_apps/pypo/airtime-liquidsoap
deleted file mode 100755
index def0aaae1..000000000
--- a/python_apps/pypo/airtime-liquidsoap
+++ /dev/null
@@ -1,48 +0,0 @@
-#!/bin/bash -e
-
-debug="f"
-
-showhelp () {
- echo "Usage: airtime-liquidsoap [options]
---help|-h Displays usage information.
---debug|-d Print error messages to console"
-}
-
-set -- $(getopt -l help,debug "hd" "$@")
-while [ $# -gt 0 ]
-do
- case "$1" in
- (-h|--help) showhelp; exit 0;;
- (-d|--debug) debug="t";;
-
- (--) shift; break;;
- (-*) echo "$0: error - unrecognized option $1" 1>&2; exit 1;;
- (*) break;;
- esac
- shift
-done
-
-
-virtualenv_bin="/usr/lib/airtime/airtime_virtualenv/bin/"
-. ${virtualenv_bin}activate
-
-export HOME="/var/tmp/airtime/pypo/"
-api_client_path="/usr/lib/airtime/"
-if [ $debug = "t" ]; then
- ls_path="/usr/bin/airtime-liquidsoap --verbose -f"
-else
- ls_path="/usr/bin/airtime-liquidsoap --verbose -f -d"
-fi
-ls_param="/usr/lib/airtime/pypo/bin/liquidsoap_scripts/ls_script.liq"
-
-export PYTHONPATH=${api_client_path}
-
-SCRIPT=`readlink -f $0`
-# Absolute directory this script is in
-SCRIPTPATH=`dirname $SCRIPT`
-
-cd $SCRIPTPATH/liquidsoap_scripts
-python generate_liquidsoap_cfg.py
-
-exec ${ls_path} ${ls_param} 2>&1
-# EOF
diff --git a/python_apps/pypo/airtime-liquidsoap-init-d b/python_apps/pypo/airtime-liquidsoap-init-d
deleted file mode 100755
index f8b749c2b..000000000
--- a/python_apps/pypo/airtime-liquidsoap-init-d
+++ /dev/null
@@ -1,125 +0,0 @@
-#!/bin/bash
-
-### BEGIN INIT INFO
-# Provides: airtime-liquidsoap
-# Required-Start: $local_fs $remote_fs $network $syslog $all
-# Required-Stop: $local_fs $remote_fs $network $syslog
-# Default-Start: 2 3 4 5
-# Default-Stop: 0 1 6
-# Short-Description: Liquidsoap daemon
-### END INIT INFO
-
-USERID=pypo
-GROUPID=pypo
-NAME="Liquidsoap Playout Engine"
-
-DAEMON=/usr/lib/airtime/pypo/bin/airtime-liquidsoap
-PIDFILE=/var/run/airtime-liquidsoap.pid
-EXEC='/usr/bin/airtime-liquidsoap'
-
-start () {
- mkdir -p /var/log/airtime/pypo-liquidsoap
- chown $USERID:$GROUPID /var/log/airtime/pypo-liquidsoap
-
- chown $USERID:$GROUPID /etc/airtime
- touch /etc/airtime/liquidsoap.cfg
- chown $USERID:$GROUPID /etc/airtime/liquidsoap.cfg
-
- touch $PIDFILE
- chown $USERID:$GROUPID $PIDFILE
-
- #start-stop-daemon --start --quiet --chuid $USERID:$GROUPID \
- #--pidfile $PIDFILE --nicelevel -15 --startas $DAEMON
- start-stop-daemon --start --quiet --chuid $USERID:$GROUPID \
- --nicelevel -15 --startas $DAEMON --exec $EXEC
-}
-
-stop () {
- timeout --version >/dev/null 2>&1
- RESULT="$?"
-
- #send term signal after 10 seconds
- if [ "$RESULT" = "0" ]; then
- timeout -s9 10s /usr/lib/airtime/airtime_virtualenv/bin/python \
- /usr/lib/airtime/pypo/bin/liquidsoap_scripts/liquidsoap_prepare_terminate.py
- else
- #some earlier versions of Ubuntu (Lucid) had a different timeout
- #command that takes different input parameters.
- timeout 10 /usr/lib/airtime/airtime_virtualenv/bin/python \
- /usr/lib/airtime/pypo/bin/liquidsoap_scripts/liquidsoap_prepare_terminate.py
- fi
- # Send TERM after 5 seconds, wait at most 30 seconds.
- #start-stop-daemon --stop --oknodo --retry=TERM/10/KILL/5 --quiet --pidfile $PIDFILE
- start-stop-daemon --stop --oknodo --retry=TERM/10/KILL/5 --quiet --exec $EXEC
-
- rm -f $PIDFILE
- sleep 2
-}
-
-start_with_monit () {
- start
- monit monitor airtime-liquidsoap >/dev/null 2>&1
-}
-
-stop_with_monit() {
- monit unmonitor airtime-liquidsoap >/dev/null 2>&1
- stop
-}
-
-
-
-
-case "${1:-''}" in
- 'stop')
- echo "* Stopping Liquidsoap without notifying Monit process watchdog. If Monit is
-* running it will automatically bring the Liquidsoap back up. You probably want
-* 'stop-with-monit' instead of 'stop'."
- echo -n "Stopping $NAME: "
- stop
- echo "Done."
- ;;
- 'start')
- echo "* Starting $NAME without Monit process watchdog. To make sure Monit is watching
-* Liquidsoap, use 'start-with-monit' instead of 'start'."
- echo -n "Starting $NAME: "
- start
- echo "Done."
- ;;
- 'restart')
- # restart commands here
- echo -n "Restarting $NAME: "
- stop
- start
- echo "Done."
- ;;
-
- 'status')
- if [ -f "$PIDFILE" ]; then
- pid=`cat $PIDFILE`
- if [ -d "/proc/$pid" ]; then
- echo "$NAME is running"
- exit 0
- fi
- fi
- echo "$NAME is not running"
- exit 1
- ;;
- 'start-with-monit')
- # restart commands here
- echo -n "Starting $NAME: "
- start_with_monit
- echo "Done."
- ;;
- 'stop-with-monit')
- # restart commands here
- echo -n "Stopping $NAME: "
- stop_with_monit
- echo "Done."
- ;;
-
- *) # no parameter specified
- echo "Usage: $SELF start|stop|restart|status"
- exit 1
- ;;
-
-esac
diff --git a/python_apps/pypo/airtime-playout b/python_apps/pypo/airtime-playout
deleted file mode 100755
index 06a63c4f9..000000000
--- a/python_apps/pypo/airtime-playout
+++ /dev/null
@@ -1,35 +0,0 @@
-#!/bin/bash
-
-virtualenv_bin="/usr/lib/airtime/airtime_virtualenv/bin/"
-. ${virtualenv_bin}activate
-
-# Absolute path to this script
-SCRIPT=`readlink -f $0`
-# Absolute directory this script is in
-pypo_path=`dirname $SCRIPT`
-
-api_client_path="/usr/lib/airtime/"
-pypo_script="pypocli.py"
-cd ${pypo_path}
-
-set +e
-cat /etc/default/locale | grep -i "LANG=.*UTF-\?8"
-set -e
-if [ "$?" != "0" ]; then
- echo "non UTF-8 default locale found in /etc/default/locale." > /var/log/airtime/pypo/error.log
- exit 1
-fi
-
-export HOME="/var/tmp/airtime/pypo/"
-export PYTHONPATH=${api_client_path}:$PYTHONPATH
-export LC_ALL=`cat /etc/default/locale | grep "LANG=" | cut -d= -f2 | tr -d "\n\""`
-export TERM=xterm
-
-
-#Nothing to do with Pypo, but for container maintenance. Let's parse the IP address
-#so we may more easily manage our instance containers
-ifconfig eth0 | egrep -o 'inet addr:([0-9]{1,3}\.){3}[0-9]{1,3}' | cut -d':' -f2 > /etc/airtime_ip_addr
-
-exec python ${pypo_path}/${pypo_script} > /var/log/airtime/pypo/py-interpreter.log 2>&1
-
-# EOF
diff --git a/python_apps/pypo/bin/airtime-liquidsoap b/python_apps/pypo/bin/airtime-liquidsoap
new file mode 100755
index 000000000..7863ba692
--- /dev/null
+++ b/python_apps/pypo/bin/airtime-liquidsoap
@@ -0,0 +1,5 @@
+#!/usr/bin/python
+import runpy
+
+# Run the liquidsoap python module
+runpy.run_module('liquidsoap')
diff --git a/python_apps/pypo/bin/airtime-playout b/python_apps/pypo/bin/airtime-playout
new file mode 100755
index 000000000..6e847a072
--- /dev/null
+++ b/python_apps/pypo/bin/airtime-playout
@@ -0,0 +1,5 @@
+#!/usr/bin/python
+import runpy
+
+runpy.run_module("pypo", run_name="__main__")
+
diff --git a/python_apps/pypo/pyponotify.py b/python_apps/pypo/bin/pyponotify
old mode 100644
new mode 100755
similarity index 97%
rename from python_apps/pypo/pyponotify.py
rename to python_apps/pypo/bin/pyponotify
index 46eb76159..bea57298d
--- a/python_apps/pypo/pyponotify.py
+++ b/python_apps/pypo/bin/pyponotify
@@ -1,3 +1,4 @@
+#!/usr/bin/env python
# -*- coding: utf-8 -*-
import traceback
@@ -50,7 +51,7 @@ parser.add_option("-n", "--liquidsoap-started", help="notify liquidsoap started"
(options, args) = parser.parse_args()
# configure logging
-logging.config.fileConfig("notify_logging.cfg")
+logging.config.fileConfig('/etc/airtime/notify_logging.cfg')
logger = logging.getLogger('notify')
LogWriter.override_std_err(logger)
@@ -59,7 +60,7 @@ LogWriter.override_std_err(logger)
# loading config file
try:
- config = ConfigObj('/etc/airtime/pypo.cfg')
+ config = ConfigObj('/etc/airtime/airtime.conf')
except Exception, e:
logger.error('Error loading config file: %s', e)
diff --git a/python_apps/pypo/notify_logging.cfg b/python_apps/pypo/install/notify_logging.cfg
similarity index 100%
rename from python_apps/pypo/notify_logging.cfg
rename to python_apps/pypo/install/notify_logging.cfg
diff --git a/python_apps/pypo/install/pypo-copy-files.py b/python_apps/pypo/install/pypo-copy-files.py
deleted file mode 100644
index e88b46a64..000000000
--- a/python_apps/pypo/install/pypo-copy-files.py
+++ /dev/null
@@ -1,140 +0,0 @@
-import os
-import grp
-import stat
-import shutil
-import sys
-import subprocess
-import random
-import string
-import re
-from configobj import ConfigObj
-
-if os.geteuid() != 0:
- print "Please run this as root."
- sys.exit(1)
-
-def get_current_script_dir():
- current_script_dir = os.path.realpath(__file__)
- index = current_script_dir.rindex('/')
- return current_script_dir[0:index]
-
-def copy_dir(src_dir, dest_dir):
- if (os.path.exists(dest_dir)) and (dest_dir != "/"):
- shutil.rmtree(dest_dir)
- if not (os.path.exists(dest_dir)):
- #print "Copying directory "+os.path.realpath(src_dir)+" to "+os.path.realpath(dest_dir)
- shutil.copytree(src_dir, dest_dir)
-
-def create_dir(path):
- try:
- os.makedirs(path)
- except Exception, e:
- pass
-
-def get_rand_string(length=10):
- return ''.join(random.choice(string.ascii_uppercase + string.digits) for x in range(length))
-
-def get_rand_string(length=10):
- return ''.join(random.choice(string.ascii_uppercase + string.digits) for x in range(length))
-
-def get_monit_version():
- version = 0
- try:
- p = subprocess.Popen(['monit', '-V'], stdout=subprocess.PIPE)
- out = p.communicate()[0].strip()
- search = re.search(r'This is Monit version (.*)\n', out, re.IGNORECASE)
-
- if search:
- matches = search.groups()
- if len(matches) == 1:
- version = matches[0]
- except Exception:
- print "Could not get monit version"
-
- return version
-
-#return 1 if version1 > version2
-#return 0 if version1 == version2
-#return -1 if version1 < version2
-def version_compare(version1, version2):
- def normalize(v):
- return [int(x) for x in re.sub(r'(\.0+)*$','', v).split(".")]
- return cmp(normalize(version1), normalize(version2))
-
-PATH_INI_FILE = '/etc/airtime/pypo.cfg'
-
-try:
- # Absolute path this script is in
- current_script_dir = get_current_script_dir()
-
- if not os.path.exists(PATH_INI_FILE):
- shutil.copy('%s/../pypo.cfg'%current_script_dir, PATH_INI_FILE)
-
- try:
- os.remove("/etc/airtime/liquidsoap.cfg")
- except Exception, e:
- pass
- gid = grp.getgrnam("pypo").gr_gid
- os.chown("/etc/airtime", -1, gid)
- os.chmod("/etc/airtime", stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR | stat.S_IRGRP | stat.S_IWGRP | stat.S_IXGRP | stat.S_IROTH | stat.S_IXOTH)
-
- # load config file
- try:
- config = ConfigObj(PATH_INI_FILE)
- except Exception, e:
- print 'Error loading config file: ', e
- sys.exit(1)
-
- #copy monit files
- shutil.copy('%s/../../monit/monit-airtime-generic.cfg'%current_script_dir, '/etc/monit/conf.d/')
- subprocess.call('sed -i "s/\$admin_pass/%s/g" /etc/monit/conf.d/monit-airtime-generic.cfg' % get_rand_string(), shell=True)
-
- monit_version = get_monit_version()
- if version_compare(monit_version, "5.3.0") >= 0:
- shutil.copy('%s/../monit-airtime-liquidsoap.cfg' % current_script_dir, \
- '/etc/monit/conf.d/monit-airtime-liquidsoap.cfg')
- else:
- shutil.copy('%s/../monit-pre530-airtime-liquidsoap.cfg' % current_script_dir, \
- '/etc/monit/conf.d/monit-airtime-liquidsoap.cfg')
-
- shutil.copy('%s/../monit-airtime-playout.cfg'%current_script_dir, '/etc/monit/conf.d/')
-
- #create pypo log dir
- create_dir(config['pypo_log_dir'])
- os.system("chown -R pypo:pypo "+config["pypo_log_dir"])
-
- #create liquidsoap log dir
- create_dir(config['liquidsoap_log_dir'])
- os.system("chown -R pypo:pypo "+config["liquidsoap_log_dir"])
-
- #create cache, tmp, file dirs
- create_dir(config['cache_dir'])
- create_dir(config['file_dir'])
- create_dir(config['tmp_dir'])
-
- create_dir(config["base_recorded_files"])
-
- #copy files to bin dir
- copy_dir("%s/.."%current_script_dir, config["bin_dir"]+"/bin/")
-
- # delete /usr/lib/airtime/pypo/bin/liquidsoap_scripts/liquidsoap.cfg
- # as we don't use it anymore.(CC-2552)
- os.remove(config["bin_dir"]+"/bin/liquidsoap_scripts/liquidsoap.cfg")
-
- #set permissions in bin dir and cache dir
- os.system("chmod 755 "+os.path.join(config["bin_dir"], "bin/liquidsoap_scripts/notify.sh"))
- os.system("chown -R pypo:pypo "+config["bin_dir"])
- os.system("chown -R pypo:pypo "+config["cache_base_dir"])
- os.system("chown -R pypo:pypo "+config["base_recorded_files"])
-
- #copy init.d script
- shutil.copy(config["bin_dir"]+"/bin/airtime-playout-init-d", "/etc/init.d/airtime-playout")
- shutil.copy(config["bin_dir"]+"/bin/airtime-liquidsoap-init-d", "/etc/init.d/airtime-liquidsoap")
-
- #copy log rotate script
- shutil.copy(config["bin_dir"]+"/bin/liquidsoap_scripts/airtime-liquidsoap.logrotate", "/etc/logrotate.d/airtime-liquidsoap")
-
-except Exception, e:
- print e
-
-
diff --git a/python_apps/pypo/install/pypo-initialize.py b/python_apps/pypo/install/pypo-initialize.py
deleted file mode 100644
index 68fe858fb..000000000
--- a/python_apps/pypo/install/pypo-initialize.py
+++ /dev/null
@@ -1,95 +0,0 @@
-import platform
-import shutil
-from subprocess import Popen, PIPE
-import subprocess
-import sys
-import os
-sys.path.append('/usr/lib/airtime/')
-from api_clients import api_client
-from configobj import ConfigObj
-
-import logging
-
-if os.geteuid() != 0:
- print "Please run this as root."
- sys.exit(1)
-
-"""
- This function returns the codename of the host OS by querying lsb_release.
- If lsb_release does not exist, or an exception occurs the codename returned
- is 'unknown'
-"""
-def get_os_codename():
- try:
- p = Popen("which lsb_release > /dev/null", shell=True)
- sts = os.waitpid(p.pid, 0)[1]
-
- if (sts == 0):
- #lsb_release is available on this system. Let's get the os codename
- p = Popen("lsb_release -sc", shell=True, stdout=PIPE)
- codename = p.communicate()[0].strip('\r\n')
-
- p = Popen("lsb_release -sd", shell=True, stdout=PIPE)
- fullname = p.communicate()[0].strip('\r\n')
-
- return (codename, fullname)
- except Exception, e:
- pass
-
- return ("unknown", "unknown")
-
-PATH_INI_FILE = '/etc/airtime/pypo.cfg'
-PATH_LIQUIDSOAP_BIN = '/usr/lib/airtime/pypo/bin/liquidsoap_bin'
-
-#any debian/ubuntu codename in this et will automatically use the natty liquidsoap binary
-arch_map = dict({"32bit":"i386", "64bit":"amd64"})
-
-# load config file
-try:
- config = ConfigObj(PATH_INI_FILE)
-except Exception, e:
- print 'Error loading config file: ', e
- sys.exit(1)
-
-try:
- #select appropriate liquidsoap file for given system os/architecture
- architecture = platform.architecture()[0]
- arch = arch_map[architecture]
-
- print "* Detecting OS: ...",
- (codename, fullname) = get_os_codename()
- print " Found %s (%s) on %s architecture" % (fullname, codename, arch)
-
- print " * Creating symlink to Liquidsoap binary"
-
- p = Popen("which liquidsoap", shell=True, stdout=PIPE)
- liq_path = p.communicate()[0].strip()
- symlink_path = "/usr/bin/airtime-liquidsoap"
-
- if p.returncode == 0:
- try:
- os.unlink(symlink_path)
- except Exception:
- #liq_path DNE, which is OK.
- pass
-
- os.symlink(liq_path, symlink_path)
- else:
- print " * Liquidsoap binary not found!"
- sys.exit(1)
-
- #initialize init.d scripts
- subprocess.call("update-rc.d airtime-playout defaults >/dev/null 2>&1", shell=True)
- subprocess.call("update-rc.d airtime-liquidsoap defaults >/dev/null 2>&1", shell=True)
-
- #clear out an previous pypo cache
- print "* Clearing previous pypo cache"
- subprocess.call("rm -rf /var/tmp/airtime/pypo/cache/scheduler/* >/dev/null 2>&1", shell=True)
-
- if "airtime_service_start" in os.environ and os.environ["airtime_service_start"] == "t":
- print "* Waiting for pypo processes to start..."
- subprocess.call("invoke-rc.d airtime-liquidsoap start > /dev/null 2>&1", shell=True)
- subprocess.call("invoke-rc.d airtime-playout start > /dev/null 2>&1", shell=True)
-
-except Exception, e:
- print e
diff --git a/python_apps/pypo/install/pypo-remove-files.py b/python_apps/pypo/install/pypo-remove-files.py
deleted file mode 100644
index 3a20a2dda..000000000
--- a/python_apps/pypo/install/pypo-remove-files.py
+++ /dev/null
@@ -1,54 +0,0 @@
-import os
-import shutil
-import sys
-from configobj import ConfigObj
-
-if os.geteuid() != 0:
- print "Please run this as root."
- sys.exit(1)
-
-PATH_INI_FILE = '/etc/airtime/pypo.cfg'
-
-def remove_file(path):
- try:
- os.remove(path)
- except Exception, e:
- pass
-
-# load config file
-try:
- config = ConfigObj(PATH_INI_FILE)
-except Exception, e:
- print 'Error loading config file: ', e
- sys.exit(1)
-
-try:
- #remove log rotate script
- print " * Removing Pypo Log Rotate Script"
- remove_file("/etc/logrotate.d/airtime-liquidsoap")
-
- #remove init.d script
- print " * Removing Pypo init.d Script"
- remove_file("/etc/init.d/airtime-playout")
- remove_file("/etc/init.d/airtime-liquidsoap")
-
- #remove bin, cache, tmp and file dir
- print " * Removing Pypo Program Directory"
- shutil.rmtree(config['bin_dir'], ignore_errors=True)
- shutil.rmtree(config['cache_dir'], ignore_errors=True)
- shutil.rmtree(config['file_dir'], ignore_errors=True)
- shutil.rmtree(config['tmp_dir'], ignore_errors=True)
-
- #remove liquidsoap and pypo log dir
- print " * Removing Pypo Log Directories"
- shutil.rmtree(config['liquidsoap_log_dir'], ignore_errors=True)
- shutil.rmtree(config['pypo_log_dir'], ignore_errors=True)
-
- #remove monit files
- print " * Removing Pypo Monit Files"
- remove_file("/etc/monit/conf.d/monit-airtime-playout.cfg")
- remove_file("/etc/monit/conf.d/monit-airtime-liquidsoap.cfg")
- remove_file("/etc/monit/conf.d/monit-airtime-generic.cfg")
-
-except Exception, e:
- print e
diff --git a/python_apps/pypo/install/pypo-uninitialize.py b/python_apps/pypo/install/pypo-uninitialize.py
deleted file mode 100644
index 65ac91991..000000000
--- a/python_apps/pypo/install/pypo-uninitialize.py
+++ /dev/null
@@ -1,33 +0,0 @@
-import os
-import sys
-import subprocess
-
-if os.geteuid() != 0:
- print "Please run this as root."
- sys.exit(1)
-
-try:
- #stop pypo and liquidsoap processes
- print "Waiting for Pypo process to stop...",
- try:
- os.remove("/usr/bin/airtime-liquidsoap")
- except Exception, e:
- pass
- if (os.path.exists('/etc/init.d/airtime-playout')):
- subprocess.call("invoke-rc.d airtime-playout stop", shell=True)
- print "OK"
- else:
- print "Wasn't running"
-
- print "Waiting for Liquidsoap process to stop...",
- if (os.path.exists('/etc/init.d/airtime-liquidsoap')):
- subprocess.call("invoke-rc.d airtime-liquidsoap stop", shell=True)
- print "OK"
- else:
- print "Wasn't running"
-
- subprocess.call("update-rc.d -f airtime-playout remove".split(" "))
- subprocess.call("update-rc.d -f airtime-liquidsoap remove".split(" "))
-
-except Exception, e:
- print e
diff --git a/python_apps/pypo/logging.cfg b/python_apps/pypo/install/pypo_logging.cfg
similarity index 100%
rename from python_apps/pypo/logging.cfg
rename to python_apps/pypo/install/pypo_logging.cfg
diff --git a/python_apps/pypo/install/sysvinit/airtime-liquidsoap b/python_apps/pypo/install/sysvinit/airtime-liquidsoap
new file mode 100755
index 000000000..34ddf2f4a
--- /dev/null
+++ b/python_apps/pypo/install/sysvinit/airtime-liquidsoap
@@ -0,0 +1,78 @@
+#!/bin/bash
+
+### BEGIN INIT INFO
+# Provides: airtime-liquidsoap
+# Required-Start: $local_fs $remote_fs $network $syslog $all
+# Required-Stop: $local_fs $remote_fs $network $syslog
+# Default-Start: 2 3 4 5
+# Default-Stop: 0 1 6
+# Short-Description: Manage airtime-liquidsoap daemon
+### END INIT INFO
+
+USERID=www-data
+GROUPID=www-data
+NAME=airtime-liquidsoap
+
+DAEMON=/usr/bin/$NAME
+PIDFILE=/var/run/$NAME.pid
+
+# Exit if the package is not installed
+[ -x "$DAEMON" ] || exit 0
+
+# Read configuration variable file if it is present
+[ -r /etc/default/$NAME ] && . /etc/default/$NAME
+
+# Load the VERBOSE setting and other rcS variables
+. /lib/init/vars.sh
+
+# Define LSB log_* functions.
+# Depend on lsb-base (>= 3.2-14) to ensure that this file is present
+# and status_of_proc is working.
+. /lib/lsb/init-functions
+
+start () {
+ start-stop-daemon --start --background --quiet --chuid $USERID:$GROUPID \
+ --make-pidfile --pidfile $PIDFILE --startas $DAEMON
+}
+
+stop () {
+ # Send TERM after 5 seconds, wait at most 30 seconds.
+ start-stop-daemon --stop --oknodo --retry TERM/5/0/30 --quiet --pidfile $PIDFILE
+ rm -f $PIDFILE
+}
+
+case "${1:-''}" in
+ 'start')
+ # start commands here
+ echo -n "Starting $NAME: "
+ start
+ echo "Done."
+ ;;
+ 'stop')
+ # stop commands here
+ echo -n "Stopping $NAME: "
+ stop
+ echo "Done."
+ ;;
+ 'restart')
+ # restart commands here
+ echo -n "Restarting $NAME: "
+ stop
+ start
+ echo "Done."
+ ;;
+ 'force-reload')
+ # reload commands here
+ echo -n "Reloading $NAME: "
+ stop
+ start
+ echo "Done."
+ ;;
+ 'status')
+ status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $?
+ ;;
+ *) # no parameter specified
+ echo "Usage: $SELF start|stop|restart|status"
+ exit 1
+ ;;
+esac
diff --git a/python_apps/pypo/airtime-playout-init-d b/python_apps/pypo/install/sysvinit/airtime-playout
similarity index 64%
rename from python_apps/pypo/airtime-playout-init-d
rename to python_apps/pypo/install/sysvinit/airtime-playout
index 1d760d43a..b5f6754fc 100755
--- a/python_apps/pypo/airtime-playout-init-d
+++ b/python_apps/pypo/install/sysvinit/airtime-playout
@@ -9,16 +9,29 @@
# Short-Description: Manage airtime-playout daemon
### END INIT INFO
-USERID=root
-NAME="Airtime Scheduler"
+USERID=www-data
+GROUPID=www-data
+NAME=airtime-playout
-DAEMON=/usr/lib/airtime/pypo/bin/airtime-playout
-PIDFILE=/var/run/airtime-playout.pid
+DAEMON=/usr/bin/$NAME
+PIDFILE=/var/run/$NAME.pid
+
+# Exit if the package is not installed
+[ -x "$DAEMON" ] || exit 0
+
+# Read configuration variable file if it is present
+[ -r /etc/default/$NAME ] && . /etc/default/$NAME
+
+# Load the VERBOSE setting and other rcS variables
+. /lib/init/vars.sh
+
+# Define LSB log_* functions.
+# Depend on lsb-base (>= 3.2-14) to ensure that this file is present
+# and status_of_proc is working.
+. /lib/lsb/init-functions
start () {
- mkdir -p /var/log/airtime/pypo
-
- start-stop-daemon --start --background --quiet --chuid $USERID:$USERID \
+ start-stop-daemon --start --background --quiet --chuid $USERID:$GROUPID \
--make-pidfile --pidfile $PIDFILE --startas $DAEMON
}
@@ -28,16 +41,6 @@ stop () {
rm -f $PIDFILE
}
-start_with_monit() {
- start
- monit monitor airtime-playout >/dev/null 2>&1
-}
-
-stop_with_monit() {
- monit unmonitor airtime-playout >/dev/null 2>&1
- stop
-}
-
case "${1:-''}" in
'start')
# start commands here
@@ -58,26 +61,18 @@ case "${1:-''}" in
start
echo "Done."
;;
- 'start-with-monit')
- # restart commands here
- echo -n "Starting $NAME: "
- start_with_monit
+ 'force-reload')
+ # reload commands here
+ echo -n "Reloading $NAME: "
+ stop
+ start
echo "Done."
;;
- 'stop-with-monit')
- # restart commands here
- echo -n "Stopping $NAME: "
- stop_with_monit
- echo "Done."
- ;;
-
'status')
- # status commands here
- /usr/bin/airtime-check-system
+ status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $?
;;
*) # no parameter specified
echo "Usage: $SELF start|stop|restart|status"
exit 1
;;
-
esac
diff --git a/python_apps/pypo/install/upstart/airtime-liquidsoap.conf.template b/python_apps/pypo/install/upstart/airtime-liquidsoap.conf.template
new file mode 100644
index 000000000..7a975e632
--- /dev/null
+++ b/python_apps/pypo/install/upstart/airtime-liquidsoap.conf.template
@@ -0,0 +1,15 @@
+description "Airtime Liquidsoap"
+author "help@sourcefabric.org"
+
+start on runlevel [2345]
+stop on runlevel [!2345]
+
+respawn
+
+setuid WEB_USER
+setgid WEB_USER
+
+env LANG='en_US.UTF-8'
+env LC_ALL='en_US.UTF-8'
+
+exec airtime-liquidsoap
diff --git a/python_apps/pypo/install/upstart/airtime-playout.conf.template b/python_apps/pypo/install/upstart/airtime-playout.conf.template
new file mode 100644
index 000000000..fe2d3c8dc
--- /dev/null
+++ b/python_apps/pypo/install/upstart/airtime-playout.conf.template
@@ -0,0 +1,15 @@
+description "Pypo"
+author "help@sourcefabric.org"
+
+start on runlevel [2345]
+stop on runlevel [!2345]
+
+respawn
+
+setuid WEB_USER
+setgid WEB_USER
+
+env LANG='en_US.UTF-8'
+env LC_ALL='en_US.UTF-8'
+
+exec airtime-playout
\ No newline at end of file
diff --git a/python_apps/pypo/liquidsoap/__init__.py b/python_apps/pypo/liquidsoap/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/python_apps/pypo/liquidsoap/__main__.py b/python_apps/pypo/liquidsoap/__main__.py
new file mode 100644
index 000000000..55f6cd724
--- /dev/null
+++ b/python_apps/pypo/liquidsoap/__main__.py
@@ -0,0 +1,27 @@
+""" Runs Airtime liquidsoap
+"""
+
+import argparse
+import os
+import generate_liquidsoap_cfg
+
+PYPO_HOME = '/var/tmp/airtime/pypo/'
+
+def run():
+ '''Entry-point for this application'''
+ print "Airtime Liquidsoap"
+ parser = argparse.ArgumentParser()
+ parser.add_argument("-d", "--debug", help="run in debug mode", action="store_true")
+ args = parser.parse_args()
+
+ os.environ["HOME"] = PYPO_HOME
+
+ generate_liquidsoap_cfg.run()
+ script_path = os.path.join(os.path.dirname(__file__), 'ls_script.liq')
+
+ if args.debug:
+ os.execl('/usr/bin/liquidsoap', 'airtime-liquidsoap', script_path, '--verbose', '-f', '--debug')
+ else:
+ os.execl('/usr/bin/liquidsoap', 'airtime-liquidsoap', script_path, '--verbose', '-f')
+
+run()
\ No newline at end of file
diff --git a/python_apps/pypo/liquidsoap_scripts/aac.liq b/python_apps/pypo/liquidsoap/aac.liq
similarity index 100%
rename from python_apps/pypo/liquidsoap_scripts/aac.liq
rename to python_apps/pypo/liquidsoap/aac.liq
diff --git a/python_apps/pypo/liquidsoap_scripts/aacplus.liq b/python_apps/pypo/liquidsoap/aacplus.liq
similarity index 100%
rename from python_apps/pypo/liquidsoap_scripts/aacplus.liq
rename to python_apps/pypo/liquidsoap/aacplus.liq
diff --git a/python_apps/pypo/liquidsoap_scripts/airtime-liquidsoap.logrotate b/python_apps/pypo/liquidsoap/airtime-liquidsoap.logrotate
similarity index 85%
rename from python_apps/pypo/liquidsoap_scripts/airtime-liquidsoap.logrotate
rename to python_apps/pypo/liquidsoap/airtime-liquidsoap.logrotate
index 9e0efed20..c08f5491c 100644
--- a/python_apps/pypo/liquidsoap_scripts/airtime-liquidsoap.logrotate
+++ b/python_apps/pypo/liquidsoap/airtime-liquidsoap.logrotate
@@ -6,6 +6,6 @@
notifempty
sharedscripts
postrotate
- start-stop-daemon --stop --signal USR1 --quiet --pidfile /var/run/airtime-liquidsoap.pid
+ start-stop-daemon --stop --signal USR1 --quiet --pidfile /var/run/airtime/airtime-liquidsoap.pid
endscript
}
diff --git a/python_apps/pypo/liquidsoap_scripts/fdkaac.liq b/python_apps/pypo/liquidsoap/fdkaac.liq
similarity index 100%
rename from python_apps/pypo/liquidsoap_scripts/fdkaac.liq
rename to python_apps/pypo/liquidsoap/fdkaac.liq
diff --git a/python_apps/pypo/liquidsoap_scripts/generate_liquidsoap_cfg.py b/python_apps/pypo/liquidsoap/generate_liquidsoap_cfg.py
similarity index 69%
rename from python_apps/pypo/liquidsoap_scripts/generate_liquidsoap_cfg.py
rename to python_apps/pypo/liquidsoap/generate_liquidsoap_cfg.py
index ec5d10cc3..fd78d6ddb 100644
--- a/python_apps/pypo/liquidsoap_scripts/generate_liquidsoap_cfg.py
+++ b/python_apps/pypo/liquidsoap/generate_liquidsoap_cfg.py
@@ -30,27 +30,27 @@ def generate_liquidsoap_config(ss):
fh.write('log_file = "/var/log/airtime/pypo-liquidsoap/