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 +

+ + + + + + + + + + + + +
+ Component + + Description + + Status or Solution +
+ +
+ + + + + + + + + + + + + + +
+ PHP Dependencies +
+ Zend + + Zend MVC Framework + + "> + Ubuntu: try running sudo apt-get install libzend-framework-php +
Debian: try running sudo apt-get install zendframework + +
+ Postgres + + PDO and PostgreSQL libraries + + "> + Try running sudo apt-get install php5-pgsql + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ External Services +
+ Database + + Database configuration for Airtime + + "> + 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 + +
+
+ diff --git a/airtime_mvc/application/configs/constants.php b/airtime_mvc/application/configs/constants.php index bb5184895..99e33054a 100644 --- a/airtime_mvc/application/configs/constants.php +++ b/airtime_mvc/application/configs/constants.php @@ -19,6 +19,7 @@ define('LICENSE_URL' , 'http://www.gnu.org/licenses/agpl-3.0-standalone.h define('AIRTIME_COPYRIGHT_DATE' , '2010-2012'); define('AIRTIME_REST_VERSION' , '1.1'); define('AIRTIME_API_VERSION' , '1.1'); +define('AIRTIME_CODE_VERSION' , '2.5.2'); // Metadata Keys for files define('MDATA_KEY_FILEPATH' , 'filepath'); diff --git a/airtime_mvc/application/controllers/ApiController.php b/airtime_mvc/application/controllers/ApiController.php index 38c453d9e..1a784e366 100644 --- a/airtime_mvc/application/controllers/ApiController.php +++ b/airtime_mvc/application/controllers/ApiController.php @@ -342,7 +342,7 @@ class ApiController extends Zend_Controller_Action * variables in the result to reflect the given timezone. * * @param object $result reference to the object to send back to the user - * @param string $timezone the user's timezone parameter value + * @param string $timezone the user's timezone parameter value * @param boolean $upcase whether the timezone output should be upcased */ private function applyLiveTimezoneAdjustments(&$result, $timezone, $upcase) diff --git a/airtime_mvc/application/controllers/ErrorController.php b/airtime_mvc/application/controllers/ErrorController.php index 8a62d9ea6..5fd75837e 100644 --- a/airtime_mvc/application/controllers/ErrorController.php +++ b/airtime_mvc/application/controllers/ErrorController.php @@ -38,9 +38,12 @@ class ErrorController extends Zend_Controller_Action { } // Log exception, if logger available + /* No idea why this doesn't work or why it was implemented like this. Disabling it -- Albert if (($log = $this->getLog())) { $log->crit($this->view->message, $errors->exception); - } + }*/ + //Logging that actually works: -- Albert + Logging::error($this->view->message . ": " . $errors->exception); // conditionally display exceptions if ($this->getInvokeArg('displayExceptions') == true) { diff --git a/airtime_mvc/application/controllers/SystemstatusController.php b/airtime_mvc/application/controllers/SystemstatusController.php index 543fbef70..6098f71b7 100644 --- a/airtime_mvc/application/controllers/SystemstatusController.php +++ b/airtime_mvc/application/controllers/SystemstatusController.php @@ -13,18 +13,9 @@ class SystemstatusController extends Zend_Controller_Action public function indexAction() { - /* - $services = array( - "pypo"=>Application_Model_Systemstatus::GetPypoStatus(), - "liquidsoap"=>Application_Model_Systemstatus::GetLiquidsoapStatus(), - //"media-monitor"=>Application_Model_Systemstatus::GetMediaMonitorStatus(), - ); - */ - $partitions = Application_Model_Systemstatus::GetDiskInfo(); $this->view->status = new StdClass; - //$this->view->status->services = $services; $this->view->status->partitions = $partitions; } } diff --git a/airtime_mvc/application/controllers/UpgradeController.php b/airtime_mvc/application/controllers/UpgradeController.php index 518e173ac..2da9de1b0 100644 --- a/airtime_mvc/application/controllers/UpgradeController.php +++ b/airtime_mvc/application/controllers/UpgradeController.php @@ -13,45 +13,25 @@ class UpgradeController extends Zend_Controller_Action return; } - $upgraders = array(); - array_push($upgraders, new AirtimeUpgrader253()); - array_push($upgraders, new AirtimeUpgrader254()); - array_push($upgraders, new AirtimeUpgrader255()); - array_push($upgraders, new AirtimeUpgrader259()); - array_push($upgraders, new AirtimeUpgrader2510()); - array_push($upgraders, new AirtimeUpgrader2511()); - array_push($upgraders, new AirtimeUpgrader2512()); - - $didWePerformAnUpgrade = false; - try - { - for ($i = 0; $i < count($upgraders); $i++) - { - $upgrader = $upgraders[$i]; - if ($upgrader->checkIfUpgradeSupported()) - { - // pass __DIR__ to the upgrades, since __DIR__ returns parent dir of file, not executor - $upgrader->upgrade(__DIR__); //This will throw an exception if the upgrade fails. - $didWePerformAnUpgrade = true; - $this->getResponse() - ->setHttpResponseCode(200) - ->appendBody("Upgrade to Airtime " . $upgrader->getNewVersion() . " OK
"); - $i = 0; //Start over, in case the upgrade handlers are not in ascending order. - } - } + try { + $upgradeManager = new UpgradeManager(); + $didWePerformAnUpgrade = $upgradeManager->doUpgrade(); - if (!$didWePerformAnUpgrade) - { + if (!$didWePerformAnUpgrade) { $this->getResponse() - ->setHttpResponseCode(200) - ->appendBody("No upgrade was performed. The current Airtime version is " . AirtimeUpgrader::getCurrentVersion() . ".
"); + ->setHttpResponseCode(200) + ->appendBody("No upgrade was performed. The current schema version is " . Application_Model_Preference::GetSchemaVersion() . ".
"); + } else { + $this->getResponse() + ->setHttpResponseCode(200) + ->appendBody("Upgrade to Airtime schema version " . Application_Model_Preference::GetSchemaVersion() . " OK
"); } } catch (Exception $e) { $this->getResponse() - ->setHttpResponseCode(400) - ->appendBody($e->getMessage()); + ->setHttpResponseCode(400) + ->appendBody($e->getMessage()); } } diff --git a/airtime_mvc/application/controllers/upgrade_sql/airtime_2.5.2/upgrade.sql b/airtime_mvc/application/controllers/upgrade_sql/airtime_2.5.2/upgrade.sql new file mode 100644 index 000000000..2f805382d --- /dev/null +++ b/airtime_mvc/application/controllers/upgrade_sql/airtime_2.5.2/upgrade.sql @@ -0,0 +1,6 @@ +-- Replacing system_version with schema_version +DELETE FROM cc_pref WHERE keystr = 'system_version'; +INSERT INTO cc_pref (keystr, valstr) VALUES ('schema_version', '2.5.2'); + +ALTER TABLE cc_show ADD COLUMN image_path varchar(255) DEFAULT ''; +ALTER TABLE cc_show_instances ADD COLUMN description varchar(255) DEFAULT ''; diff --git a/airtime_mvc/application/models/Preference.php b/airtime_mvc/application/models/Preference.php index 1387d326b..6e9de3d39 100644 --- a/airtime_mvc/application/models/Preference.php +++ b/airtime_mvc/application/models/Preference.php @@ -874,10 +874,30 @@ class Application_Model_Preference return self::getValue("enable_stream_conf"); } - - public static function SetAirtimeVersion($version) + + public static function GetSchemaVersion() { - self::setValue("system_version", $version); + CcPrefPeer::clearInstancePool(); //Ensure we don't get a cached Propel object (cached DB results) + //because we're updating this version number within this HTTP request as well. + + //New versions use schema_version + $pref = CcPrefQuery::create() + ->filterByKeystr('schema_version') + ->findOne(); + + if (empty($pref)) { + //Pre-2.5.2 releases all used this ambiguous "system_version" key to represent both the code and schema versions... + $pref = CcPrefQuery::create() + ->filterByKeystr('system_version') + ->findOne(); + } + $schemaVersion = $pref->getValStr(); + return $schemaVersion; + } + + public static function SetSchemaVersion($version) + { + self::setValue("schema_version", $version); } public static function GetAirtimeVersion() diff --git a/airtime_mvc/application/models/Show.php b/airtime_mvc/application/models/Show.php index f96ad7ee0..4f593a139 100644 --- a/airtime_mvc/application/models/Show.php +++ b/airtime_mvc/application/models/Show.php @@ -1287,7 +1287,7 @@ SQL; "starts" => $rows[$i-1]['starts'], "ends" => $rows[$i-1]['ends'], "record" => $rows[$i-1]['record'], - "image_path" => $rows[$i-1]['image_path'], + "image_path" => $rows[$i-1]['image_path'], "type" => "show"); } @@ -1345,7 +1345,6 @@ SQL; "starts" => $rows[$previousShowIndex]['starts'], "ends" => $rows[$previousShowIndex]['ends'], "record" => $rows[$previousShowIndex]['record'], - "image_path" => $rows[$previousShowIndex]['image_path'], "type" => "show"); } diff --git a/airtime_mvc/application/models/StoredFile.php b/airtime_mvc/application/models/StoredFile.php index 32d6ec371..05d2728e9 100644 --- a/airtime_mvc/application/models/StoredFile.php +++ b/airtime_mvc/application/models/StoredFile.php @@ -1024,14 +1024,16 @@ SQL; $LIQUIDSOAP_ERRORS = array('TagLib: MPEG::Properties::read() -- Could not find a valid last MPEG frame in the stream.'); // Ask Liquidsoap if file is playable - $ls_command = sprintf('/usr/bin/airtime-liquidsoap -v -c "output.dummy(audio_to_stereo(single(%s)))" 2>&1', + /* CC-5990/5991 - Changed to point directly to liquidsoap, removed PATH export */ + $command = sprintf('liquidsoap -v -c "output.dummy(audio_to_stereo(single(%s)))" 2>&1', escapeshellarg($audio_file)); - $command = "export PATH=/usr/local/bin:/usr/bin:/bin/usr/bin/ && $ls_command"; exec($command, $output, $rv); $isError = count($output) > 0 && in_array($output[0], $LIQUIDSOAP_ERRORS); + Logging::info("Is error?! : " . $isError); + Logging::info("ls playability response: " . $rv); return ($rv == 0 && !$isError); } diff --git a/airtime_mvc/application/models/Systemstatus.php b/airtime_mvc/application/models/Systemstatus.php index 1b07099c9..b97ea491e 100644 --- a/airtime_mvc/application/models/Systemstatus.php +++ b/airtime_mvc/application/models/Systemstatus.php @@ -6,15 +6,15 @@ class Application_Model_Systemstatus public static function GetMonitStatus($p_ip) { $CC_CONFIG = Config::getConfig(); - $monit_user = $CC_CONFIG['monit_user']; - $monit_password = $CC_CONFIG['monit_password']; +// $monit_user = $CC_CONFIG['monit_user']; +// $monit_password = $CC_CONFIG['monit_password']; $url = "http://$p_ip:2812/_status?format=xml"; $ch = curl_init(); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_URL, $url); - curl_setopt($ch, CURLOPT_USERPWD, "$monit_user:$monit_password"); +// curl_setopt($ch, CURLOPT_USERPWD, "$monit_user:$monit_password"); //wait a max of 3 seconds before aborting connection attempt curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 3); $result = curl_exec($ch); diff --git a/airtime_mvc/application/upgrade/Upgrades.php b/airtime_mvc/application/upgrade/Upgrades.php index 9468753d6..812a36fb9 100644 --- a/airtime_mvc/application/upgrade/Upgrades.php +++ b/airtime_mvc/application/upgrade/Upgrades.php @@ -1,21 +1,75 @@ runUpgrades($upgraders, (dirname(__DIR__) . "/controllers")); + } + + /** + * Run a given set of upgrades + * + * @param array $upgraders the upgrades to perform + * @param string $dir the directory containing the upgrade sql + * @return boolean whether or not an upgrade was performed + */ + public function runUpgrades($upgraders, $dir) { + $upgradePerformed = false; + + for($i = 0; $i < count($upgraders); $i++) { + $upgrader = $upgraders[$i]; + if ($upgrader->checkIfUpgradeSupported()) { + // pass the given directory to the upgrades, since __DIR__ returns parent dir of file, not executor + $upgrader->upgrade($dir); // This will throw an exception if the upgrade fails. + $upgradePerformed = true; + $i = 0; // Start over, in case the upgrade handlers are not in ascending order. + } + } + + return $upgradePerformed; + } + +} + abstract class AirtimeUpgrader { - /** Versions that this upgrader class can upgrade from (an array of version strings). */ - abstract protected function getSupportedVersions(); - /** The version that this upgrader class will upgrade to. (returns a version string) */ + /** Schema versions that this upgrader class can upgrade from (an array of version strings). */ + abstract protected function getSupportedSchemaVersions(); + /** The schema version that this upgrader class will upgrade to. (returns a version string) */ abstract public function getNewVersion(); - public static function getCurrentVersion() + public static function getCurrentSchemaVersion() { - CcPrefPeer::clearInstancePool(); //Ensure we don't get a cached Propel object (cached DB results) - //because we're updating this version number within this HTTP request as well. - $pref = CcPrefQuery::create() - ->filterByKeystr('system_version') - ->findOne(); - $airtime_version = $pref->getValStr(); - return $airtime_version; + return Application_Model_Preference::GetSchemaVersion(); } /** @@ -24,7 +78,7 @@ abstract class AirtimeUpgrader */ public function checkIfUpgradeSupported() { - if (!in_array(AirtimeUpgrader::getCurrentVersion(), $this->getSupportedVersions())) { + if (!in_array(AirtimeUpgrader::getCurrentSchemaVersion(), $this->getSupportedSchemaVersions())) { return false; } return true; @@ -58,9 +112,10 @@ abstract class AirtimeUpgrader class AirtimeUpgrader253 extends AirtimeUpgrader { - protected function getSupportedVersions() + protected function getSupportedSchemaVersions() { return array('2.5.1', '2.5.2'); + } public function getNewVersion() { @@ -109,8 +164,8 @@ class AirtimeUpgrader253 extends AirtimeUpgrader $database = $values['database']['dbname']; passthru("export PGPASSWORD=$password && psql -h $host -U $username -q -f $dir/upgrade_sql/airtime_".$this->getNewVersion()."/upgrade.sql $database 2>&1 | grep -v -E \"will create implicit sequence|will create implicit index\""); - - Application_Model_Preference::SetAirtimeVersion($this->getNewVersion()); + Application_Model_Preference::SetSchemaVersion($this->getNewVersion()); + //clear out the cache Cache::clear(); @@ -125,7 +180,7 @@ class AirtimeUpgrader253 extends AirtimeUpgrader class AirtimeUpgrader254 extends AirtimeUpgrader { - protected function getSupportedVersions() + protected function getSupportedSchemaVersions() { return array('2.5.3'); } @@ -195,7 +250,7 @@ class AirtimeUpgrader254 extends AirtimeUpgrader } //$con->commit(); - Application_Model_Preference::SetAirtimeVersion($newVersion); + Application_Model_Preference::SetSchemaVersion($newVersion); Cache::clear(); $this->toggleMaintenanceScreen(false); @@ -211,7 +266,7 @@ class AirtimeUpgrader254 extends AirtimeUpgrader } class AirtimeUpgrader255 extends AirtimeUpgrader { - protected function getSupportedVersions() { + protected function getSupportedSchemaVersions() { return array ( '2.5.4' ); @@ -243,7 +298,7 @@ class AirtimeUpgrader255 extends AirtimeUpgrader { passthru("export PGPASSWORD=$password && psql -h $host -U $username -q -f $dir/upgrade_sql/airtime_" .$this->getNewVersion()."/upgrade.sql $database 2>&1 | grep -v -E \"will create implicit sequence|will create implicit index\""); - Application_Model_Preference::SetAirtimeVersion($newVersion); + Application_Model_Preference::SetSchemaVersion($newVersion); Cache::clear(); $this->toggleMaintenanceScreen(false); @@ -257,7 +312,7 @@ class AirtimeUpgrader255 extends AirtimeUpgrader { } class AirtimeUpgrader259 extends AirtimeUpgrader { - protected function getSupportedVersions() { + protected function getSupportedSchemaVersions() { return array ( '2.5.5' ); @@ -289,7 +344,7 @@ class AirtimeUpgrader259 extends AirtimeUpgrader { passthru("export PGPASSWORD=$password && psql -h $host -U $username -q -f $dir/upgrade_sql/airtime_" .$this->getNewVersion()."/upgrade.sql $database 2>&1 | grep -v -E \"will create implicit sequence|will create implicit index\""); - Application_Model_Preference::SetAirtimeVersion($newVersion); + Application_Model_Preference::SetSchemaVersion($newVersion); Cache::clear(); $this->toggleMaintenanceScreen(false); @@ -302,7 +357,7 @@ class AirtimeUpgrader259 extends AirtimeUpgrader { class AirtimeUpgrader2510 extends AirtimeUpgrader { - protected function getSupportedVersions() { + protected function getSupportedSchemaVersions() { return array ( '2.5.9' ); @@ -334,7 +389,7 @@ class AirtimeUpgrader2510 extends AirtimeUpgrader passthru("export PGPASSWORD=$password && psql -h $host -U $username -q -f $dir/upgrade_sql/airtime_" .$this->getNewVersion()."/upgrade.sql $database 2>&1 | grep -v -E \"will create implicit sequence|will create implicit index\""); - Application_Model_Preference::SetAirtimeVersion($newVersion); + Application_Model_Preference::SetSchemaVersion($newVersion); Cache::clear(); $this->toggleMaintenanceScreen(false); @@ -347,7 +402,7 @@ class AirtimeUpgrader2510 extends AirtimeUpgrader class AirtimeUpgrader2511 extends AirtimeUpgrader { - protected function getSupportedVersions() { + protected function getSupportedSchemaVersions() { return array ( '2.5.10' ); @@ -375,7 +430,7 @@ class AirtimeUpgrader2511 extends AirtimeUpgrader $disk_usage = $queryResult[0]; Application_Model_Preference::setDiskUsage($disk_usage); - Application_Model_Preference::SetAirtimeVersion($newVersion); + Application_Model_Preference::SetSchemaVersion($newVersion); Cache::clear(); $this->toggleMaintenanceScreen(false); @@ -391,7 +446,7 @@ class AirtimeUpgrader2511 extends AirtimeUpgrader class AirtimeUpgrader2512 extends AirtimeUpgrader { - protected function getSupportedVersions() { + protected function getSupportedSchemaVersions() { return array ( '2.5.10', '2.5.11' @@ -424,7 +479,7 @@ class AirtimeUpgrader2512 extends AirtimeUpgrader passthru("export PGPASSWORD=$password && psql -h $host -U $username -q -f $dir/upgrade_sql/airtime_" .$this->getNewVersion()."/upgrade.sql $database 2>&1 | grep -v -E \"will create implicit sequence|will create implicit index\""); - Application_Model_Preference::SetAirtimeVersion($newVersion); + Application_Model_Preference::SetSchemaVersion($newVersion); Cache::clear(); $this->toggleMaintenanceScreen(false); diff --git a/airtime_mvc/application/views/scripts/dashboard/about.phtml b/airtime_mvc/application/views/scripts/dashboard/about.phtml index 98e93e724..05880b422 100644 --- a/airtime_mvc/application/views/scripts/dashboard/about.phtml +++ b/airtime_mvc/application/views/scripts/dashboard/about.phtml @@ -11,7 +11,7 @@ echo sprintf(_('%1$s %2$s, the open radio software for scheduling and remote sta $this->airtime_version) ?>
-
© 2013 +
© " . COMPANY_NAME . " " . COMPANY_SUFFIX diff --git a/airtime_mvc/application/views/scripts/systemstatus/index.phtml b/airtime_mvc/application/views/scripts/systemstatus/index.phtml index de8dea94a..f8f43104d 100644 --- a/airtime_mvc/application/views/scripts/systemstatus/index.phtml +++ b/airtime_mvc/application/views/scripts/systemstatus/index.phtml @@ -1,8 +1,178 @@ - + + + - - - - - -
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Zend + + Zend MVC Framework + + "> + Ubuntu: try running sudo apt-get install libzend-framework-php +
Debian: try running sudo apt-get install zendframework + +
+ Postgres + + PDO and PostgreSQL libraries + + "> + Try running sudo apt-get install php5-pgsql + +
+ Database + + Database configuration for Airtime + + "> + 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 @@ + + +
+

Database Settings

+ +

+ Enter your Airtime database settings here. Empty or non-existent databases will be created and populated + if the given user has administrative permissions in postgres. +

+
+ + " /> + +
+
+ + " /> + +
+
+ + " /> + +
+
+ + " /> + +
+ +
+

+ This may take up to 30 seconds to complete! +

+ +
+
+ + \ 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 @@ + + +
+

Manual Step: Start Airtime Services

+ +

+ Looks like you're almost done! As a final step, please run the following commands from the terminal: +

+
sudo service airtime-playout start
+sudo service airtime-liquidsoap start
+sudo service airtime-media-monitor start
+

+ Click "Done!" to bring up the Airtime configuration checklist; if your configuration is all green, + you're ready to get started with your personal Airtime station! +

+

+ If you need to re-run the web installer, just remove /etc/airtime/airtime.conf. +

+
+ +
+
+ + \ 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 @@ + + +
+

General Settings

+

+ These values are automatically pulled from your webserver settings, under most circumstances you will not need to change them. +

+ +
+
+ + "/> + +
+
+ + "/> + +
+ +
+
+ + +
+
+ + 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 @@ + + +
+

Media Settings

+ +

+ Here you can set the default media storage directory for Airtime. If left blank, we'll create a new + directory located at /srv/airtime/stor/ for you. +

+
+ + + + + Note that you need to enter the fully qualified path name! + +
+ +
+ + +
+
+ + \ 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 @@ + + +
+

RabbitMQ Settings

+ +

+ RabbitMQ is an AMQP-based messaging system used by Airtime. You should only edit these settings + if you have changed the defaults since running the installer, or if you've opted to install RabbitMQ manually. +

+

+ In either case, we recommend that you change at least the default password provided - + you can do this by running the following line from the command line:
+ sudo rabbitmqctl change_password <username> <newpassword> +

+
+ Advanced
+
+
+
+ + " /> + +
+
+ + " /> + + + You probably want to change this! + +
+
+ + " /> + +
+
+ + " /> + +
+
+ + " /> + +
+ +
+
+ + +
+
+ + 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 @@ + + + + + + + + + + + + +
+ + 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 -; 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/