From c261182c8f2047b7d6d465cf207cd8afc739d1f2 Mon Sep 17 00:00:00 2001
From: drigato <denise.rigato@sourcefabric.org>
Date: Thu, 12 Feb 2015 14:08:06 -0500
Subject: [PATCH 01/60] Skeleton player form/view/controller

---
 airtime_mvc/application/configs/ACL.php       |  4 ++-
 .../application/configs/navigation.php        |  7 +++++
 .../EmbeddableplayerController.php            | 31 +++++++++++++++++++
 .../application/forms/EmbeddablePlayer.php    | 20 ++++++++++++
 .../scripts/embeddableplayer/index.phtml      | 15 +++++++++
 .../views/scripts/form/embeddableplayer.html  |  6 ++++
 6 files changed, 82 insertions(+), 1 deletion(-)
 create mode 100644 airtime_mvc/application/controllers/EmbeddableplayerController.php
 create mode 100644 airtime_mvc/application/forms/EmbeddablePlayer.php
 create mode 100644 airtime_mvc/application/views/scripts/embeddableplayer/index.phtml
 create mode 100644 airtime_mvc/application/views/scripts/form/embeddableplayer.html

diff --git a/airtime_mvc/application/configs/ACL.php b/airtime_mvc/application/configs/ACL.php
index c41f00a47..243e105d3 100644
--- a/airtime_mvc/application/configs/ACL.php
+++ b/airtime_mvc/application/configs/ACL.php
@@ -36,7 +36,8 @@ $ccAcl->add(new Zend_Acl_Resource('library'))
       ->add(new Zend_Acl_Resource('rest:media'))
       ->add(new Zend_Acl_Resource('rest:show-image'))
       ->add(new Zend_Acl_Resource('billing'))
-      ->add(new Zend_Acl_Resource('provisioning'));
+      ->add(new Zend_Acl_Resource('provisioning'))
+      ->add(new Zend_Acl_Resource('embeddableplayer'));
 
 /** Creating permissions */
 $ccAcl->allow('G', 'index')
@@ -68,6 +69,7 @@ $ccAcl->allow('G', 'index')
       ->allow('A', 'user')
       ->allow('A', 'systemstatus')
       ->allow('A', 'preference')
+      ->allow('A', 'embeddableplayer')
       ->allow('S', 'billing');
       
 
diff --git a/airtime_mvc/application/configs/navigation.php b/airtime_mvc/application/configs/navigation.php
index 14438bdfe..01c8aa385 100644
--- a/airtime_mvc/application/configs/navigation.php
+++ b/airtime_mvc/application/configs/navigation.php
@@ -85,6 +85,13 @@ $pages = array(
                 'controller' => 'listenerstat',
                 'action'     => 'index',
                 'resource'   => 'listenerstat'
+            ),
+            array(
+                'label'      => _('Embeddable Player'),
+                'module'     => 'default',
+                'controller' => 'embeddableplayer',
+                'action'     => 'index',
+                'resource'   => 'embeddableplayer'
             )
         )
     ),
diff --git a/airtime_mvc/application/controllers/EmbeddableplayerController.php b/airtime_mvc/application/controllers/EmbeddableplayerController.php
new file mode 100644
index 000000000..3cd0e3af4
--- /dev/null
+++ b/airtime_mvc/application/controllers/EmbeddableplayerController.php
@@ -0,0 +1,31 @@
+<?php
+
+class EmbeddablePlayerController extends Zend_Controller_Action
+{
+    public function init()
+    {
+
+    }
+    
+    public function indexAction()
+    {
+        $form = new Application_Form_EmbeddablePlayer();
+
+        $request = $this->getRequest();
+
+        if ($request->isPost()) {
+            $formValues = $request->getPost();
+            if ($form->isValid($formValues)) {
+
+                $this->view->statusMsg = "<div class='success'>". _("Preferences updated.")."</div>";
+
+            } else {
+
+            }
+
+            $this->view->form = $form;
+        }
+
+        $this->view->form = $form;
+    }
+}
\ No newline at end of file
diff --git a/airtime_mvc/application/forms/EmbeddablePlayer.php b/airtime_mvc/application/forms/EmbeddablePlayer.php
new file mode 100644
index 000000000..e9dd6b151
--- /dev/null
+++ b/airtime_mvc/application/forms/EmbeddablePlayer.php
@@ -0,0 +1,20 @@
+<?php
+
+class Application_Form_EmbeddablePlayer extends Zend_Form_SubForm
+{
+    public function init()
+    {
+        $this->setDecorators(array(
+            array('ViewScript', array('viewScript' => 'form/embeddableplayer.html'))
+        ));
+
+
+        $displayTrackMetadata = new Zend_Form_Element_Checkbox('display_track_metadata');
+        $displayTrackMetadata->setValue(true);
+        $displayTrackMetadata->setLabel(_('Display track metadata?'));
+        $this->addElement($displayTrackMetadata);
+
+        $submit = new Zend_Form_Element_Submit('submit');
+        $this->addElement($submit);
+    }
+}
\ No newline at end of file
diff --git a/airtime_mvc/application/views/scripts/embeddableplayer/index.phtml b/airtime_mvc/application/views/scripts/embeddableplayer/index.phtml
new file mode 100644
index 000000000..df666df29
--- /dev/null
+++ b/airtime_mvc/application/views/scripts/embeddableplayer/index.phtml
@@ -0,0 +1,15 @@
+<div class="ui-widget ui-widget-content block-shadow simple-formblock clearfix padded-strong preferences">
+    <h2 style="float:left"><?php echo _("Embeddable Player") ?></h2>
+    <?php $baseUrl = Application_Common_OsPath::getBaseDir(); ?>
+    <form method="post" id="pref_form" enctype="multipart/form-data">
+
+        <?php echo $this->form->getElement('submit')->render() ?>
+        <div style="clear:both"></div>
+        <?php
+
+        echo $this->statusMsg;
+        echo $this->form;
+        ?>
+        <br />
+    </form>
+</div>
diff --git a/airtime_mvc/application/views/scripts/form/embeddableplayer.html b/airtime_mvc/application/views/scripts/form/embeddableplayer.html
new file mode 100644
index 000000000..4a8844f58
--- /dev/null
+++ b/airtime_mvc/application/views/scripts/form/embeddableplayer.html
@@ -0,0 +1,6 @@
+<fieldset class="padded">
+    <dl class="zend_form">
+        <?php echo $this->element->getElement('display_track_metadata'); ?>
+
+    </dl>
+</fieldset>
\ No newline at end of file

From 56cae342594c311a126148c74bec86ffc8eb29f0 Mon Sep 17 00:00:00 2001
From: drigato <denise.rigato@sourcefabric.org>
Date: Thu, 12 Feb 2015 14:20:54 -0500
Subject: [PATCH 02/60] Fix typo

---
 .../application/views/scripts/embeddableplayer/index.phtml   | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/airtime_mvc/application/views/scripts/embeddableplayer/index.phtml b/airtime_mvc/application/views/scripts/embeddableplayer/index.phtml
index df666df29..51e00dc03 100644
--- a/airtime_mvc/application/views/scripts/embeddableplayer/index.phtml
+++ b/airtime_mvc/application/views/scripts/embeddableplayer/index.phtml
@@ -1,15 +1,16 @@
 <div class="ui-widget ui-widget-content block-shadow simple-formblock clearfix padded-strong preferences">
     <h2 style="float:left"><?php echo _("Embeddable Player") ?></h2>
     <?php $baseUrl = Application_Common_OsPath::getBaseDir(); ?>
-    <form method="post" id="pref_form" enctype="multipart/form-data">
+    <form method="post" id="player_form" enctype="multipart/form-data">
+
 
-        <?php echo $this->form->getElement('submit')->render() ?>
         <div style="clear:both"></div>
         <?php
 
         echo $this->statusMsg;
         echo $this->form;
         ?>
+        <?php echo $this->form->getElement('submit')->render() ?>
         <br />
     </form>
 </div>

From 4fd7b4c622315ef94e3c16b03eaae271c0acddb3 Mon Sep 17 00:00:00 2001
From: drigato <denise.rigato@sourcefabric.org>
Date: Tue, 17 Feb 2015 11:48:43 -0500
Subject: [PATCH 03/60] SAAS-585: Create Embeddable Player form

Added stream urls - hardcoded for now
---
 airtime_mvc/application/forms/EmbeddablePlayer.php       | 9 ++++++++-
 .../application/views/scripts/form/embeddableplayer.html | 2 ++
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/airtime_mvc/application/forms/EmbeddablePlayer.php b/airtime_mvc/application/forms/EmbeddablePlayer.php
index e9dd6b151..57c46bed9 100644
--- a/airtime_mvc/application/forms/EmbeddablePlayer.php
+++ b/airtime_mvc/application/forms/EmbeddablePlayer.php
@@ -8,12 +8,19 @@ class Application_Form_EmbeddablePlayer extends Zend_Form_SubForm
             array('ViewScript', array('viewScript' => 'form/embeddableplayer.html'))
         ));
 
-
         $displayTrackMetadata = new Zend_Form_Element_Checkbox('display_track_metadata');
         $displayTrackMetadata->setValue(true);
         $displayTrackMetadata->setLabel(_('Display track metadata?'));
         $this->addElement($displayTrackMetadata);
 
+        $streamURL = new Zend_Form_Element_Radio('stream_url');
+        $streamURL->setMultiOptions(array(
+            'AAC' => 'http://127.0.0.1:8000/airtime_a',
+            'MP3' => 'http://127.0.0.1:8000/airtime_b'
+        ));
+        $streamURL->setLabel(_('Select stream:'));
+        $this->addElement($streamURL);
+
         $submit = new Zend_Form_Element_Submit('submit');
         $this->addElement($submit);
     }
diff --git a/airtime_mvc/application/views/scripts/form/embeddableplayer.html b/airtime_mvc/application/views/scripts/form/embeddableplayer.html
index 4a8844f58..8a1ad551e 100644
--- a/airtime_mvc/application/views/scripts/form/embeddableplayer.html
+++ b/airtime_mvc/application/views/scripts/form/embeddableplayer.html
@@ -2,5 +2,7 @@
     <dl class="zend_form">
         <?php echo $this->element->getElement('display_track_metadata'); ?>
 
+        <?php echo $this->element->getElement('stream_url'); ?>
+
     </dl>
 </fieldset>
\ No newline at end of file

From a931e282e13f4a0870188d1dbce5c640d8c254f9 Mon Sep 17 00:00:00 2001
From: drigato <denise.rigato@sourcefabric.org>
Date: Fri, 20 Feb 2015 15:44:25 -0500
Subject: [PATCH 04/60] SAAS-585: Create Embeddable Player form

Fixed up the stream urls options
---
 airtime_mvc/application/forms/EmbeddablePlayer.php | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/airtime_mvc/application/forms/EmbeddablePlayer.php b/airtime_mvc/application/forms/EmbeddablePlayer.php
index 57c46bed9..a8eb137ce 100644
--- a/airtime_mvc/application/forms/EmbeddablePlayer.php
+++ b/airtime_mvc/application/forms/EmbeddablePlayer.php
@@ -14,10 +14,13 @@ class Application_Form_EmbeddablePlayer extends Zend_Form_SubForm
         $this->addElement($displayTrackMetadata);
 
         $streamURL = new Zend_Form_Element_Radio('stream_url');
-        $streamURL->setMultiOptions(array(
-            'AAC' => 'http://127.0.0.1:8000/airtime_a',
-            'MP3' => 'http://127.0.0.1:8000/airtime_b'
-        ));
+        $urlOptions = Array();
+        foreach(Application_Model_StreamSetting::getStreamUrls() as $type => $url) {
+            $urlOptions[$url] = $type;
+        }
+        $streamURL->setMultiOptions(
+            $urlOptions
+        );
         $streamURL->setLabel(_('Select stream:'));
         $this->addElement($streamURL);
 

From 6dcc7ee2fce0d4432c058fbec613b0e749c92d72 Mon Sep 17 00:00:00 2001
From: drigato <denise.rigato@sourcefabric.org>
Date: Fri, 20 Feb 2015 15:50:40 -0500
Subject: [PATCH 05/60] SAAS-587: Add stream urls to station-metadata API

---
 .../application/controllers/ApiController.php    |  1 +
 .../application/forms/EmbeddablePlayer.php       |  2 +-
 airtime_mvc/application/models/StreamSetting.php | 16 ++++++++++++++++
 3 files changed, 18 insertions(+), 1 deletion(-)

diff --git a/airtime_mvc/application/controllers/ApiController.php b/airtime_mvc/application/controllers/ApiController.php
index 124b4b4d0..5f1847f77 100644
--- a/airtime_mvc/application/controllers/ApiController.php
+++ b/airtime_mvc/application/controllers/ApiController.php
@@ -637,6 +637,7 @@ class ApiController extends Zend_Controller_Action
             $result["description"] = Application_Model_Preference::GetStationDescription();
             $result["timezone"] = Application_Model_Preference::GetDefaultTimezone();
             $result["locale"] = Application_Model_Preference::GetDefaultLocale();
+            $result["enabled_stream_urls"] = Application_Model_StreamSetting::getStreamUrls();
             
             // used by caller to determine if the airtime they are running or widgets in use is out of date.
             $result['AIRTIME_API_VERSION'] = AIRTIME_API_VERSION;
diff --git a/airtime_mvc/application/forms/EmbeddablePlayer.php b/airtime_mvc/application/forms/EmbeddablePlayer.php
index a8eb137ce..2accf23a5 100644
--- a/airtime_mvc/application/forms/EmbeddablePlayer.php
+++ b/airtime_mvc/application/forms/EmbeddablePlayer.php
@@ -15,7 +15,7 @@ class Application_Form_EmbeddablePlayer extends Zend_Form_SubForm
 
         $streamURL = new Zend_Form_Element_Radio('stream_url');
         $urlOptions = Array();
-        foreach(Application_Model_StreamSetting::getStreamUrls() as $type => $url) {
+        foreach(Application_Model_StreamSetting::getEnabledStreamUrls() as $type => $url) {
             $urlOptions[$url] = $type;
         }
         $streamURL->setMultiOptions(
diff --git a/airtime_mvc/application/models/StreamSetting.php b/airtime_mvc/application/models/StreamSetting.php
index c34c09a2e..3bdac8a31 100644
--- a/airtime_mvc/application/models/StreamSetting.php
+++ b/airtime_mvc/application/models/StreamSetting.php
@@ -62,6 +62,22 @@ class Application_Model_StreamSetting
         return $result ? $result : "";
     }
 
+    public static function getEnabledStreamUrls()
+    {
+        $urls = Array();
+        $streamIds = Application_Model_StreamSetting::getEnabledStreamIds();
+        foreach ($streamIds as $id) {
+            $prefix = $id."_";
+            $streamData = Application_Model_StreamSetting::getStreamData($id);
+            $host = $streamData[$prefix."host"];
+            $port = $streamData[$prefix."port"];
+            $mount = $streamData[$prefix."mount"];
+            $type = $streamData[$prefix."type"];
+            $urls[$type] = "http://$host:$port/$mount";
+        }
+        return $urls;
+    }
+
     /* Returns the id's of all streams that are enabled in an array. An
      * example of the array returned in JSON notation is ["s1", "s2", "s3"] */
     public static function getEnabledStreamIds()

From 5e9252a562c1bf7a799d2c00df467a2a2d58991c Mon Sep 17 00:00:00 2001
From: drigato <denise.rigato@sourcefabric.org>
Date: Fri, 20 Feb 2015 15:52:13 -0500
Subject: [PATCH 06/60] SAAS-587: Add stream urls to station-metadata API

Fix typo
---
 airtime_mvc/application/controllers/ApiController.php | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/airtime_mvc/application/controllers/ApiController.php b/airtime_mvc/application/controllers/ApiController.php
index 5f1847f77..2e8b2a55b 100644
--- a/airtime_mvc/application/controllers/ApiController.php
+++ b/airtime_mvc/application/controllers/ApiController.php
@@ -637,7 +637,7 @@ class ApiController extends Zend_Controller_Action
             $result["description"] = Application_Model_Preference::GetStationDescription();
             $result["timezone"] = Application_Model_Preference::GetDefaultTimezone();
             $result["locale"] = Application_Model_Preference::GetDefaultLocale();
-            $result["enabled_stream_urls"] = Application_Model_StreamSetting::getStreamUrls();
+            $result["enabled_stream_urls"] = Application_Model_StreamSetting::getEnabledStreamUrls();
             
             // used by caller to determine if the airtime they are running or widgets in use is out of date.
             $result['AIRTIME_API_VERSION'] = AIRTIME_API_VERSION;

From 2272451e08a575676dffe590e3aaba2fa9b478de Mon Sep 17 00:00:00 2001
From: drigato <denise.rigato@sourcefabric.org>
Date: Wed, 25 Feb 2015 17:10:41 -0500
Subject: [PATCH 07/60] Added placeholders for player embed code and preview

---
 airtime_mvc/application/configs/conf.php      |  2 +-
 .../EmbeddableplayerController.php            | 19 ++++---------------
 .../application/forms/EmbeddablePlayer.php    | 16 +++++++++++-----
 .../scripts/embeddableplayer/index.phtml      |  7 ++-----
 .../views/scripts/form/embeddableplayer.html  |  8 --------
 .../views/scripts/form/embeddableplayer.phtml | 13 +++++++++++++
 airtime_mvc/public/css/embed-player.css       |  4 ++++
 7 files changed, 35 insertions(+), 34 deletions(-)
 delete mode 100644 airtime_mvc/application/views/scripts/form/embeddableplayer.html
 create mode 100644 airtime_mvc/application/views/scripts/form/embeddableplayer.phtml
 create mode 100644 airtime_mvc/public/css/embed-player.css

diff --git a/airtime_mvc/application/configs/conf.php b/airtime_mvc/application/configs/conf.php
index d38a03797..6cf5f9d6c 100644
--- a/airtime_mvc/application/configs/conf.php
+++ b/airtime_mvc/application/configs/conf.php
@@ -92,7 +92,7 @@ class Config {
     public static function setAirtimeVersion() {
         $airtime_version = Application_Model_Preference::GetAirtimeVersion();
         $uniqueid = Application_Model_Preference::GetUniqueId();
-        $buildVersion = file_get_contents(self::$rootDir."/../VERSION");
+        $buildVersion = @file_get_contents(self::$rootDir."/../VERSION");
         self::$CC_CONFIG['airtime_version'] = md5($airtime_version.$buildVersion);
     }
     
diff --git a/airtime_mvc/application/controllers/EmbeddableplayerController.php b/airtime_mvc/application/controllers/EmbeddableplayerController.php
index 3cd0e3af4..f30683b79 100644
--- a/airtime_mvc/application/controllers/EmbeddableplayerController.php
+++ b/airtime_mvc/application/controllers/EmbeddableplayerController.php
@@ -9,23 +9,12 @@ class EmbeddablePlayerController extends Zend_Controller_Action
     
     public function indexAction()
     {
+        $CC_CONFIG = Config::getConfig();
+        $baseUrl = Application_Common_OsPath::getBaseDir();
+        $this->view->headLink()->appendStylesheet($baseUrl.'css/embed-player.css?'.$CC_CONFIG['airtime_version']);
+
         $form = new Application_Form_EmbeddablePlayer();
 
-        $request = $this->getRequest();
-
-        if ($request->isPost()) {
-            $formValues = $request->getPost();
-            if ($form->isValid($formValues)) {
-
-                $this->view->statusMsg = "<div class='success'>". _("Preferences updated.")."</div>";
-
-            } else {
-
-            }
-
-            $this->view->form = $form;
-        }
-
         $this->view->form = $form;
     }
 }
\ No newline at end of file
diff --git a/airtime_mvc/application/forms/EmbeddablePlayer.php b/airtime_mvc/application/forms/EmbeddablePlayer.php
index 2accf23a5..00f49384a 100644
--- a/airtime_mvc/application/forms/EmbeddablePlayer.php
+++ b/airtime_mvc/application/forms/EmbeddablePlayer.php
@@ -5,15 +5,22 @@ class Application_Form_EmbeddablePlayer extends Zend_Form_SubForm
     public function init()
     {
         $this->setDecorators(array(
-            array('ViewScript', array('viewScript' => 'form/embeddableplayer.html'))
+            array('ViewScript', array('viewScript' => 'form/embeddableplayer.phtml'))
         ));
 
-        $displayTrackMetadata = new Zend_Form_Element_Checkbox('display_track_metadata');
+        $embedSrc = new Zend_Form_Element_Text('player_embed_src');
+        $embedSrc->setAttrib("readonly", "readonly");
+        $embedSrc->setAttrib("class", "player_embed_src");
+        $embedSrc->setValue('<iframe></iframe>');
+        $embedSrc->removeDecorator('label');
+        $this->addElement($embedSrc);
+
+        $displayTrackMetadata = new Zend_Form_Element_Checkbox('player_display_track_metadata');
         $displayTrackMetadata->setValue(true);
         $displayTrackMetadata->setLabel(_('Display track metadata?'));
         $this->addElement($displayTrackMetadata);
 
-        $streamURL = new Zend_Form_Element_Radio('stream_url');
+        $streamURL = new Zend_Form_Element_Radio('player_stream_url');
         $urlOptions = Array();
         foreach(Application_Model_StreamSetting::getEnabledStreamUrls() as $type => $url) {
             $urlOptions[$url] = $type;
@@ -21,10 +28,9 @@ class Application_Form_EmbeddablePlayer extends Zend_Form_SubForm
         $streamURL->setMultiOptions(
             $urlOptions
         );
+        $streamURL->setValue(0);
         $streamURL->setLabel(_('Select stream:'));
         $this->addElement($streamURL);
 
-        $submit = new Zend_Form_Element_Submit('submit');
-        $this->addElement($submit);
     }
 }
\ No newline at end of file
diff --git a/airtime_mvc/application/views/scripts/embeddableplayer/index.phtml b/airtime_mvc/application/views/scripts/embeddableplayer/index.phtml
index 51e00dc03..0a9e66daa 100644
--- a/airtime_mvc/application/views/scripts/embeddableplayer/index.phtml
+++ b/airtime_mvc/application/views/scripts/embeddableplayer/index.phtml
@@ -1,16 +1,13 @@
 <div class="ui-widget ui-widget-content block-shadow simple-formblock clearfix padded-strong preferences">
     <h2 style="float:left"><?php echo _("Embeddable Player") ?></h2>
     <?php $baseUrl = Application_Common_OsPath::getBaseDir(); ?>
+
     <form method="post" id="player_form" enctype="multipart/form-data">
 
 
         <div style="clear:both"></div>
-        <?php
+        <?php echo $this->form; ?>
 
-        echo $this->statusMsg;
-        echo $this->form;
-        ?>
-        <?php echo $this->form->getElement('submit')->render() ?>
         <br />
     </form>
 </div>
diff --git a/airtime_mvc/application/views/scripts/form/embeddableplayer.html b/airtime_mvc/application/views/scripts/form/embeddableplayer.html
deleted file mode 100644
index 8a1ad551e..000000000
--- a/airtime_mvc/application/views/scripts/form/embeddableplayer.html
+++ /dev/null
@@ -1,8 +0,0 @@
-<fieldset class="padded">
-    <dl class="zend_form">
-        <?php echo $this->element->getElement('display_track_metadata'); ?>
-
-        <?php echo $this->element->getElement('stream_url'); ?>
-
-    </dl>
-</fieldset>
\ No newline at end of file
diff --git a/airtime_mvc/application/views/scripts/form/embeddableplayer.phtml b/airtime_mvc/application/views/scripts/form/embeddableplayer.phtml
new file mode 100644
index 000000000..f1ca8d478
--- /dev/null
+++ b/airtime_mvc/application/views/scripts/form/embeddableplayer.phtml
@@ -0,0 +1,13 @@
+<fieldset class="padded">
+    <dl class="zend_form">
+
+        <?php echo $this->element->getElement('player_embed_src'); ?>
+
+        <?php echo $this->element->getElement('player_display_track_metadata'); ?>
+
+        <?php echo $this->element->getElement('player_stream_url'); ?>
+
+        <div style="clear:both"></div>
+        <div id="embed_player_preview">player preview holder</div>
+    </dl>
+</fieldset>
\ No newline at end of file
diff --git a/airtime_mvc/public/css/embed-player.css b/airtime_mvc/public/css/embed-player.css
new file mode 100644
index 000000000..1f19319e8
--- /dev/null
+++ b/airtime_mvc/public/css/embed-player.css
@@ -0,0 +1,4 @@
+#embed_player_preview {
+    margin-top:20px;
+    border: 1px solid;
+}

From d61b75f105e234927c607f2bcf8886430e6c40dd Mon Sep 17 00:00:00 2001
From: Albert Santoni <albert.santoni@sourcefabric.org>
Date: Tue, 3 Mar 2015 16:08:53 -0500
Subject: [PATCH 08/60] Added a working 4th stream

---
 .../controllers/PreferenceController.php       |  8 +++++++-
 airtime_mvc/build/sql/defaultdata.sql          | 18 ++++++++++++++++++
 .../js/airtime/preferences/streamsetting.js    |  9 ++++++---
 .../pypo/liquidsoap_scripts/liquidsoap.cfg     | 18 +++++++++++++++---
 .../pypo/liquidsoap_scripts/ls_script.liq      | 16 +++++++++++++++-
 5 files changed, 61 insertions(+), 8 deletions(-)

diff --git a/airtime_mvc/application/controllers/PreferenceController.php b/airtime_mvc/application/controllers/PreferenceController.php
index 219e35e01..6a0ba3541 100644
--- a/airtime_mvc/application/controllers/PreferenceController.php
+++ b/airtime_mvc/application/controllers/PreferenceController.php
@@ -223,6 +223,9 @@ class PreferenceController extends Zend_Controller_Action
                 } elseif (strpos($v[0], "s3_data") !== false) {
                    preg_match('/\[(.*)\]/', $v[0], $matches);
                     $s3_data[$matches[1]] = $v[1];
+                } elseif (strpos($v[0], "s4_data") !== false) {
+                   preg_match('/\[(.*)\]/', $v[0], $matches);
+                    $s4_data[$matches[1]] = $v[1];
                 } else {
                     $values[$v[0]] = $v[1];
                 }
@@ -230,6 +233,7 @@ class PreferenceController extends Zend_Controller_Action
             $values["s1_data"] = $s1_data;
             $values["s2_data"] = $s2_data;
             $values["s3_data"] = $s3_data;
+            $values["s4_data"] = $s4_data;
 
             $error = false;
             if ($form->isValid($values)) {
@@ -245,6 +249,7 @@ class PreferenceController extends Zend_Controller_Action
                 $s1_set_admin_pass = !empty($values["s1_data"]["admin_pass"]);
                 $s2_set_admin_pass = !empty($values["s2_data"]["admin_pass"]);
                 $s3_set_admin_pass = !empty($values["s3_data"]["admin_pass"]);
+                $s4_set_admin_pass = !empty($values["s4_data"]["admin_pass"]);
 
                 // this goes into cc_pref table
                 Application_Model_Preference::SetStreamLabelFormat($values['streamFormat']);
@@ -290,6 +295,7 @@ class PreferenceController extends Zend_Controller_Action
                     "s1_set_admin_pass"=>$s1_set_admin_pass,
                     "s2_set_admin_pass"=>$s2_set_admin_pass,
                     "s3_set_admin_pass"=>$s3_set_admin_pass,
+                    "s4_set_admin_pass"=>$s4_set_admin_pass,
                 ));
             } else {
                 $live_stream_subform->updateVariables();
@@ -441,7 +447,7 @@ class PreferenceController extends Zend_Controller_Action
     public function getAdminPasswordStatusAction()
     {
         $out = array();
-        for ($i=1; $i<=3; $i++) {
+        for ($i=1; $i<=4; $i++) {
             if (Application_Model_StreamSetting::getAdminPass('s'.$i)=='') {
                 $out["s".$i] = false;
             } else {
diff --git a/airtime_mvc/build/sql/defaultdata.sql b/airtime_mvc/build/sql/defaultdata.sql
index 3c1a60752..438dfc979 100644
--- a/airtime_mvc/build/sql/defaultdata.sql
+++ b/airtime_mvc/build/sql/defaultdata.sql
@@ -358,3 +358,21 @@ INSERT INTO cc_pref (subjid, keystr, valstr) VALUES (1, 'user_timezone', 'UTC');
 INSERT INTO cc_pref (keystr, valstr) VALUES ('import_timestamp', '0');
 
 --end added in 2.5.2
+
+INSERT INTO cc_stream_setting ("keyname", "value", "type") VALUES ('s4_enable', 'false', 'boolean');
+INSERT INTO cc_stream_setting ("keyname", "value", "type") VALUES ('s4_output', 'icecast', 'string');
+INSERT INTO cc_stream_setting ("keyname", "value", "type") VALUES ('s4_name', '', 'string');
+INSERT INTO cc_stream_setting ("keyname", "value", "type") VALUES ('s4_type', '', 'string');
+INSERT INTO cc_stream_setting ("keyname", "value", "type") VALUES ('s4_bitrate', '', 'integer');
+INSERT INTO cc_stream_setting ("keyname", "value", "type") VALUES ('s4_host', '', 'string');
+INSERT INTO cc_stream_setting ("keyname", "value", "type") VALUES ('s4_port', '', 'integer');
+INSERT INTO cc_stream_setting ("keyname", "value", "type") VALUES ('s4_user', '', 'string');
+INSERT INTO cc_stream_setting ("keyname", "value", "type") VALUES ('s4_pass', '', 'string');
+INSERT INTO cc_stream_setting ("keyname", "value", "type") VALUES ('s4_admin_user', '', 'string');
+INSERT INTO cc_stream_setting ("keyname", "value", "type") VALUES ('s4_admin_pass', '', 'string');
+INSERT INTO cc_stream_setting ("keyname", "value", "type") VALUES ('s4_mount', '', 'string');
+INSERT INTO cc_stream_setting ("keyname", "value", "type") VALUES ('s4_url', '', 'string');
+INSERT INTO cc_stream_setting ("keyname", "value", "type") VALUES ('s4_description', '', 'string');
+INSERT INTO cc_stream_setting ("keyname", "value", "type") VALUES ('s4_genre', '', 'string');
+INSERT INTO cc_stream_setting (keyname, value, type) VALUES ('s4_channels', 'stereo', 'string');
+
diff --git a/airtime_mvc/public/js/airtime/preferences/streamsetting.js b/airtime_mvc/public/js/airtime/preferences/streamsetting.js
index 7529783a0..0fd0cd90a 100644
--- a/airtime_mvc/public/js/airtime/preferences/streamsetting.js
+++ b/airtime_mvc/public/js/airtime/preferences/streamsetting.js
@@ -443,7 +443,7 @@ function setSliderForReplayGain(){
     $( "#replayGainModifier" ).val( $( "#slider-range-max" ).slider( "value" ) );
 }
 
-function setPseudoAdminPassword(s1, s2, s3) {
+function setPseudoAdminPassword(s1, s2, s3, s4) {
     if (s1) {
         $('#s1_data-admin_pass').val('xxxxxx');
     }
@@ -453,11 +453,14 @@ function setPseudoAdminPassword(s1, s2, s3) {
     if (s3) {
         $('#s3_data-admin_pass').val('xxxxxx');
     }
+    if (s4) {
+        $('#s4_data-admin_pass').val('xxxxxx');
+    }
 }
 
 function getAdminPasswordStatus() {
     $.ajax({ url: baseUrl+'Preference/get-admin-password-status/format/json', dataType:"json", success:function(data){
-        setPseudoAdminPassword(data.s1, data.s2, data.s3);
+        setPseudoAdminPassword(data.s1, data.s2, data.s3, data.s4);
       }});   
 }
 
@@ -476,7 +479,7 @@ $(document).ready(function() {
                 $('#content').empty().append(json.html);
                 setupEventListeners();
                 setSliderForReplayGain();
-                setPseudoAdminPassword(json.s1_set_admin_pass, json.s2_set_admin_pass, json.s3_set_admin_pass);
+                setPseudoAdminPassword(json.s1_set_admin_pass, json.s2_set_admin_pass, json.s3_set_admin_pass, json.s4_set_admin_pass);
             });
         }
     });
diff --git a/python_apps/pypo/liquidsoap_scripts/liquidsoap.cfg b/python_apps/pypo/liquidsoap_scripts/liquidsoap.cfg
index d76e3af3d..bb6c6d88f 100644
--- a/python_apps/pypo/liquidsoap_scripts/liquidsoap.cfg
+++ b/python_apps/pypo/liquidsoap_scripts/liquidsoap.cfg
@@ -10,18 +10,22 @@ output_sound_device_type = "ALSA"
 s1_output = "icecast"
 s2_output = "icecast"
 s3_output = "icecast"
+s4_output = "icecast"
 
 s1_enable = true
 s2_enable = false
 s3_enable = false
+s4_enable = false
 
 s1_type = "ogg"
 s2_type = "ogg"
 s3_type = "mp3"
+s4_type = "mp3"
 
 s1_bitrate = 128
 s2_bitrate = 128
 s3_bitrate = 160
+s4_bitrate = 160
 
 ###########################################
 # Logging settings                        #
@@ -35,31 +39,39 @@ log_file = "/var/log/airtime/pypo-liquidsoap/<script>.log"
 s1_host = "127.0.0.1"
 s2_host = "127.0.0.1"
 s3_host = "127.0.0.1"
+s4_host = "127.0.0.1"
 s1_port = 8000
 s2_port = 8000
 s3_port = 8000
+s4_port = 8000
 s1_user = ""
 s2_user = ""
 s3_user = ""
+s4_user = ""
 s1_pass = "hackme"
 s2_pass = "hackme"
 s3_pass = "hackme"
+s4_pass = "hackme"
 
 # Icecast mountpoint names
 s1_mount = "airtime_128.ogg"
 s2_mount = "airtime_128.ogg"
 s3_mount = "airtime_160.mp3"
+s4_mount = "airtime_160.mp3"
 
 # Webstream metadata settings
 s1_url = "http://airtime.sourcefabric.org"
 s2_url = "http://airtime.sourcefabric.org"
 s3_url = "http://airtime.sourcefabric.org"
-s1_description = "Airtime Radio! stream1"
-s2_description = "Airtime Radio! stream2"
-s3_description = "Airtime Radio! stream3"
+s4_url = "http://airtime.sourcefabric.org"
+s1_description = "Airtime Radio! Stream 1"
+s2_description = "Airtime Radio! Stream 2"
+s3_description = "Airtime Radio! Stream 3"
+s4_description = "Airtime Radio! Stream 4"
 s1_genre = "genre"
 s2_genre = "genre"
 s3_genre = "genre"
+s4_genre = "genre"
 
 # Audio stream metadata for vorbis/ogg is disabled by default
 # due to a number of client media players that disconnect
diff --git a/python_apps/pypo/liquidsoap_scripts/ls_script.liq b/python_apps/pypo/liquidsoap_scripts/ls_script.liq
index ba4f8568d..398def91a 100644
--- a/python_apps/pypo/liquidsoap_scripts/ls_script.liq
+++ b/python_apps/pypo/liquidsoap_scripts/ls_script.liq
@@ -29,9 +29,11 @@ dynamic_metadata_callback = ref fun (s) -> begin () end
 s1_connected = ref ''
 s2_connected = ref ''
 s3_connected = ref ''
+s4_connected = ref ''
 s1_namespace = ref ''
 s2_namespace = ref ''
 s3_namespace = ref ''
+s4_namespace = ref ''
 just_switched = ref false
 
 %include "ls_lib.liq"
@@ -103,7 +105,7 @@ server.register(namespace="vars",
                 fun (s) -> begin log("vars.bootup_time") time := s s end)
 server.register(namespace="streams",
                 "connection_status",
-                fun (s) -> begin log("streams.connection_status") "1:#{!s1_connected},2:#{!s2_connected},3:#{!s3_connected}" end)
+                fun (s) -> begin log("streams.connection_status") "1:#{!s1_connected},2:#{!s2_connected},3:#{!s3_connected}:#{!s4_connected}" end)
 server.register(namespace="vars",
                 "default_dj_fade",
                 fun (s) -> begin log("vars.default_dj_fade") default_dj_fade := float_of_string(s) s end)
@@ -399,6 +401,18 @@ if s3_enable == true then
                 s3_connected, s3_description, s3_channels)
 end
 
+if s4_enable == true then
+    if s4_output == 'shoutcast' then
+        s4_namespace := "shoutcast_stream_4"
+    else
+        s4_namespace := s4_mount
+    end
+    server.register(namespace=!s4_namespace, "connected", fun (s) -> begin log("#{!s4_namespace}.connected") !s4_connected end)
+    output_to(s4_output, s4_type, s4_bitrate, s4_host, s4_port, s4_pass,
+                s4_mount, s4_url, s4_name, s4_genre, s4_user, s, "4",
+                s4_connected, s4_description, s4_channels)
+end
+
 command = "/usr/lib/airtime/pypo/bin/liquidsoap_scripts/notify.sh --liquidsoap-started &"
 log(command)
 system(command)

From 968b739bf41b77574b65887d6be1e6f7999f12b9 Mon Sep 17 00:00:00 2001
From: Albert Santoni <albert.santoni@sourcefabric.org>
Date: Tue, 10 Mar 2015 12:41:45 -0400
Subject: [PATCH 09/60] Make 4th stream backwards compatible with the
 autogenerated liquidsoap.cfg

---
 python_apps/pypo/liquidsoap_scripts/ls_script.liq | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/python_apps/pypo/liquidsoap_scripts/ls_script.liq b/python_apps/pypo/liquidsoap_scripts/ls_script.liq
index 398def91a..46ced98dc 100644
--- a/python_apps/pypo/liquidsoap_scripts/ls_script.liq
+++ b/python_apps/pypo/liquidsoap_scripts/ls_script.liq
@@ -401,6 +401,7 @@ if s3_enable == true then
                 s3_connected, s3_description, s3_channels)
 end
 
+%ifdef s4_enable
 if s4_enable == true then
     if s4_output == 'shoutcast' then
         s4_namespace := "shoutcast_stream_4"
@@ -412,6 +413,8 @@ if s4_enable == true then
                 s4_mount, s4_url, s4_name, s4_genre, s4_user, s, "4",
                 s4_connected, s4_description, s4_channels)
 end
+%endif
+
 
 command = "/usr/lib/airtime/pypo/bin/liquidsoap_scripts/notify.sh --liquidsoap-started &"
 log(command)

From 6232e3f4f00611e089bc7cb3ccb16ef7fde91fae Mon Sep 17 00:00:00 2001
From: Albert Santoni <albert.santoni@sourcefabric.org>
Date: Tue, 10 Mar 2015 12:52:00 -0400
Subject: [PATCH 10/60] Better backwards compatibility fix for 4 streams

---
 python_apps/pypo/liquidsoap_scripts/ls_script.liq | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/python_apps/pypo/liquidsoap_scripts/ls_script.liq b/python_apps/pypo/liquidsoap_scripts/ls_script.liq
index 46ced98dc..38f647f7f 100644
--- a/python_apps/pypo/liquidsoap_scripts/ls_script.liq
+++ b/python_apps/pypo/liquidsoap_scripts/ls_script.liq
@@ -33,7 +33,6 @@ s4_connected = ref ''
 s1_namespace = ref ''
 s2_namespace = ref ''
 s3_namespace = ref ''
-s4_namespace = ref ''
 just_switched = ref false
 
 %include "ls_lib.liq"
@@ -402,6 +401,7 @@ if s3_enable == true then
 end
 
 %ifdef s4_enable
+s4_namespace = ref ''
 if s4_enable == true then
     if s4_output == 'shoutcast' then
         s4_namespace := "shoutcast_stream_4"

From 6c46f0a15681d753f52f42eaf3a95f62b2ced1a8 Mon Sep 17 00:00:00 2001
From: drigato <denise.rigato@sourcefabric.org>
Date: Tue, 10 Mar 2015 16:32:35 -0400
Subject: [PATCH 11/60] Added player preview to view

Everything is hardcoded right now
---
 .../EmbeddableplayerController.php            |    9 +-
 .../application/forms/EmbeddablePlayer.php    |    2 +-
 .../scripts/embeddableplayer/embed-code.phtml |   18 +
 .../views/scripts/form/embeddableplayer.phtml |    2 +-
 .../embeddableplayer/ffmp3-mcclean.xml        |   10 +
 .../embeddableplayer/ffmp3-mcclean/bg.png     |  Bin 0 -> 3649 bytes
 .../embeddableplayer/ffmp3-mcclean/holder.png |  Bin 0 -> 830 bytes
 .../embeddableplayer/ffmp3-mcclean/play.gif   |  Bin 0 -> 1493 bytes
 .../ffmp3-mcclean/playclick.jpg               |  Bin 0 -> 1422 bytes
 .../ffmp3-mcclean/statusplay.png              |  Bin 0 -> 138 bytes
 .../ffmp3-mcclean/statusstop.png              |  Bin 0 -> 136 bytes
 .../embeddableplayer/ffmp3-mcclean/stop.jpg   |  Bin 0 -> 1459 bytes
 .../ffmp3-mcclean/stopclick.jpg               |  Bin 0 -> 1459 bytes
 .../public/js/airtime/embeddableplayer/mrp.js | 3012 +++++++++++++++++
 .../js/airtime/embeddableplayer/muses.swf     |  Bin 0 -> 74589 bytes
 15 files changed, 3047 insertions(+), 6 deletions(-)
 create mode 100644 airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml
 create mode 100644 airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean.xml
 create mode 100644 airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean/bg.png
 create mode 100644 airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean/holder.png
 create mode 100644 airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean/play.gif
 create mode 100644 airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean/playclick.jpg
 create mode 100644 airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean/statusplay.png
 create mode 100644 airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean/statusstop.png
 create mode 100644 airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean/stop.jpg
 create mode 100644 airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean/stopclick.jpg
 create mode 100644 airtime_mvc/public/js/airtime/embeddableplayer/mrp.js
 create mode 100644 airtime_mvc/public/js/airtime/embeddableplayer/muses.swf

diff --git a/airtime_mvc/application/controllers/EmbeddableplayerController.php b/airtime_mvc/application/controllers/EmbeddableplayerController.php
index f30683b79..4536d7e18 100644
--- a/airtime_mvc/application/controllers/EmbeddableplayerController.php
+++ b/airtime_mvc/application/controllers/EmbeddableplayerController.php
@@ -9,12 +9,13 @@ class EmbeddablePlayerController extends Zend_Controller_Action
     
     public function indexAction()
     {
-        $CC_CONFIG = Config::getConfig();
-        $baseUrl = Application_Common_OsPath::getBaseDir();
-        $this->view->headLink()->appendStylesheet($baseUrl.'css/embed-player.css?'.$CC_CONFIG['airtime_version']);
-
         $form = new Application_Form_EmbeddablePlayer();
 
         $this->view->form = $form;
     }
+
+    public function embedCodeAction()
+    {
+        $this->view->layout()->disableLayout();
+     }
 }
\ No newline at end of file
diff --git a/airtime_mvc/application/forms/EmbeddablePlayer.php b/airtime_mvc/application/forms/EmbeddablePlayer.php
index 00f49384a..4b9353aad 100644
--- a/airtime_mvc/application/forms/EmbeddablePlayer.php
+++ b/airtime_mvc/application/forms/EmbeddablePlayer.php
@@ -11,7 +11,7 @@ class Application_Form_EmbeddablePlayer extends Zend_Form_SubForm
         $embedSrc = new Zend_Form_Element_Text('player_embed_src');
         $embedSrc->setAttrib("readonly", "readonly");
         $embedSrc->setAttrib("class", "player_embed_src");
-        $embedSrc->setValue('<iframe></iframe>');
+        $embedSrc->setValue('<iframe frameborder="0" src="http://localhost/embeddableplayer/embed-code"></iframe>');
         $embedSrc->removeDecorator('label');
         $this->addElement($embedSrc);
 
diff --git a/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml b/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml
new file mode 100644
index 000000000..74da31357
--- /dev/null
+++ b/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml
@@ -0,0 +1,18 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+
+<head>
+    <script src="http://localhost/widgets/muses/self_hosted/mrp.js" type="text/javascript"></script>
+</head>
+
+<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="180" height="60" bgcolor="#FFFFFF">
+    <param name="movie" value="muses.swf" />
+    <param name="flashvars" value="url=http://albertprov1.out.airtime.pro:8000/albertprov1_a&lang=auto&codec=mp3&volume=100&introurl=&tracking=true&jsevents=true&buffering=5&skin=http://localhost/js/airtime/embeddableplayer/ffmp3-mcclean.xml&title=Albert's%20Test Stream" />
+    <param name="wmode" value="window" />
+    <param name="allowscriptaccess" value="always" />
+    <param name="bgcolor" value="#FFFFFF" />
+    <param name="scale" value="noscale" />
+    <embed src="http://localhost/js/airtime/embeddableplayer/muses.swf" flashvars="url=http://albertprov1.out.airtime.pro:8000/albertprov1_a&lang=auto&codec=mp3&volume=100&introurl=&tracking=true&jsevents=true&buffering=5&skin=http://localhost/js/airtime/embeddableplayer/ffmp3-mcclean.xml&title=Albert's%20Test Stream" width="180" scale="noscale" height="60" wmode="window" bgcolor="#FFFFFF" allowscriptaccess="always" type="application/x-shockwave-flash" />
+</object>
+
+</html>
\ No newline at end of file
diff --git a/airtime_mvc/application/views/scripts/form/embeddableplayer.phtml b/airtime_mvc/application/views/scripts/form/embeddableplayer.phtml
index f1ca8d478..568540d7f 100644
--- a/airtime_mvc/application/views/scripts/form/embeddableplayer.phtml
+++ b/airtime_mvc/application/views/scripts/form/embeddableplayer.phtml
@@ -8,6 +8,6 @@
         <?php echo $this->element->getElement('player_stream_url'); ?>
 
         <div style="clear:both"></div>
-        <div id="embed_player_preview">player preview holder</div>
+        <iframe frameborder="0" src="http://localhost/embeddableplayer/embed-code"></iframe>
     </dl>
 </fieldset>
\ No newline at end of file
diff --git a/airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean.xml b/airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean.xml
new file mode 100644
index 000000000..57d7c3eab
--- /dev/null
+++ b/airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean.xml
@@ -0,0 +1,10 @@
+<ffmp3-skin folder="ffmp3-mcclean">
+  <bg image="bg.png" x="0" y="0" />
+  <play image="play.gif" x="8" y="29" clickimage="playclick.jpg" />
+  <stop image="stop.jpg" x="40" y="29" clickimage="stopclick.jpg" />
+  <text x="13" y="9" width="154" height="17" color="#ffffff" font="Arial" size="11" />
+  <songtitle x="12" y="83" width="210" height="22" color="#000000" font="Arial" size="12" />
+  <artist x="12" y="103" width="210" height="22" color="#000000" font="Arial" size="12" />
+  <volume mode="holder" x="71" y="33" width="100" height="17" holderImage="holder.png" />
+  <status imagePlay="statusplay.png" imageStop="statusstop.png" x="13" y="34" />
+</ffmp3-skin>
\ No newline at end of file
diff --git a/airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean/bg.png b/airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean/bg.png
new file mode 100644
index 0000000000000000000000000000000000000000..a399e16be7eeeb3a6a26d2488b98293dbf0eb29e
GIT binary patch
literal 3649
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
T`Az`^00000NkvXXu0mjf8;ca6

literal 0
HcmV?d00001

diff --git a/airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean/holder.png b/airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean/holder.png
new file mode 100644
index 0000000000000000000000000000000000000000..8b61d23458835ad36e762af595eb72011e809860
GIT binary patch
literal 830
zcmV-E1Ht@>P)<h;3K|Lk000e1NJLTq000pH000mO1^@s7hc=|i00004XF*Lt006JZ
zHwB960000PbVXQnQ*UN;cVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU!&`Cr=RCwBA
zU;u*e-@pF{(M&+B+||_uVk-j#5aY39$F#trH*em&s;#Yk6(E2>9M-2#pZ<@DiTUs5
z<_6Nk3KC@e_U+rB|3CnuL41G!0tqsF{P^(>2!mC;fBzmN3zp#G;$mQ8W@cvCwQCmx
z4-XFmhz$b%fByXW55gceKmZn~90x!U2(C25R!V&a576G0g3plfGI<IiRs<Sa3*12`
znN0RRh9`t@=A3&<smB<H!iJyzNo%e3w$_r?nxvHEoTE|-2_Z-+wIOlg%7!}u@BL6?
z3_3Q%C;EVccILsH@f+raO_<Ls01ae}!XOMr;g>eLiByUXLZD}H3<Ns4c5{+mz$-Ww
zyhX3jn{+8ILOQfdruKhg0xvxN_Xzp^tphdB^G$F9MIWJg?Y;MJ2{IvB+gfWfe~O|w
z?1cFmLdcX-==&Z?lAx|@aK=m<W4g9&QB@VJwMf$x&N<|Hj$s%&y)4VOX&OjzeV&D~
zELYErd$<slnx^R&Jr6S$kK;H#;<_mw&X_6jkPmWmXVGcHev0mrz5W6;O~tAa0#R^7
z4k9E)QifAfr!*g6Z6lZ_wT-Q$wi5h-Lu~woyCPzfUND_l<Qqcl(kKW<&CJF%c`)eP
zoww|pH><>AoHtGLh`Ssh_kJ8lF-_CoCML@c=Xw5s($A)8zF>J$ZaedR{}z^d*LD3g
z48y+bI!Ym^o$I>t%iOkY!F}?`XPpxLx~}V2m|$t!c7x+MOBjX{%q`23Uk1HPKI>S&
zqX96XdpahLV=1SmX;ObW3Rjmh=XoxIAP`BC2*WU>!&t|99x|3?`G(hVm!|2aL6&9P
zKM$c*i=q&H-*0QIQwF;L9-=6s9y5Ah6c}tr<!q5b9{H?W>wkR*&>~Ns=N+r6`h>XO
zn8c#Moa@{tZ{_dA_J;qB8Mp*)fUA{64&N$m-T_}gug1&x0ct_DHu;mWmjD0&07*qo
IM6N<$g2~ExeE<Le

literal 0
HcmV?d00001

diff --git a/airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean/play.gif b/airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean/play.gif
new file mode 100644
index 0000000000000000000000000000000000000000..150591ffc95dfe9d45c6815eea1dce1f50c08941
GIT binary patch
literal 1493
zcmWlYc|6p47{`Z@tS(zANoYE05u3!8#EdI7n@T6bW=F3!t=H;M;U$K(vayV#gACF*
z29;?j#x>)Z`OSSFznS0Mv_z!5+WmQdpXc*=KF|02?-w10I^Y-Yh;Ts6BM=841p4P5
z2`D^zsPM>7kB;n8c>KWK?;-c~6CZK|ecjYQdaL}y3!=h`A_9xif#s->l2CL>#8Est
z=m|QQfC_933vLNV6QhD(9Yei}LU%=lzdnI^c`~~592R#qrSfW0SMnXw{aci~fugV=
zad?CXb4+#yt;R${m(D8_VxcQo$#0jT<P2>N4u{Ln&o3w_C@wB8DJdx{E5qaQ6%`fL
z)zyz5KhC6NJ!*PXMl3IHEw5~?u5PWux8ZAQY6t{EeSLjnV`Fo3b8BlWi9~8|Z|~^n
zc=P5>S63IAOr}sM-QC?iJw5N<y?g)ueKsGLsm490J|_&ls2^^uqc;$k4fSIUy}iAC
zF#Xj2J}OLqe?OHv05do^I5adgJUmRJ(dcyg$jHd(=;+wk*!cK3lR3^{FqliQ#sDS*
zfE{20Y=FUJF#!NzumA?YX0ka9IIvhO0ARCN95%q=u-LG%*=!Dn!)9~Y93F=U3zx&?
z^8hZF2k?0uF6=xWmnY!!`2rZ8kS`Dk1R}n0NdzLHkRuQZcp`yNBoK>40*O>06beO4
zNJJ8$NFo*sMQ}^RLa|sZk-%9hkx3O2u}lK1R3;V5;7Kl#N~JQHOe&R2<uaK<s!+(}
za=AhQKT*o0pj-he6rfzCQA$Nhg-ofGgP=mGQYe*55Cl~!m0GP<f*KX5RjV~h4XA?P
zf=5UVX(1&Dsnig>hEy7j8iF8=Mgu`wjZUl8LU5}gy;iH&>I^!aL95rmqBX&zUZ*$e
zbsG3$5)KAPZ`2tLI{gwx_?QevBkV?_K|g6QPMA!Srpbv3BWx4@nkFVD^%F~cfSH<_
znwgpTH2-mScJ|XeTyy^+5OZ_0b8~a^^9!FpfByRQtIL9g83OSI;f{b=`V$E2Z-|5y
z7Y2=j&Q!^oUp5b~bR?&$ySG=*rTi0kmJ~x`bN`edzPC6Bn(~g<^<+3NEKqbzMZoD=
zpKFPlhnKo<O+)0A;UXEOYC8L)?d^xLjVE3PZGYR)`r_mh@aAjvuSFMmO#wO=yTRmB
z{tZ#QnvSNuQopohR#8gcA9B|)Y{p;9B-{&KX&T_JB==esIcIY5OH$6xLLxb>C!V6s
zLi?u3Yr`CU_ud#deB~{%5_Kl_6_)MbsrPE`G|=h=#dJHH7+n%jkZQfQFV8!9w9)VU
zkZpzc73@IV3Jr0F6wlZn*k=|$?2#~5YPN01mW`F3$9)!znwJ!h_@0~JwvVn!dSGpS
zFk_OvexhvNbbJGydLWkX7DJ9Zo7`7xVQuCo{P{cgHg3Ar#wh2Y;z(jwP{i)0=whn*
z@{NEQqN|fSvZp0EddNNs**=0pwq%dE*G0w!ncFlzGh1I*cX?zt@}7QRD|!ooj=^WL
z>C2GoGR>_{$Mxs$d|KE}$0VkK7ETq3)X-AQx!M)TRnFI`mS>_*(zlhz*ySTJMXZqT
z(>-gorG+O{*2qFzPjkyt0nh78Q=0s&>?4V!P}h9-Y?^C<&kY*VEY#C-U#5-CF4xQ*
zt|<G+XIV4?epL|8B|F18#Jl{PnSqcW=U`<YaUIOtdXxAT>(Y7K!hE%7<}9me>;1L@
zbjv-TzK{*U%GBjf)GyPyTW-@xc}^Kz)*e#xDmVAF@i}WPD$^71<T<7GW(_;04@_G*
zrP$s<lSK|*!JDwVFh`$aORG?uuho%IPHAnJ4-V5!sd)}4;Z$&U!aA4!m7$5O2lnTE
zh?e%Ne|Pb+zZjQlvC`WaGvu&Xlr^y0t6NE>A<Hl9v)zXvSx^?6vT`?FbpPAJ&PQ;y
SV?4}fdT<kV)^QC2;r~A$;C_q%

literal 0
HcmV?d00001

diff --git a/airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean/playclick.jpg b/airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean/playclick.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..48bbd4954a037eefc63f038727b538a96ec2b0da
GIT binary patch
literal 1422
zcma)5X;4#F6u$Spmjwiym#}7<vQt_?2^gxOWf6?ZqJkJ|*+~=;I}kNu+!}V2HAn!h
zr9>f4#u;(JDJTqtB4O1k%Ya}(1}#&S8bMnaHGKg^e|pZ`nLFov-&ya~4e7=KEr7R)
z2Ot7~kWip|3UGh1AV~rsz<}Nebko4mSC|~X69`)f3q*k_hLR190YJh5Kx+ZOssJG6
z>qbB(fS)eN2SJzQ9UXy?@DgXq@u?SGE5NCM2|h<54iFroIMlU)E}~FEKN1p|f?@`X
z={_<8j6@;R0FfI-NlSJVLr8!I$<_>0x|^N58BR<AK`|-?zJnkTN9h=_VX)&&NWQji
z@#*gNoHWHgzw<&59$k;dkY!8ZAdaBGn#PW!-^FZvLqur`wbu43i2;ecfDEzsg+km0
zuxZxMeM90zX)?vbE9$$t`@je#a5#z+tC*TH+?~5EQ7e_b_>-x9#`S&kPuRSJS{~TE
z-J)d;bFznkQy~P9gm7Ey5)SV<)IFopc)s%Dns$45MfN8}O*~^KMvTlo(Xa*^C#Yjh
zq^dRZc9R#6{TEZ~y+B6v<W7r}%Er>G%lW-3m4c677+7$j3$Dw!dGszx?REASwoDdh
zcvbi!4Iz6Y%JvsU2Y;w3Zb*xIVYS($uQ#*2FG?gVAvt&Hz+#96n4g`rWc_{5ZJujW
z+f6lxHqTfY3YvZF-wMTy+GZZR+jVrRJh|W<1wtZnLv+GV4o!_;3lewJOG9X_>n#Ia
zD9jFF{LSdnFku_}Oa~>Uh$`=&QuZ{6hi7hun2ypN<DA3Gk=Q81JXL{lOhj8s<WAe!
zgY{>a1wVe4C7EuKx8c1(GZlPJ=nc&oubv(C(5Uh1T>H9nt1T|giN3-gDP>AA*Xh~~
z_lGOLEDR7+U6iF^%O5|$ohq`nhI0-a=2dT~jykpF-xzIdgx8h7ngVKAT_@`wm8aga
z%~?4(+YxNs8j#W%-10_k;L;}Z;KmB_xB7?5@E{pO!7vV$416O|o&P(z@_X<7LzN>V
z+G)*vqt)yi`OMK~t5nvSg@Hj7dfS}U0f+HvMXY;#bDmt9Q{6wdw=C4vt$pbD>9=Ey
zrxSMV`R*Z|5gmLr!fi*D1NT&5c3C<<U)tYm7H#IS+LD><IW;)Ja<tmO92mdeeYqe`
z^t^=%66Bu0KNde3yU9)b?d5ZE&X%Vy)r;HIXKj75a@9G(^gfc4&ylbrbF`lslGmNt
z#ecju7-dil)^f^f@?P(MzgIn>yUO+Dwz`t=<D>GRJ0%%>hfM#y{%5rZzhn4c@1<i5
z3S6G$Vq{RniCkcPc-OS-jpO;$#TTM)n6@dE9DKTDNO0QuUJ_>yZmmRaQ_Yvvtd``v
z)t&g|ROY_yR6)%nzm3t4Ee}u&SBy@k^;nd*Y)_iW<#Ak!Oq%;x!>Dz^j?hx4>gu`&
z*_xsHyegk>&5T%b68yE$_|@&KKCZ>ou?rc>=!=u%OD)s7tAp32uLv~>y5@JZK%`Wy
zLPG3wr9POvL|!qU!e;~KB^!aQ8ZmKD1WxzdS^P1mzG6+0Z}GW|ljgYGLXejr>Ix8L
hW-=&JW`n^lDRiV&I%`i@Zl%i<#m3Syo`mRs_<xxh-|hea

literal 0
HcmV?d00001

diff --git a/airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean/statusplay.png b/airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean/statusplay.png
new file mode 100644
index 0000000000000000000000000000000000000000..d751aac25ba5107d963191a806f72dbaf13e8bdf
GIT binary patch
literal 138
zcmeAS@N?(olHy`uVBq!ia0vp^Od!m`#=yYHy3uwMki(Mh=<CS9u>OQOYu8I4U$VqC
zq9iy!t)x7$D3!r6B|j-u!8128JvAsbF{QHbWU38Nk&LH{V@SoVq=X;(zt|KSBpg^A
i8Vrr@h*uqEU}11fX1%|yRKOOfj=|H_&t;ucLK6VcjwMR~

literal 0
HcmV?d00001

diff --git a/airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean/statusstop.png b/airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean/statusstop.png
new file mode 100644
index 0000000000000000000000000000000000000000..e0cce0d1a8407d07b2b8470cfedcbb3b7a0c96b8
GIT binary patch
literal 136
zcmeAS@N?(olHy`uVBq!ia0vp^Od!m`#=yYHy3uwMki(Mh=<CS9u>OQOYu8I4U$VqC
zq9iy!t)x7$D3!r6B|j-u!8128JvAsbF{QHbWU38Nk(8&4V@SoVq#x%Gd|*>(kZ@pe
gXfS-ozOjLU!C@|IGjG!oQ=lpaPgg&ebxsLQ0I(4y>;M1&

literal 0
HcmV?d00001

diff --git a/airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean/stop.jpg b/airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean/stop.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..c7fda38d84c849610b89f211a34fd222b515e527
GIT binary patch
literal 1459
zcmex=<NpH&0WUXCHwH!~28I+MWcdGvLC~c%IlGd9k%5H)B*^gp9fO)<N`6u*L&^c5
z2qQCtC<`+i7cT<?QzZif^CJcZmO~5-tQ-H|W@uqxBpxs!05cpwwKFj?0%d_1E<r5g
z{~-oJ4hAU(8D>U71|~s9W<kdPM;NXE9m~WFbUhrfaj>v5vvV>sGBC0-!bO1$W+oO^
zHg*mH21XV}CKh(M6blnGD;pz&fP#=PyP%=5vxumwATZomnV49(xS^^Tfp!QAv9KBn
zD>^C}iLeDGHZI)g6x3uanzTvTIl1|;X{(u=5Can<&^N4blfk-J1QZMv3xxs~UR2s7
z40IF|D>Dl-%wa&UC<=TqbPP<KxKUx@!Hb2B4?q6D#lQnpz$C~l2#l0BGYn;~UJX37
zN^0|zn*Ddz^c_EXTX*|;X9YR)GQ}N-({~+Yn^iK;_&HD)2iVU{oVj1*cU*0);JlI9
z^4awBq51>fy4{RtzLf>K?Y#OoP(|vZ$t%wmSC{MBoxfR%Blm34U;m~atepuMWK7qM
zN_!q#&kDM&q<Yk<cbddG&1F&PGWK8v%pe8VBx)mqv)#VVQ1t6~$Kk^ecR1oXOUg^*
zC)W={OkrZPXIkf4a&=;D=FF|1N?2E2<mSB((GQYZy~=dA)bA$i*K8q&XI#JOutK3B
zvL@nRooP%>&P*ZE2V6qwr!MX4=6(m(!pI2J;@qgIRT3UFN%X+iAT1U(=kt8GW4`zA
z-u9hG*VpFoPoHRgqenbbZm+fY6n5)UDT|-1#hyNGjcJ+u-?(RMU$|Jbih0>hzuc)U
zGyS66)4!_68e8RFclkOsF4A?!AC)R)<Giz5H_egU^Rn=IwAVAge8tm^YV$e!KJMCZ
zDNOQ^Vzlql4RzPeTn<&9I2!N#Wx*}o%)CeUGJ?GWyt)`)ST*?jZe2d(`62mTyAIyk
zTU_*cyExyU^Jdpxzt`FEdFeKzvqnviyHqYsP)m9mQLP;ll~;E5R_oK(zjsT|4qdNU
zT@oO5H>`zkO3f*+H?wzFZ?b3WvUb^e>(28xAKUh)|MQP8vp?Y+f92QVmDj)56n>BA
z|5Wm8A|z;-8SNE!B>A~dXlP4%vtEGr^zsk`eP;HkM4Ly3c^w+3Ox7j8;reL$>g=nB
zV*0rn)%SE18l3(!ELy9)VP>I|X~nv-z(t&&9xiBX%ww5)YSVm2e)+6<y3VS-2U3j!
zr!P61#ywr{<+@kT-ZpE7FE+Nnv>y_`AZwS*NcnSZflM&3_^wO$b=v3e2{OvsvSRI;
zDu^0pkeWq2dym-!7yLeG^Qa_X8s|>0bB}{x@4iv9QS7+D0_%`d9d6DM8^9V6>0Ln1
z!Dmu~0^ENBn&(z5t!!^93T5)Ty3pT2U<tDW+Z)5oJuM>FeE&17@t;}MmCo2V&r0gT
zJ+YH}VoGPZwro5wEnpFwr#Hi`9d9@5lqqfPnBm5B@REYld<)sP$ytvRQde>bJ(zhV
zZ7G-V4VM25N0;OTYnq+B&K9oo&$gfw?n!|qhj=I0Wt1vBl$Tg^F!q{W2ggk<vHD#5
zHjRpBF6*m2>Xia^`Ch*Y)&TOcz(UPQ3NjrnuL5(WxHhhFnDMeB`G}Vu>#7U(B{sLt
j-kf*rV_i&&<6WDi@4L2qSJ@S<aKrcE?3e3T|Gx<UPJI59

literal 0
HcmV?d00001

diff --git a/airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean/stopclick.jpg b/airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean/stopclick.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..a25e025be1b2ecf0ffd3906fcc2c3cf9f6382873
GIT binary patch
literal 1459
zcmex=<NpH&0WUXCHwH!~28I+MWcdGvLC~c%IlGd9k%5H)B*^gp9fO)<N`6u*L&^c5
z2qQCtC<`+i7cT<?QwakD^ECzrmhB7-tQ-H|W@uqxBpxs!05cpwwKFj?0%d_1E<r5g
z{~-oJ4hAU(8D>U71|~s9W<kdPM;Oil9m~WFbUhrfaj<hTv#>HUGB7bS!bO1$7FK39
zb`AlcdPZgzgcLIi6Du2o0HcDCFuRems4>uRMn*PfRyKC1W=1Av76w5@Az@a-L=ne8
zqa@?Tg-T6}O^cLOQbf(%gn;Uqm{~dDRsneof&zvt3JW(L6jDqqoTwBetjsFR2n=9m
zCN{WRfxb{Q6mU%Z5U5btIC0^@jTayOzs0}<bQqH$vmh`!HeRqZz3;4Ith0f~Ys*u+
zzlmmk8aLj><=To%oqgm!(Z^e_nIR#2;!L0}4xn!tS(#FmqULlZGtIhMayI*X^3PN4
zJHjKor=G8xb#?W1oBG;{$EU8z%{r<Rd(=QH#y)o9U#<J|y8nCy>t_P#zplnFbF5(A
z+l`9z78R*Wdzvm+WN>^1mS+aZU(wF-WL|aZ_TwuD%9h{gVpV#x&$DVp{FV({ru#!o
zVPdmqS}hj+<NAW;ZiVl1CU5TE`S_}YwKqyJ`)xhMAdr%UDpi#;`COC*4>epl_VK>n
zQsq9YTA!T~$#<o?E*<39@SA`BG0UV~wRX!~T3s8&-rV*2&#+M2>-5xb`@x0)Bgmd<
z=4-Y2%lg9G=1r2EC$X+$O6JnbTB(!V+4~qG7f&x-+UKGgXK7yQ?j{pDbrrLwSo-bN
z-h0C9O8K6Bve7AY@(DHzZqJv_$ojW^#fx2MR@eE92Tyu4>z3S^AD=en{Y<xyd>ilV
z<&aVC`!e><B>jKcg$Fd0H{HIo)qkamiFH(hp19Q78$G(qf8YK$b=sRc_2V;hj#diz
zu3Ej!y2(2-&@^PVXl+d4t1BLtPKBAyQF=b{<bgu7HP!(u&c-fM&+2@(B26GmVv6LF
zNe`BVJ-na2nLpa}UiPLZf5NLjZ2o(`;dg%j^QZY=%j)0!6Mprp-hSHMZ4jR`GukT(
zZ=R{Xc!Pc$TWDSFq=#D~g}mn2<!oJIGe=tV_dfN_9euYnGwgm%aN^iH^{#U1mxV&t
zj(UBMlX|mq<AM`6=e&2@-cc}B_=I@=-5^F)vl&;t^Y|ROcfDKo;q#or=d*TY?*8+o
zv_1V-;bKUff^1wN%scV-+Ktu9Kd$R9KQ(LD<^1^Acq6?F8GeC}Akhj^weV<BkBpL|
zrDjRqhhs@B$EEI_P_W!tb8MN%T;+L-I<6&{Eod+)oRBw-UmU0jk<<km9CkE!Fu*-1
zFxxlNKv2n3X3Djq0|D`}Y)(SWT^0(bXH8^S(;ThV@s#JiZQi7N<#%0AGR(<au6=at
z^xWnJ8y0dV6^rWhUD@wdp2E{)n(7r1=;@(hGc9>;^#+zJ+V+17`Zj5}uJ7Z0I+uIX
zE{PYFetk2m)*HLSy(zGq_l2{|iJtbh=AeaUH;<g`yj8kom)D02m8#Yg?9S|)we6Co
z(Yl|@$`7e>Mda<%hx=S$@xh>GuPpA4&bH?18aW5ttXwvAs;ezpW#^c}VUzIn)?DEk
kn{NKJ^9{XofU6-j@721uzV2CCj2i+HXA}zk*#G|~0Q5EfJpcdz

literal 0
HcmV?d00001

diff --git a/airtime_mvc/public/js/airtime/embeddableplayer/mrp.js b/airtime_mvc/public/js/airtime/embeddableplayer/mrp.js
new file mode 100644
index 000000000..74bc30836
--- /dev/null
+++ b/airtime_mvc/public/js/airtime/embeddableplayer/mrp.js
@@ -0,0 +1,3012 @@
+(function(n) {
+    function w(a, c) {
+        function r() {}
+        r.prototype = a;
+        var b = new r,
+            f;
+        for (f in c) b[f] = c[f];
+        c.toString !== Object.prototype.toString && (b.toString = c.toString);
+        return b
+    }
+
+    function B(a) {
+        return a instanceof Array ? function() {
+            return m.iter(a)
+        } : "function" == typeof a.iterator ? p(a, a.iterator) : a.iterator
+    }
+
+    function p(a, c) {
+        if (null == c) return null;
+        null == c.__id__ && (c.__id__ = G++);
+        var b;
+        null == a.hx__closures__ ? a.hx__closures__ = {} : b = a.hx__closures__[c.__id__];
+        null == b && (b = function() {
+            return b.method.apply(b.scope, arguments)
+        },
+            b.scope = a, b.method = c, a.hx__closures__[c.__id__] = b);
+        return b
+    }
+    n.muses = n.muses || {};
+    var s = function(a, c) {
+        c = c.split("u").join("");
+        this.r = new RegExp(a, c)
+    };
+    s.__name__ = !0;
+    s.prototype = {
+        r: null,
+        match: function(a) {
+            this.r.global && (this.r.lastIndex = 0);
+            this.r.m = this.r.exec(a);
+            this.r.s = a;
+            return null != this.r.m
+        },
+        matched: function(a) {
+            if (null != this.r.m && 0 <= a && a < this.r.m.length) return this.r.m[a];
+            throw "EReg::matched";
+        },
+        __class__: s
+    };
+    var m = function() {};
+    m.__name__ = !0;
+    m.cca = function(a, c) {
+        var b = a.charCodeAt(c);
+        return b != b ? void 0 :
+            b
+    };
+    m.substr = function(a, c, b) {
+        if (null != c && 0 != c && null != b && 0 > b) return "";
+        null == b && (b = a.length);
+        0 > c ? (c = a.length + c, 0 > c && (c = 0)) : 0 > b && (b = a.length + b - c);
+        return a.substr(c, b)
+    };
+    m.indexOf = function(a, c, b) {
+        var e = a.length;
+        0 > b && (b += e, 0 > b && (b = 0));
+        for (; b < e;) {
+            if (a[b] === c) return b;
+            b++
+        }
+        return -1
+    };
+    m.remove = function(a, c) {
+        var b = m.indexOf(a, c, 0);
+        if (-1 == b) return !1;
+        a.splice(b, 1);
+        return !0
+    };
+    m.iter = function(a) {
+        return {
+            cur: 0,
+            arr: a,
+            hasNext: function() {
+                return this.cur < this.arr.length
+            },
+            next: function() {
+                return this.arr[this.cur++]
+            }
+        }
+    };
+    var x =
+        function() {};
+    x.__name__ = !0;
+    x.exists = function(a, c) {
+        for (var b = B(a)(); b.hasNext();) {
+            var e = b.next();
+            if (c(e)) return !0
+        }
+        return !1
+    };
+    var A = function() {
+        this.length = 0
+    };
+    A.__name__ = !0;
+    A.prototype = {
+        h: null,
+        length: null,
+        iterator: function() {
+            return {
+                h: this.h,
+                hasNext: function() {
+                    return null != this.h
+                },
+                next: function() {
+                    if (null == this.h) return null;
+                    var a = this.h[0];
+                    this.h = this.h[1];
+                    return a
+                }
+            }
+        },
+        __class__: A
+    };
+    var g = n.MRP = function() {};
+    g.__name__ = !0;
+    g.setObject = function() {
+        eval("MRP.instance = document." + g.objectId + ";");
+        null == g.instance &&
+        (g.instance = document.getElementById(g.objectId))
+    };
+    g.setElementId = function(a) {
+        g.elementId = a
+    };
+    g.setObjectId = function(a) {
+        g.objectId = a;
+        g.setObject()
+    };
+    g.play = function() {
+        g.instance.playSound()
+    };
+    g.stop = function() {
+        g.instance.stopSound()
+    };
+    g.setVolume = function(a) {
+        g.instance.setVolume(a / 100)
+    };
+    g.showInfo = function(a) {
+        g.instance.showInfo(a)
+    };
+    g.setTitle = function(a) {
+        g.instance.setTitle(a)
+    };
+    g.setUrl = function(a) {
+        g.instance.setUrl(a)
+    };
+    g.setFallbackUrl = function(a) {
+        g.instance.setFallbackUrl(a)
+    };
+    g.setCallbackFunction =
+        function(a) {
+            musesCallback = a
+        };
+    g.callbackExists = function() {
+        var a = "error",
+            a = typeof musesCallback;
+        return "undefined" != a && "error" != a
+    };
+    g.getScriptBaseHREF = function() {
+        return ("https:" == window.document.location.protocol ? "https://" : "http://") + "hosted.muses.org"
+    };
+    g.getSkin = function(a, c) {
+        return -1 != a.indexOf("/") || c && ("original" == a || "tiny" == a) ? a : g.getScriptBaseHREF() + "/muses-" + a + ".xml"
+    };
+    g.insert = function(a) {
+        null == a.elementId && null != g.elementId && (a.elementId = g.elementId);
+        FlashDetect.versionAtLeast(10, 1) ? g.flashInsert(a) :
+            g.jsInsert(a)
+    };
+    g.jsInsert = function(a) {
+        a.autoplay = !1;
+        g.playerCounter++;
+        var c = "MusesRadioPlayer-HTML5-player-" + g.playerCounter,
+            b = '<div id="' + c + '" style="width:' + a.width + "px;height:" + a.height + 'px"></div>';
+        null == a.elementId ? window.document.write(b) : window.document.getElementById(a.elementId).innerHTML = b;
+        a.elementId = c;
+        a.skin = g.getSkin(a.skin, !1);
+        new d.Muses(a)
+    };
+    g.flashInsert = function(a) {
+        null == a.wmode && (a.wmode = "window");
+        null == a.id && (a.id = g.objectId);
+        var c = "url=" + a.url,
+            c = c + ("&lang=" + (null != a.lang ? a.lang :
+                    "auto")),
+            c = c + ("&codec=" + a.codec),
+            c = c + "&tracking=true" + ("&volume=" + (null != a.volume ? a.volume : 100));
+        null != a.introurl && (c += "&introurl=" + a.introurl);
+        null != a.autoplay && (c += "&autoplay=" + (a.autoplay ? "true" : "false"));
+        null != a.jsevents && (c += "&jsevents=" + (a.jsevents ? "true" : "false"));
+        null != a.buffering && (c += "&buffering=" + a.buffering);
+        null != a.metadataProxy && (c += "&metadataproxy=" + a.metadataProxy);
+        null != a.reconnectTime && (c += "&reconnecttime=" + a.reconnectTime);
+        null != a.fallbackUrl && (c += "&fallback=" + a.fallbackUrl);
+        var c =
+                c + ("&skin=" + g.getSkin(a.skin, !0)),
+            c = c + ("&title=" + a.title),
+            c = c + ("&welcome=" + a.welcome),
+            b = g.getScriptBaseHREF() + "/muses-hosted.swf",
+            e = 'width="' + a.width + '" height="' + a.height + '" ';
+        null != a.bgcolor && (e += 'bgcolor="' + a.bgcolor + '" ');
+        var f = '<object id="' + a.id + '" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" ' + e + ">",
+            f = f + ('<param name="movie" value="' + b + '" />') + ('<param name="flashvars" value="' + c + '" />'),
+            f = f + ('<param name="wmode" value="' + a.wmode + '" />'),
+            f = f + '<param name="allowScriptAccess" value="always" />',
+            f = f + '<param name="scale" value="noscale" />';
+        null != a.bgcolor && (f += '<param name="bgcolor" value="' + a.bgcolor + '" />');
+        f += '<embed name="' + a.id + '" src="' + b + '" flashvars="' + c + '" scale="noscale" wmode="' + a.wmode + '" ' + e + ' allowScriptAccess="always" type="application/x-shockwave-flash" />';
+        f += "</object>";
+        null != a.callbackFunction ? g.setCallbackFunction(a.callbackFunction) : 1 != a.jsevents || g.callbackExists() || g.setCallbackFunction(function(a, c) {});
+        null == a.elementId ? window.document.write(f) : window.document.getElementById(a.elementId).innerHTML =
+            f;
+        g.setObject()
+    };
+    g.main = function() {
+        g.getScriptBaseHREF()
+    };
+    var z = function() {};
+    z.__name__ = !0;
+    z.prototype = {
+        exists: null,
+        remove: null,
+        iterator: null,
+        __class__: z
+    };
+    Math.__name__ = !0;
+    var v = function() {};
+    v.__name__ = !0;
+    v.field = function(a, c) {
+        try {
+            return a[c]
+        } catch (b) {
+            return null
+        }
+    };
+    v.setField = function(a, c, b) {
+        a[c] = b
+    };
+    v.isFunction = function(a) {
+        return "function" == typeof a && !(a.__name__ || a.__ename__)
+    };
+    var y = function() {};
+    y.__name__ = !0;
+    y.string = function(a) {
+        return u.Boot.__string_rec(a, "")
+    };
+    y.parseInt = function(a) {
+        var c = parseInt(a,
+            10);
+        0 != c || 120 != m.cca(a, 1) && 88 != m.cca(a, 1) || (c = parseInt(a));
+        return isNaN(c) ? null : c
+    };
+    var C = function() {
+        this.b = ""
+    };
+    C.__name__ = !0;
+    C.prototype = {
+        b: null,
+        add: function(a) {
+            this.b += y.string(a)
+        },
+        addSub: function(a, c, b) {
+            this.b = null == b ? this.b + m.substr(a, c, null) : this.b + m.substr(a, c, b)
+        },
+        __class__: C
+    };
+    var t = function() {};
+    t.__name__ = !0;
+    t.urlEncode = function(a) {
+        return encodeURIComponent(a)
+    };
+    t.isSpace = function(a, c) {
+        var b = m.cca(a, c);
+        return 8 < b && 14 > b || 32 == b
+    };
+    t.ltrim = function(a) {
+        for (var c = a.length, b = 0; b < c && t.isSpace(a, b);) b++;
+        return 0 < b ? m.substr(a, b, c - b) : a
+    };
+    t.rtrim = function(a) {
+        for (var c = a.length, b = 0; b < c && t.isSpace(a, c - b - 1);) b++;
+        return 0 < b ? m.substr(a, 0, c - b) : a
+    };
+    t.trim = function(a) {
+        return t.ltrim(t.rtrim(a))
+    };
+    t.replace = function(a, c, b) {
+        return a.split(c).join(b)
+    };
+    t.fastCodeAt = function(a, c) {
+        return a.charCodeAt(c)
+    };
+    var D = function() {};
+    D.__name__ = !0;
+    D.getInstanceFields = function(a) {
+        var c = [],
+            b;
+        for (b in a.prototype) c.push(b);
+        m.remove(c, "__class__");
+        m.remove(c, "__properties__");
+        return c
+    };
+    var h = function() {};
+    h.__name__ = !0;
+    h.parse = function(a) {
+        return q.xml.Parser.parse(a)
+    };
+    h.createElement = function(a) {
+        var c = new h;
+        c.nodeType = h.Element;
+        c._children = [];
+        c._attributes = new q.ds.StringMap;
+        c.set_nodeName(a);
+        return c
+    };
+    h.createPCData = function(a) {
+        var c = new h;
+        c.nodeType = h.PCData;
+        c.set_nodeValue(a);
+        return c
+    };
+    h.createCData = function(a) {
+        var c = new h;
+        c.nodeType = h.CData;
+        c.set_nodeValue(a);
+        return c
+    };
+    h.createComment = function(a) {
+        var c = new h;
+        c.nodeType = h.Comment;
+        c.set_nodeValue(a);
+        return c
+    };
+    h.createDocType = function(a) {
+        var c = new h;
+        c.nodeType = h.DocType;
+        c.set_nodeValue(a);
+        return c
+    };
+    h.createProcessingInstruction =
+        function(a) {
+            var c = new h;
+            c.nodeType = h.ProcessingInstruction;
+            c.set_nodeValue(a);
+            return c
+        };
+    h.createDocument = function() {
+        var a = new h;
+        a.nodeType = h.Document;
+        a._children = [];
+        return a
+    };
+    h.prototype = {
+        nodeType: null,
+        _nodeName: null,
+        _nodeValue: null,
+        _attributes: null,
+        _children: null,
+        _parent: null,
+        get_nodeName: function() {
+            if (this.nodeType != h.Element) throw "bad nodeType";
+            return this._nodeName
+        },
+        set_nodeName: function(a) {
+            if (this.nodeType != h.Element) throw "bad nodeType";
+            return this._nodeName = a
+        },
+        set_nodeValue: function(a) {
+            if (this.nodeType ==
+                h.Element || this.nodeType == h.Document) throw "bad nodeType";
+            return this._nodeValue = a
+        },
+        get: function(a) {
+            if (this.nodeType != h.Element) throw "bad nodeType";
+            return this._attributes.get(a)
+        },
+        set: function(a, c) {
+            if (this.nodeType != h.Element) throw "bad nodeType";
+            this._attributes.set(a, c)
+        },
+        exists: function(a) {
+            if (this.nodeType != h.Element) throw "bad nodeType";
+            return this._attributes.exists(a)
+        },
+        attributes: function() {
+            if (this.nodeType != h.Element) throw "bad nodeType";
+            return this._attributes.keys()
+        },
+        elements: function() {
+            if (null ==
+                this._children) throw "bad nodetype";
+            return {
+                cur: 0,
+                x: this._children,
+                hasNext: function() {
+                    for (var a = this.cur, c = this.x.length; a < c && this.x[a].nodeType != h.Element;) a += 1;
+                    this.cur = a;
+                    return a < c
+                },
+                next: function() {
+                    for (var a = this.cur, c = this.x.length; a < c;) {
+                        var b = this.x[a],
+                            a = a + 1;
+                        if (b.nodeType == h.Element) return this.cur = a, b
+                    }
+                    return null
+                }
+            }
+        },
+        addChild: function(a) {
+            if (null == this._children) throw "bad nodetype";
+            null != a._parent && m.remove(a._parent._children, a);
+            a._parent = this;
+            this._children.push(a)
+        },
+        __class__: h
+    };
+    var b = {
+        Campaign: function(a) {
+            this.responseCount =
+                0;
+            "direct" != a && "organic" != a && "referral" != a && b.Tracker._raiseError("Campaign type has to be one of the Campaign::TYPE_* constant values.", "Campaign.new");
+            this.type = a;
+            switch (a) {
+                case "direct":
+                    this.source = this.name = "(direct)";
+                    this.medium = "(none)";
+                    break;
+                case "referral":
+                    this.name = "(referral)";
+                    this.medium = "referral";
+                    break;
+                case "organic":
+                    this.name = "(organic)", this.medium = "organic"
+            }
+            this.creationTime = new b.DateTime
+        }
+    };
+    b.Campaign.__name__ = !0;
+    b.Campaign.createFromReferrer = function(a) {
+        var c = new b.Campaign("referral");
+        a = new b.URLParser(a);
+        c.source = a.host;
+        c.content = a.path;
+        return c
+    };
+    b.Campaign.prototype = {
+        type: null,
+        creationTime: null,
+        responseCount: null,
+        id: null,
+        source: null,
+        gClickId: null,
+        dClickId: null,
+        name: null,
+        medium: null,
+        term: null,
+        content: null,
+        validate: function() {
+            null == this.source && b.Tracker._raiseError('Campaigns need to have at least the "source" attribute defined.', "Campaign.validate")
+        },
+        setType: function(a) {
+            this.type = a
+        },
+        getType: function() {
+            return this.type
+        },
+        setCreationTime: function(a) {
+            this.creationTime = a
+        },
+        getCreationTime: function() {
+            return this.creationTime
+        },
+        setResponseCount: function(a) {
+            this.responseCount = a
+        },
+        getResponseCount: function() {
+            return this.responseCount
+        },
+        increaseResponseCount: function(a) {
+            null == a && (a = 1);
+            this.responseCount += a
+        },
+        setId: function(a) {
+            this.id = a
+        },
+        getId: function() {
+            return this.id
+        },
+        setSource: function(a) {
+            this.source = a
+        },
+        getSource: function() {
+            return this.source
+        },
+        setGClickId: function(a) {
+            this.gClickId = a
+        },
+        getGClickId: function() {
+            return this.gClickId
+        },
+        setDClickId: function(a) {
+            this.dClickId = a
+        },
+        getDClickId: function() {
+            return this.dClickId
+        },
+        setName: function(a) {
+            this.name =
+                a
+        },
+        getName: function() {
+            return this.name
+        },
+        setMedium: function(a) {
+            this.medium = a
+        },
+        getMedium: function() {
+            return this.medium
+        },
+        setTerm: function(a) {
+            this.term = a
+        },
+        getTerm: function() {
+            return this.term
+        },
+        setContent: function(a) {
+            this.content = a
+        },
+        getContent: function() {
+            return this.content
+        },
+        __class__: b.Campaign
+    };
+    b.Config = function(a) {
+        null == a && (a = !1);
+        this.sitespeedSampleRate = 1;
+        this.endPointPath = "/__utm.gif";
+        this.endPointHost = "www.google-analytics.com";
+        this.urlScheme = "http";
+        this.requestTimeout = 1;
+        this.sendOnShutdown = this.fireAndForget = !1;
+        this.errorSeverity = 2;
+        this.setUrlScheme("http" + (a ? "s" : ""))
+    };
+    b.Config.__name__ = !0;
+    b.Config.prototype = {
+        errorSeverity: null,
+        sendOnShutdown: null,
+        fireAndForget: null,
+        loggingCallback: null,
+        requestTimeout: null,
+        urlScheme: null,
+        endPointHost: null,
+        endPointPath: null,
+        sitespeedSampleRate: null,
+        getErrorSeverity: function() {
+            return this.errorSeverity
+        },
+        setErrorSeverity: function(a) {
+            this.errorSeverity = a
+        },
+        getSendOnShutdown: function() {
+            return this.sendOnShutdown
+        },
+        setSendOnShutdown: function(a) {
+            this.sendOnShutdown = a
+        },
+        getFireAndForget: function() {
+            return this.fireAndForget
+        },
+        setFireAndForget: function(a) {
+            this.fireAndForget = a
+        },
+        getLoggingCallback: function() {
+            return this.loggingCallback
+        },
+        setLoggingCallback: function(a) {
+            this.loggingCallback = a
+        },
+        getRequestTimeout: function() {
+            return this.requestTimeout
+        },
+        setRequestTimeout: function(a) {
+            this.requestTimeout = a
+        },
+        getUrlScheme: function() {
+            return this.urlScheme
+        },
+        setUrlScheme: function(a) {
+            return this.urlScheme = a
+        },
+        getEndPointHost: function() {
+            return this.endPointHost
+        },
+        setEndPointHost: function(a) {
+            this.endPointHost = a
+        },
+        getEndPointPath: function() {
+            return this.endPointPath
+        },
+        setEndPointPath: function(a) {
+            this.endPointPath = a
+        },
+        getSitespeedSampleRate: function() {
+            return this.sitespeedSampleRate
+        },
+        setSitespeedSampleRate: function(a) {
+            0 > a || 100 < a ? b.Tracker._raiseError("For consistency with ga.js, sample rates must be specified as a number between 0 and 100.", "config.setSitespeedSampleRate") : this.sitespeedSampleRate = a
+        },
+        __class__: b.Config
+    };
+    b.CustomVariable = function(a, c, b, e) {
+        null == e && (e = 0);
+        null == a && (a = 0);
+        this.scope = 3;
+        0 != a && this.setIndex(a);
+        null != c && this.setName(c);
+        null != b && this.setValue(b);
+        0 != e && this.setScope(e)
+    };
+    b.CustomVariable.__name__ = !0;
+    b.CustomVariable.prototype = {
+        index: null,
+        name: null,
+        value: null,
+        scope: null,
+        validate: function() {
+            128 < (this.name + y.string(this.value)).length && b.Tracker._raiseError("Custom Variable combined name and value length must not be larger than 128 bytes.", "CustomVariable.validate")
+        },
+        getIndex: function() {
+            return this.index
+        },
+        setIndex: function(a) {
+            (1 > a || 5 < a) && b.Tracker._raiseError("Custom Variable index has to be between 1 and 5.", "CustomVariable.setIndex");
+            this.index =
+                a
+        },
+        getName: function() {
+            return this.name
+        },
+        setName: function(a) {
+            this.name = a
+        },
+        getValue: function() {
+            return this.value
+        },
+        setValue: function(a) {
+            this.value = a
+        },
+        getScope: function() {
+            return this.scope
+        },
+        setScope: function(a) {
+            3 != a && 2 != a && 1 != a && b.Tracker._raiseError("Custom Variable scope has to be one of the CustomVariable::SCOPE_* constant values.", "CustomVariable.setScope");
+            this.scope = a
+        },
+        __class__: b.CustomVariable
+    };
+    b.DateTime = function(a) {
+        this.date = null == a ? Math.round((new Date).getTime()) + "" : a
+    };
+    b.DateTime.__name__ = !0;
+    b.DateTime.prototype = {
+        date: null,
+        toString: function() {
+            return this.date
+        },
+        __class__: b.DateTime
+    };
+    b.Event = function(a, c, b, e, f) {
+        null == f && (f = !1);
+        null == e && (e = 0);
+        this.noninteraction = !1;
+        null != a && this.setCategory(a);
+        null != c && this.setAction(c);
+        null != b && this.setLabel(b);
+        this.setValue(e);
+        this.setNoninteraction(f)
+    };
+    b.Event.__name__ = !0;
+    b.Event.prototype = {
+        category: null,
+        action: null,
+        label: null,
+        value: null,
+        noninteraction: null,
+        validate: function() {
+            null != this.category && null != this.action || b.Tracker._raiseError("Events need at least to have a category and action defined.",
+                "Event.validate")
+        },
+        getCategory: function() {
+            return this.category
+        },
+        setCategory: function(a) {
+            this.category = a
+        },
+        getAction: function() {
+            return this.action
+        },
+        setAction: function(a) {
+            this.action = a
+        },
+        getLabel: function() {
+            return this.label
+        },
+        setLabel: function(a) {
+            this.label = a
+        },
+        getValue: function() {
+            return this.value
+        },
+        setValue: function(a) {
+            this.value = a
+        },
+        getNoninteraction: function() {
+            return this.noninteraction
+        },
+        setNoninteraction: function(a) {
+            this.noninteraction = a
+        },
+        __class__: b.Event
+    };
+    b.Item = function() {
+        this.quantity = 1
+    };
+    b.Item.__name__ = !0;
+    b.Item.prototype = {
+        orderId: null,
+        sku: null,
+        name: null,
+        variation: null,
+        price: null,
+        quantity: null,
+        validate: function() {
+            null == this.sku && b.Tracker._raiseError("Items need to have a sku/product code defined.", "Item.validate")
+        },
+        getOrderId: function() {
+            return this.orderId
+        },
+        setOrderId: function(a) {
+            this.orderId = a
+        },
+        getSku: function() {
+            return this.sku
+        },
+        setSku: function(a) {
+            this.sku = a
+        },
+        getName: function() {
+            return this.name
+        },
+        setName: function(a) {
+            this.name = a
+        },
+        getVariation: function() {
+            return this.variation
+        },
+        setVariation: function(a) {
+            this.variation =
+                a
+        },
+        getPrice: function() {
+            return this.price
+        },
+        setPrice: function(a) {
+            this.price = a
+        },
+        getQuantity: function() {
+            return this.quantity
+        },
+        setQuantity: function(a) {
+            this.quantity = a
+        },
+        __class__: b.Item
+    };
+    b.Page = function(a) {
+        this.setPath(a)
+    };
+    b.Page.__name__ = !0;
+    b.Page.prototype = {
+        path: null,
+        title: null,
+        charset: null,
+        referrer: null,
+        loadTime: null,
+        setPath: function(a) {
+            null != a && "/" != a.charAt(0) && b.Tracker._raiseError('The page path should always start with a slash ("/").', "Page.setPath");
+            this.path = a
+        },
+        getPath: function() {
+            return this.path
+        },
+        setTitle: function(a) {
+            this.title = a
+        },
+        getTitle: function() {
+            return this.title
+        },
+        setCharset: function(a) {
+            this.charset = a
+        },
+        getCharset: function() {
+            return this.charset
+        },
+        setReferrer: function(a) {
+            this.referrer = a
+        },
+        getReferrer: function() {
+            return this.referrer
+        },
+        setLoadTime: function(a) {
+            this.loadTime = a
+        },
+        getLoadTime: function() {
+            return this.loadTime
+        },
+        __class__: b.Page
+    };
+    b.Session = function() {
+        this.setSessionId(this.generateSessionId());
+        this.setTrackCount(0);
+        this.setStartTime(new b.DateTime)
+    };
+    b.Session.__name__ = !0;
+    b.Session.prototype = {
+        sessionId: null,
+        trackCount: null,
+        startTime: null,
+        fromUtmb: function(a) {
+            a = a.split(".");
+            if (4 != a.length) return b.Tracker._raiseError('The given "__utmb" cookie value is invalid.', "Session.fromUtmb"), this;
+            this.setTrackCount(b.internals.Util.parseInt(a[1], 0));
+            this.setStartTime(new b.DateTime(a[3]));
+            return this
+        },
+        generateSessionId: function() {
+            return b.internals.Util.generate32bitRandom()
+        },
+        getSessionId: function() {
+            return this.sessionId
+        },
+        setSessionId: function(a) {
+            this.sessionId = a
+        },
+        getTrackCount: function() {
+            return this.trackCount
+        },
+        setTrackCount: function(a) {
+            this.trackCount = a
+        },
+        increaseTrackCount: function(a) {
+            null == a && (a = 1);
+            this.trackCount += a
+        },
+        getStartTime: function() {
+            return this.startTime
+        },
+        setStartTime: function(a) {
+            this.startTime = a
+        },
+        __class__: b.Session
+    };
+    b.SocialInteraction = function(a, c, b) {
+        null != a && this.setNetwork(a);
+        null != c && this.setAction(c);
+        null != b && this.setTarget(b)
+    };
+    b.SocialInteraction.__name__ = !0;
+    b.SocialInteraction.prototype = {
+        network: null,
+        action: null,
+        target: null,
+        validate: function() {
+            null != this.network && null != this.action || b.Tracker._raiseError('Social interactions need to have at least the "network" and "action" attributes defined.',
+                "SocialInteraction.validate")
+        },
+        setNetwork: function(a) {
+            this.network = a
+        },
+        getNetwork: function() {
+            return this.network
+        },
+        setAction: function(a) {
+            this.action = a
+        },
+        getAction: function() {
+            return this.action
+        },
+        setTarget: function(a) {
+            this.target = a
+        },
+        getTarget: function() {
+            return this.target
+        },
+        __class__: b.SocialInteraction
+    };
+    b.Stats = function() {};
+    b.Stats.__name__ = !0;
+    b.Stats.init = function(a, c) {
+        null == b.Stats.accountId && (b.Stats.accountId = a, b.Stats.domainName = c, b.Stats.tracker = new b.Tracker(a, c), b.Stats.cache = new q.ds.StringMap,
+            b.Stats.session = new b.Session, b.Stats.loadVisitor())
+    };
+    b.Stats.trackPageview = function(a, c) {
+        var r = "page:" + a;
+        if (!b.Stats.cache.exists(r)) {
+            var e = new b.Page(a);
+            null != c && e.setTitle(c);
+            e = new b._Stats.GATrackObject(e, null);
+            b.Stats.cache.set(r, e)
+        }
+        b.Stats.track(r)
+    };
+    b.Stats.trackEvent = function(a, c, r, e) {
+        null == e && (e = 0);
+        var f = "event:" + a + "/" + c + "/" + r + ":" + e;
+        b.Stats.cache.exists(f) || (a = new b._Stats.GATrackObject(null, new b.Event(a, c, r, e)), b.Stats.cache.set(f, a));
+        b.Stats.track(f)
+    };
+    b.Stats.track = function(a) {
+        b.Stats.cache.get(a).track(b.Stats.tracker,
+            b.Stats.visitor, b.Stats.session);
+        b.Stats.persistVisitor()
+    };
+    b.Stats.loadVisitor = function() {
+        b.Stats.visitor = new b.Visitor;
+        b.Stats.visitor.setUserAgent("-not-set- [haxe]");
+        b.Stats.visitor.setScreenResolution("1024x768");
+        b.Stats.visitor.setLocale("en_US");
+        b.Stats.visitor.getUniqueId();
+        b.Stats.visitor.addSession(b.Stats.session);
+        b.Stats.persistVisitor()
+    };
+    b.Stats.persistVisitor = function() {};
+    b._Stats = {};
+    b._Stats.GATrackObject = function(a, c) {
+        this.page = a;
+        this.event = c
+    };
+    b._Stats.GATrackObject.__name__ = !0;
+    b._Stats.GATrackObject.prototype = {
+        event: null,
+        page: null,
+        track: function(a, c, b) {
+            null != this.page && a.trackPageview(this.page, b, c);
+            null != this.event && a.trackEvent(this.event, b, c)
+        },
+        __class__: b._Stats.GATrackObject
+    };
+    b.Tracker = function(a, c, r) {
+        this.allowHash = !0;
+        this.customVariables = [];
+        b.Tracker.setConfig(null != r ? r : new b.Config);
+        this.setAccountId(a);
+        this.setDomainName(c)
+    };
+    b.Tracker.__name__ = !0;
+    b.Tracker.getConfig = function() {
+        return b.Tracker.config
+    };
+    b.Tracker.setConfig = function(a) {
+        b.Tracker.config = a
+    };
+    b.Tracker._raiseError = function(a, c) {
+        a = c + "(): " +
+        a;
+        switch (null != b.Tracker.config ? b.Tracker.config.getErrorSeverity() : 0) {
+            case 1:
+                console.log(a);
+                break;
+            case 2:
+                throw a;
+        }
+    };
+    b.Tracker.prototype = {
+        accountId: null,
+        domainName: null,
+        allowHash: null,
+        customVariables: null,
+        campaign: null,
+        setAccountId: function(a) {
+            (new s("^(UA|MO)-[0-9]*-[0-9]*$", "")).match(a) || b.Tracker._raiseError('"' + a + '" is not a valid Google Analytics account ID.', "Tracker.setAccountId");
+            this.accountId = a
+        },
+        getAccountId: function() {
+            return this.accountId
+        },
+        setDomainName: function(a) {
+            this.domainName = a
+        },
+        getDomainName: function() {
+            return this.domainName
+        },
+        setAllowHash: function(a) {
+            this.allowHash = a
+        },
+        getAllowHash: function() {
+            return this.allowHash
+        },
+        addCustomVariable: function(a) {
+            a.validate();
+            this.customVariables[a.getIndex()] = a
+        },
+        getCustomVariables: function() {
+            return this.customVariables
+        },
+        removeCustomVariable: function(a) {
+            m.remove(this.customVariables, this.customVariables[a])
+        },
+        setCampaign: function(a) {
+            null != a && a.validate();
+            this.campaign = a
+        },
+        getCampaign: function() {
+            return this.campaign
+        },
+        trackPageview: function(a,
+                                c, r) {
+            var e = new b.internals.request.PageviewRequest(b.Tracker.config);
+            e.setPage(a);
+            e.setSession(c);
+            e.setVisitor(r);
+            e.setTracker(this);
+            e.send()
+        },
+        trackEvent: function(a, c, r) {
+            a.validate();
+            var e = new b.internals.request.EventRequest(b.Tracker.config);
+            e.setEvent(a);
+            e.setSession(c);
+            e.setVisitor(r);
+            e.setTracker(this);
+            e.send()
+        },
+        trackTransaction: function(a, c, r) {
+            a.validate();
+            var e = new b.internals.request.TransactionRequest(b.Tracker.config);
+            e.setTransaction(a);
+            e.setSession(c);
+            e.setVisitor(r);
+            e.setTracker(this);
+            e.send();
+            for (a = a.getItems().iterator(); a.hasNext();) {
+                e = a.next();
+                e.validate();
+                var f = new b.internals.request.ItemRequest(b.Tracker.config);
+                f.setItem(e);
+                f.setSession(c);
+                f.setVisitor(r);
+                f.setTracker(this);
+                f.send()
+            }
+        },
+        trackSocial: function(a, c, r, e) {
+            var f = new b.internals.request.SocialInteractionRequest(b.Tracker.config);
+            f.setSocialInteraction(a);
+            f.setPage(c);
+            f.setSession(r);
+            f.setVisitor(e);
+            f.setTracker(this);
+            f.send()
+        },
+        __class__: b.Tracker
+    };
+    b.Transaction = function() {
+        this.items = new q.ds.StringMap
+    };
+    b.Transaction.__name__ = !0;
+    b.Transaction.prototype = {
+        orderId: null,
+        affiliation: null,
+        total: null,
+        tax: null,
+        shipping: null,
+        city: null,
+        region: null,
+        country: null,
+        items: null,
+        validate: function() {
+            null == this.items && b.Tracker._raiseError("Transactions need to consist of at least one item.", "Transaction.validate")
+        },
+        addItem: function(a) {
+            a.setOrderId(this.orderId);
+            var c = a.getSku();
+            this.items.set(c, a)
+        },
+        getItems: function() {
+            return this.items
+        },
+        getOrderId: function() {
+            return this.orderId
+        },
+        setOrderId: function(a) {
+            this.orderId = a;
+            for (var c = this.items.iterator(); c.hasNext();) c.next().setOrderId(a)
+        },
+        getAffiliation: function() {
+            return this.affiliation
+        },
+        setAffiliation: function(a) {
+            this.affiliation = a
+        },
+        getTotal: function() {
+            return this.total
+        },
+        setTotal: function(a) {
+            this.total = a
+        },
+        getTax: function() {
+            return this.tax
+        },
+        setTax: function(a) {
+            this.tax = a
+        },
+        getShipping: function() {
+            return this.shipping
+        },
+        setShipping: function(a) {
+            this.shipping = a
+        },
+        getCity: function() {
+            return this.city
+        },
+        setCity: function(a) {
+            this.city = a
+        },
+        getRegion: function() {
+            return this.region
+        },
+        setRegion: function(a) {
+            this.region = a
+        },
+        getCountry: function() {
+            return this.country
+        },
+        setCountry: function(a) {
+            this.country = a
+        },
+        __class__: b.Transaction
+    };
+    b.URLParser = function(a) {
+        this.url = a;
+        var c = new s("^(?:(?![^:@]+:[^:@/]*@)([^:/?#.]+):)?(?://)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:/?#]*)(?::(\\d*))?)(((/(?:[^?#](?![^?#/]*\\.[^?#/.]+(?:[?#]|$)))*/?)?([^?#/]*))(?:\\?([^#]*))?(?:#(.*))?)", "");
+        c.match(a);
+        a = 0;
+        for (var r = b.URLParser.parts.length; a < r;) {
+            var e = a++;
+            v.setField(this, b.URLParser.parts[e], c.matched(e))
+        }
+    };
+    b.URLParser.__name__ = !0;
+    b.URLParser.parse = function(a) {
+        return new b.URLParser(a)
+    };
+    b.URLParser.prototype = {
+        url: null,
+        source: null,
+        protocol: null,
+        authority: null,
+        userInfo: null,
+        user: null,
+        password: null,
+        host: null,
+        port: null,
+        relative: null,
+        path: null,
+        directory: null,
+        file: null,
+        query: null,
+        anchor: null,
+        toString: function() {
+            for (var a = "For Url -> " + this.url + "\n", c = 0, r = b.URLParser.parts.length; c < r;) var e = c++,
+                a = a + (b.URLParser.parts[e] + ": " + y.string(v.field(this, b.URLParser.parts[e])) + (e == b.URLParser.parts.length - 1 ? "" : "\n"));
+            return a
+        },
+        __class__: b.URLParser
+    };
+    b.Visitor = function() {
+        var a = new b.DateTime;
+        this.uniqueId =
+            0;
+        this.setFirstVisitTime(a);
+        this.setPreviousVisitTime(a);
+        this.setCurrentVisitTime(a);
+        this.setVisitCount(1)
+    };
+    b.Visitor.__name__ = !0;
+    b.Visitor.prototype = {
+        uniqueId: null,
+        firstVisitTime: null,
+        previousVisitTime: null,
+        currentVisitTime: null,
+        visitCount: null,
+        ipAddress: null,
+        userAgent: null,
+        locale: null,
+        flashVersion: null,
+        javaEnabled: null,
+        screenColorDepth: null,
+        screenResolution: null,
+        fromUtma: function(a) {
+            a = a.split(".");
+            if (6 != a.length) return b.Tracker._raiseError('The given "__utma" cookie value is invalid.', "Visitor.fromUtma"),
+                this;
+            this.setUniqueId(b.internals.Util.parseInt(a[1], 0));
+            this.setFirstVisitTime(new b.DateTime(a[2]));
+            this.setPreviousVisitTime(new b.DateTime(a[3]));
+            this.setCurrentVisitTime(new b.DateTime(a[4]));
+            this.setVisitCount(b.internals.Util.parseInt(a[5], 0));
+            return this
+        },
+        generateHash: function() {
+            return b.internals.Util.generateHash(this.userAgent + this.screenResolution + this.screenColorDepth)
+        },
+        generateUniqueId: function() {
+            return (b.internals.Util.generate32bitRandom() ^ this.generateHash()) & 2147483647
+        },
+        setUniqueId: function(a) {
+            (0 >
+            a || 2147483647 < a) && b.Tracker._raiseError("Visitor unique ID has to be a 32-bit integer between 0 and 2147483647.", "Visitor.setUniqueId");
+            this.uniqueId = a
+        },
+        getUniqueId: function() {
+            0 == this.uniqueId && (this.uniqueId = this.generateUniqueId());
+            return this.uniqueId
+        },
+        addSession: function(a) {
+            a = a.getStartTime();
+            a != this.currentVisitTime && (this.previousVisitTime = this.currentVisitTime, this.currentVisitTime = a, ++this.visitCount)
+        },
+        setFirstVisitTime: function(a) {
+            this.firstVisitTime = a
+        },
+        getFirstVisitTime: function() {
+            return this.firstVisitTime
+        },
+        setPreviousVisitTime: function(a) {
+            this.previousVisitTime = a
+        },
+        getPreviousVisitTime: function() {
+            return this.previousVisitTime
+        },
+        setCurrentVisitTime: function(a) {
+            this.currentVisitTime = a
+        },
+        getCurrentVisitTime: function() {
+            return this.currentVisitTime
+        },
+        setVisitCount: function(a) {
+            this.visitCount = a
+        },
+        getVisitCount: function() {
+            return this.visitCount
+        },
+        setIpAddress: function(a) {
+            this.ipAddress = a
+        },
+        getIpAddress: function() {
+            return this.ipAddress
+        },
+        setUserAgent: function(a) {
+            this.userAgent = a
+        },
+        getUserAgent: function() {
+            return this.userAgent
+        },
+        setLocale: function(a) {
+            this.locale = a
+        },
+        getLocale: function() {
+            return this.locale
+        },
+        setFlashVersion: function(a) {
+            this.flashVersion = a
+        },
+        getFlashVersion: function() {
+            return this.flashVersion
+        },
+        setJavaEnabled: function(a) {
+            this.javaEnabled = a
+        },
+        getJavaEnabled: function() {
+            return this.javaEnabled
+        },
+        setScreenColorDepth: function(a) {
+            this.screenColorDepth = a
+        },
+        getScreenColorDepth: function() {
+            return this.screenColorDepth
+        },
+        setScreenResolution: function(a) {
+            this.screenResolution = a
+        },
+        getScreenResolution: function() {
+            return this.screenResolution
+        },
+        __class__: b.Visitor
+    };
+    b.internals = {};
+    b.internals.ParameterHolder = function() {
+        this.utmwv = "5.2.5";
+        this.utmr = this.utmcs = this.utmfl = this.utmje = "0"
+    };
+    b.internals.ParameterHolder.__name__ = !0;
+    b.internals.ParameterHolder.prototype = {
+        utmwv: null,
+        utmac: null,
+        utmhn: null,
+        utmvid: null,
+        utmt: null,
+        utms: null,
+        utmn: null,
+        utmcc: null,
+        utme: null,
+        utmni: null,
+        utmu: null,
+        utmp: null,
+        utmdt: null,
+        utmcs: null,
+        utmr: null,
+        utmip: null,
+        utmul: null,
+        utmfl: null,
+        utmje: null,
+        utmsc: null,
+        utmsr: null,
+        __utma: null,
+        utmhid: null,
+        __utmb: null,
+        __utmc: null,
+        utmipc: null,
+        utmipn: null,
+        utmipr: null,
+        utmiqt: null,
+        utmiva: null,
+        utmtid: null,
+        utmtst: null,
+        utmtto: null,
+        utmttx: null,
+        utmtsp: null,
+        utmtci: null,
+        utmtrg: null,
+        utmtco: null,
+        utmcn: null,
+        utmcr: null,
+        utmcid: null,
+        utmcsr: null,
+        utmgclid: null,
+        utmdclid: null,
+        utmccn: null,
+        utmcmd: null,
+        utmctr: null,
+        utmcct: null,
+        utmcvr: null,
+        __utmz: null,
+        utmsn: null,
+        utmsa: null,
+        utmsid: null,
+        __utmx: null,
+        __utmv: null,
+        toHashTable: function() {
+            for (var a = new q.ds.StringMap, c = 0, r = D.getInstanceFields(b.internals.ParameterHolder); c < r.length;) {
+                var e = r[c];
+                ++c;
+                if ("_" != e.charAt(0) &&
+                    !v.isFunction(v.field(this, e))) {
+                    var f = v.field(this, e);
+                    a.set(e, f)
+                }
+            }
+            return a
+        },
+        toQueryString: function() {
+            for (var a = "", c = 0, r = D.getInstanceFields(b.internals.ParameterHolder); c < r.length;) {
+                var e = r[c];
+                ++c;
+                "_" == e.charAt(0) || v.isFunction(v.field(this, e)) || null == v.field(this, e) || "null" == v.field(this, e) || (a += e + "=" + t.replace(y.string(v.field(this, e)) + "", "&", "%26") + "&")
+            }
+            return a
+        },
+        __class__: b.internals.ParameterHolder
+    };
+    b.internals.Util = function() {};
+    b.internals.Util.__name__ = !0;
+    b.internals.Util.encodeUriComponent =
+        function(a) {
+            return b.internals.Util.convertToUriComponentEncoding(t.urlEncode(a))
+        };
+    b.internals.Util.stringReplaceArray = function(a, c, b) {
+        for (var e = 0, f = c.length; e < f;) {
+            var d = e++;
+            null != c[d] && (a = t.replace(a + " ", c[d], b[d]))
+        }
+        return t.trim(a)
+    };
+    b.internals.Util.parseInt = function(a, c) {
+        return null == a ? c : y.parseInt(a)
+    };
+    b.internals.Util.convertToUriComponentEncoding = function(a) {
+        return b.internals.Util.stringReplaceArray(a, "!*'() +".split(""), "%21 %2A %27 %28 %29 %20 %20".split(" "))
+    };
+    b.internals.Util.generate32bitRandom =
+        function() {
+            return Math.round(2147483647 * Math.random())
+        };
+    b.internals.Util.generateHash = function(a) {
+        var c = 1,
+            b;
+        if (null != a && "" != a)
+            for (var c = 0, e = a.length - 1; 0 <= e;) b = m.cca(a, e), c = (c << 6 & 268435455) + b + (b << 14), b = c & 266338304, 0 != b && (c ^= b >> 21), e--;
+        return c
+    };
+    b.internals.X10 = function() {
+        this.projectData = new q.ds.StringMap;
+        this.KEY = "k";
+        this.VALUE = "v";
+        this.SET = ["k", "v"];
+        this.DELIM_BEGIN = "(";
+        this.DELIM_END = ")";
+        this.DELIM_SET = "*";
+        this.DELIM_NUM_VALUE = "!";
+        this.MINIMUM = 1;
+        this.ESCAPE_CHAR_MAP = new q.ds.StringMap;
+        this.ESCAPE_CHAR_MAP.set("'",
+            "'0");
+        this.ESCAPE_CHAR_MAP.set(")", "'1");
+        this.ESCAPE_CHAR_MAP.set("*", "'2");
+        this.ESCAPE_CHAR_MAP.set("!", "'3")
+    };
+    b.internals.X10.__name__ = !0;
+    b.internals.X10.prototype = {
+        projectData: null,
+        KEY: null,
+        VALUE: null,
+        SET: null,
+        DELIM_BEGIN: null,
+        DELIM_END: null,
+        DELIM_SET: null,
+        DELIM_NUM_VALUE: null,
+        ESCAPE_CHAR_MAP: null,
+        MINIMUM: null,
+        hasProject: function(a) {
+            return this.projectData.exists(a)
+        },
+        setKey: function(a, c, b) {
+            this.setInternal(a, this.KEY, c, b)
+        },
+        getKey: function(a, c) {
+            return this.getInternal(a, this.KEY, c)
+        },
+        clearKey: function(a) {
+            this.clearInternal(a,
+                this.KEY)
+        },
+        setValue: function(a, c, b) {
+            this.setInternal(a, this.VALUE, c, b)
+        },
+        getValue: function(a, c) {
+            return this.getInternal(a, this.VALUE, c)
+        },
+        clearValue: function(a) {
+            this.clearInternal(a, this.VALUE)
+        },
+        setInternal: function(a, c, b, e) {
+            if (!this.projectData.exists(a)) {
+                var f = new q.ds.StringMap;
+                this.projectData.set(a, f)
+            }
+            a = this.projectData.get(a);
+            a.exists(c) || a.set(c, []);
+            a.get(c)[b] = e
+        },
+        getInternal: function(a, c, b) {
+            if (!this.projectData.exists(a)) return null;
+            a = this.projectData.get(a);
+            if (!a.exists(c)) return null;
+            c = a.get(c);
+            return null == c[b] ? null : c[b]
+        },
+        clearInternal: function(a, c) {
+            var b;
+            if (b = this.projectData.exists(a)) b = this.projectData.get(a).exists(c);
+            b && this.projectData.get(a).remove(c)
+        },
+        escapeExtensibleValue: function(a) {
+            for (var c = "", b = 0, e = a.length; b < e;) var f = b++,
+                f = a.charAt(f),
+                c = this.ESCAPE_CHAR_MAP.exists(f) ? c + this.ESCAPE_CHAR_MAP.get(f) : c + f;
+            return c
+        },
+        SORT_NUMERIC: function(a, c) {
+            return a == c ? 0 : a > c ? 1 : -1
+        },
+        renderDataType: function(a) {
+            for (var c = [], b = 0, e = 0, f = a.length; e < f;) {
+                var d = e++,
+                    g = a[d];
+                if (null != g) {
+                    var k = "";
+                    d != this.MINIMUM &&
+                    d - 1 != b && (k += d, k += this.DELIM_NUM_VALUE);
+                    k += this.escapeExtensibleValue(g);
+                    c.push(k)
+                }
+                b = d
+            }
+            return this.DELIM_BEGIN + c.join(this.DELIM_SET) + this.DELIM_END
+        },
+        renderProject: function(a) {
+            for (var c = "", b = !1, e = 0, f = this.SET.length; e < f;) {
+                var d = e++;
+                a.exists(this.SET[d]) ? (b && (c += this.SET[d]), c += this.renderDataType(a.get(this.SET[d])), b = !1) : b = !0
+            }
+            return c
+        },
+        renderUrlString: function() {
+            for (var a = "", c = this.projectData.keys(); c.hasNext();) var b = c.next(),
+                a = a + (b + this.renderProject(this.projectData.get(b)));
+            return a
+        },
+        __class__: b.internals.X10
+    };
+    b.internals.request = {};
+    b.internals.request.Request = function(a) {
+        this.setConfig(null != a ? a : new b.Config)
+    };
+    b.internals.request.Request.__name__ = !0;
+    b.internals.request.Request.onError = function(a) {};
+    b.internals.request.Request.prototype = {
+        type: null,
+        config: null,
+        userAgent: null,
+        tracker: null,
+        visitor: null,
+        session: null,
+        getConfig: function() {
+            return this.config
+        },
+        setConfig: function(a) {
+            this.config = a
+        },
+        setUserAgent: function(a) {
+            this.userAgent = a
+        },
+        getTracker: function() {
+            return this.tracker
+        },
+        setTracker: function(a) {
+            this.tracker =
+                a
+        },
+        getVisitor: function() {
+            return this.visitor
+        },
+        setVisitor: function(a) {
+            this.visitor = a
+        },
+        getSession: function() {
+            return this.session
+        },
+        setSession: function(a) {
+            this.session = a
+        },
+        increaseTrackCount: function() {
+            this.session.increaseTrackCount();
+            500 < this.session.getTrackCount() && b.Tracker._raiseError("Google Analytics does not guarantee to process more than 500 requests per session.", "Request.buildHttpRequest");
+            null != this.tracker.getCampaign() && this.tracker.getCampaign().increaseResponseCount()
+        },
+        send: function() {
+            if (null !=
+                this.config.getEndPointHost()) {
+                var a = this.buildParameters();
+                null != this.visitor && (this.setUserAgent(this.visitor.getUserAgent()), a.utmvid = this.visitor.getUniqueId());
+                a = b.internals.Util.convertToUriComponentEncoding(a.toQueryString());
+                a = this.config.getUrlScheme() + "://" + this.config.getEndPointHost() + this.config.getEndPointPath() + "?" + a;
+                this.increaseTrackCount();
+                (new Image).src = a
+            }
+        },
+        getType: function() {
+            return null
+        },
+        buildParameters: function() {
+            var a = new b.internals.ParameterHolder;
+            a.utmac = this.tracker.getAccountId();
+            a.utmhn = this.tracker.getDomainName();
+            a.utmt = "" + this.getType();
+            a.utmn = b.internals.Util.generate32bitRandom();
+            a.utmip = this.visitor.getIpAddress();
+            a.utmhid = this.session.getSessionId();
+            a.utms = this.session.getTrackCount();
+            a = this.buildVisitorParameters(a);
+            a = this.buildCustomVariablesParameter(a);
+            a = this.buildCampaignParameters(a);
+            return a = this.buildCookieParameters(a)
+        },
+        buildVisitorParameters: function(a) {
+            null != this.visitor.getLocale() && (a.utmul = t.replace(this.visitor.getLocale(), "_", "-").toLowerCase());
+            null !=
+            this.visitor.getFlashVersion() && (a.utmfl = this.visitor.getFlashVersion());
+            this.visitor.getJavaEnabled() ? a.utmje = "1" : a.utmje = "0";
+            null != this.visitor.getScreenColorDepth() && (a.utmsc = this.visitor.getScreenColorDepth() + "-bit");
+            a.utmsr = this.visitor.getScreenResolution();
+            return a
+        },
+        buildCustomVariablesParameter: function(a) {
+            var c = this.tracker.getCustomVariables();
+            if (null == c) return a;
+            5 < c.length && b.Tracker._raiseError("The sum of all custom variables cannot exceed 5 in any given request.", "Request.buildCustomVariablesParameter");
+            var r = new b.internals.X10,
+                e, f;
+            r.clearKey("8");
+            r.clearKey("9");
+            r.clearKey("11");
+            for (var d = 0; d < c.length;) {
+                var g = c[d];
+                ++d;
+                e = b.internals.Util.encodeUriComponent(g.getName());
+                f = b.internals.Util.encodeUriComponent(g.getValue());
+                r.setKey("8", g.getIndex(), e);
+                r.setKey("9", g.getIndex(), f);
+                3 != g.getScope() && r.setKey("11", g.getIndex(), g.getScope())
+            }
+            c = r.renderUrlString();
+            null != c && (a.utme = null == a.utme ? c : a.utme + c);
+            return a
+        },
+        buildCookieParameters: function(a) {
+            var c = this.generateDomainHash();
+            a.__utma = c + ".";
+            a.__utma +=
+                this.visitor.getUniqueId() + ".";
+            a.__utma += this.visitor.getFirstVisitTime().toString() + ".";
+            a.__utma += this.visitor.getPreviousVisitTime().toString() + ".";
+            a.__utma += this.visitor.getCurrentVisitTime().toString() + ".";
+            a.__utma += this.visitor.getVisitCount();
+            a.__utmb = c + ".";
+            a.__utmb += this.session.getTrackCount() + ".";
+            a.__utmb += "10.";
+            a.__utmb += this.session.getStartTime().toString();
+            a.__utmc = c;
+            c = "__utma=" + a.__utma + ";";
+            null != a.__utmz && (c += "+__utmz=" + a.__utmz + ";");
+            null != a.__utmv && (c += "+__utmv=" + a.__utmv + ";");
+            a.utmcc =
+                c;
+            return a
+        },
+        buildCampaignParameters: function(a) {
+            var c = this.tracker.getCampaign();
+            if (null == c) return a;
+            a.__utmz = this.generateDomainHash() + ".";
+            a.__utmz += c.getCreationTime().toString() + ".";
+            a.__utmz += this.visitor.getVisitCount() + ".";
+            a.__utmz += c.getResponseCount() + ".";
+            c = "utmcid=" + c.getId() + "|utmcsr=" + c.getSource() + "|utmgclid=" + c.getGClickId() + "|utmdclid=" + c.getDClickId() + "|utmccn=" + c.getName() + "|utmcmd=" + c.getMedium() + "|utmctr=" + c.getTerm() + "|utmcct=" + c.getContent();
+            a.__utmz += t.replace(t.replace(c, "+",
+                "%20"), " ", "%20");
+            return a
+        },
+        generateDomainHash: function() {
+            var a = 1;
+            this.tracker.getAllowHash() && (a = b.internals.Util.generateHash(this.tracker.getDomainName()));
+            return a
+        },
+        __class__: b.internals.request.Request
+    };
+    b.internals.request.EventRequest = function(a) {
+        b.internals.request.Request.call(this, a)
+    };
+    b.internals.request.EventRequest.__name__ = !0;
+    b.internals.request.EventRequest.__super__ = b.internals.request.Request;
+    b.internals.request.EventRequest.prototype = w(b.internals.request.Request.prototype, {
+        event: null,
+        getType: function() {
+            return "event"
+        },
+        buildParameters: function() {
+            var a = b.internals.request.Request.prototype.buildParameters.call(this),
+                c = new b.internals.X10;
+            c.clearKey("5");
+            c.clearValue("5");
+            c.setKey("5", 1, this.event.getCategory());
+            c.setKey("5", 2, this.event.getAction());
+            null != this.event.getLabel() && c.setKey("5", 3, this.event.getLabel());
+            0 != this.event.getValue() && c.setValue("5", 1, this.event.getValue());
+            c = c.renderUrlString();
+            null != c && (a.utme = null == a.utme ? c : a.utme + c);
+            this.event.getNoninteraction() && (a.utmni =
+                1);
+            return a
+        },
+        getEvent: function() {
+            return this.event
+        },
+        setEvent: function(a) {
+            this.event = a
+        },
+        __class__: b.internals.request.EventRequest
+    });
+    b.internals.request.ItemRequest = function(a) {
+        b.internals.request.Request.call(this, a)
+    };
+    b.internals.request.ItemRequest.__name__ = !0;
+    b.internals.request.ItemRequest.__super__ = b.internals.request.Request;
+    b.internals.request.ItemRequest.prototype = w(b.internals.request.Request.prototype, {
+        item: null,
+        getType: function() {
+            return "item"
+        },
+        buildParameters: function() {
+            var a = b.internals.request.Request.prototype.buildParameters.call(this);
+            a.utmtid = this.item.getOrderId();
+            a.utmipc = this.item.getSku();
+            a.utmipn = this.item.getName();
+            a.utmiva = this.item.getVariation();
+            a.utmipr = this.item.getPrice();
+            a.utmiqt = this.item.getQuantity();
+            return a
+        },
+        buildVisitorParameters: function(a) {
+            return a
+        },
+        buildCustomVariablesParameter: function(a) {
+            return a
+        },
+        getItem: function() {
+            return this.item
+        },
+        setItem: function(a) {
+            this.item = a
+        },
+        __class__: b.internals.request.ItemRequest
+    });
+    b.internals.request.PageviewRequest = function(a) {
+        b.internals.request.Request.call(this, a)
+    };
+    b.internals.request.PageviewRequest.__name__ = !0;
+    b.internals.request.PageviewRequest.__super__ = b.internals.request.Request;
+    b.internals.request.PageviewRequest.prototype = w(b.internals.request.Request.prototype, {
+        page: null,
+        getType: function() {
+            return null
+        },
+        buildParameters: function() {
+            var a = b.internals.request.Request.prototype.buildParameters.call(this);
+            a.utmp = this.page.getPath();
+            a.utmdt = this.page.getTitle();
+            null != this.page.getCharset() && (a.utmcs = this.page.getCharset());
+            null != this.page.getReferrer() && (a.utmr = this.page.getReferrer());
+            0 != this.page.getLoadTime() &&
+            a.utmn % 100 < this.config.getSitespeedSampleRate() && (a.utme = null == a.utme ? "0" : a.utme + 0);
+            return a
+        },
+        getPage: function() {
+            return this.page
+        },
+        setPage: function(a) {
+            this.page = a
+        },
+        __class__: b.internals.request.PageviewRequest
+    });
+    b.internals.request.SocialInteractionRequest = function(a) {
+        b.internals.request.PageviewRequest.call(this, a)
+    };
+    b.internals.request.SocialInteractionRequest.__name__ = !0;
+    b.internals.request.SocialInteractionRequest.__super__ = b.internals.request.PageviewRequest;
+    b.internals.request.SocialInteractionRequest.prototype =
+        w(b.internals.request.PageviewRequest.prototype, {
+            socialInteraction: null,
+            getType: function() {
+                return "social"
+            },
+            buildParameters: function() {
+                var a = b.internals.request.PageviewRequest.prototype.buildParameters.call(this);
+                a.utmsn = this.socialInteraction.getNetwork();
+                a.utmsa = this.socialInteraction.getAction();
+                a.utmsid = this.socialInteraction.getTarget();
+                null == a.utmsid && (a.utmsid = this.page.getPath());
+                return a
+            },
+            getSocialInteraction: function() {
+                return this.socialInteraction
+            },
+            setSocialInteraction: function(a) {
+                this.socialInteraction =
+                    a
+            },
+            __class__: b.internals.request.SocialInteractionRequest
+        });
+    b.internals.request.TransactionRequest = function(a) {
+        b.internals.request.Request.call(this, a)
+    };
+    b.internals.request.TransactionRequest.__name__ = !0;
+    b.internals.request.TransactionRequest.__super__ = b.internals.request.Request;
+    b.internals.request.TransactionRequest.prototype = w(b.internals.request.Request.prototype, {
+        transaction: null,
+        getType: function() {
+            return "tran"
+        },
+        buildParameters: function() {
+            var a = b.internals.request.Request.prototype.buildParameters.call(this);
+            a.utmtid = this.transaction.getOrderId();
+            a.utmtst = this.transaction.getAffiliation();
+            a.utmtto = this.transaction.getTotal();
+            a.utmttx = this.transaction.getTax();
+            a.utmtsp = this.transaction.getShipping();
+            a.utmtci = this.transaction.getCity();
+            a.utmtrg = this.transaction.getRegion();
+            a.utmtco = this.transaction.getCountry();
+            return a
+        },
+        buildVisitorParameters: function(a) {
+            return a
+        },
+        buildCustomVariablesParameter: function(a) {
+            return a
+        },
+        getTransaction: function() {
+            return this.transaction
+        },
+        setTransaction: function(a) {
+            this.transaction =
+                a
+        },
+        __class__: b.internals.request.TransactionRequest
+    });
+    var q = {
+        Http: function(a) {
+            this.url = a;
+            this.headers = new A;
+            this.params = new A;
+            this.async = !0
+        }
+    };
+    q.Http.__name__ = !0;
+    q.Http.requestUrl = function(a) {
+        a = new q.Http(a);
+        a.async = !1;
+        var c = null;
+        a.onData = function(a) {
+            c = a
+        };
+        a.onError = function(a) {
+            throw a;
+        };
+        a.request(!1);
+        return c
+    };
+    q.Http.prototype = {
+        url: null,
+        responseData: null,
+        async: null,
+        postData: null,
+        headers: null,
+        params: null,
+        req: null,
+        request: function(a) {
+            var c = this;
+            c.responseData = null;
+            var b = this.req = u.Browser.createXMLHttpRequest(),
+                e = function(a) {
+                    if (4 == b.readyState) {
+                        var e;
+                        try {
+                            e = b.status
+                        } catch (f) {
+                            e = null
+                        }
+                        void 0 == e && (e = null);
+                        if (null != e) c.onStatus(e);
+                        if (null != e && 200 <= e && 400 > e) c.req = null, c.onData(c.responseData = b.responseText);
+                        else if (null == e) c.req = null, c.onError("Failed to connect or resolve host");
+                        else switch (e) {
+                                case 12029:
+                                    c.req = null;
+                                    c.onError("Failed to connect to host");
+                                    break;
+                                case 12007:
+                                    c.req = null;
+                                    c.onError("Unknown host");
+                                    break;
+                                default:
+                                    c.req = null, c.responseData = b.responseText, c.onError("Http Error #" + b.status)
+                            }
+                    }
+                };
+            this.async &&
+            (b.onreadystatechange = e);
+            var f = this.postData;
+            if (null != f) a = !0;
+            else
+                for (var d = this.params.iterator(); d.hasNext();) var g = d.next(),
+                    f = null == f ? "" : f + "&",
+                    f = f + (encodeURIComponent(g.param) + "=" + encodeURIComponent(g.value));
+            try {
+                if (a) b.open("POST", this.url, this.async);
+                else if (null != f) {
+                    var k = 1 >= this.url.split("?").length;
+                    b.open("GET", this.url + (k ? "?" : "&") + f, this.async);
+                    f = null
+                } else b.open("GET", this.url, this.async)
+            } catch (h) {
+                c.req = null;
+                this.onError(h.toString());
+                return
+            }!x.exists(this.headers, function(a) {
+                return "Content-Type" ==
+                    a.header
+            }) && a && null == this.postData && b.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
+            for (a = this.headers.iterator(); a.hasNext();) d = a.next(), b.setRequestHeader(d.header, d.value);
+            b.send(f);
+            this.async || e(null)
+        },
+        onData: function(a) {},
+        onError: function(a) {},
+        onStatus: function(a) {},
+        __class__: q.Http
+    };
+    q.Timer = function(a) {
+        var c = this;
+        this.id = setInterval(function() {
+            c.run()
+        }, a)
+    };
+    q.Timer.__name__ = !0;
+    q.Timer.delay = function(a, c) {
+        var b = new q.Timer(c);
+        b.run = function() {
+            b.stop();
+            a()
+        };
+        return b
+    };
+    q.Timer.prototype = {
+        id: null,
+        stop: function() {
+            null != this.id && (clearInterval(this.id), this.id = null)
+        },
+        run: function() {},
+        __class__: q.Timer
+    };
+    q.ds = {};
+    q.ds.StringMap = function() {
+        this.h = {}
+    };
+    q.ds.StringMap.__name__ = !0;
+    q.ds.StringMap.__interfaces__ = [z];
+    q.ds.StringMap.prototype = {
+        h: null,
+        set: function(a, c) {
+            this.h["$" + a] = c
+        },
+        get: function(a) {
+            return this.h["$" + a]
+        },
+        exists: function(a) {
+            return this.h.hasOwnProperty("$" + a)
+        },
+        remove: function(a) {
+            a = "$" + a;
+            if (!this.h.hasOwnProperty(a)) return !1;
+            delete this.h[a];
+            return !0
+        },
+        keys: function() {
+            var a = [],
+                c;
+            for (c in this.h) this.h.hasOwnProperty(c) && a.push(c.substr(1));
+            return m.iter(a)
+        },
+        iterator: function() {
+            return {
+                ref: this.h,
+                it: this.keys(),
+                hasNext: function() {
+                    return this.it.hasNext()
+                },
+                next: function() {
+                    var a = this.it.next();
+                    return this.ref["$" + a]
+                }
+            }
+        },
+        __class__: q.ds.StringMap
+    };
+    q.io = {};
+    q.io.Eof = function() {};
+    q.io.Eof.__name__ = !0;
+    q.io.Eof.prototype = {
+        toString: function() {
+            return "Eof"
+        },
+        __class__: q.io.Eof
+    };
+    q.xml = {};
+    q.xml.Parser = function() {};
+    q.xml.Parser.__name__ = !0;
+    q.xml.Parser.parse = function(a) {
+        var c = h.createDocument();
+        q.xml.Parser.doParse(a, 0, c);
+        return c
+    };
+    q.xml.Parser.doParse = function(a, c, b) {
+        null == c && (c = 0);
+        for (var e = null, f = 1, d = 1, g = null, k = 0, p = 0, n = 0, l = a.charCodeAt(c), s = new C; l == l;) {
+            switch (f) {
+                case 0:
+                    switch (l) {
+                        case 10:
+                        case 13:
+                        case 9:
+                        case 32:
+                            break;
+                        default:
+                            f = d;
+                            continue
+                    }
+                    break;
+                case 1:
+                    switch (l) {
+                        case 60:
+                            f = 0;
+                            d = 2;
+                            break;
+                        default:
+                            k = c;
+                            f = 13;
+                            continue
+                    }
+                    break;
+                case 13:
+                    60 == l ? (d = h.createPCData(s.b + m.substr(a, k, c - k)), s = new C, b.addChild(d), p++, f = 0, d = 2) : 38 == l && (s.addSub(a, k, c - k), f = 18, d = 13, k = c + 1);
+                    break;
+                case 17:
+                    93 == l && 93 == a.charCodeAt(c + 1) &&
+                    62 == a.charCodeAt(c + 2) && (f = h.createCData(m.substr(a, k, c - k)), b.addChild(f), p++, c += 2, f = 1);
+                    break;
+                case 2:
+                    switch (l) {
+                        case 33:
+                            if (91 == a.charCodeAt(c + 1)) {
+                                c += 2;
+                                if ("CDATA[" != m.substr(a, c, 6).toUpperCase()) throw "Expected <![CDATA[";
+                                c += 5;
+                                f = 17
+                            } else if (68 == a.charCodeAt(c + 1) || 100 == a.charCodeAt(c + 1)) {
+                                if ("OCTYPE" != m.substr(a, c + 2, 6).toUpperCase()) throw "Expected <!DOCTYPE";
+                                c += 8;
+                                f = 16
+                            } else {
+                                if (45 != a.charCodeAt(c + 1) || 45 != a.charCodeAt(c + 2)) throw "Expected \x3c!--";
+                                c += 2;
+                                f = 15
+                            }
+                            k = c + 1;
+                            break;
+                        case 63:
+                            f = 14;
+                            k = c;
+                            break;
+                        case 47:
+                            if (null ==
+                                b) throw "Expected node name";
+                            k = c + 1;
+                            f = 0;
+                            d = 10;
+                            break;
+                        default:
+                            f = 3;
+                            k = c;
+                            continue
+                    }
+                    break;
+                case 3:
+                    if (!(97 <= l && 122 >= l || 65 <= l && 90 >= l || 48 <= l && 57 >= l || 58 == l || 46 == l || 95 == l || 45 == l)) {
+                        if (c == k) throw "Expected node name";
+                        e = h.createElement(m.substr(a, k, c - k));
+                        b.addChild(e);
+                        f = 0;
+                        d = 4;
+                        continue
+                    }
+                    break;
+                case 4:
+                    switch (l) {
+                        case 47:
+                            f = 11;
+                            p++;
+                            break;
+                        case 62:
+                            f = 9;
+                            p++;
+                            break;
+                        default:
+                            f = 5;
+                            k = c;
+                            continue
+                    }
+                    break;
+                case 5:
+                    if (!(97 <= l && 122 >= l || 65 <= l && 90 >= l || 48 <= l && 57 >= l || 58 == l || 46 == l || 95 == l || 45 == l)) {
+                        if (k == c) throw "Expected attribute name";
+                        g = m.substr(a,
+                            k, c - k);
+                        if (e.exists(g)) throw "Duplicate attribute";
+                        f = 0;
+                        d = 6;
+                        continue
+                    }
+                    break;
+                case 6:
+                    switch (l) {
+                        case 61:
+                            f = 0;
+                            d = 7;
+                            break;
+                        default:
+                            throw "Expected =";
+                    }
+                    break;
+                case 7:
+                    switch (l) {
+                        case 34:
+                        case 39:
+                            f = 8;
+                            k = c;
+                            break;
+                        default:
+                            throw 'Expected "';
+                    }
+                    break;
+                case 8:
+                    l == a.charCodeAt(k) && (d = m.substr(a, k + 1, c - k - 1), e.set(g, d), f = 0, d = 4);
+                    break;
+                case 9:
+                    k = c = q.xml.Parser.doParse(a, c, e);
+                    f = 1;
+                    break;
+                case 11:
+                    switch (l) {
+                        case 62:
+                            f = 1;
+                            break;
+                        default:
+                            throw "Expected >";
+                    }
+                    break;
+                case 12:
+                    switch (l) {
+                        case 62:
+                            return 0 == p && b.addChild(h.createPCData("")), c;
+                        default:
+                            throw "Expected >";
+                    }
+                case 10:
+                    if (!(97 <= l && 122 >= l || 65 <= l && 90 >= l || 48 <= l && 57 >= l || 58 == l || 46 == l || 95 == l || 45 == l)) {
+                        if (k == c) throw "Expected node name";
+                        if (m.substr(a, k, c - k) != b.get_nodeName()) throw "Expected </" + b.get_nodeName() + ">";
+                        f = 0;
+                        d = 12;
+                        continue
+                    }
+                    break;
+                case 15:
+                    45 == l && 45 == a.charCodeAt(c + 1) && 62 == a.charCodeAt(c + 2) && (b.addChild(h.createComment(m.substr(a, k, c - k))), c += 2, f = 1);
+                    break;
+                case 16:
+                    91 == l ? n++ : 93 == l ? n-- : 62 == l && 0 == n && (b.addChild(h.createDocType(m.substr(a, k, c - k))), f = 1);
+                    break;
+                case 14:
+                    63 == l && 62 == a.charCodeAt(c + 1) && (c++, f = m.substr(a,
+                        k + 1, c - k - 2), b.addChild(h.createProcessingInstruction(f)), f = 1);
+                    break;
+                case 18:
+                    59 == l && (k = m.substr(a, k, c - k), 35 == k.charCodeAt(0) ? (k = 120 == k.charCodeAt(1) ? y.parseInt("0" + m.substr(k, 1, k.length - 1)) : y.parseInt(m.substr(k, 1, k.length - 1)), s.add(String.fromCharCode(k))) : q.xml.Parser.escapes.exists(k) ? s.add(q.xml.Parser.escapes.get(k)) : s.b += y.string("&" + k + ";"), k = c + 1, f = d)
+            }
+            l = t.fastCodeAt(a, ++c)
+        }
+        1 == f && (k = c, f = 13);
+        if (13 == f) return c == k && 0 != p || b.addChild(h.createPCData(s.b + m.substr(a, k, c - k))), c;
+        throw "Unexpected end";
+    };
+    var u = {
+        Boot: function() {}
+    };
+    u.Boot.__name__ = !0;
+    u.Boot.getClass = function(a) {
+        return a instanceof Array && null == a.__enum__ ? Array : a.__class__
+    };
+    u.Boot.__string_rec = function(a, c) {
+        if (null == a) return "null";
+        if (5 <= c.length) return "<...>";
+        var b = typeof a;
+        "function" == b && (a.__name__ || a.__ename__) && (b = "object");
+        switch (b) {
+            case "object":
+                if (a instanceof Array) {
+                    if (a.__enum__) {
+                        if (2 == a.length) return a[0];
+                        b = a[0] + "(";
+                        c += "\t";
+                        for (var e = 2, d = a.length; e < d;) var g = e++,
+                            b = 2 != g ? b + ("," + u.Boot.__string_rec(a[g], c)) : b + u.Boot.__string_rec(a[g],
+                                c);
+                        return b + ")"
+                    }
+                    b = a.length;
+                    e = "[";
+                    c += "\t";
+                    for (d = 0; d < b;) g = d++, e += (0 < g ? "," : "") + u.Boot.__string_rec(a[g], c);
+                    return e + "]"
+                }
+                try {
+                    e = a.toString
+                } catch (h) {
+                    return "???"
+                }
+                if (null != e && e != Object.toString && (b = a.toString(), "[object Object]" != b)) return b;
+                b = null;
+                e = "{\n";
+                c += "\t";
+                d = null != a.hasOwnProperty;
+                for (b in a) d && !a.hasOwnProperty(b) || "prototype" == b || "__class__" == b || "__super__" == b || "__interfaces__" == b || "__properties__" == b || (2 != e.length && (e += ", \n"), e += c + b + " : " + u.Boot.__string_rec(a[b], c));
+                c = c.substring(1);
+                return e +
+                    ("\n" + c + "}");
+            case "function":
+                return "<function>";
+            case "string":
+                return a;
+            default:
+                return String(a)
+        }
+    };
+    u.Boot.__interfLoop = function(a, c) {
+        if (null == a) return !1;
+        if (a == c) return !0;
+        var b = a.__interfaces__;
+        if (null != b)
+            for (var e = 0, d = b.length; e < d;) {
+                var g = e++,
+                    g = b[g];
+                if (g == c || u.Boot.__interfLoop(g, c)) return !0
+            }
+        return u.Boot.__interfLoop(a.__super__, c)
+    };
+    u.Boot.__instanceof = function(a, c) {
+        if (null == c) return !1;
+        switch (c) {
+            case H:
+                return (a | 0) === a;
+            case E:
+                return "number" == typeof a;
+            case F:
+                return "boolean" == typeof a;
+            case String:
+                return "string" ==
+                    typeof a;
+            case Array:
+                return a instanceof Array && null == a.__enum__;
+            case I:
+                return !0;
+            default:
+                if (null != a) {
+                    if ("function" == typeof c && (a instanceof c || u.Boot.__interfLoop(u.Boot.getClass(a), c))) return !0
+                } else return !1;
+                return c == J && null != a.__name__ || c == K && null != a.__ename__ ? !0 : a.__enum__ == c
+        }
+    };
+    u.Browser = function() {};
+    u.Browser.__name__ = !0;
+    u.Browser.createXMLHttpRequest = function() {
+        if ("undefined" != typeof XMLHttpRequest) return new XMLHttpRequest;
+        if ("undefined" != typeof ActiveXObject) return new ActiveXObject("Microsoft.XMLHTTP");
+        throw "Unable to create XMLHttpRequest object.";
+    };
+    var d = {};
+    d.Muses = n.muses.Muses = function(a) {
+        this.src = this.name = this.lastMessage = null;
+        this.progress = 0;
+        this.lastAudioName = null;
+        this.playURL = "";
+        this.playTimeout = this.bufferingTimeout = 0;
+        this.desiredStatus = "stop";
+        this.audio = this.lastAudioStatus = this.lastAudioSrc = null;
+        this.src = a.url;
+        this.name = a.title;
+        this.audio = new Audio;
+        this.ui = new d.UI(this, a);
+        a.autoplay && (a = window.navigator.userAgent.toLowerCase(), -1 == a.indexOf("iphone") && -1 == a.indexOf("ipad") && -1 == a.indexOf("ipod") &&
+        this.playAudio())
+    };
+    d.Muses.__name__ = !0;
+    d.Muses.initTimer = function(a) {
+        -1 == m.indexOf(d.Muses.instances, a, 0) && d.Muses.instances.push(a);
+        null == d.Muses.statusTimer && (d.Muses.statusTimer = new q.Timer(500), d.Muses.statusTimer.run = function() {
+            for (var a = 0, b = d.Muses.instances; a < b.length;) {
+                var e = b[a];
+                ++a;
+                try {
+                    e.checkAudioStatus()
+                } catch (f) {
+                    if (u.Boot.__instanceof(f, String)) console.log("Error: " + f);
+                    else throw f;
+                }
+            }
+        })
+    };
+    d.Muses.prototype = {
+        audio: null,
+        lastAudioStatus: null,
+        lastAudioSrc: null,
+        desiredStatus: null,
+        playTimeout: null,
+        bufferingTimeout: null,
+        playURL: null,
+        lastAudioName: null,
+        progress: null,
+        src: null,
+        name: null,
+        lastMessage: null,
+        ui: null,
+        playAudio: function() {
+            d.Muses.initTimer(this);
+            this.stopAudio(!1);
+            this.playURL = this.src;
+            this.desiredStatus = "play";
+            this.playTimeout = 3600;
+            this.bufferingTimeout = 40;
+            this.lastAudioSrc = this.audio.src = this.src;
+            this.lastAudioName = this.name;
+            this.lastAudioStatus = null;
+            this.audio.autoplay = !0;
+            this.audio.play();
+            this.ui.setPlaying();
+            d.Tracker.track(this.src, this.name, this.ui, !0)
+        },
+        stopAudio: function(a) {
+            this.desiredStatus =
+                "stop";
+            null != this.audio && (this.audio.pause(), this.audio.src = "");
+            a && (this.lastAudioStatus = 4)
+        },
+        retryAudio: function() {
+            var a = this;
+            this.lastAudioStatus = -1;
+            q.Timer.delay(function() {
+                -1 == a.lastAudioStatus && a.playAudio()
+            }, 2E3)
+        },
+        setVolume: function(a) {
+            this.audio.volume = a;
+            null != this.ui && this.ui.setVolume(a)
+        },
+        checkAudioStatus: function() {
+            var a = "",
+                a = null;
+            if (null != this.audio) {
+                a = this.audio.networkState;
+                y.string(this.audio.error);
+                if (2 == a || 1 == a) a = 0 == this.audio.played.length ? 1 : 2;
+                if (null != this.audio.error || 4 == this.lastAudioStatus) a =
+                    3
+            }
+            0 == a ? (a = "Error al conectar", this.lastMessage != a && this.ui.setError()) : -1 == a ? a = "retry..." : null == a ? a = "init" : 1 == a ? (this.bufferingTimeout--, 0 == this.bufferingTimeout && this.retryAudio(), a = "Buffering... " + Math.round(this.bufferingTimeout / 2), this.lastMessage != a && this.ui.setBuffering()) : 2 == a ? (this.playTimeout--, 0 == this.playTimeout && this.retryAudio(), a = "Playing... ", this.lastMessage != a && this.ui.setPlaying()) : 4 == a || 3 == a ? "play" == this.desiredStatus ? (a = "Error de red", this.retryAudio(), this.lastMessage != a && this.ui.setError()) :
+                (a = "Stopped.", this.lastMessage != a && this.ui.setStopped()) : (a = "ERROR: " + a, console.log(a));
+            this.lastMessage = a
+        },
+        __class__: d.Muses
+    };
+    d.Tracker = function() {};
+    d.Tracker.__name__ = !0;
+    d.Tracker.track = function(a, c, g, e) {
+        d.Tracker.enabled && (null == d.Tracker.tracked && (d.Tracker.tracked = new q.ds.StringMap, b.Stats.init("UA-12297597-1", "hosted.musesradioplayer.com")), e && d.Tracker.tracked.get(a) || (b.Stats.trackPageview("/tracker/track.php?version=0.2 beta&url=" + a + "&player=HTML5&skin=" + g.skin, "Muses - HTML5 Tracking [Radio: " +
+        c + "]"), d.Tracker.tracked.set(a, !0)))
+    };
+    d.UI = n.muses.UI = function(a, c) {
+        this.skinFolder = this.baseURL = this.skinDomain = "";
+        this.togglePlayStopEnabled = this.lastToggleValue = !1;
+        this.mainDiv = this.playButton = this.stopButton = this.volumeControl = this.bg = this.statusText = this.artistText = this.songTitleText = this.statusLed = null;
+        this.skin = "";
+        var b = this;
+        this.title = c.title;
+        this.skin = c.skin;
+        this.muses = a;
+        this.mainDiv = window.document.getElementById(c.elementId);
+        this.mainDiv.style.position = "relative";
+        this.statusText = new d.skin.TitleText(this);
+        this.artistText = new d.skin.TitleText(this);
+        this.songTitleText = new d.skin.TitleText(this);
+        this.statusLed = new d.skin.StatusLed(this);
+        this.volumeControl = new d.skin.VolumeControl(this, this.muses);
+        this.volumeControl.setVolume(c.volume / 100);
+        this.playButton = new d.skin.Button(this, "play");
+        this.stopButton = new d.skin.Button(this, "stop");
+        this.loadSkin(this.skin);
+        this.statusLed.configured && this.mainDiv.appendChild(this.statusLed.container);
+        this.statusText.configured && this.mainDiv.appendChild(this.statusText.container);
+        this.artistText.configured && this.mainDiv.appendChild(this.artistText.container);
+        this.songTitleText.configured && this.mainDiv.appendChild(this.songTitleText.container);
+        this.volumeControl.configured && this.mainDiv.appendChild(this.volumeControl.container);
+        this.mainDiv.appendChild(this.playButton.container);
+        this.mainDiv.appendChild(this.stopButton.container);
+        this.stopButton.container.onclick = function(a) {
+            b.muses.stopAudio(!1)
+        };
+        this.playButton.container.onclick = function(a) {
+            b.muses.playAudio()
+        };
+        this.showInfo(c.welcome)
+    };
+    d.UI.__name__ = !0;
+    d.UI.parseInt = function(a, c) {
+        return null == a ? c : y.parseInt(a)
+    };
+    d.UI.prototype = {
+        skin: null,
+        mainDiv: null,
+        playButton: null,
+        stopButton: null,
+        volumeControl: null,
+        bg: null,
+        statusText: null,
+        artistText: null,
+        songTitleText: null,
+        statusLed: null,
+        togglePlayStopEnabled: null,
+        lastToggleValue: null,
+        skinFolder: null,
+        baseURL: null,
+        skinDomain: null,
+        title: null,
+        titleTimer: null,
+        muses: null,
+        XmlToLower: function(a) {
+            for (var c = a.attributes(); c.hasNext();) {
+                var b = c.next();
+                a.set(b.toLowerCase(), a.get(b))
+            }
+        },
+        enablePlayStopToggle: function() {
+            this.togglePlayStopEnabled = !0;
+            this.togglePlayStop(this.lastToggleValue)
+        },
+        togglePlayStop: function(a) {
+            this.lastToggleValue = a;
+            this.togglePlayStopEnabled && (this.playButton.setVisible(!a), this.stopButton.setVisible(a))
+        },
+        makeAbsolute: function(a) {
+            return -1 != a.indexOf("://") ? a : "/" == a.charAt(0) ? this.skinDomain + a : this.baseURL + a
+        },
+        getDomainName: function(a) {
+            a += "/";
+            var c = a.indexOf("://");
+            if (-1 == c) return "";
+            c = a.indexOf("/", c + 3);
+            return m.substr(a, 0, c)
+        },
+        getDirName: function(a) {
+            var c = a.lastIndexOf("/");
+            return -1 == c ? "" : m.substr(a, 0, c + 1)
+        },
+        loadSkin: function(a) {
+            var c =
+                q.Http.requestUrl(a);
+            this.baseURL = this.getDirName(a);
+            this.skinDomain = this.getDomainName(a);
+            a = !1;
+            for (c = h.parse(c).elements(); c.hasNext();) {
+                var b = c.next();
+                if ("ffmp3-skin" != b.get_nodeName().toLowerCase() && "muses-skin" != b.get_nodeName().toLowerCase()) break;
+                this.XmlToLower(b);
+                null == b.get("folder") ? this.skinFolder = "" : this.skinFolder = b.get("folder");
+                (a = null == b.get("toggleplaystop") ? !1 : "true" == b.get("toggleplaystop")) && this.enablePlayStopToggle();
+                0 < this.skinFolder.length && "/" != this.skinFolder.charAt(this.skinFolder.length -
+                1) && (this.skinFolder += "/");
+                this.skinFolder = this.makeAbsolute(this.skinFolder);
+                for (a = b.elements(); a.hasNext();) switch (b = a.next(), this.XmlToLower(b), b.get_nodeName().toLowerCase()) {
+                    case "bg":
+                        this.configureBG(b);
+                        break;
+                    case "play":
+                        this.playButton.configure(b);
+                        break;
+                    case "stop":
+                        this.stopButton.configure(b);
+                        break;
+                    case "text":
+                        this.statusText.configureText(b, "left");
+                        break;
+                    case "status":
+                        this.statusLed.configure(b);
+                        break;
+                    case "volume":
+                        this.volumeControl.configure(b);
+                        break;
+                    case "artist":
+                        this.artistText.configureText(b,
+                            "left");
+                        break;
+                    case "songtitle":
+                        this.songTitleText.configureText(b, "left")
+                }
+            }
+        },
+        loadImage: function(a, c) {
+            a.src = this.skinFolder + c
+        },
+        configureBG: function(a) {
+            this.bg = new Image;
+            this.loadImage(this.bg, a.get("image"));
+            this.bg.style.position = "absolute";
+            this.bg.style.left = d.UI.parseInt(a.get("x"), 0) + "px";
+            this.bg.style.top = d.UI.parseInt(a.get("y"), 0) + "px";
+            this.mainDiv.appendChild(this.bg)
+        },
+        configureButton: function(a, c) {
+            a.src = this.skinFolder + c.get("image");
+            a.style.position = "absolute";
+            a.style.left = d.UI.parseInt(c.get("x"),
+                0) + "px";
+            a.style.top = d.UI.parseInt(c.get("y"), 0) + "px"
+        },
+        setPlaying: function() {
+            this.showInfo("Play");
+            this.statusLed.on();
+            this.togglePlayStop(!0)
+        },
+        setStopped: function() {
+            this.showInfo("Stop");
+            this.statusLed.off();
+            this.togglePlayStop(!1)
+        },
+        setBuffering: function() {
+            this.showInfo("Buffering");
+            this.statusLed.on();
+            this.togglePlayStop(!0)
+        },
+        setError: function() {
+            this.showInfo("Error");
+            this.statusLed.off()
+        },
+        setVolume: function(a) {
+            this.volumeControl.setVolume(a);
+            this.showInfo("Volume: " + Math.round(100 * a) + "%")
+        },
+        showInfo: function(a,
+                           c) {
+            null == c && (c = !0);
+            null == a ? this.restoreTitle() : (null != this.titleTimer && this.titleTimer.stop(), this.statusText.setText(a), c && (this.titleTimer = new q.Timer(2E3), this.titleTimer.run = p(this, this.restoreTitle)))
+        },
+        restoreTitle: function() {
+            null != this.titleTimer && this.titleTimer.stop();
+            this.statusText.setText(this.title)
+        },
+        __class__: d.UI
+    };
+    d.skin = {};
+    d.skin.UIComponent = function(a) {
+        this.ui = a;
+        this.configured = !1;
+        this.container = window.document.createElement("div");
+        this.container.style.position = "absolute"
+    };
+    d.skin.UIComponent.__name__ = !0;
+    d.skin.UIComponent.prototype = {
+        container: null,
+        configured: null,
+        ui: null,
+        setVisible: function(a) {
+            this.container.style.display = a ? "block" : "none"
+        },
+        configure: function(a) {
+            this.configured = !0;
+            this.container.style.left = d.UI.parseInt(a.get("x"), 0) + "px";
+            this.container.style.top = d.UI.parseInt(a.get("y"), 0) + "px";
+            null != a.get("width") && (this.container.style.width = d.UI.parseInt(a.get("width"), 0) + "px");
+            null != a.get("height") && (this.container.style.height = d.UI.parseInt(a.get("height"), 0) + "px")
+        },
+        appendChild: function(a,
+                              c) {
+            null == c && (c = !0);
+            a.style.position = "absolute";
+            a.style.left = a.style.top = "0px";
+            a.style.display = c ? "block" : "none";
+            this.container.appendChild(a)
+        },
+        __class__: d.skin.UIComponent
+    };
+    d.skin.Button = function(a, c) {
+        var b = this;
+        d.skin.UIComponent.call(this, a);
+        this.mouseOverState = new Image;
+        this.mouseDownState = new Image;
+        this.noMouseState = new Image;
+        this.container.title = c;
+        this.mouseDownState.style.opacity = "0";
+        this.mouseOverState.style.opacity = "0";
+        this.container.onmouseup = function(a) {
+            b.mouseDownState.style.opacity = "0";
+            b.mouseOverState.style.opacity = "1"
+        };
+        this.container.onmousedown = function(a) {
+            b.mouseDownState.style.opacity = "1";
+            b.mouseOverState.style.opacity = "0"
+        };
+        this.container.onmouseover = function(a) {
+            b.mouseOverState.style.opacity = "1"
+        };
+        this.container.onmouseout = function(a) {
+            b.mouseDownState.style.opacity = "0";
+            b.mouseOverState.style.opacity = "0"
+        }
+    };
+    d.skin.Button.__name__ = !0;
+    d.skin.Button.__super__ = d.skin.UIComponent;
+    d.skin.Button.prototype = w(d.skin.UIComponent.prototype, {
+        mouseOverState: null,
+        mouseDownState: null,
+        noMouseState: null,
+        configure: function(a) {
+            d.skin.UIComponent.prototype.configure.call(this, a);
+            null != a.get("bgimage") && (this.ui.loadImage(this.noMouseState, a.get("bgimage")), this.appendChild(this.noMouseState));
+            null != a.get("clickimage") && (this.ui.loadImage(this.mouseDownState, a.get("clickimage")), this.appendChild(this.mouseDownState));
+            this.ui.loadImage(this.mouseOverState, a.get("image"));
+            this.appendChild(this.mouseOverState)
+        },
+        __class__: d.skin.Button
+    });
+    d.skin.StatusLed = function(a) {
+        d.skin.UIComponent.call(this, a);
+        this.playMC =
+            new Image;
+        this.stopMC = new Image
+    };
+    d.skin.StatusLed.__name__ = !0;
+    d.skin.StatusLed.__super__ = d.skin.UIComponent;
+    d.skin.StatusLed.prototype = w(d.skin.UIComponent.prototype, {
+        playMC: null,
+        stopMC: null,
+        configure: function(a) {
+            d.skin.UIComponent.prototype.configure.call(this, a);
+            null != a.get("imageplay") && -1 == a.get("imageplay").indexOf(".swf") && (this.ui.loadImage(this.playMC, a.get("imageplay")), this.appendChild(this.playMC, !1));
+            null != a.get("imagestop") && -1 == a.get("imagestop").indexOf(".swf") && (this.ui.loadImage(this.stopMC,
+                a.get("imagestop")), this.appendChild(this.stopMC, !0))
+        },
+        on: function() {
+            this.playMC.style.display = "block";
+            this.stopMC.style.display = "none"
+        },
+        off: function() {
+            this.playMC.style.display = "none";
+            this.stopMC.style.display = "block"
+        },
+        __class__: d.skin.StatusLed
+    });
+    d.skin.TitleText = function(a) {
+        d.skin.UIComponent.call(this, a);
+        this.container.style.fontFamily = "Silkscreen";
+        this.container.style.fontSize = "12px"
+    };
+    d.skin.TitleText.__name__ = !0;
+    d.skin.TitleText.__super__ = d.skin.UIComponent;
+    d.skin.TitleText.prototype = w(d.skin.UIComponent.prototype, {
+        configureText: function(a, b) {
+            this.configure(a);
+            switch (a.get("align")) {
+                case "center":
+                    this.container.style.textAlign = "center";
+                    break;
+                case "right":
+                    this.container.style.textAlign = "right";
+                    break;
+                default:
+                    this.container.style.textAlign = b
+            }
+            this.container.style.padding = "2px";
+            this.container.style.whiteSpace = "nowrap";
+            this.container.style.fontFamily = a.get("font");
+            this.container.style.fontSize = d.UI.parseInt(a.get("size"), 12) + "px";
+            this.container.style.color = a.get("color");
+            this.container.style.overflow = "hidden"
+        },
+        setText: function(a) {
+            this.container.innerHTML =
+                a
+        },
+        __class__: d.skin.TitleText
+    });
+    d.skin.VolumeControl = function(a, b) {
+        d.skin.UIComponent.call(this, a);
+        this.muses = b;
+        this.firstDraw = !0;
+        this.bars = null;
+        this.mousePressed = !1;
+        this.volume = 1;
+        this.setMode("bars");
+        this.draw(this.container);
+        this.vertMargin = this.horizMargin = this.height = this.width = 0;
+        this.barStep = 2;
+        this.barWidth = 1;
+        this.barColors = this.bgColors = null
+    };
+    d.skin.VolumeControl.__name__ = !0;
+    d.skin.VolumeControl.__super__ = d.skin.UIComponent;
+    d.skin.VolumeControl.prototype = w(d.skin.UIComponent.prototype, {
+        volume: null,
+        width: null,
+        height: null,
+        horizMargin: null,
+        horizDesp: null,
+        vertMargin: null,
+        vertDesp: null,
+        barStep: null,
+        barWidth: null,
+        bgColors: null,
+        barColors: null,
+        bars: null,
+        cover: null,
+        spriteBar: null,
+        firstDraw: null,
+        mode: null,
+        holder: null,
+        mousePressed: null,
+        muses: null,
+        draw: function(a) {},
+        setMode: function(a) {
+            switch (a.toLowerCase()) {
+                case "bars":
+                    this.draw = p(this, this.drawBars);
+                    break;
+                case "holder":
+                    this.draw = p(this, this.drawHolder);
+                    break;
+                case "vholder":
+                    this.draw = p(this, this.drawVHolder)
+            }
+            this.mode = a
+        },
+        drawHolder: function(a) {
+            this.holder.style.left =
+                this.volume * (this.width - this.holder.width) + "px"
+        },
+        drawVHolder: function(a) {
+            this.holder.style.top = (1 - this.volume) * (this.height - this.holder.height) + "px"
+        },
+        drawBars: function(a) {
+            if (null != this.barColors && 0 != this.barStep && (a = Math.round((this.width - 2 * this.horizMargin) / this.barStep), 0 != a)) {
+                var b = (this.height - 2 * this.vertMargin + 1) / a,
+                    d = this.height - this.vertMargin,
+                    e = this.horizMargin;
+                if (null == this.bars) {
+                    this.bars = [];
+                    for (var f = 0; f < a;) {
+                        var g = f++,
+                            h;
+                        h = window.document.createElement("div");
+                        this.bars.push(h);
+                        this.appendChild(h);
+                        h.style.left = e + g * this.barStep + "px";
+                        h.style.top = d - g * b + "px";
+                        h.style.width = Math.round(this.barWidth) + "px";
+                        h.style.height = Math.ceil(g * b) + "px"
+                    }
+                }
+                b = 0;
+                for (d = Math.round(this.volume * a); b < d;) e = b++, this.bars[e].style.backgroundColor = this.barColors[0];
+                for (b = Math.round(this.volume * a); b < a;) d = b++, this.bars[d].style.backgroundColor = this.barColors[1]
+            }
+        },
+        setVolume: function(a) {
+            this.volume != a && (this.volume = a, 1 < this.volume && (this.volume = 1), 0 > this.volume && (this.volume = 0), this.muses.setVolume(this.volume), this.draw(this.container))
+        },
+        getVolume: function() {
+            return this.volume
+        },
+        mouseDown: function(a) {
+            var b;
+            this.mousePressed = !0;
+            "vholder" != this.mode ? (a = a.layerX, b = this.width) : (a = this.height - a.layerY, b = this.height);
+            a -= .06 * b;
+            0 > a && (a = 0);
+            a = Math.round(1.06 * a);
+            a > b && (a = b);
+            this.setVolume(a / (b - 2))
+        },
+        mouseUp: function(a) {
+            this.mousePressed = !1
+        },
+        mouseMove: function(a) {
+            this.mousePressed && this.mouseDown(a)
+        },
+        mouseWheel: function(a) {
+            0 < a.wheelDelta ? this.setVolume(this.volume + .025) : this.setVolume(this.volume - .025)
+        },
+        configure: function(a) {
+            d.skin.UIComponent.prototype.configure.call(this,
+                a);
+            this.width = d.UI.parseInt(a.get("width"), 0);
+            this.height = d.UI.parseInt(a.get("height"), 0);
+            this.barColors = [a.get("color1"), a.get("color2")];
+            this.barStep = d.UI.parseInt(a.get("barstep"), 2);
+            this.barWidth = d.UI.parseInt(a.get("barwidth"), 1);
+            var b;
+            b = null != a.get("mode") ? a.get("mode").toLowerCase() : null;
+            this.setMode(b);
+            if ("holder" == b || "vholder" == b) this.holder = new Image, this.holder.onload = p(this, this.holderLoad), this.ui.loadImage(this.holder, a.get("holderimage")), this.appendChild(this.holder);
+            this.draw(this.container);
+            this.cover = window.document.createElement("div");
+            this.cover.onmousedown = p(this, this.mouseDown);
+            this.cover.onmousemove = p(this, this.mouseMove);
+            this.cover.onmousewheel = p(this, this.mouseWheel);
+            this.cover.onmouseup = p(this, this.mouseUp);
+            this.cover.onmouseout = p(this, this.mouseUp);
+            this.cover.style.width = this.container.style.width;
+            this.cover.style.height = this.container.style.height;
+            this.appendChild(this.cover)
+        },
+        holderLoad: function(a) {
+            this.holder.style.left = .5 * (this.width - this.holder.width) + "px";
+            this.holder.style.top =
+                .5 * (this.height - this.holder.height) + "px";
+            this.draw(this.container)
+        },
+        __class__: d.skin.VolumeControl
+    });
+    var G = 0;
+    Array.prototype.indexOf && (m.indexOf = function(a, b, d) {
+        return Array.prototype.indexOf.call(a, b, d)
+    });
+    Math.NaN = Number.NaN;
+    Math.NEGATIVE_INFINITY = Number.NEGATIVE_INFINITY;
+    Math.POSITIVE_INFINITY = Number.POSITIVE_INFINITY;
+    Math.isFinite = function(a) {
+        return isFinite(a)
+    };
+    Math.isNaN = function(a) {
+        return isNaN(a)
+    };
+    String.prototype.__class__ = String;
+    String.__name__ = !0;
+    Array.__name__ = !0;
+    Date.prototype.__class__ =
+        Date;
+    Date.__name__ = ["Date"];
+    var H = {
+            __name__: ["Int"]
+        },
+        I = {
+            __name__: ["Dynamic"]
+        },
+        E = Number;
+    E.__name__ = ["Float"];
+    var F = Boolean;
+    F.__ename__ = ["Bool"];
+    var J = {
+            __name__: ["Class"]
+        },
+        K = {};
+    h.Element = "element";
+    h.PCData = "pcdata";
+    h.CData = "cdata";
+    h.Comment = "comment";
+    h.DocType = "doctype";
+    h.ProcessingInstruction = "processingInstruction";
+    h.Document = "document";
+    g.objectId = "MRPObject";
+    g.playerCounter = 0;
+    g.__hostPrefix = "hosted";
+    g.__hostMidfix = "muses";
+    b.Campaign.TYPE_DIRECT = "direct";
+    b.Campaign.TYPE_ORGANIC = "organic";
+    b.Campaign.TYPE_REFERRAL =
+        "referral";
+    b.Config.ERROR_SEVERITY_SILENCE = 0;
+    b.Config.ERROR_SEVERITY_TRACE = 1;
+    b.Config.ERROR_SEVERITY_EXCEPTIONS = 2;
+    b.CustomVariable.SCOPE_VISITOR = 1;
+    b.CustomVariable.SCOPE_SESSION = 2;
+    b.CustomVariable.SCOPE_PAGE = 3;
+    b.Page.REFERRER_INTERNAL = "0";
+    b.Tracker.VERSION = "5.2.5";
+    b.URLParser.parts = "source protocol authority userInfo user password host port relative path directory file query anchor".split(" ");
+    b.internals.X10.OBJECT_KEY_NUM = 1;
+    b.internals.X10.TYPE_KEY_NUM = 2;
+    b.internals.X10.LABEL_KEY_NUM = 3;
+    b.internals.X10.VALUE_VALUE_NUM =
+        1;
+    b.internals.request.Request.TYPE_EVENT = "event";
+    b.internals.request.Request.TYPE_TRANSACTION = "tran";
+    b.internals.request.Request.TYPE_ITEM = "item";
+    b.internals.request.Request.TYPE_SOCIAL = "social";
+    b.internals.request.Request.TYPE_CUSTOMVARIABLE = "var";
+    b.internals.request.Request.X10_CUSTOMVAR_NAME_PROJECT_ID = "8";
+    b.internals.request.Request.X10_CUSTOMVAR_VALUE_PROJECT_ID = "9";
+    b.internals.request.Request.X10_CUSTOMVAR_SCOPE_PROJECT_ID = "11";
+    b.internals.request.Request.CAMPAIGN_DELIMITER = "|";
+    b.internals.request.EventRequest.X10_EVENT_PROJECT_ID =
+        "5";
+    q.xml.Parser.escapes = function(a) {
+        a = new q.ds.StringMap;
+        a.set("lt", "<");
+        a.set("gt", ">");
+        a.set("amp", "&");
+        a.set("quot", '"');
+        a.set("apos", "'");
+        a.set("nbsp", String.fromCharCode(160));
+        return a
+    }(this);
+    d.Muses.VERSION = "0.2 beta";
+    d.Muses.instances = [];
+    d.Tracker.enabled = !0;
+    g.main()
+})("undefined" != typeof window ? window : exports);
+var FlashDetect = new function() {
+    var n = this;
+    n.installed = !1;
+    n.raw = "";
+    n.major = -1;
+    n.minor = -1;
+    n.revision = -1;
+    n.revisionStr = "";
+    var w = [{
+            name: "ShockwaveFlash.ShockwaveFlash.7",
+            version: function(p) {
+                return B(p)
+            }
+        }, {
+            name: "ShockwaveFlash.ShockwaveFlash.6",
+            version: function(p) {
+                var n = "6,0,21";
+                try {
+                    p.AllowScriptAccess = "always", n = B(p)
+                } catch (m) {}
+                return n
+            }
+        }, {
+            name: "ShockwaveFlash.ShockwaveFlash",
+            version: function(p) {
+                return B(p)
+            }
+        }],
+        B = function(p) {
+            var n = -1;
+            try {
+                n = p.GetVariable("$version")
+            } catch (m) {}
+            return n
+        };
+    n.majorAtLeast = function(p) {
+        return n.major >=
+            p
+    };
+    n.minorAtLeast = function(p) {
+        return n.minor >= p
+    };
+    n.revisionAtLeast = function(p) {
+        return n.revision >= p
+    };
+    n.versionAtLeast = function(p) {
+        var s = [n.major, n.minor, n.revision],
+            m = Math.min(s.length, arguments.length);
+        for (i = 0; i < m; i++)
+            if (s[i] >= arguments[i]) {
+                if (!(i + 1 < m && s[i] == arguments[i])) return !0
+            } else return !1
+    };
+    n.FlashDetect = function() {
+        var p, s, m, x, A;
+        if (navigator.plugins && 0 < navigator.plugins.length) {
+            var g = navigator.mimeTypes;
+            if (g && g["application/x-shockwave-flash"] && g["application/x-shockwave-flash"].enabledPlugin &&
+                g["application/x-shockwave-flash"].enabledPlugin.description) {
+                p = g = g["application/x-shockwave-flash"].enabledPlugin.description;
+                var g = p.split(/ +/),
+                    z = g[2].split(/\./),
+                    g = g[3];
+                s = parseInt(z[0], 10);
+                m = parseInt(z[1], 10);
+                x = g;
+                A = parseInt(g.replace(/[a-zA-Z]/g, ""), 10) || n.revision;
+                n.raw = p;
+                n.major = s;
+                n.minor = m;
+                n.revisionStr = x;
+                n.revision = A;
+                n.installed = !0
+            }
+        } else if (-1 == navigator.appVersion.indexOf("Mac") && window.execScript)
+            for (g = -1, z = 0; z < w.length && -1 == g; z++) {
+                p = -1;
+                try {
+                    p = new ActiveXObject(w[z].name)
+                } catch (v) {
+                    p = {
+                        activeXError: !0
+                    }
+                }
+                p.activeXError ||
+                (n.installed = !0, g = w[z].version(p), -1 != g && (p = g, x = p.split(","), s = parseInt(x[0].split(" ")[1], 10), m = parseInt(x[1], 10), A = parseInt(x[2], 10), x = x[2], n.raw = p, n.major = s, n.minor = m, n.revision = A, n.revisionStr = x))
+            }
+    }()
+};
+FlashDetect.JS_RELEASE = "1.0.4";
\ No newline at end of file
diff --git a/airtime_mvc/public/js/airtime/embeddableplayer/muses.swf b/airtime_mvc/public/js/airtime/embeddableplayer/muses.swf
new file mode 100644
index 0000000000000000000000000000000000000000..0a23f07cf1ece131ba9c4b902c855d4ea246ebbf
GIT binary patch
literal 74589
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
Szwqxq*An{+`1%+A*h7G?D}~+w

literal 0
HcmV?d00001


From 7744e6b6560c0c366d4ac3f3401a67fdfe7dc2ec Mon Sep 17 00:00:00 2001
From: drigato <denise.rigato@sourcefabric.org>
Date: Tue, 10 Mar 2015 16:34:06 -0400
Subject: [PATCH 12/60] Delete player css file for now

---
 airtime_mvc/public/css/embed-player.css | 4 ----
 1 file changed, 4 deletions(-)
 delete mode 100644 airtime_mvc/public/css/embed-player.css

diff --git a/airtime_mvc/public/css/embed-player.css b/airtime_mvc/public/css/embed-player.css
deleted file mode 100644
index 1f19319e8..000000000
--- a/airtime_mvc/public/css/embed-player.css
+++ /dev/null
@@ -1,4 +0,0 @@
-#embed_player_preview {
-    margin-top:20px;
-    border: 1px solid;
-}

From 8198d89095575e69214230d6ca1426cf587cf4d9 Mon Sep 17 00:00:00 2001
From: drigato <denise.rigato@sourcefabric.org>
Date: Tue, 10 Mar 2015 16:47:08 -0400
Subject: [PATCH 13/60] small change to player form

---
 .../application/controllers/EmbeddableplayerController.php      | 2 +-
 airtime_mvc/application/forms/EmbeddablePlayer.php              | 1 -
 2 files changed, 1 insertion(+), 2 deletions(-)

diff --git a/airtime_mvc/application/controllers/EmbeddableplayerController.php b/airtime_mvc/application/controllers/EmbeddableplayerController.php
index 4536d7e18..6fc2d9e13 100644
--- a/airtime_mvc/application/controllers/EmbeddableplayerController.php
+++ b/airtime_mvc/application/controllers/EmbeddableplayerController.php
@@ -17,5 +17,5 @@ class EmbeddablePlayerController extends Zend_Controller_Action
     public function embedCodeAction()
     {
         $this->view->layout()->disableLayout();
-     }
+    }
 }
\ No newline at end of file
diff --git a/airtime_mvc/application/forms/EmbeddablePlayer.php b/airtime_mvc/application/forms/EmbeddablePlayer.php
index 4b9353aad..230037de7 100644
--- a/airtime_mvc/application/forms/EmbeddablePlayer.php
+++ b/airtime_mvc/application/forms/EmbeddablePlayer.php
@@ -10,7 +10,6 @@ class Application_Form_EmbeddablePlayer extends Zend_Form_SubForm
 
         $embedSrc = new Zend_Form_Element_Text('player_embed_src');
         $embedSrc->setAttrib("readonly", "readonly");
-        $embedSrc->setAttrib("class", "player_embed_src");
         $embedSrc->setValue('<iframe frameborder="0" src="http://localhost/embeddableplayer/embed-code"></iframe>');
         $embedSrc->removeDecorator('label');
         $this->addElement($embedSrc);

From 0042fb50fe3ca792e9b73fd39d5189cf42e1d32e Mon Sep 17 00:00:00 2001
From: Albert Santoni <albert.santoni@sourcefabric.org>
Date: Tue, 10 Mar 2015 19:15:38 -0400
Subject: [PATCH 14/60] Refactor some stuff related to four streams, Liquidsoap
 is a piece of shit too - no dynamic variables

---
 .../application/controllers/ApiController.php |   2 +-
 .../controllers/PreferenceController.php      |  10 +-
 .../application/models/StreamSetting.php      | 203 +++++++++---------
 .../generate_liquidsoap_cfg.py                |  23 +-
 .../pypo/liquidsoap_scripts/ls_script.liq     |   5 +-
 python_apps/pypo/listenerstat.py              |   4 +-
 python_apps/pypo/pypofetch.py                 |  93 +-------
 python_apps/pypo/pypoliquidsoap.py            |   1 +
 python_apps/pypo/pyponotify.py                |  10 +-
 9 files changed, 130 insertions(+), 221 deletions(-)

diff --git a/airtime_mvc/application/controllers/ApiController.php b/airtime_mvc/application/controllers/ApiController.php
index c90b41c22..b07cccd51 100644
--- a/airtime_mvc/application/controllers/ApiController.php
+++ b/airtime_mvc/application/controllers/ApiController.php
@@ -1308,7 +1308,7 @@ class ApiController extends Zend_Controller_Action
     }
 
     public function getStreamParametersAction() {
-        $streams = array("s1", "s2", "s3");
+        $streams = array("s1", "s2", "s3", "s4");
         $stream_params = array();
         foreach ($streams as $s) {
             $stream_params[$s] =
diff --git a/airtime_mvc/application/controllers/PreferenceController.php b/airtime_mvc/application/controllers/PreferenceController.php
index 6a0ba3541..b06a9e1ed 100644
--- a/airtime_mvc/application/controllers/PreferenceController.php
+++ b/airtime_mvc/application/controllers/PreferenceController.php
@@ -141,11 +141,7 @@ class PreferenceController extends Zend_Controller_Action
         $this->view->headScript()->appendFile($baseUrl.'js/airtime/preferences/streamsetting.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
 
         // get current settings
-        $temp = Application_Model_StreamSetting::getStreamSetting();
-        $setting = array();
-        foreach ($temp as $t) {
-            $setting[$t['keyname']] = $t['value'];
-        }
+        $setting = Application_Model_StreamSetting::getStreamSetting();
 
         $name_map = array(
 				'ogg' => 'Ogg Vorbis',
@@ -208,6 +204,7 @@ class PreferenceController extends Zend_Controller_Action
             $s1_data = array();
             $s2_data = array();
             $s3_data = array();
+            $s4_data = array();
             $values = array();
             foreach($postData as $k=>$v) {
                 $v = explode('=', urldecode($v));
@@ -447,7 +444,8 @@ class PreferenceController extends Zend_Controller_Action
     public function getAdminPasswordStatusAction()
     {
         $out = array();
-        for ($i=1; $i<=4; $i++) {
+        $num_of_stream = intval(Application_Model_Preference::GetNumOfStreams());
+        for ($i=1; $i<=$num_of_stream; $i++) {
             if (Application_Model_StreamSetting::getAdminPass('s'.$i)=='') {
                 $out["s".$i] = false;
             } else {
diff --git a/airtime_mvc/application/models/StreamSetting.php b/airtime_mvc/application/models/StreamSetting.php
index c34c09a2e..832849474 100644
--- a/airtime_mvc/application/models/StreamSetting.php
+++ b/airtime_mvc/application/models/StreamSetting.php
@@ -1,4 +1,7 @@
 <?php
+
+define("MAX_NUM_STREAMS", 4);
+
 class Application_Model_StreamSetting
 {
     public static function setValue($key, $value, $type)
@@ -41,7 +44,7 @@ class Application_Model_StreamSetting
         }
     }
 
-    public static function getValue($key)
+    public static function getValue($key, $default="")
     {
         $con = Propel::getConnection();
         
@@ -59,7 +62,7 @@ class Application_Model_StreamSetting
             throw new Exception("Error: $msg");
         }
 
-        return $result ? $result : "";
+        return $result ? $result : $default;
     }
 
     /* Returns the id's of all streams that are enabled in an array. An
@@ -83,50 +86,62 @@ class Application_Model_StreamSetting
         return $ids;
     }
 
-    /* Returns only global data as array*/
-    public static function getGlobalData()
-    {
-        $con = Propel::getConnection();
-        $sql = "SELECT * "
-            ."FROM cc_stream_setting "
-            ."WHERE keyname IN ('output_sound_device', 'icecast_vorbis_metadata')";
-
-        $rows = Application_Common_Database::prepareAndExecute($sql, array(), 'all');
-        
-        $data = array();
-
-        foreach ($rows as $row) {
-            $data[$row["keyname"]] = $row["value"];
-        }
-
-        return $data;
-    }
-
     /* Returns all information related to a specific stream. An example
      * of a stream id is 's1' or 's2'. */
     public static function getStreamData($p_streamId)
     {
-        $con = Propel::getConnection();
-        $streamId = pg_escape_string($p_streamId);
-        $sql = "SELECT * "
-                ."FROM cc_stream_setting "
-                ."WHERE keyname LIKE '{$streamId}_%'";
-
-        $stmt = $con->prepare($sql);
-        
-        if ($stmt->execute()) {
-            $rows = $stmt->fetchAll();
-        } else {
-            $msg = implode(',', $stmt->errorInfo());
-            throw new Exception("Error: $msg");
-        }
+        $rows = CcStreamSettingQuery::create()
+            ->filterByDbKeyName("${p_streamId}_%")
+            ->find();
 
+        //This is way too much code because someone made only stupid decisions about how
+        //the layout of this table worked. The git history doesn't lie.
         $data = array();
-
         foreach ($rows as $row) {
-            $data[$row["keyname"]] = $row["value"];
+            $key = $row->getDbKeyName();
+            $value = $row->getDbValue();
+            $type = $row->getDbType();
+            //Fix stupid defaults so we end up with proper typing in our JSON
+            if ($row->getDbType() == "boolean") {
+                if (empty($value)) {
+                    //In Python, there is no way to tell the difference between ints and booleans,
+                    //which we need to differentiate between for when we're generating the Liquidsoap
+                    //config file. Returning booleans as a string is a workaround that lets us do that.
+                    $value = "false";
+                }
+                $data[$key] = $value;
+            }
+            elseif ($row->getDbType() == "integer") {
+                if (empty($value)) {
+                    $value = 0;
+                }
+                $data[$key] = intval($value);
+            }
+            else {
+                $data[$key] = $value;
+            }
         }
 
+        //Add in defaults in case they don't exist in the database.
+        $keyPrefix = $p_streamId . '_';
+        self::ensureKeyExists($keyPrefix . 'admin_pass', $data);
+        self::ensureKeyExists($keyPrefix . 'admin_user', $data);
+        self::ensureKeyExists($keyPrefix . 'bitrate', $data, 128);
+        self::ensureKeyExists($keyPrefix . 'channels', $data, "stereo");
+        self::ensureKeyExists($keyPrefix . 'description', $data);
+        self::ensureKeyExists($keyPrefix . 'enable', $data, "false");
+        self::ensureKeyExists($keyPrefix . 'genre', $data);
+        self::ensureKeyExists($keyPrefix . 'host', $data);
+        self::ensureKeyExists($keyPrefix . 'liquidsoap_error', $data, "waiting");
+        self::ensureKeyExists($keyPrefix . 'mount', $data);
+        self::ensureKeyExists($keyPrefix . 'name', $data);
+        self::ensureKeyExists($keyPrefix . 'output', $data);
+        self::ensureKeyExists($keyPrefix . 'pass', $data);
+        self::ensureKeyExists($keyPrefix . 'port', $data, 8000);
+        self::ensureKeyExists($keyPrefix . 'type', $data);
+        self::ensureKeyExists($keyPrefix . 'url', $data);
+        self::ensureKeyExists($keyPrefix . 'user', $data);
+
         return $data;
     }
 
@@ -134,76 +149,41 @@ class Application_Model_StreamSetting
      * make data easier to iterate over */
     public static function getStreamDataNormalized($p_streamId)
     {
-        $con = Propel::getConnection();
-        $streamId = pg_escape_string($p_streamId);
-        $sql = "SELECT * "
-                ."FROM cc_stream_setting "
-                ."WHERE keyname LIKE '{$streamId}_%'";
-
-        $stmt = $con->prepare($sql);
-        
-        if ($stmt->execute()) {
-            $rows = $stmt->fetchAll();
-        } else {
-            $msg = implode(',', $stmt->errorInfo());
-            throw new Exception("Error: $msg");
+        $settings = self::getStreamData($p_streamId);
+        foreach ($settings as $key => $value)
+        {
+            unset($settings[$key]);
+            $newKey = substr($key, strlen($p_streamId)+1); //$p_streamId is assumed to be the key prefix.
+            $settings[$newKey] = $value;
         }
+        return $settings;
+    }
 
-        $data = array();
-
-        foreach ($rows as $row) {
-            list($id, $key) = explode("_", $row["keyname"], 2);
-            $data[$key] = $row["value"];
+    private static function ensureKeyExists($key, &$array, $default='')
+    {
+        if (!array_key_exists($key, $array)) {
+            $array[$key] = $default;
         }
-
-        return $data;
+        return $array;
     }
 
     public static function getStreamSetting()
     {
-        $con = Propel::getConnection();
-        $sql = "SELECT *"
-                ." FROM cc_stream_setting"
-                ." WHERE keyname not like '%_error' AND keyname not like '%_admin_%'";
-
-        $rows = Application_Common_Database::prepareAndExecute($sql, array(), 'all');
-
-        $exists = array();
-
-        foreach ($rows as $r) {
-            if ($r['keyname'] == 'master_live_stream_port') {
-                $exists['master_live_stream_port'] = true;
-            } elseif ($r['keyname'] == 'master_live_stream_mp') {
-                $exists['master_live_stream_mp'] = true;
-            } elseif ($r['keyname'] == 'dj_live_stream_port') {
-                $exists['dj_live_stream_port'] = true;
-            } elseif ($r['keyname'] == 'dj_live_stream_mp') {
-                $exists['dj_live_stream_mp'] = true;
-            }
+        $settings = array();
+        $numStreams = MAX_NUM_STREAMS;
+        for ($streamIdx = 1; $streamIdx <= $numStreams; $streamIdx++)
+        {
+            $settings = array_merge($settings, self::getStreamData("s" . $streamIdx));
         }
-
-        if (!isset($exists["master_live_stream_port"])) {
-            $rows[] = array("keyname" =>"master_live_stream_port",
-                            "value"=>self::getMasterLiveStreamPort(),
-                            "type"=>"integer");
-        }
-        if (!isset($exists["master_live_stream_mp"])) {
-            $rows[] = array("keyname" =>"master_live_stream_mp",
-                            "value"=>self::getMasterLiveStreamMountPoint(),
-                            "type"=>"string");
-        }
-        if (!isset($exists["dj_live_stream_port"])) {
-            $rows[] = array("keyname" =>"dj_live_stream_port",
-                            "value"=>self::getDjLiveStreamPort(),
-                            "type"=>"integer");
-        }
-        if (!isset($exists["dj_live_stream_mp"])) {
-            $rows[] = array("keyname" =>"dj_live_stream_mp",
-                            "value"=>self::getDjLiveStreamMountPoint(),
-                            "type"=>"string");
-        }
-
-        return $rows;
+        $settings["master_live_stream_port"] = self::getMasterLiveStreamPort();
+        $settings["master_live_stream_mp"] = self::getMasterLiveStreamMountPoint();
+        $settings["dj_live_stream_port"] = self::getDjLiveStreamPort();
+        $settings["dj_live_stream_mp"] = self::getDjLiveStreamMountPoint();
+        $settings["off_air_meta"] = self::getOffAirMeta();
+        $settings["icecast_vorbis_metadata"] = self::getIcecastVorbisMetadata();
+        $settings["output_sound_device"] = self::getOutputSoundDevice();
+        $settings["output_sound_device_type"] = self::getOutputSoundDeviceType();
+        return $settings;
     }
 
 
@@ -211,7 +191,10 @@ class Application_Model_StreamSetting
     {
         $stream_setting = CcStreamSettingQuery::create()->filterByDbKeyName($key)->findOne();
         if (is_null($stream_setting)) {
-            throw new Exception("Keyname $key does not exist!");
+            //throw new Exception("Keyname $key does not exist!");
+            $stream_setting = new CcStreamSetting();
+            $stream_setting->setDbKeyName($key);
+            $stream_setting->setDbType("");
         }
 
         $stream_setting->setDbValue($value);
@@ -411,7 +394,7 @@ class Application_Model_StreamSetting
 
     public static function getMasterLiveStreamPort()
     {
-        return self::getValue("master_live_stream_port");
+        return self::getValue("master_live_stream_port", 8001);
     }
 
     public static function setMasterLiveStreamMountPoint($value)
@@ -421,7 +404,7 @@ class Application_Model_StreamSetting
 
     public static function getMasterLiveStreamMountPoint()
     {
-        return self::getValue("master_live_stream_mp");
+        return self::getValue("master_live_stream_mp", "/master");
     }
 
     public static function setDjLiveStreamPort($value)
@@ -431,7 +414,7 @@ class Application_Model_StreamSetting
 
     public static function getDjLiveStreamPort()
     {
-        return self::getValue("dj_live_stream_port");
+        return self::getValue("dj_live_stream_port", 8001);
     }
 
     public static function setDjLiveStreamMountPoint($value)
@@ -441,7 +424,7 @@ class Application_Model_StreamSetting
 
     public static function getDjLiveStreamMountPoint()
     {
-        return self::getValue("dj_live_stream_mp");
+        return self::getValue("dj_live_stream_mp", "/show");
     }
     
     public static function getAdminUser($stream){
@@ -488,4 +471,16 @@ class Application_Model_StreamSetting
     public static function SetListenerStatError($key, $v) {
         self::setValue($key, $v, 'string');
     }
+
+    public static function getIcecastVorbisMetadata() {
+        return self::getValue("icecast_vorbis_metadata", "");
+    }
+
+    public static function getOutputSoundDevice() {
+        return self::getValue("output_sound_device", "false");
+    }
+
+    public static function getOutputSoundDeviceType() {
+        return self::getValue("output_sound_device_type", "");
+    }
 }
diff --git a/python_apps/pypo/liquidsoap_scripts/generate_liquidsoap_cfg.py b/python_apps/pypo/liquidsoap_scripts/generate_liquidsoap_cfg.py
index 45bdb46f4..ec5d10cc3 100644
--- a/python_apps/pypo/liquidsoap_scripts/generate_liquidsoap_cfg.py
+++ b/python_apps/pypo/liquidsoap_scripts/generate_liquidsoap_cfg.py
@@ -10,18 +10,23 @@ def generate_liquidsoap_config(ss):
     fh.write("################################################\n")
     fh.write("# THIS FILE IS AUTO GENERATED. DO NOT CHANGE!! #\n")
     fh.write("################################################\n")
+    fh.write("# The ignore() lines are to squash unused variable warnings\n")
 
-    for d in data:
-        key = d['keyname']
+    for key, value in data.iteritems():
+        try:
+            str_buffer = "%s = %s\n" % (key, int(value))
+        except ValueError:
+            try: # Is it a boolean?
+                if "true" in value or "false" in value:
+                    str_buffer = "%s = %s\n" % (key, value.lower())
+                else:
+                    raise ValueError() # Just drop into the except below
+            except: #Everything else is a string
+                str_buffer = "%s = \"%s\"\n" % (key, value)
 
-        str_buffer = d[u'keyname'] + " = "
-        if d[u'type'] == 'string':
-            val = '"%s"' % d['value']
-        else:
-            val = d[u'value']
-            val = val if len(val) > 0 else "0"
-        str_buffer = "%s = %s\n" % (key, val)
         fh.write(str_buffer.encode('utf-8'))
+        # ignore squashes unused variable errors from Liquidsoap
+        fh.write(("ignore(%s)\n" % key).encode('utf-8'))
 
     fh.write('log_file = "/var/log/airtime/pypo-liquidsoap/<script>.log"\n')
     fh.close()
diff --git a/python_apps/pypo/liquidsoap_scripts/ls_script.liq b/python_apps/pypo/liquidsoap_scripts/ls_script.liq
index 38f647f7f..ccc3a0776 100644
--- a/python_apps/pypo/liquidsoap_scripts/ls_script.liq
+++ b/python_apps/pypo/liquidsoap_scripts/ls_script.liq
@@ -104,7 +104,7 @@ server.register(namespace="vars",
                 fun (s) -> begin log("vars.bootup_time") time := s s end)
 server.register(namespace="streams",
                 "connection_status",
-                fun (s) -> begin log("streams.connection_status") "1:#{!s1_connected},2:#{!s2_connected},3:#{!s3_connected}:#{!s4_connected}" end)
+                fun (s) -> begin log("streams.connection_status") "1:#{!s1_connected},2:#{!s2_connected},3:#{!s3_connected},4:#{!s4_connected}" end)
 server.register(namespace="vars",
                 "default_dj_fade",
                 fun (s) -> begin log("vars.default_dj_fade") default_dj_fade := float_of_string(s) s end)
@@ -400,9 +400,9 @@ if s3_enable == true then
                 s3_connected, s3_description, s3_channels)
 end
 
-%ifdef s4_enable
 s4_namespace = ref ''
 if s4_enable == true then
+    log("Stream 4 Enabled")
     if s4_output == 'shoutcast' then
         s4_namespace := "shoutcast_stream_4"
     else
@@ -413,7 +413,6 @@ if s4_enable == true then
                 s4_mount, s4_url, s4_name, s4_genre, s4_user, s, "4",
                 s4_connected, s4_description, s4_channels)
 end
-%endif
 
 
 command = "/usr/lib/airtime/pypo/bin/liquidsoap_scripts/notify.sh --liquidsoap-started &"
diff --git a/python_apps/pypo/listenerstat.py b/python_apps/pypo/listenerstat.py
index c97ca030d..a7f99e816 100644
--- a/python_apps/pypo/listenerstat.py
+++ b/python_apps/pypo/listenerstat.py
@@ -118,10 +118,10 @@ class ListenerStat(Thread):
                     else:
                         stats.append(self.get_shoutcast_stats(v))
                     self.update_listener_stat_error(v["mount"], 'OK')
-                except Exception, e:
+                except Exception as e:
                     try:
                         self.update_listener_stat_error(v["mount"], str(e))
-                    except Exception, e:
+                    except Exception as e:
                         self.logger.error('Exception: %s', e)
 
         return stats
diff --git a/python_apps/pypo/pypofetch.py b/python_apps/pypo/pypofetch.py
index 5564825a3..5f3ce5503 100644
--- a/python_apps/pypo/pypofetch.py
+++ b/python_apps/pypo/pypofetch.py
@@ -216,98 +216,9 @@ class PypoFetch(Thread):
     TODO: This function needs to be way shorter, and refactored :/ - MK
     """
     def regenerate_liquidsoap_conf(self, setting):
-        existing = {}
+        self.restart_liquidsoap()
+        self.update_liquidsoap_connection_status()
 
-        setting = sorted(setting.items())
-        try:
-            fh = open('/etc/airtime/liquidsoap.cfg', 'r')
-        except IOError, e:
-            #file does not exist
-            self.restart_liquidsoap()
-            return
-
-        self.logger.info("Reading existing config...")
-        # read existing conf file and build dict
-        while True:
-            line = fh.readline()
-
-            # empty line means EOF
-            if not line:
-                break
-
-            line = line.strip()
-
-            if not len(line) or line[0] == "#":
-                continue
-
-            try:
-                key, value = line.split('=', 1)
-            except ValueError:
-                continue
-            key = key.strip()
-            value = value.strip()
-            value = value.replace('"', '')
-            if value == '' or value == "0":
-                value = ''
-            existing[key] = value
-        fh.close()
-
-        # dict flag for any change in config
-        change = {}
-        # this flag is to detect disable -> disable change
-        # in that case, we don't want to restart even if there are changes.
-        state_change_restart = {}
-        #restart flag
-        restart = False
-
-        self.logger.info("Looking for changes...")
-        # look for changes
-        for k, s in setting:
-            if "output_sound_device" in s[u'keyname'] or "icecast_vorbis_metadata" in s[u'keyname']:
-                dump, stream = s[u'keyname'].split('_', 1)
-                state_change_restart[stream] = False
-                # This is the case where restart is required no matter what
-                if (existing[s[u'keyname']] != str(s[u'value'])):
-                    self.logger.info("'Need-to-restart' state detected for %s...", s[u'keyname'])
-                    restart = True;
-            elif "master_live_stream_port" in s[u'keyname'] or "master_live_stream_mp" in s[u'keyname'] or "dj_live_stream_port" in s[u'keyname'] or "dj_live_stream_mp" in s[u'keyname'] or "off_air_meta" in s[u'keyname']:
-                if (existing[s[u'keyname']] != s[u'value']):
-                    self.logger.info("'Need-to-restart' state detected for %s...", s[u'keyname'])
-                    restart = True;
-            else:
-                stream, dump = s[u'keyname'].split('_', 1)
-                if "_output" in s[u'keyname']:
-                    if (existing[s[u'keyname']] != s[u'value']):
-                        self.logger.info("'Need-to-restart' state detected for %s...", s[u'keyname'])
-                        restart = True;
-                        state_change_restart[stream] = True
-                    elif (s[u'value'] != 'disabled'):
-                        state_change_restart[stream] = True
-                    else:
-                        state_change_restart[stream] = False
-                else:
-                    # setting inital value
-                    if stream not in change:
-                        change[stream] = False
-                    if not (s[u'value'] == existing[s[u'keyname']]):
-                        self.logger.info("Keyname: %s, Current value: %s, New Value: %s", s[u'keyname'], existing[s[u'keyname']], s[u'value'])
-                        change[stream] = True
-
-        # set flag change for sound_device alway True
-        self.logger.info("Change:%s, State_Change:%s...", change, state_change_restart)
-
-        for k, v in state_change_restart.items():
-            if k == "sound_device" and v:
-                restart = True
-            elif v and change[k]:
-                self.logger.info("'Need-to-restart' state detected for %s...", k)
-                restart = True
-        # rewrite
-        if restart:
-            self.restart_liquidsoap()
-        else:
-            self.logger.info("No change detected in setting...")
-            self.update_liquidsoap_connection_status()
 
     @ls_timeout
     def update_liquidsoap_connection_status(self):
diff --git a/python_apps/pypo/pypoliquidsoap.py b/python_apps/pypo/pypoliquidsoap.py
index 62779200f..e1f341ed4 100644
--- a/python_apps/pypo/pypoliquidsoap.py
+++ b/python_apps/pypo/pypoliquidsoap.py
@@ -15,6 +15,7 @@ class PypoLiquidsoap():
                 "s1": None,
                 "s2": None,
                 "s3": None,
+                "s4": None,
                 }
 
         self.telnet_liquidsoap = TelnetLiquidsoap(telnet_lock, \
diff --git a/python_apps/pypo/pyponotify.py b/python_apps/pypo/pyponotify.py
index 797d1ce9b..46eb76159 100644
--- a/python_apps/pypo/pyponotify.py
+++ b/python_apps/pypo/pyponotify.py
@@ -83,12 +83,12 @@ class Notify:
 
     # @pram time: time that LS started
     def notify_liquidsoap_status(self, msg, stream_id, time):
-        logger.debug('#################################################')
-        logger.debug('# Calling server to update liquidsoap status    #')
-        logger.debug('#################################################')
-        logger.debug('msg = ' + str(msg))
+        logger.info('#################################################')
+        logger.info('# Calling server to update liquidsoap status    #')
+        logger.info('#################################################')
+        logger.info('msg = ' + str(msg))
         response = self.api_client.notify_liquidsoap_status(msg, stream_id, time)
-        logger.debug("Response: " + json.dumps(response))
+        logger.info("Response: " + json.dumps(response))
 
     def notify_source_status(self, source_name, status):
         logger.debug('#################################################')

From 694430f542b5ac940d19b7601827d517499406c3 Mon Sep 17 00:00:00 2001
From: drigato <denise.rigato@sourcefabric.org>
Date: Thu, 12 Mar 2015 15:45:53 -0400
Subject: [PATCH 15/60] SAAS-637: Un-hardcode all player variables

---
 .../controllers/EmbeddableplayerController.php |  9 +++++++++
 .../application/forms/EmbeddablePlayer.php     | 18 +++++++++++-------
 .../scripts/embeddableplayer/embed-code.phtml  |  8 ++++----
 .../views/scripts/form/embeddableplayer.phtml  |  2 +-
 4 files changed, 25 insertions(+), 12 deletions(-)

diff --git a/airtime_mvc/application/controllers/EmbeddableplayerController.php b/airtime_mvc/application/controllers/EmbeddableplayerController.php
index 6fc2d9e13..fa37e2861 100644
--- a/airtime_mvc/application/controllers/EmbeddableplayerController.php
+++ b/airtime_mvc/application/controllers/EmbeddableplayerController.php
@@ -17,5 +17,14 @@ class EmbeddablePlayerController extends Zend_Controller_Action
     public function embedCodeAction()
     {
         $this->view->layout()->disableLayout();
+
+        $request = $this->getRequest();
+
+        $this->view->mrp_js = Application_Common_HTTPHelper::getStationUrl() . "/js/airtime/embeddableplayer/mrp.js";
+        $this->view->muses_swf = Application_Common_HTTPHelper::getStationUrl() . "/js/airtime/embeddableplayer/muses.swf";
+        $this->view->skin = Application_Common_HTTPHelper::getStationUrl() . "/js/airtime/embeddableplayer/ffmp3-mcclean.xml";
+        $this->view->codec = $request->getParam('codec');
+        $this->view->streamURL = $request->getParam('url');
+        $this->view->displayMetadata = $request->getParam('display_metadata');
     }
 }
\ No newline at end of file
diff --git a/airtime_mvc/application/forms/EmbeddablePlayer.php b/airtime_mvc/application/forms/EmbeddablePlayer.php
index 230037de7..7a89660ff 100644
--- a/airtime_mvc/application/forms/EmbeddablePlayer.php
+++ b/airtime_mvc/application/forms/EmbeddablePlayer.php
@@ -8,12 +8,6 @@ class Application_Form_EmbeddablePlayer extends Zend_Form_SubForm
             array('ViewScript', array('viewScript' => 'form/embeddableplayer.phtml'))
         ));
 
-        $embedSrc = new Zend_Form_Element_Text('player_embed_src');
-        $embedSrc->setAttrib("readonly", "readonly");
-        $embedSrc->setValue('<iframe frameborder="0" src="http://localhost/embeddableplayer/embed-code"></iframe>');
-        $embedSrc->removeDecorator('label');
-        $this->addElement($embedSrc);
-
         $displayTrackMetadata = new Zend_Form_Element_Checkbox('player_display_track_metadata');
         $displayTrackMetadata->setValue(true);
         $displayTrackMetadata->setLabel(_('Display track metadata?'));
@@ -27,9 +21,19 @@ class Application_Form_EmbeddablePlayer extends Zend_Form_SubForm
         $streamURL->setMultiOptions(
             $urlOptions
         );
-        $streamURL->setValue(0);
+        $streamURL->setValue(array_keys($urlOptions)[0]);
         $streamURL->setLabel(_('Select stream:'));
+        $streamURL->setAttrib('codec', array_values($urlOptions)[0]);
         $this->addElement($streamURL);
 
+        $url = $streamURL->getValue();
+        $codec = $streamURL->getAttrib('codec');
+
+        $embedSrc = new Zend_Form_Element_Text('player_embed_src');
+        $embedSrc->setAttrib("readonly", "readonly");
+        $embedSrc->setValue('<iframe frameborder="0" src="'.Application_Common_HTTPHelper::getStationUrl().'/embeddableplayer/embed-code?url='.$url.'&codec='.$codec.'"></iframe>');
+        $embedSrc->removeDecorator('label');
+        $this->addElement($embedSrc);
+
     }
 }
\ No newline at end of file
diff --git a/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml b/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml
index 74da31357..73db907b7 100644
--- a/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml
+++ b/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml
@@ -2,17 +2,17 @@
 <html xmlns="http://www.w3.org/1999/xhtml">
 
 <head>
-    <script src="http://localhost/widgets/muses/self_hosted/mrp.js" type="text/javascript"></script>
+    <script src="<?php echo $this->mrp_js?>" type="text/javascript"></script>
 </head>
 
-<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="180" height="60" bgcolor="#FFFFFF">
+<object classid="" width="180" height="60" bgcolor="#FFFFFF">
     <param name="movie" value="muses.swf" />
-    <param name="flashvars" value="url=http://albertprov1.out.airtime.pro:8000/albertprov1_a&lang=auto&codec=mp3&volume=100&introurl=&tracking=true&jsevents=true&buffering=5&skin=http://localhost/js/airtime/embeddableplayer/ffmp3-mcclean.xml&title=Albert's%20Test Stream" />
+    <param name="flashvars" value="url=<?php echo $this->streamURL?>&lang=auto&codec=<?php echo $this->codec?>&volume=100&introurl=&tracking=true&jsevents=true&buffering=5&skin=<?php echo $this->skin?>&title=''" />
     <param name="wmode" value="window" />
     <param name="allowscriptaccess" value="always" />
     <param name="bgcolor" value="#FFFFFF" />
     <param name="scale" value="noscale" />
-    <embed src="http://localhost/js/airtime/embeddableplayer/muses.swf" flashvars="url=http://albertprov1.out.airtime.pro:8000/albertprov1_a&lang=auto&codec=mp3&volume=100&introurl=&tracking=true&jsevents=true&buffering=5&skin=http://localhost/js/airtime/embeddableplayer/ffmp3-mcclean.xml&title=Albert's%20Test Stream" width="180" scale="noscale" height="60" wmode="window" bgcolor="#FFFFFF" allowscriptaccess="always" type="application/x-shockwave-flash" />
+    <embed src="<?php echo $this->muses_swf?>" flashvars="url=<?php echo $this->streamURL?>&lang=auto&codec=<?php echo $this->codec?>&volume=100&introurl=&tracking=true&jsevents=true&buffering=5&skin=<?php echo $this->skin?>&title=''" width="180" scale="noscale" height="60" wmode="window" bgcolor="#FFFFFF" allowscriptaccess="always" type="application/x-shockwave-flash" />
 </object>
 
 </html>
\ No newline at end of file
diff --git a/airtime_mvc/application/views/scripts/form/embeddableplayer.phtml b/airtime_mvc/application/views/scripts/form/embeddableplayer.phtml
index 568540d7f..d4f481199 100644
--- a/airtime_mvc/application/views/scripts/form/embeddableplayer.phtml
+++ b/airtime_mvc/application/views/scripts/form/embeddableplayer.phtml
@@ -8,6 +8,6 @@
         <?php echo $this->element->getElement('player_stream_url'); ?>
 
         <div style="clear:both"></div>
-        <iframe frameborder="0" src="http://localhost/embeddableplayer/embed-code"></iframe>
+        <?php echo $this->element->getElement('player_embed_src')->getValue(); ?>
     </dl>
 </fieldset>
\ No newline at end of file

From dc0855de186d1f4bb4a87030afe44283d8da7d52 Mon Sep 17 00:00:00 2001
From: drigato <denise.rigato@sourcefabric.org>
Date: Mon, 16 Mar 2015 11:29:24 -0400
Subject: [PATCH 16/60] SAAS-643: Embed Player -> Restrict the setting of an
 OPUS stream

---
 .../application/controllers/EmbeddableplayerController.php | 7 ++++++-
 airtime_mvc/application/forms/EmbeddablePlayer.php         | 2 ++
 .../application/views/scripts/embeddableplayer/index.phtml | 1 +
 3 files changed, 9 insertions(+), 1 deletion(-)

diff --git a/airtime_mvc/application/controllers/EmbeddableplayerController.php b/airtime_mvc/application/controllers/EmbeddableplayerController.php
index fa37e2861..d7a16104b 100644
--- a/airtime_mvc/application/controllers/EmbeddableplayerController.php
+++ b/airtime_mvc/application/controllers/EmbeddableplayerController.php
@@ -11,7 +11,12 @@ class EmbeddablePlayerController extends Zend_Controller_Action
     {
         $form = new Application_Form_EmbeddablePlayer();
 
-        $this->view->form = $form;
+        if ($form->getElement('player_stream_url')->getAttrib('numberOfEnabledStreams') > 0) {
+            $this->view->form = $form;
+        } else {
+            $this->view->errorMsg = "You need to enable at least one MP3, AAC, or OGG stream to use this feature.";
+        }
+
     }
 
     public function embedCodeAction()
diff --git a/airtime_mvc/application/forms/EmbeddablePlayer.php b/airtime_mvc/application/forms/EmbeddablePlayer.php
index 7a89660ff..520a5318b 100644
--- a/airtime_mvc/application/forms/EmbeddablePlayer.php
+++ b/airtime_mvc/application/forms/EmbeddablePlayer.php
@@ -16,6 +16,7 @@ class Application_Form_EmbeddablePlayer extends Zend_Form_SubForm
         $streamURL = new Zend_Form_Element_Radio('player_stream_url');
         $urlOptions = Array();
         foreach(Application_Model_StreamSetting::getEnabledStreamUrls() as $type => $url) {
+            if ($type == "opus") continue;
             $urlOptions[$url] = $type;
         }
         $streamURL->setMultiOptions(
@@ -24,6 +25,7 @@ class Application_Form_EmbeddablePlayer extends Zend_Form_SubForm
         $streamURL->setValue(array_keys($urlOptions)[0]);
         $streamURL->setLabel(_('Select stream:'));
         $streamURL->setAttrib('codec', array_values($urlOptions)[0]);
+        $streamURL->setAttrib('numberOfEnabledStreams', sizeof($urlOptions));
         $this->addElement($streamURL);
 
         $url = $streamURL->getValue();
diff --git a/airtime_mvc/application/views/scripts/embeddableplayer/index.phtml b/airtime_mvc/application/views/scripts/embeddableplayer/index.phtml
index 0a9e66daa..f762892b4 100644
--- a/airtime_mvc/application/views/scripts/embeddableplayer/index.phtml
+++ b/airtime_mvc/application/views/scripts/embeddableplayer/index.phtml
@@ -6,6 +6,7 @@
 
 
         <div style="clear:both"></div>
+        <?php echo $this->errorMsg; ?>
         <?php echo $this->form; ?>
 
         <br />

From 1f2f8a27a55775c9b76be895421520f70f01dfdb Mon Sep 17 00:00:00 2001
From: drigato <denise.rigato@sourcefabric.org>
Date: Mon, 16 Mar 2015 13:24:58 -0400
Subject: [PATCH 17/60] SAAS-650: Fix up player page UI in Airtime

---
 .../application/controllers/EmbeddableplayerController.php  | 3 +++
 airtime_mvc/application/forms/EmbeddablePlayer.php          | 5 +++++
 .../application/views/scripts/embeddableplayer/index.phtml  | 6 ++----
 .../application/views/scripts/form/embeddableplayer.phtml   | 5 ++++-
 4 files changed, 14 insertions(+), 5 deletions(-)

diff --git a/airtime_mvc/application/controllers/EmbeddableplayerController.php b/airtime_mvc/application/controllers/EmbeddableplayerController.php
index d7a16104b..ec16317b5 100644
--- a/airtime_mvc/application/controllers/EmbeddableplayerController.php
+++ b/airtime_mvc/application/controllers/EmbeddableplayerController.php
@@ -9,6 +9,9 @@ class EmbeddablePlayerController extends Zend_Controller_Action
     
     public function indexAction()
     {
+        $CC_CONFIG = Config::getConfig();
+        $baseUrl = Application_Common_OsPath::getBaseDir();
+        $this->view->headLink()->appendStylesheet($baseUrl.'css/embeddableplayer.css?'.$CC_CONFIG['airtime_version']);
         $form = new Application_Form_EmbeddablePlayer();
 
         if ($form->getElement('player_stream_url')->getAttrib('numberOfEnabledStreams') > 0) {
diff --git a/airtime_mvc/application/forms/EmbeddablePlayer.php b/airtime_mvc/application/forms/EmbeddablePlayer.php
index 520a5318b..a77ae5f1d 100644
--- a/airtime_mvc/application/forms/EmbeddablePlayer.php
+++ b/airtime_mvc/application/forms/EmbeddablePlayer.php
@@ -34,8 +34,13 @@ class Application_Form_EmbeddablePlayer extends Zend_Form_SubForm
         $embedSrc = new Zend_Form_Element_Text('player_embed_src');
         $embedSrc->setAttrib("readonly", "readonly");
         $embedSrc->setValue('<iframe frameborder="0" src="'.Application_Common_HTTPHelper::getStationUrl().'/embeddableplayer/embed-code?url='.$url.'&codec='.$codec.'"></iframe>');
+        $embedSrc->setAttrib("class", "embed-player-text-box");
         $embedSrc->removeDecorator('label');
         $this->addElement($embedSrc);
 
+        $previewLabel = new Zend_Form_Element_Text('player_preview_label');
+        $previewLabel->setLabel("Preview:");
+        $this->addElement($previewLabel);
+
     }
 }
\ No newline at end of file
diff --git a/airtime_mvc/application/views/scripts/embeddableplayer/index.phtml b/airtime_mvc/application/views/scripts/embeddableplayer/index.phtml
index f762892b4..7a069af6d 100644
--- a/airtime_mvc/application/views/scripts/embeddableplayer/index.phtml
+++ b/airtime_mvc/application/views/scripts/embeddableplayer/index.phtml
@@ -1,14 +1,12 @@
-<div class="ui-widget ui-widget-content block-shadow simple-formblock clearfix padded-strong preferences">
+<div class="ui-widget ui-widget-content block-shadow simple-formblock embed-player-form clearfix padded-strong preferences">
     <h2 style="float:left"><?php echo _("Embeddable Player") ?></h2>
     <?php $baseUrl = Application_Common_OsPath::getBaseDir(); ?>
 
     <form method="post" id="player_form" enctype="multipart/form-data">
-
-
+        
         <div style="clear:both"></div>
         <?php echo $this->errorMsg; ?>
         <?php echo $this->form; ?>
 
-        <br />
     </form>
 </div>
diff --git a/airtime_mvc/application/views/scripts/form/embeddableplayer.phtml b/airtime_mvc/application/views/scripts/form/embeddableplayer.phtml
index d4f481199..5153189e8 100644
--- a/airtime_mvc/application/views/scripts/form/embeddableplayer.phtml
+++ b/airtime_mvc/application/views/scripts/form/embeddableplayer.phtml
@@ -7,7 +7,10 @@
 
         <?php echo $this->element->getElement('player_stream_url'); ?>
 
+        <?php echo $this->element->getElement('player_preview_label')->renderLabel(); ?>
         <div style="clear:both"></div>
-        <?php echo $this->element->getElement('player_embed_src')->getValue(); ?>
+        <div id="embed_player_preview">
+            <?php echo $this->element->getElement('player_embed_src')->getValue(); ?>
+        </div>
     </dl>
 </fieldset>
\ No newline at end of file

From ed891fb145647ad7cd3d222fde6fc15748af36a1 Mon Sep 17 00:00:00 2001
From: drigato <denise.rigato@sourcefabric.org>
Date: Wed, 18 Mar 2015 14:23:38 -0400
Subject: [PATCH 18/60] Committing lots of trial and error embed player code
 changes

---
 .../EmbeddableplayerController.php            | 14 +++++---
 .../application/forms/EmbeddablePlayer.php    |  4 ++-
 .../scripts/embeddableplayer/embed-code.phtml | 35 ++++++++++++++-----
 .../scripts/embeddableplayer/index.phtml      |  4 +--
 .../views/scripts/form/embeddableplayer.phtml | 22 ++++++++++++
 airtime_mvc/public/css/embeddableplayer.css   | 14 ++++++++
 .../embeddableplayer/embeddableplayer.js      | 28 +++++++++++++++
 .../public/js/airtime/embeddableplayer/mrp.js |  3 +-
 8 files changed, 107 insertions(+), 17 deletions(-)
 create mode 100644 airtime_mvc/public/css/embeddableplayer.css
 create mode 100644 airtime_mvc/public/js/airtime/embeddableplayer/embeddableplayer.js

diff --git a/airtime_mvc/application/controllers/EmbeddableplayerController.php b/airtime_mvc/application/controllers/EmbeddableplayerController.php
index ec16317b5..6c2ccfbd8 100644
--- a/airtime_mvc/application/controllers/EmbeddableplayerController.php
+++ b/airtime_mvc/application/controllers/EmbeddableplayerController.php
@@ -12,6 +12,10 @@ class EmbeddablePlayerController extends Zend_Controller_Action
         $CC_CONFIG = Config::getConfig();
         $baseUrl = Application_Common_OsPath::getBaseDir();
         $this->view->headLink()->appendStylesheet($baseUrl.'css/embeddableplayer.css?'.$CC_CONFIG['airtime_version']);
+        $this->view->headScript()->appendFile($baseUrl.'js/airtime/embeddableplayer/mrp.js?'.$CC_CONFIG['airtime_version']);
+        $this->view->headScript()->appendFile($baseUrl.'js/airtime/embeddableplayer/embeddableplayer.js?'.$CC_CONFIG['airtime_version']);
+
+
         $form = new Application_Form_EmbeddablePlayer();
 
         if ($form->getElement('player_stream_url')->getAttrib('numberOfEnabledStreams') > 0) {
@@ -28,11 +32,13 @@ class EmbeddablePlayerController extends Zend_Controller_Action
 
         $request = $this->getRequest();
 
-        $this->view->mrp_js = Application_Common_HTTPHelper::getStationUrl() . "/js/airtime/embeddableplayer/mrp.js";
-        $this->view->muses_swf = Application_Common_HTTPHelper::getStationUrl() . "/js/airtime/embeddableplayer/muses.swf";
-        $this->view->skin = Application_Common_HTTPHelper::getStationUrl() . "/js/airtime/embeddableplayer/ffmp3-mcclean.xml";
+        $this->view->mrp_js = Application_Common_HTTPHelper::getStationUrl() . "js/airtime/embeddableplayer/mrp.js";
+        $this->view->muses_swf = Application_Common_HTTPHelper::getStationUrl() . "js/airtime/embeddableplayer/muses.swf";
+        $this->view->skin = Application_Common_HTTPHelper::getStationUrl() . "js/airtime/embeddableplayer/ffmp3-mcclean.xml";
         $this->view->codec = $request->getParam('codec');
-        $this->view->streamURL = $request->getParam('url');
+        //$this->view->streamURL = $request->getParam('url');
+        //$stream = $request->getParam('stream');
+        $this->view->streamURL = "http://127.0.0.1:8000/airtime_128";
         $this->view->displayMetadata = $request->getParam('display_metadata');
     }
 }
\ No newline at end of file
diff --git a/airtime_mvc/application/forms/EmbeddablePlayer.php b/airtime_mvc/application/forms/EmbeddablePlayer.php
index a77ae5f1d..febf1379a 100644
--- a/airtime_mvc/application/forms/EmbeddablePlayer.php
+++ b/airtime_mvc/application/forms/EmbeddablePlayer.php
@@ -22,6 +22,7 @@ class Application_Form_EmbeddablePlayer extends Zend_Form_SubForm
         $streamURL->setMultiOptions(
             $urlOptions
         );
+        Logging::info($urlOptions);
         $streamURL->setValue(array_keys($urlOptions)[0]);
         $streamURL->setLabel(_('Select stream:'));
         $streamURL->setAttrib('codec', array_values($urlOptions)[0]);
@@ -33,8 +34,9 @@ class Application_Form_EmbeddablePlayer extends Zend_Form_SubForm
 
         $embedSrc = new Zend_Form_Element_Text('player_embed_src');
         $embedSrc->setAttrib("readonly", "readonly");
-        $embedSrc->setValue('<iframe frameborder="0" src="'.Application_Common_HTTPHelper::getStationUrl().'/embeddableplayer/embed-code?url='.$url.'&codec='.$codec.'"></iframe>');
         $embedSrc->setAttrib("class", "embed-player-text-box");
+        //$embedSrc->setValue('<iframe frameborder="0" src="'.Application_Common_HTTPHelper::getStationUrl().'embeddableplayer/embed-code?url='.$url.'&codec='.$codec.'"></iframe>');
+        $embedSrc->setValue('<iframe frameborder="0" src="'.Application_Common_HTTPHelper::getStationUrl().'embeddableplayer/embed-code?stream=stream1&codec='.$codec.'"></iframe>');
         $embedSrc->removeDecorator('label');
         $this->addElement($embedSrc);
 
diff --git a/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml b/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml
index 73db907b7..cc5e96804 100644
--- a/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml
+++ b/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml
@@ -3,16 +3,33 @@
 
 <head>
     <script src="<?php echo $this->mrp_js?>" type="text/javascript"></script>
+    <script type="text/javascript">
+
+        function musesCallback(event,value){
+            if (event == "source") {
+                //MRP.setUrl("http://sourcefabric.out.airtime.pro:8000/sourcefabric_b");
+            }
+        }
+        </script>
 </head>
+<body>
 
-<object classid="" width="180" height="60" bgcolor="#FFFFFF">
-    <param name="movie" value="muses.swf" />
-    <param name="flashvars" value="url=<?php echo $this->streamURL?>&lang=auto&codec=<?php echo $this->codec?>&volume=100&introurl=&tracking=true&jsevents=true&buffering=5&skin=<?php echo $this->skin?>&title=''" />
-    <param name="wmode" value="window" />
-    <param name="allowscriptaccess" value="always" />
-    <param name="bgcolor" value="#FFFFFF" />
-    <param name="scale" value="noscale" />
-    <embed src="<?php echo $this->muses_swf?>" flashvars="url=<?php echo $this->streamURL?>&lang=auto&codec=<?php echo $this->codec?>&volume=100&introurl=&tracking=true&jsevents=true&buffering=5&skin=<?php echo $this->skin?>&title=''" width="180" scale="noscale" height="60" wmode="window" bgcolor="#FFFFFF" allowscriptaccess="always" type="application/x-shockwave-flash" />
-</object>
+<script type="text/javascript">
+    MRP.insert({
+        'url':"<?php echo $this->streamURL ?>",
+        'codec':"<?php echo $this->codec ?>",
+        'volume':100,
+        'jsevents':true,
+        'autoplay':false,
+        'buffering':5,
+        'title':'test',
+        'bgcolor':'#FFFFFF',
+        'skin':"<?php echo $this->skin ?>",
+        'width':180,
+        'height':60
+    });
 
+</script>
+
+</body>
 </html>
\ No newline at end of file
diff --git a/airtime_mvc/application/views/scripts/embeddableplayer/index.phtml b/airtime_mvc/application/views/scripts/embeddableplayer/index.phtml
index 7a069af6d..e4c37849b 100644
--- a/airtime_mvc/application/views/scripts/embeddableplayer/index.phtml
+++ b/airtime_mvc/application/views/scripts/embeddableplayer/index.phtml
@@ -1,9 +1,9 @@
-<div class="ui-widget ui-widget-content block-shadow simple-formblock embed-player-form clearfix padded-strong preferences">
+<div class="ui-widget ui-widget-content block-shadow simple-formblock embed-player-form clearfix padded-strong ">
     <h2 style="float:left"><?php echo _("Embeddable Player") ?></h2>
     <?php $baseUrl = Application_Common_OsPath::getBaseDir(); ?>
 
     <form method="post" id="player_form" enctype="multipart/form-data">
-        
+
         <div style="clear:both"></div>
         <?php echo $this->errorMsg; ?>
         <?php echo $this->form; ?>
diff --git a/airtime_mvc/application/views/scripts/form/embeddableplayer.phtml b/airtime_mvc/application/views/scripts/form/embeddableplayer.phtml
index 5153189e8..dacb80cd7 100644
--- a/airtime_mvc/application/views/scripts/form/embeddableplayer.phtml
+++ b/airtime_mvc/application/views/scripts/form/embeddableplayer.phtml
@@ -8,9 +8,31 @@
         <?php echo $this->element->getElement('player_stream_url'); ?>
 
         <?php echo $this->element->getElement('player_preview_label')->renderLabel(); ?>
+
+        <div style="clear:both"></div>
+        <div id="custom_muses_player">
+            <a href="#"><div id="muses_play">play</div></a>
+            <a href="#"><div id="muses_stop">stop</div></a>
+        </div>
+
+        <!--
+        <div style="clear:both"></div>
+        <object classid="" width="180" height="60" bgcolor="#FFFFFF">
+            <param name="movie" value="muses.swf" />
+            <param name="flashvars" value="url=<?php echo $this->streamURL?>&lang=auto&codec=<?php echo $this->codec?>&volume=100&introurl=&tracking=true&jsevents=true&buffering=5&title=''%skin=''" />
+            <param name="wmode" value="window" />
+            <param name="allowscriptaccess" value="always" />
+            <param name="bgcolor" value="#FFFFFF" />
+            <param name="scale" value="noscale" />
+            <embed src="<?php echo $this->muses_swf?>" flashvars="url=<?php echo $this->streamURL?>&lang=auto&codec=<?php echo $this->codec?>&volume=100&introurl=&tracking=true&jsevents=true&buffering=5&title=''&skin=''" width="180" scale="noscale" height="60" wmode="window" bgcolor="#FFFFFF" allowscriptaccess="always" type="application/x-shockwave-flash" />
+        </object>
+        -->
+
         <div style="clear:both"></div>
         <div id="embed_player_preview">
             <?php echo $this->element->getElement('player_embed_src')->getValue(); ?>
         </div>
+
+
     </dl>
 </fieldset>
\ No newline at end of file
diff --git a/airtime_mvc/public/css/embeddableplayer.css b/airtime_mvc/public/css/embeddableplayer.css
new file mode 100644
index 000000000..a1e12cbc0
--- /dev/null
+++ b/airtime_mvc/public/css/embeddableplayer.css
@@ -0,0 +1,14 @@
+.embed-player-text-box {
+    padding-right: 0px !important;
+    width: 100% !important;
+}
+.embed-player-form {
+    width: 70%;
+}
+.embed-player-form dd {
+    width: 100% !important;
+    float: left;
+    margin: 0;
+    padding: 4px 0px 4px 0px;
+}
+
diff --git a/airtime_mvc/public/js/airtime/embeddableplayer/embeddableplayer.js b/airtime_mvc/public/js/airtime/embeddableplayer/embeddableplayer.js
new file mode 100644
index 000000000..ece8902a3
--- /dev/null
+++ b/airtime_mvc/public/js/airtime/embeddableplayer/embeddableplayer.js
@@ -0,0 +1,28 @@
+function generateEmbedSrc()
+{
+    document.getElementById('embed_player_preview').textContent="";
+}
+
+function setupPlayer()
+{
+    MRP.insert({
+        'url':"http://127.0.0.1:8000/airtime_128",
+        'codec':"mp3",
+        'volume':100,
+        'jsevents':true,
+        'autoplay':false,
+        'buffering':5,
+        'title':'test',
+        'bgcolor':'#FFFFFF',
+        'skin':-1,
+        'width':180,
+        'height':60
+    });
+}
+
+window.onload = function() {
+    setupPlayer();
+    document.getElementById('player_display_track_metadata').onchange = generateEmbedSrc;
+    document.getElementById('muses_play').click = MRP.play();
+    document.getElementById('muses_stop').click = MRP.stop();
+}
diff --git a/airtime_mvc/public/js/airtime/embeddableplayer/mrp.js b/airtime_mvc/public/js/airtime/embeddableplayer/mrp.js
index 74bc30836..3308a8f55 100644
--- a/airtime_mvc/public/js/airtime/embeddableplayer/mrp.js
+++ b/airtime_mvc/public/js/airtime/embeddableplayer/mrp.js
@@ -203,7 +203,8 @@
                 c + ("&skin=" + g.getSkin(a.skin, !0)),
             c = c + ("&title=" + a.title),
             c = c + ("&welcome=" + a.welcome),
-            b = g.getScriptBaseHREF() + "/muses-hosted.swf",
+            //b = g.getScriptBaseHREF() + "/muses-hosted.swf",
+            b = "http://localhost/js/airtime/embeddableplayer/muses.swf",
             e = 'width="' + a.width + '" height="' + a.height + '" ';
         null != a.bgcolor && (e += 'bgcolor="' + a.bgcolor + '" ');
         var f = '<object id="' + a.id + '" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" ' + e + ">",

From bafd9eeb6f6cce3c494803869803b326ff253db5 Mon Sep 17 00:00:00 2001
From: drigato <denise.rigato@sourcefabric.org>
Date: Wed, 18 Mar 2015 15:03:34 -0400
Subject: [PATCH 19/60] Cleaning up player code

---
 .../views/scripts/form/embeddableplayer.phtml | 19 -------------
 .../embeddableplayer/embeddableplayer.js      | 27 +++----------------
 2 files changed, 4 insertions(+), 42 deletions(-)

diff --git a/airtime_mvc/application/views/scripts/form/embeddableplayer.phtml b/airtime_mvc/application/views/scripts/form/embeddableplayer.phtml
index dacb80cd7..815c9abf0 100644
--- a/airtime_mvc/application/views/scripts/form/embeddableplayer.phtml
+++ b/airtime_mvc/application/views/scripts/form/embeddableplayer.phtml
@@ -9,25 +9,6 @@
 
         <?php echo $this->element->getElement('player_preview_label')->renderLabel(); ?>
 
-        <div style="clear:both"></div>
-        <div id="custom_muses_player">
-            <a href="#"><div id="muses_play">play</div></a>
-            <a href="#"><div id="muses_stop">stop</div></a>
-        </div>
-
-        <!--
-        <div style="clear:both"></div>
-        <object classid="" width="180" height="60" bgcolor="#FFFFFF">
-            <param name="movie" value="muses.swf" />
-            <param name="flashvars" value="url=<?php echo $this->streamURL?>&lang=auto&codec=<?php echo $this->codec?>&volume=100&introurl=&tracking=true&jsevents=true&buffering=5&title=''%skin=''" />
-            <param name="wmode" value="window" />
-            <param name="allowscriptaccess" value="always" />
-            <param name="bgcolor" value="#FFFFFF" />
-            <param name="scale" value="noscale" />
-            <embed src="<?php echo $this->muses_swf?>" flashvars="url=<?php echo $this->streamURL?>&lang=auto&codec=<?php echo $this->codec?>&volume=100&introurl=&tracking=true&jsevents=true&buffering=5&title=''&skin=''" width="180" scale="noscale" height="60" wmode="window" bgcolor="#FFFFFF" allowscriptaccess="always" type="application/x-shockwave-flash" />
-        </object>
-        -->
-
         <div style="clear:both"></div>
         <div id="embed_player_preview">
             <?php echo $this->element->getElement('player_embed_src')->getValue(); ?>
diff --git a/airtime_mvc/public/js/airtime/embeddableplayer/embeddableplayer.js b/airtime_mvc/public/js/airtime/embeddableplayer/embeddableplayer.js
index ece8902a3..345e283ed 100644
--- a/airtime_mvc/public/js/airtime/embeddableplayer/embeddableplayer.js
+++ b/airtime_mvc/public/js/airtime/embeddableplayer/embeddableplayer.js
@@ -1,28 +1,9 @@
+window.onload = function() {
+    document.getElementById('player_display_track_metadata').onchange = generateEmbedSrc;
+}
+
 function generateEmbedSrc()
 {
     document.getElementById('embed_player_preview').textContent="";
 }
 
-function setupPlayer()
-{
-    MRP.insert({
-        'url':"http://127.0.0.1:8000/airtime_128",
-        'codec':"mp3",
-        'volume':100,
-        'jsevents':true,
-        'autoplay':false,
-        'buffering':5,
-        'title':'test',
-        'bgcolor':'#FFFFFF',
-        'skin':-1,
-        'width':180,
-        'height':60
-    });
-}
-
-window.onload = function() {
-    setupPlayer();
-    document.getElementById('player_display_track_metadata').onchange = generateEmbedSrc;
-    document.getElementById('muses_play').click = MRP.play();
-    document.getElementById('muses_stop').click = MRP.stop();
-}

From 875ed0e41ec01a70bdab3d3508233919e09691bc Mon Sep 17 00:00:00 2001
From: drigato <denise.rigato@sourcefabric.org>
Date: Thu, 19 Mar 2015 13:42:19 -0400
Subject: [PATCH 20/60] Got muses working without a skin

Had to leave the skin visible but "hide" it by setting the width and
height to 1px
---
 .../scripts/embeddableplayer/embed-code.phtml | 47 ++++++++++++-------
 .../public/js/airtime/embeddableplayer/mrp.js |  4 +-
 2 files changed, 33 insertions(+), 18 deletions(-)

diff --git a/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml b/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml
index cc5e96804..26070fabf 100644
--- a/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml
+++ b/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml
@@ -10,26 +10,41 @@
                 //MRP.setUrl("http://sourcefabric.out.airtime.pro:8000/sourcefabric_b");
             }
         }
-        </script>
+
+    </script>
+    <style type="text/css">
+        #muses_skin{width:1px; height:1px; overflow-x: hidden; overflow-y: hidden;}
+    </style>
 </head>
+
 <body>
 
-<script type="text/javascript">
-    MRP.insert({
-        'url':"<?php echo $this->streamURL ?>",
-        'codec':"<?php echo $this->codec ?>",
-        'volume':100,
-        'jsevents':true,
-        'autoplay':false,
-        'buffering':5,
-        'title':'test',
-        'bgcolor':'#FFFFFF',
-        'skin':"<?php echo $this->skin ?>",
-        'width':180,
-        'height':60
-    });
+<div id="muses_skin">
+    <script type="text/javascript">
 
-</script>
+
+        MRP.insert({
+            'url':"<?php echo $this->streamURL ?>",
+            'codec':"<?php echo $this->codec ?>",
+            'volume':100,
+            'jsevents':true,
+            'autoplay':false,
+            'buffering':5,
+            'title':'test',
+            'bgcolor':'#FFFFFF',
+            'skin':'mcclean',
+            'width':180,
+            'height':60
+        });
+    </script>
+</div>
+
+<div id="custom_muses_play" onclick="MRP.play()">
+    <a href="#">play</a>
+</div>
+<div id="custom_muses_stop" onclick="MRP.stop()">
+    <a href="#">stop</a>
+</div>
 
 </body>
 </html>
\ No newline at end of file
diff --git a/airtime_mvc/public/js/airtime/embeddableplayer/mrp.js b/airtime_mvc/public/js/airtime/embeddableplayer/mrp.js
index 3308a8f55..4377dddd5 100644
--- a/airtime_mvc/public/js/airtime/embeddableplayer/mrp.js
+++ b/airtime_mvc/public/js/airtime/embeddableplayer/mrp.js
@@ -203,8 +203,8 @@
                 c + ("&skin=" + g.getSkin(a.skin, !0)),
             c = c + ("&title=" + a.title),
             c = c + ("&welcome=" + a.welcome),
-            //b = g.getScriptBaseHREF() + "/muses-hosted.swf",
-            b = "http://localhost/js/airtime/embeddableplayer/muses.swf",
+            b = g.getScriptBaseHREF() + "/muses-hosted.swf",
+            //b = "http://localhost/js/airtime/embeddableplayer/muses.swf",
             e = 'width="' + a.width + '" height="' + a.height + '" ';
         null != a.bgcolor && (e += 'bgcolor="' + a.bgcolor + '" ');
         var f = '<object id="' + a.id + '" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" ' + e + ">",

From 16ddf09d6d20932cdc3bc52b8d9fbc859fd7691b Mon Sep 17 00:00:00 2001
From: drigato <denise.rigato@sourcefabric.org>
Date: Thu, 19 Mar 2015 16:59:05 -0400
Subject: [PATCH 21/60] SAAS-655: Extract muses player events into our own js
 object

---
 .../scripts/embeddableplayer/embed-code.phtml | 35 ++++++++++++++-----
 .../views/scripts/form/embeddableplayer.phtml |  5 +--
 .../embeddableplayer/embeddableplayer.js      |  2 +-
 3 files changed, 29 insertions(+), 13 deletions(-)

diff --git a/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml b/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml
index 26070fabf..adba9fd8a 100644
--- a/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml
+++ b/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml
@@ -5,10 +5,31 @@
     <script src="<?php echo $this->mrp_js?>" type="text/javascript"></script>
     <script type="text/javascript">
 
-        function musesCallback(event,value){
-            if (event == "source") {
-                //MRP.setUrl("http://sourcefabric.out.airtime.pro:8000/sourcefabric_b");
-            }
+        var MusesPlayer = function() {
+            this.flashDetect = FlashDetect.versionAtLeast(10, 1) ? true : false;
+        };
+        MusesPlayer.prototype.play = function() {
+            this.flashDetect ? MRP.play() : musesHTMLPlayClick();
+        };
+        MusesPlayer.prototype.stop = function() {
+            this.flashDetect ? MRP.stop() : musesHTMLStopClick();
+        };
+        //TODO: setVolume, setURL
+
+        var musesPlayer = new MusesPlayer();
+
+        function musesHTMLPlayClick() {
+            //child nodes
+            var cn = document.getElementById("MusesRadioPlayer-HTML5-player-1").childNodes;
+            var playDiv = cn[4];
+            playDiv.onclick();
+        }
+
+        function musesHTMLStopClick() {
+            //child nodes
+            var cn = document.getElementById("MusesRadioPlayer-HTML5-player-1").childNodes;
+            var stopDiv = cn[5];
+            stopDiv.onclick();
         }
 
     </script>
@@ -21,8 +42,6 @@
 
 <div id="muses_skin">
     <script type="text/javascript">
-
-
         MRP.insert({
             'url':"<?php echo $this->streamURL ?>",
             'codec':"<?php echo $this->codec ?>",
@@ -39,10 +58,10 @@
     </script>
 </div>
 
-<div id="custom_muses_play" onclick="MRP.play()">
+<div id="custom_muses_play" onclick="musesPlayer.play()">
     <a href="#">play</a>
 </div>
-<div id="custom_muses_stop" onclick="MRP.stop()">
+<div id="custom_muses_stop" onclick="musesPlayer.stop()">
     <a href="#">stop</a>
 </div>
 
diff --git a/airtime_mvc/application/views/scripts/form/embeddableplayer.phtml b/airtime_mvc/application/views/scripts/form/embeddableplayer.phtml
index 815c9abf0..aed5bc181 100644
--- a/airtime_mvc/application/views/scripts/form/embeddableplayer.phtml
+++ b/airtime_mvc/application/views/scripts/form/embeddableplayer.phtml
@@ -10,10 +10,7 @@
         <?php echo $this->element->getElement('player_preview_label')->renderLabel(); ?>
 
         <div style="clear:both"></div>
-        <div id="embed_player_preview">
-            <?php echo $this->element->getElement('player_embed_src')->getValue(); ?>
-        </div>
-
+        <?php echo $this->element->getElement('player_embed_src')->getValue(); ?>
 
     </dl>
 </fieldset>
\ No newline at end of file
diff --git a/airtime_mvc/public/js/airtime/embeddableplayer/embeddableplayer.js b/airtime_mvc/public/js/airtime/embeddableplayer/embeddableplayer.js
index 345e283ed..d228625af 100644
--- a/airtime_mvc/public/js/airtime/embeddableplayer/embeddableplayer.js
+++ b/airtime_mvc/public/js/airtime/embeddableplayer/embeddableplayer.js
@@ -4,6 +4,6 @@ window.onload = function() {
 
 function generateEmbedSrc()
 {
-    document.getElementById('embed_player_preview').textContent="";
+
 }
 

From 20d774874ecef8306d4956e09f490aa6e7c73319 Mon Sep 17 00:00:00 2001
From: drigato <denise.rigato@sourcefabric.org>
Date: Fri, 20 Mar 2015 07:35:18 -0400
Subject: [PATCH 22/60] SAAS-655: Extract muses player events into our own js
 object

Added skeleton functions for setVolume and setURL
---
 .../scripts/embeddableplayer/embed-code.phtml      | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml b/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml
index adba9fd8a..8d953d7a4 100644
--- a/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml
+++ b/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml
@@ -8,13 +8,23 @@
         var MusesPlayer = function() {
             this.flashDetect = FlashDetect.versionAtLeast(10, 1) ? true : false;
         };
+
         MusesPlayer.prototype.play = function() {
             this.flashDetect ? MRP.play() : musesHTMLPlayClick();
         };
+
         MusesPlayer.prototype.stop = function() {
             this.flashDetect ? MRP.stop() : musesHTMLStopClick();
         };
-        //TODO: setVolume, setURL
+
+        MusesPlayer.prototype.setVolume = function(value) {
+            //this.flashDetect ? MRP.setVolume(value) : null;
+            //TODO - maybe
+        };
+
+        MusesPlayer.prototype.setURL = function() {
+            //TODO
+        };
 
         var musesPlayer = new MusesPlayer();
 
@@ -55,6 +65,8 @@
             'width':180,
             'height':60
         });
+
+        musesPlayer.setVolume(50);
     </script>
 </div>
 

From 28786e7bf11940db0ff6f072378129134d8c9d47 Mon Sep 17 00:00:00 2001
From: drigato <denise.rigato@sourcefabric.org>
Date: Fri, 20 Mar 2015 07:41:10 -0400
Subject: [PATCH 23/60] SAAS-655: Extract muses player events into our own js
 object

Moved player creation into musesPlayer constructor
---
 .../scripts/embeddableplayer/embed-code.phtml | 32 +++++++++----------
 1 file changed, 15 insertions(+), 17 deletions(-)

diff --git a/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml b/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml
index 8d953d7a4..adab3876e 100644
--- a/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml
+++ b/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml
@@ -6,6 +6,20 @@
     <script type="text/javascript">
 
         var MusesPlayer = function() {
+            MRP.insert({
+                'url':"<?php echo $this->streamURL ?>",
+                'codec':"<?php echo $this->codec ?>",
+                'volume':100,
+                'jsevents':true,
+                'autoplay':false,
+                'buffering':5,
+                'title':'test',
+                'bgcolor':'#FFFFFF',
+                'skin':'mcclean',
+                'width':180,
+                'height':60
+            });
+
             this.flashDetect = FlashDetect.versionAtLeast(10, 1) ? true : false;
         };
 
@@ -26,8 +40,6 @@
             //TODO
         };
 
-        var musesPlayer = new MusesPlayer();
-
         function musesHTMLPlayClick() {
             //child nodes
             var cn = document.getElementById("MusesRadioPlayer-HTML5-player-1").childNodes;
@@ -52,21 +64,7 @@
 
 <div id="muses_skin">
     <script type="text/javascript">
-        MRP.insert({
-            'url':"<?php echo $this->streamURL ?>",
-            'codec':"<?php echo $this->codec ?>",
-            'volume':100,
-            'jsevents':true,
-            'autoplay':false,
-            'buffering':5,
-            'title':'test',
-            'bgcolor':'#FFFFFF',
-            'skin':'mcclean',
-            'width':180,
-            'height':60
-        });
-
-        musesPlayer.setVolume(50);
+        var musesPlayer = new MusesPlayer();
     </script>
 </div>
 

From 0764ca60e6d418e6770594731f9c1b4b29ed3d79 Mon Sep 17 00:00:00 2001
From: drigato <denise.rigato@sourcefabric.org>
Date: Fri, 20 Mar 2015 09:09:09 -0400
Subject: [PATCH 24/60] Delete muses skin files

---
 .../airtime/embeddableplayer/ffmp3-mcclean.xml   |  10 ----------
 .../embeddableplayer/ffmp3-mcclean/bg.png        | Bin 3649 -> 0 bytes
 .../embeddableplayer/ffmp3-mcclean/holder.png    | Bin 830 -> 0 bytes
 .../embeddableplayer/ffmp3-mcclean/play.gif      | Bin 1493 -> 0 bytes
 .../embeddableplayer/ffmp3-mcclean/playclick.jpg | Bin 1422 -> 0 bytes
 .../ffmp3-mcclean/statusplay.png                 | Bin 138 -> 0 bytes
 .../ffmp3-mcclean/statusstop.png                 | Bin 136 -> 0 bytes
 .../embeddableplayer/ffmp3-mcclean/stop.jpg      | Bin 1459 -> 0 bytes
 .../embeddableplayer/ffmp3-mcclean/stopclick.jpg | Bin 1459 -> 0 bytes
 9 files changed, 10 deletions(-)
 delete mode 100644 airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean.xml
 delete mode 100644 airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean/bg.png
 delete mode 100644 airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean/holder.png
 delete mode 100644 airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean/play.gif
 delete mode 100644 airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean/playclick.jpg
 delete mode 100644 airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean/statusplay.png
 delete mode 100644 airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean/statusstop.png
 delete mode 100644 airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean/stop.jpg
 delete mode 100644 airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean/stopclick.jpg

diff --git a/airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean.xml b/airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean.xml
deleted file mode 100644
index 57d7c3eab..000000000
--- a/airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<ffmp3-skin folder="ffmp3-mcclean">
-  <bg image="bg.png" x="0" y="0" />
-  <play image="play.gif" x="8" y="29" clickimage="playclick.jpg" />
-  <stop image="stop.jpg" x="40" y="29" clickimage="stopclick.jpg" />
-  <text x="13" y="9" width="154" height="17" color="#ffffff" font="Arial" size="11" />
-  <songtitle x="12" y="83" width="210" height="22" color="#000000" font="Arial" size="12" />
-  <artist x="12" y="103" width="210" height="22" color="#000000" font="Arial" size="12" />
-  <volume mode="holder" x="71" y="33" width="100" height="17" holderImage="holder.png" />
-  <status imagePlay="statusplay.png" imageStop="statusstop.png" x="13" y="34" />
-</ffmp3-skin>
\ No newline at end of file
diff --git a/airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean/bg.png b/airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean/bg.png
deleted file mode 100644
index a399e16be7eeeb3a6a26d2488b98293dbf0eb29e..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 3649
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
T`Az`^00000NkvXXu0mjf8;ca6

diff --git a/airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean/holder.png b/airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean/holder.png
deleted file mode 100644
index 8b61d23458835ad36e762af595eb72011e809860..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 830
zcmV-E1Ht@>P)<h;3K|Lk000e1NJLTq000pH000mO1^@s7hc=|i00004XF*Lt006JZ
zHwB960000PbVXQnQ*UN;cVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU!&`Cr=RCwBA
zU;u*e-@pF{(M&+B+||_uVk-j#5aY39$F#trH*em&s;#Yk6(E2>9M-2#pZ<@DiTUs5
z<_6Nk3KC@e_U+rB|3CnuL41G!0tqsF{P^(>2!mC;fBzmN3zp#G;$mQ8W@cvCwQCmx
z4-XFmhz$b%fByXW55gceKmZn~90x!U2(C25R!V&a576G0g3plfGI<IiRs<Sa3*12`
znN0RRh9`t@=A3&<smB<H!iJyzNo%e3w$_r?nxvHEoTE|-2_Z-+wIOlg%7!}u@BL6?
z3_3Q%C;EVccILsH@f+raO_<Ls01ae}!XOMr;g>eLiByUXLZD}H3<Ns4c5{+mz$-Ww
zyhX3jn{+8ILOQfdruKhg0xvxN_Xzp^tphdB^G$F9MIWJg?Y;MJ2{IvB+gfWfe~O|w
z?1cFmLdcX-==&Z?lAx|@aK=m<W4g9&QB@VJwMf$x&N<|Hj$s%&y)4VOX&OjzeV&D~
zELYErd$<slnx^R&Jr6S$kK;H#;<_mw&X_6jkPmWmXVGcHev0mrz5W6;O~tAa0#R^7
z4k9E)QifAfr!*g6Z6lZ_wT-Q$wi5h-Lu~woyCPzfUND_l<Qqcl(kKW<&CJF%c`)eP
zoww|pH><>AoHtGLh`Ssh_kJ8lF-_CoCML@c=Xw5s($A)8zF>J$ZaedR{}z^d*LD3g
z48y+bI!Ym^o$I>t%iOkY!F}?`XPpxLx~}V2m|$t!c7x+MOBjX{%q`23Uk1HPKI>S&
zqX96XdpahLV=1SmX;ObW3Rjmh=XoxIAP`BC2*WU>!&t|99x|3?`G(hVm!|2aL6&9P
zKM$c*i=q&H-*0QIQwF;L9-=6s9y5Ah6c}tr<!q5b9{H?W>wkR*&>~Ns=N+r6`h>XO
zn8c#Moa@{tZ{_dA_J;qB8Mp*)fUA{64&N$m-T_}gug1&x0ct_DHu;mWmjD0&07*qo
IM6N<$g2~ExeE<Le

diff --git a/airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean/play.gif b/airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean/play.gif
deleted file mode 100644
index 150591ffc95dfe9d45c6815eea1dce1f50c08941..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 1493
zcmWlYc|6p47{`Z@tS(zANoYE05u3!8#EdI7n@T6bW=F3!t=H;M;U$K(vayV#gACF*
z29;?j#x>)Z`OSSFznS0Mv_z!5+WmQdpXc*=KF|02?-w10I^Y-Yh;Ts6BM=841p4P5
z2`D^zsPM>7kB;n8c>KWK?;-c~6CZK|ecjYQdaL}y3!=h`A_9xif#s->l2CL>#8Est
z=m|QQfC_933vLNV6QhD(9Yei}LU%=lzdnI^c`~~592R#qrSfW0SMnXw{aci~fugV=
zad?CXb4+#yt;R${m(D8_VxcQo$#0jT<P2>N4u{Ln&o3w_C@wB8DJdx{E5qaQ6%`fL
z)zyz5KhC6NJ!*PXMl3IHEw5~?u5PWux8ZAQY6t{EeSLjnV`Fo3b8BlWi9~8|Z|~^n
zc=P5>S63IAOr}sM-QC?iJw5N<y?g)ueKsGLsm490J|_&ls2^^uqc;$k4fSIUy}iAC
zF#Xj2J}OLqe?OHv05do^I5adgJUmRJ(dcyg$jHd(=;+wk*!cK3lR3^{FqliQ#sDS*
zfE{20Y=FUJF#!NzumA?YX0ka9IIvhO0ARCN95%q=u-LG%*=!Dn!)9~Y93F=U3zx&?
z^8hZF2k?0uF6=xWmnY!!`2rZ8kS`Dk1R}n0NdzLHkRuQZcp`yNBoK>40*O>06beO4
zNJJ8$NFo*sMQ}^RLa|sZk-%9hkx3O2u}lK1R3;V5;7Kl#N~JQHOe&R2<uaK<s!+(}
za=AhQKT*o0pj-he6rfzCQA$Nhg-ofGgP=mGQYe*55Cl~!m0GP<f*KX5RjV~h4XA?P
zf=5UVX(1&Dsnig>hEy7j8iF8=Mgu`wjZUl8LU5}gy;iH&>I^!aL95rmqBX&zUZ*$e
zbsG3$5)KAPZ`2tLI{gwx_?QevBkV?_K|g6QPMA!Srpbv3BWx4@nkFVD^%F~cfSH<_
znwgpTH2-mScJ|XeTyy^+5OZ_0b8~a^^9!FpfByRQtIL9g83OSI;f{b=`V$E2Z-|5y
z7Y2=j&Q!^oUp5b~bR?&$ySG=*rTi0kmJ~x`bN`edzPC6Bn(~g<^<+3NEKqbzMZoD=
zpKFPlhnKo<O+)0A;UXEOYC8L)?d^xLjVE3PZGYR)`r_mh@aAjvuSFMmO#wO=yTRmB
z{tZ#QnvSNuQopohR#8gcA9B|)Y{p;9B-{&KX&T_JB==esIcIY5OH$6xLLxb>C!V6s
zLi?u3Yr`CU_ud#deB~{%5_Kl_6_)MbsrPE`G|=h=#dJHH7+n%jkZQfQFV8!9w9)VU
zkZpzc73@IV3Jr0F6wlZn*k=|$?2#~5YPN01mW`F3$9)!znwJ!h_@0~JwvVn!dSGpS
zFk_OvexhvNbbJGydLWkX7DJ9Zo7`7xVQuCo{P{cgHg3Ar#wh2Y;z(jwP{i)0=whn*
z@{NEQqN|fSvZp0EddNNs**=0pwq%dE*G0w!ncFlzGh1I*cX?zt@}7QRD|!ooj=^WL
z>C2GoGR>_{$Mxs$d|KE}$0VkK7ETq3)X-AQx!M)TRnFI`mS>_*(zlhz*ySTJMXZqT
z(>-gorG+O{*2qFzPjkyt0nh78Q=0s&>?4V!P}h9-Y?^C<&kY*VEY#C-U#5-CF4xQ*
zt|<G+XIV4?epL|8B|F18#Jl{PnSqcW=U`<YaUIOtdXxAT>(Y7K!hE%7<}9me>;1L@
zbjv-TzK{*U%GBjf)GyPyTW-@xc}^Kz)*e#xDmVAF@i}WPD$^71<T<7GW(_;04@_G*
zrP$s<lSK|*!JDwVFh`$aORG?uuho%IPHAnJ4-V5!sd)}4;Z$&U!aA4!m7$5O2lnTE
zh?e%Ne|Pb+zZjQlvC`WaGvu&Xlr^y0t6NE>A<Hl9v)zXvSx^?6vT`?FbpPAJ&PQ;y
SV?4}fdT<kV)^QC2;r~A$;C_q%

diff --git a/airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean/playclick.jpg b/airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean/playclick.jpg
deleted file mode 100644
index 48bbd4954a037eefc63f038727b538a96ec2b0da..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 1422
zcma)5X;4#F6u$Spmjwiym#}7<vQt_?2^gxOWf6?ZqJkJ|*+~=;I}kNu+!}V2HAn!h
zr9>f4#u;(JDJTqtB4O1k%Ya}(1}#&S8bMnaHGKg^e|pZ`nLFov-&ya~4e7=KEr7R)
z2Ot7~kWip|3UGh1AV~rsz<}Nebko4mSC|~X69`)f3q*k_hLR190YJh5Kx+ZOssJG6
z>qbB(fS)eN2SJzQ9UXy?@DgXq@u?SGE5NCM2|h<54iFroIMlU)E}~FEKN1p|f?@`X
z={_<8j6@;R0FfI-NlSJVLr8!I$<_>0x|^N58BR<AK`|-?zJnkTN9h=_VX)&&NWQji
z@#*gNoHWHgzw<&59$k;dkY!8ZAdaBGn#PW!-^FZvLqur`wbu43i2;ecfDEzsg+km0
zuxZxMeM90zX)?vbE9$$t`@je#a5#z+tC*TH+?~5EQ7e_b_>-x9#`S&kPuRSJS{~TE
z-J)d;bFznkQy~P9gm7Ey5)SV<)IFopc)s%Dns$45MfN8}O*~^KMvTlo(Xa*^C#Yjh
zq^dRZc9R#6{TEZ~y+B6v<W7r}%Er>G%lW-3m4c677+7$j3$Dw!dGszx?REASwoDdh
zcvbi!4Iz6Y%JvsU2Y;w3Zb*xIVYS($uQ#*2FG?gVAvt&Hz+#96n4g`rWc_{5ZJujW
z+f6lxHqTfY3YvZF-wMTy+GZZR+jVrRJh|W<1wtZnLv+GV4o!_;3lewJOG9X_>n#Ia
zD9jFF{LSdnFku_}Oa~>Uh$`=&QuZ{6hi7hun2ypN<DA3Gk=Q81JXL{lOhj8s<WAe!
zgY{>a1wVe4C7EuKx8c1(GZlPJ=nc&oubv(C(5Uh1T>H9nt1T|giN3-gDP>AA*Xh~~
z_lGOLEDR7+U6iF^%O5|$ohq`nhI0-a=2dT~jykpF-xzIdgx8h7ngVKAT_@`wm8aga
z%~?4(+YxNs8j#W%-10_k;L;}Z;KmB_xB7?5@E{pO!7vV$416O|o&P(z@_X<7LzN>V
z+G)*vqt)yi`OMK~t5nvSg@Hj7dfS}U0f+HvMXY;#bDmt9Q{6wdw=C4vt$pbD>9=Ey
zrxSMV`R*Z|5gmLr!fi*D1NT&5c3C<<U)tYm7H#IS+LD><IW;)Ja<tmO92mdeeYqe`
z^t^=%66Bu0KNde3yU9)b?d5ZE&X%Vy)r;HIXKj75a@9G(^gfc4&ylbrbF`lslGmNt
z#ecju7-dil)^f^f@?P(MzgIn>yUO+Dwz`t=<D>GRJ0%%>hfM#y{%5rZzhn4c@1<i5
z3S6G$Vq{RniCkcPc-OS-jpO;$#TTM)n6@dE9DKTDNO0QuUJ_>yZmmRaQ_Yvvtd``v
z)t&g|ROY_yR6)%nzm3t4Ee}u&SBy@k^;nd*Y)_iW<#Ak!Oq%;x!>Dz^j?hx4>gu`&
z*_xsHyegk>&5T%b68yE$_|@&KKCZ>ou?rc>=!=u%OD)s7tAp32uLv~>y5@JZK%`Wy
zLPG3wr9POvL|!qU!e;~KB^!aQ8ZmKD1WxzdS^P1mzG6+0Z}GW|ljgYGLXejr>Ix8L
hW-=&JW`n^lDRiV&I%`i@Zl%i<#m3Syo`mRs_<xxh-|hea

diff --git a/airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean/statusplay.png b/airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean/statusplay.png
deleted file mode 100644
index d751aac25ba5107d963191a806f72dbaf13e8bdf..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 138
zcmeAS@N?(olHy`uVBq!ia0vp^Od!m`#=yYHy3uwMki(Mh=<CS9u>OQOYu8I4U$VqC
zq9iy!t)x7$D3!r6B|j-u!8128JvAsbF{QHbWU38Nk&LH{V@SoVq=X;(zt|KSBpg^A
i8Vrr@h*uqEU}11fX1%|yRKOOfj=|H_&t;ucLK6VcjwMR~

diff --git a/airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean/statusstop.png b/airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean/statusstop.png
deleted file mode 100644
index e0cce0d1a8407d07b2b8470cfedcbb3b7a0c96b8..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 136
zcmeAS@N?(olHy`uVBq!ia0vp^Od!m`#=yYHy3uwMki(Mh=<CS9u>OQOYu8I4U$VqC
zq9iy!t)x7$D3!r6B|j-u!8128JvAsbF{QHbWU38Nk(8&4V@SoVq#x%Gd|*>(kZ@pe
gXfS-ozOjLU!C@|IGjG!oQ=lpaPgg&ebxsLQ0I(4y>;M1&

diff --git a/airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean/stop.jpg b/airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean/stop.jpg
deleted file mode 100644
index c7fda38d84c849610b89f211a34fd222b515e527..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 1459
zcmex=<NpH&0WUXCHwH!~28I+MWcdGvLC~c%IlGd9k%5H)B*^gp9fO)<N`6u*L&^c5
z2qQCtC<`+i7cT<?QzZif^CJcZmO~5-tQ-H|W@uqxBpxs!05cpwwKFj?0%d_1E<r5g
z{~-oJ4hAU(8D>U71|~s9W<kdPM;NXE9m~WFbUhrfaj>v5vvV>sGBC0-!bO1$W+oO^
zHg*mH21XV}CKh(M6blnGD;pz&fP#=PyP%=5vxumwATZomnV49(xS^^Tfp!QAv9KBn
zD>^C}iLeDGHZI)g6x3uanzTvTIl1|;X{(u=5Can<&^N4blfk-J1QZMv3xxs~UR2s7
z40IF|D>Dl-%wa&UC<=TqbPP<KxKUx@!Hb2B4?q6D#lQnpz$C~l2#l0BGYn;~UJX37
zN^0|zn*Ddz^c_EXTX*|;X9YR)GQ}N-({~+Yn^iK;_&HD)2iVU{oVj1*cU*0);JlI9
z^4awBq51>fy4{RtzLf>K?Y#OoP(|vZ$t%wmSC{MBoxfR%Blm34U;m~atepuMWK7qM
zN_!q#&kDM&q<Yk<cbddG&1F&PGWK8v%pe8VBx)mqv)#VVQ1t6~$Kk^ecR1oXOUg^*
zC)W={OkrZPXIkf4a&=;D=FF|1N?2E2<mSB((GQYZy~=dA)bA$i*K8q&XI#JOutK3B
zvL@nRooP%>&P*ZE2V6qwr!MX4=6(m(!pI2J;@qgIRT3UFN%X+iAT1U(=kt8GW4`zA
z-u9hG*VpFoPoHRgqenbbZm+fY6n5)UDT|-1#hyNGjcJ+u-?(RMU$|Jbih0>hzuc)U
zGyS66)4!_68e8RFclkOsF4A?!AC)R)<Giz5H_egU^Rn=IwAVAge8tm^YV$e!KJMCZ
zDNOQ^Vzlql4RzPeTn<&9I2!N#Wx*}o%)CeUGJ?GWyt)`)ST*?jZe2d(`62mTyAIyk
zTU_*cyExyU^Jdpxzt`FEdFeKzvqnviyHqYsP)m9mQLP;ll~;E5R_oK(zjsT|4qdNU
zT@oO5H>`zkO3f*+H?wzFZ?b3WvUb^e>(28xAKUh)|MQP8vp?Y+f92QVmDj)56n>BA
z|5Wm8A|z;-8SNE!B>A~dXlP4%vtEGr^zsk`eP;HkM4Ly3c^w+3Ox7j8;reL$>g=nB
zV*0rn)%SE18l3(!ELy9)VP>I|X~nv-z(t&&9xiBX%ww5)YSVm2e)+6<y3VS-2U3j!
zr!P61#ywr{<+@kT-ZpE7FE+Nnv>y_`AZwS*NcnSZflM&3_^wO$b=v3e2{OvsvSRI;
zDu^0pkeWq2dym-!7yLeG^Qa_X8s|>0bB}{x@4iv9QS7+D0_%`d9d6DM8^9V6>0Ln1
z!Dmu~0^ENBn&(z5t!!^93T5)Ty3pT2U<tDW+Z)5oJuM>FeE&17@t;}MmCo2V&r0gT
zJ+YH}VoGPZwro5wEnpFwr#Hi`9d9@5lqqfPnBm5B@REYld<)sP$ytvRQde>bJ(zhV
zZ7G-V4VM25N0;OTYnq+B&K9oo&$gfw?n!|qhj=I0Wt1vBl$Tg^F!q{W2ggk<vHD#5
zHjRpBF6*m2>Xia^`Ch*Y)&TOcz(UPQ3NjrnuL5(WxHhhFnDMeB`G}Vu>#7U(B{sLt
j-kf*rV_i&&<6WDi@4L2qSJ@S<aKrcE?3e3T|Gx<UPJI59

diff --git a/airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean/stopclick.jpg b/airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean/stopclick.jpg
deleted file mode 100644
index a25e025be1b2ecf0ffd3906fcc2c3cf9f6382873..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 1459
zcmex=<NpH&0WUXCHwH!~28I+MWcdGvLC~c%IlGd9k%5H)B*^gp9fO)<N`6u*L&^c5
z2qQCtC<`+i7cT<?QwakD^ECzrmhB7-tQ-H|W@uqxBpxs!05cpwwKFj?0%d_1E<r5g
z{~-oJ4hAU(8D>U71|~s9W<kdPM;Oil9m~WFbUhrfaj<hTv#>HUGB7bS!bO1$7FK39
zb`AlcdPZgzgcLIi6Du2o0HcDCFuRems4>uRMn*PfRyKC1W=1Av76w5@Az@a-L=ne8
zqa@?Tg-T6}O^cLOQbf(%gn;Uqm{~dDRsneof&zvt3JW(L6jDqqoTwBetjsFR2n=9m
zCN{WRfxb{Q6mU%Z5U5btIC0^@jTayOzs0}<bQqH$vmh`!HeRqZz3;4Ith0f~Ys*u+
zzlmmk8aLj><=To%oqgm!(Z^e_nIR#2;!L0}4xn!tS(#FmqULlZGtIhMayI*X^3PN4
zJHjKor=G8xb#?W1oBG;{$EU8z%{r<Rd(=QH#y)o9U#<J|y8nCy>t_P#zplnFbF5(A
z+l`9z78R*Wdzvm+WN>^1mS+aZU(wF-WL|aZ_TwuD%9h{gVpV#x&$DVp{FV({ru#!o
zVPdmqS}hj+<NAW;ZiVl1CU5TE`S_}YwKqyJ`)xhMAdr%UDpi#;`COC*4>epl_VK>n
zQsq9YTA!T~$#<o?E*<39@SA`BG0UV~wRX!~T3s8&-rV*2&#+M2>-5xb`@x0)Bgmd<
z=4-Y2%lg9G=1r2EC$X+$O6JnbTB(!V+4~qG7f&x-+UKGgXK7yQ?j{pDbrrLwSo-bN
z-h0C9O8K6Bve7AY@(DHzZqJv_$ojW^#fx2MR@eE92Tyu4>z3S^AD=en{Y<xyd>ilV
z<&aVC`!e><B>jKcg$Fd0H{HIo)qkamiFH(hp19Q78$G(qf8YK$b=sRc_2V;hj#diz
zu3Ej!y2(2-&@^PVXl+d4t1BLtPKBAyQF=b{<bgu7HP!(u&c-fM&+2@(B26GmVv6LF
zNe`BVJ-na2nLpa}UiPLZf5NLjZ2o(`;dg%j^QZY=%j)0!6Mprp-hSHMZ4jR`GukT(
zZ=R{Xc!Pc$TWDSFq=#D~g}mn2<!oJIGe=tV_dfN_9euYnGwgm%aN^iH^{#U1mxV&t
zj(UBMlX|mq<AM`6=e&2@-cc}B_=I@=-5^F)vl&;t^Y|ROcfDKo;q#or=d*TY?*8+o
zv_1V-;bKUff^1wN%scV-+Ktu9Kd$R9KQ(LD<^1^Acq6?F8GeC}Akhj^weV<BkBpL|
zrDjRqhhs@B$EEI_P_W!tb8MN%T;+L-I<6&{Eod+)oRBw-UmU0jk<<km9CkE!Fu*-1
zFxxlNKv2n3X3Djq0|D`}Y)(SWT^0(bXH8^S(;ThV@s#JiZQi7N<#%0AGR(<au6=at
z^xWnJ8y0dV6^rWhUD@wdp2E{)n(7r1=;@(hGc9>;^#+zJ+V+17`Zj5}uJ7Z0I+uIX
zE{PYFetk2m)*HLSy(zGq_l2{|iJtbh=AeaUH;<g`yj8kom)D02m8#Yg?9S|)we6Co
z(Yl|@$`7e>Mda<%hx=S$@xh>GuPpA4&bH?18aW5ttXwvAs;ezpW#^c}VUzIn)?DEk
kn{NKJ^9{XofU6-j@721uzV2CCj2i+HXA}zk*#G|~0Q5EfJpcdz


From 5c4533d7859857e90b44e895543880c7c1dbf24b Mon Sep 17 00:00:00 2001
From: drigato <denise.rigato@sourcefabric.org>
Date: Mon, 23 Mar 2015 10:11:33 -0400
Subject: [PATCH 25/60] SAAS-644: Embed Player -> Update embed src code and
 preview when an option changes

---
 .../embeddableplayer/embeddableplayer.js      | 37 +++++++++++++++++--
 1 file changed, 33 insertions(+), 4 deletions(-)

diff --git a/airtime_mvc/public/js/airtime/embeddableplayer/embeddableplayer.js b/airtime_mvc/public/js/airtime/embeddableplayer/embeddableplayer.js
index d228625af..16cfb95e3 100644
--- a/airtime_mvc/public/js/airtime/embeddableplayer/embeddableplayer.js
+++ b/airtime_mvc/public/js/airtime/embeddableplayer/embeddableplayer.js
@@ -1,9 +1,38 @@
-window.onload = function() {
-    document.getElementById('player_display_track_metadata').onchange = generateEmbedSrc;
-}
-
 function generateEmbedSrc()
 {
+    var $embedCodeParams = "?";
+    var $streamMode = getStreamMode();
+    if ($streamMode == "b") {
+        var $stream = $("input[name=player_stream_url]:radio:checked").val();
+        $embedCodeParams += "stream-mode=b&stream="+$stream;
+    } else if ($streamMode == "a") {
+        $embedCodeParams += "stream-mode=a";
+    }
+    $embedCodeParams += "\"";
 
+    $("input[name=player_embed_src]").val(function(index, value) {
+        return value.replace(/\?.*?"/, $embedCodeParams);
+    });
 }
 
+function getStreamMode() {
+    return $("input[name=player_stream_mode]:radio:checked").val();
+}
+
+$(document).ready(function() {
+    $("#player_stream_mode-element").change(function() {
+        var $streamMode = getStreamMode();
+        if ($streamMode == "a") {
+            $("#player_stream_url-element input[type='radio']").attr("disabled", "disabled");
+        } else if ($streamMode == "b") {
+            $("#player_stream_url-element input[type='radio']").removeAttr("disabled");
+        }
+
+        generateEmbedSrc();
+    });
+
+    $("#player_stream_url-element").change(function() {
+        generateEmbedSrc();
+    });
+});
+

From 2ae4d6c1c323828ee1d4ac714226a029d478d346 Mon Sep 17 00:00:00 2001
From: drigato <denise.rigato@sourcefabric.org>
Date: Mon, 23 Mar 2015 12:37:22 -0400
Subject: [PATCH 26/60] Embed Player

Added stream modes
Unhardcoded some values
Disabled opus streams
---
 .../EmbeddableplayerController.php            | 11 +++--
 .../application/forms/EmbeddablePlayer.php    | 44 +++++++++++++------
 .../application/models/StreamSetting.php      | 19 ++++++++
 .../views/scripts/form/embeddableplayer.phtml |  2 +
 .../embeddableplayer/embeddableplayer.js      | 13 ++++--
 5 files changed, 67 insertions(+), 22 deletions(-)

diff --git a/airtime_mvc/application/controllers/EmbeddableplayerController.php b/airtime_mvc/application/controllers/EmbeddableplayerController.php
index 6c2ccfbd8..8efc33c2b 100644
--- a/airtime_mvc/application/controllers/EmbeddableplayerController.php
+++ b/airtime_mvc/application/controllers/EmbeddableplayerController.php
@@ -15,7 +15,6 @@ class EmbeddablePlayerController extends Zend_Controller_Action
         $this->view->headScript()->appendFile($baseUrl.'js/airtime/embeddableplayer/mrp.js?'.$CC_CONFIG['airtime_version']);
         $this->view->headScript()->appendFile($baseUrl.'js/airtime/embeddableplayer/embeddableplayer.js?'.$CC_CONFIG['airtime_version']);
 
-
         $form = new Application_Form_EmbeddablePlayer();
 
         if ($form->getElement('player_stream_url')->getAttrib('numberOfEnabledStreams') > 0) {
@@ -34,11 +33,11 @@ class EmbeddablePlayerController extends Zend_Controller_Action
 
         $this->view->mrp_js = Application_Common_HTTPHelper::getStationUrl() . "js/airtime/embeddableplayer/mrp.js";
         $this->view->muses_swf = Application_Common_HTTPHelper::getStationUrl() . "js/airtime/embeddableplayer/muses.swf";
-        $this->view->skin = Application_Common_HTTPHelper::getStationUrl() . "js/airtime/embeddableplayer/ffmp3-mcclean.xml";
-        $this->view->codec = $request->getParam('codec');
-        //$this->view->streamURL = $request->getParam('url');
-        //$stream = $request->getParam('stream');
-        $this->view->streamURL = "http://127.0.0.1:8000/airtime_128";
+        $stream = $request->getParam('stream');
+        $streamData = Application_Model_StreamSetting::getEnabledStreamData();
+        $selectedStreamData = $streamData[$stream];
+        $this->view->streamURL = $selectedStreamData["url"];
+        $this->view->codec = $selectedStreamData["codec"];
         $this->view->displayMetadata = $request->getParam('display_metadata');
     }
 }
\ No newline at end of file
diff --git a/airtime_mvc/application/forms/EmbeddablePlayer.php b/airtime_mvc/application/forms/EmbeddablePlayer.php
index febf1379a..537abd39a 100644
--- a/airtime_mvc/application/forms/EmbeddablePlayer.php
+++ b/airtime_mvc/application/forms/EmbeddablePlayer.php
@@ -13,30 +13,48 @@ class Application_Form_EmbeddablePlayer extends Zend_Form_SubForm
         $displayTrackMetadata->setLabel(_('Display track metadata?'));
         $this->addElement($displayTrackMetadata);
 
+        $streamMode = new Zend_Form_Element_Radio('player_stream_mode');
+        $streamMode->setLabel(_('Select Stream:'));
+        $streamMode->setMultiOptions(
+            array(
+                "a" => "Use a mobile stream if possible, when appropriate. Otherwise use the highest quality stream.",
+                "b" => "Select a stream"
+            )
+        );
+        $streamMode->setValue("a");
+        $this->addElement($streamMode);
+
         $streamURL = new Zend_Form_Element_Radio('player_stream_url');
+        $opusStreamCount = 0;
         $urlOptions = Array();
-        foreach(Application_Model_StreamSetting::getEnabledStreamUrls() as $type => $url) {
-            if ($type == "opus") continue;
-            $urlOptions[$url] = $type;
+        foreach(Application_Model_StreamSetting::getEnabledStreamData() as $stream => $data) {
+            $urlOptions[$stream] = $data["codec"]." - ".$data["bitrate"]."kbps";
+            if ($data["codec"] == "opus") {
+                $opusStreamCount += 1;
+                $urlOptions[$stream] .=" - The player does not support Opus streams.";
+            }
         }
         $streamURL->setMultiOptions(
             $urlOptions
         );
-        Logging::info($urlOptions);
-        $streamURL->setValue(array_keys($urlOptions)[0]);
-        $streamURL->setLabel(_('Select stream:'));
-        $streamURL->setAttrib('codec', array_values($urlOptions)[0]);
-        $streamURL->setAttrib('numberOfEnabledStreams', sizeof($urlOptions));
-        $this->addElement($streamURL);
 
-        $url = $streamURL->getValue();
-        $codec = $streamURL->getAttrib('codec');
+        foreach ($urlOptions as $o => $v) {
+            if (strpos($v, "opus") !== false) {
+                continue;
+            } else {
+                $streamURL->setValue($o);
+                break;
+            }
+        }
+
+        $streamURL->setAttrib('numberOfEnabledStreams', sizeof($urlOptions)-$opusStreamCount);
+        $streamURL->setAttrib("disabled", "disabled");
+        $this->addElement($streamURL);
 
         $embedSrc = new Zend_Form_Element_Text('player_embed_src');
         $embedSrc->setAttrib("readonly", "readonly");
         $embedSrc->setAttrib("class", "embed-player-text-box");
-        //$embedSrc->setValue('<iframe frameborder="0" src="'.Application_Common_HTTPHelper::getStationUrl().'embeddableplayer/embed-code?url='.$url.'&codec='.$codec.'"></iframe>');
-        $embedSrc->setValue('<iframe frameborder="0" src="'.Application_Common_HTTPHelper::getStationUrl().'embeddableplayer/embed-code?stream=stream1&codec='.$codec.'"></iframe>');
+        $embedSrc->setValue('<iframe frameborder="0" src="'.Application_Common_HTTPHelper::getStationUrl().'embeddableplayer/embed-code?stream-mode=a"></iframe>');
         $embedSrc->removeDecorator('label');
         $this->addElement($embedSrc);
 
diff --git a/airtime_mvc/application/models/StreamSetting.php b/airtime_mvc/application/models/StreamSetting.php
index 3bdac8a31..49ec7a072 100644
--- a/airtime_mvc/application/models/StreamSetting.php
+++ b/airtime_mvc/application/models/StreamSetting.php
@@ -78,6 +78,25 @@ class Application_Model_StreamSetting
         return $urls;
     }
 
+    public static function getEnabledStreamData()
+    {
+        $streams = Array();
+        $streamIds = self::getEnabledStreamIds();
+        foreach ($streamIds as $id) {
+            $streamData = self::getStreamData($id);
+            $prefix = $id."_";
+            $host = $streamData[$prefix."host"];
+            $port = $streamData[$prefix."port"];
+            $mount = $streamData[$prefix."mount"];
+            $streams[$id] = Array(
+                "url" => "http://$host:$port/$mount",
+                "codec" => $streamData[$prefix."type"],
+                "bitrate" => $streamData[$prefix."bitrate"]
+            );
+        }
+        return $streams;
+    }
+
     /* Returns the id's of all streams that are enabled in an array. An
      * example of the array returned in JSON notation is ["s1", "s2", "s3"] */
     public static function getEnabledStreamIds()
diff --git a/airtime_mvc/application/views/scripts/form/embeddableplayer.phtml b/airtime_mvc/application/views/scripts/form/embeddableplayer.phtml
index aed5bc181..7ab6cb227 100644
--- a/airtime_mvc/application/views/scripts/form/embeddableplayer.phtml
+++ b/airtime_mvc/application/views/scripts/form/embeddableplayer.phtml
@@ -5,6 +5,8 @@
 
         <?php echo $this->element->getElement('player_display_track_metadata'); ?>
 
+        <?php echo $this->element->getElement('player_stream_mode'); ?>
+
         <?php echo $this->element->getElement('player_stream_url'); ?>
 
         <?php echo $this->element->getElement('player_preview_label')->renderLabel(); ?>
diff --git a/airtime_mvc/public/js/airtime/embeddableplayer/embeddableplayer.js b/airtime_mvc/public/js/airtime/embeddableplayer/embeddableplayer.js
index 16cfb95e3..a07a293f2 100644
--- a/airtime_mvc/public/js/airtime/embeddableplayer/embeddableplayer.js
+++ b/airtime_mvc/public/js/airtime/embeddableplayer/embeddableplayer.js
@@ -1,4 +1,4 @@
-function generateEmbedSrc()
+function updateEmbedSrcParams()
 {
     var $embedCodeParams = "?";
     var $streamMode = getStreamMode();
@@ -20,19 +20,26 @@ function getStreamMode() {
 }
 
 $(document).ready(function() {
+
     $("#player_stream_mode-element").change(function() {
         var $streamMode = getStreamMode();
         if ($streamMode == "a") {
             $("#player_stream_url-element input[type='radio']").attr("disabled", "disabled");
         } else if ($streamMode == "b") {
             $("#player_stream_url-element input[type='radio']").removeAttr("disabled");
+
+            $("input[name=player_stream_url]").each(function(i, obj) {
+                if ($(this).parent().text().indexOf("opus") >= 0) {
+                    $(this).attr("disabled", "disabled");
+                }
+            });
         }
 
-        generateEmbedSrc();
+        updateEmbedSrcParams();
     });
 
     $("#player_stream_url-element").change(function() {
-        generateEmbedSrc();
+        updateEmbedSrcParams();
     });
 });
 

From e32744668f5f1e80f509ebef94de8b847ca8a98d Mon Sep 17 00:00:00 2001
From: drigato <denise.rigato@sourcefabric.org>
Date: Mon, 23 Mar 2015 16:06:35 -0400
Subject: [PATCH 27/60] SAAS-661: Add mobile stream identifier on Stream
 Settings page

---
 airtime_mvc/application/forms/EmbeddablePlayer.php         | 5 ++++-
 airtime_mvc/application/forms/StreamSettingSubForm.php     | 6 ++++++
 airtime_mvc/application/models/StreamSetting.php           | 3 ++-
 .../views/scripts/form/stream-setting-form.phtml           | 7 +++++++
 .../public/js/airtime/embeddableplayer/embeddableplayer.js | 2 +-
 5 files changed, 20 insertions(+), 3 deletions(-)

diff --git a/airtime_mvc/application/forms/EmbeddablePlayer.php b/airtime_mvc/application/forms/EmbeddablePlayer.php
index 537abd39a..ba7c5fce9 100644
--- a/airtime_mvc/application/forms/EmbeddablePlayer.php
+++ b/airtime_mvc/application/forms/EmbeddablePlayer.php
@@ -28,7 +28,10 @@ class Application_Form_EmbeddablePlayer extends Zend_Form_SubForm
         $opusStreamCount = 0;
         $urlOptions = Array();
         foreach(Application_Model_StreamSetting::getEnabledStreamData() as $stream => $data) {
-            $urlOptions[$stream] = $data["codec"]." - ".$data["bitrate"]."kbps";
+            $urlOptions[$stream] = strtoupper($data["codec"])." - ".$data["bitrate"]."kbps";
+            if ($data["mobile"]) {
+                $urlOptions[$stream] .= " - Mobile friendly";
+            }
             if ($data["codec"] == "opus") {
                 $opusStreamCount += 1;
                 $urlOptions[$stream] .=" - The player does not support Opus streams.";
diff --git a/airtime_mvc/application/forms/StreamSettingSubForm.php b/airtime_mvc/application/forms/StreamSettingSubForm.php
index 874f38dc5..b84adf63d 100644
--- a/airtime_mvc/application/forms/StreamSettingSubForm.php
+++ b/airtime_mvc/application/forms/StreamSettingSubForm.php
@@ -53,6 +53,12 @@ class Application_Form_StreamSettingSubForm extends Zend_Form_SubForm
         }
         $this->addElement($enable);
 
+        $mobile = new Zend_Form_Element_Checkbox('mobile');
+        $mobile->setLabel(_('Good for mobile?'));
+        $mobile->setValue($setting[$prefix.'_mobile']);
+        $mobile->setDecorators(array('ViewHelper'));
+        $this->addElement($mobile);
+
         $type = new Zend_Form_Element_Select('type');
         $type->setLabel(_("Stream Type:"))
                 ->setMultiOptions($stream_types)
diff --git a/airtime_mvc/application/models/StreamSetting.php b/airtime_mvc/application/models/StreamSetting.php
index a85fad988..19a147798 100644
--- a/airtime_mvc/application/models/StreamSetting.php
+++ b/airtime_mvc/application/models/StreamSetting.php
@@ -94,7 +94,8 @@ class Application_Model_StreamSetting
             $streams[$id] = Array(
                 "url" => "http://$host:$port/$mount",
                 "codec" => $streamData[$prefix."type"],
-                "bitrate" => $streamData[$prefix."bitrate"]
+                "bitrate" => $streamData[$prefix."bitrate"],
+                "mobile" => $streamData[$prefix."mobile"]
             );
         }
         return $streams;
diff --git a/airtime_mvc/application/views/scripts/form/stream-setting-form.phtml b/airtime_mvc/application/views/scripts/form/stream-setting-form.phtml
index 6b76ab84a..a8d61d247 100644
--- a/airtime_mvc/application/views/scripts/form/stream-setting-form.phtml
+++ b/airtime_mvc/application/views/scripts/form/stream-setting-form.phtml
@@ -14,6 +14,13 @@
             <dd id="<?php echo $s_name?>Enabled-element">
                 <?php echo $this->element->getElement('enable')?>
             </dd>
+
+            <dt id="<?php echo $s_name?>Mobile-label">
+                <label for="<?php echo $s_name?>Mobile"><?php echo $this->element->getElement('mobile')->getLabel() ?></label>
+            </dt>
+            <dd id="<?php echo $s_name?>Mobile-element">
+                <?php echo $this->element->getElement('mobile')?>
+            </dd>
             
             <dt id="<?php echo $s_name?>Type-label">
                 <label for="<?php echo $s_name?>Type"><?php echo $this->element->getElement('type')->getLabel()?></label>
diff --git a/airtime_mvc/public/js/airtime/embeddableplayer/embeddableplayer.js b/airtime_mvc/public/js/airtime/embeddableplayer/embeddableplayer.js
index a07a293f2..376c64e57 100644
--- a/airtime_mvc/public/js/airtime/embeddableplayer/embeddableplayer.js
+++ b/airtime_mvc/public/js/airtime/embeddableplayer/embeddableplayer.js
@@ -29,7 +29,7 @@ $(document).ready(function() {
             $("#player_stream_url-element input[type='radio']").removeAttr("disabled");
 
             $("input[name=player_stream_url]").each(function(i, obj) {
-                if ($(this).parent().text().indexOf("opus") >= 0) {
+                if ($(this).parent().text().toLowerCase().indexOf("opus") >= 0) {
                     $(this).attr("disabled", "disabled");
                 }
             });

From 17358a761fdef63d08e39343f21f0188402a6d5b Mon Sep 17 00:00:00 2001
From: drigato <denise.rigato@sourcefabric.org>
Date: Wed, 25 Mar 2015 11:44:28 -0400
Subject: [PATCH 28/60] SAAS-663: Integrate player design

---
 .../EmbeddableplayerController.php            |   6 +-
 .../application/forms/EmbeddablePlayer.php    |  10 +-
 .../scripts/embeddableplayer/embed-code.phtml |  90 ++++++++-
 .../views/scripts/form/embeddableplayer.phtml |   4 +-
 .../css/colorpicker/embeddable-player.css     |   0
 .../css/embed-player-images/airtime_logo.png  | Bin 0 -> 1162 bytes
 .../public/css/embed-player-images/mute.png   | Bin 0 -> 1338 bytes
 .../css/embed-player-images/pause_button.png  | Bin 0 -> 1077 bytes
 .../css/embed-player-images/play_button.png   | Bin 0 -> 1590 bytes
 .../public/css/embed-player-images/unmute.png | Bin 0 -> 1378 bytes
 ...eplayer.css => embeddable-player-form.css} |   2 +
 airtime_mvc/public/css/embeddable-player.css  | 190 ++++++++++++++++++
 .../embeddableplayer/embeddableplayer.js      |  20 +-
 13 files changed, 307 insertions(+), 15 deletions(-)
 create mode 100644 airtime_mvc/public/css/colorpicker/embeddable-player.css
 create mode 100644 airtime_mvc/public/css/embed-player-images/airtime_logo.png
 create mode 100644 airtime_mvc/public/css/embed-player-images/mute.png
 create mode 100644 airtime_mvc/public/css/embed-player-images/pause_button.png
 create mode 100644 airtime_mvc/public/css/embed-player-images/play_button.png
 create mode 100644 airtime_mvc/public/css/embed-player-images/unmute.png
 rename airtime_mvc/public/css/{embeddableplayer.css => embeddable-player-form.css} (99%)
 create mode 100644 airtime_mvc/public/css/embeddable-player.css

diff --git a/airtime_mvc/application/controllers/EmbeddableplayerController.php b/airtime_mvc/application/controllers/EmbeddableplayerController.php
index 8efc33c2b..2a66d0b7e 100644
--- a/airtime_mvc/application/controllers/EmbeddableplayerController.php
+++ b/airtime_mvc/application/controllers/EmbeddableplayerController.php
@@ -11,7 +11,7 @@ class EmbeddablePlayerController extends Zend_Controller_Action
     {
         $CC_CONFIG = Config::getConfig();
         $baseUrl = Application_Common_OsPath::getBaseDir();
-        $this->view->headLink()->appendStylesheet($baseUrl.'css/embeddableplayer.css?'.$CC_CONFIG['airtime_version']);
+        $this->view->headLink()->appendStylesheet($baseUrl.'css/embeddable-player-form.css?'.$CC_CONFIG['airtime_version']);
         $this->view->headScript()->appendFile($baseUrl.'js/airtime/embeddableplayer/mrp.js?'.$CC_CONFIG['airtime_version']);
         $this->view->headScript()->appendFile($baseUrl.'js/airtime/embeddableplayer/embeddableplayer.js?'.$CC_CONFIG['airtime_version']);
 
@@ -31,8 +31,12 @@ class EmbeddablePlayerController extends Zend_Controller_Action
 
         $request = $this->getRequest();
 
+        $this->view->css = Application_Common_HTTPHelper::getStationUrl() . "css/embeddable-player.css";
         $this->view->mrp_js = Application_Common_HTTPHelper::getStationUrl() . "js/airtime/embeddableplayer/mrp.js";
+        $this->view->jquery = Application_Common_HTTPHelper::getStationUrl() . "js/libs/jquery-1.10.2.js";
         $this->view->muses_swf = Application_Common_HTTPHelper::getStationUrl() . "js/airtime/embeddableplayer/muses.swf";
+        $this->view->metadata_api_url = Application_Common_HTTPHelper::getStationUrl() . "api/live-info";
+        $this->view->station_name = Application_Model_Preference::GetStationName();
         $stream = $request->getParam('stream');
         $streamData = Application_Model_StreamSetting::getEnabledStreamData();
         $selectedStreamData = $streamData[$stream];
diff --git a/airtime_mvc/application/forms/EmbeddablePlayer.php b/airtime_mvc/application/forms/EmbeddablePlayer.php
index ba7c5fce9..e5086716a 100644
--- a/airtime_mvc/application/forms/EmbeddablePlayer.php
+++ b/airtime_mvc/application/forms/EmbeddablePlayer.php
@@ -17,11 +17,11 @@ class Application_Form_EmbeddablePlayer extends Zend_Form_SubForm
         $streamMode->setLabel(_('Select Stream:'));
         $streamMode->setMultiOptions(
             array(
-                "a" => "Use a mobile stream if possible, when appropriate. Otherwise use the highest quality stream.",
-                "b" => "Select a stream"
+                "auto" => "Auto detect the most appropriate stream to use.",
+                "manual" => "Select a stream:"
             )
         );
-        $streamMode->setValue("a");
+        $streamMode->setValue("auto");
         $this->addElement($streamMode);
 
         $streamURL = new Zend_Form_Element_Radio('player_stream_url');
@@ -42,7 +42,7 @@ class Application_Form_EmbeddablePlayer extends Zend_Form_SubForm
         );
 
         foreach ($urlOptions as $o => $v) {
-            if (strpos($v, "opus") !== false) {
+            if (strpos(strtolower($v), "opus") !== false) {
                 continue;
             } else {
                 $streamURL->setValue($o);
@@ -57,7 +57,7 @@ class Application_Form_EmbeddablePlayer extends Zend_Form_SubForm
         $embedSrc = new Zend_Form_Element_Text('player_embed_src');
         $embedSrc->setAttrib("readonly", "readonly");
         $embedSrc->setAttrib("class", "embed-player-text-box");
-        $embedSrc->setValue('<iframe frameborder="0" src="'.Application_Common_HTTPHelper::getStationUrl().'embeddableplayer/embed-code?stream-mode=a"></iframe>');
+        $embedSrc->setValue('<iframe frameborder="0" width="280" height="230" src="'.Application_Common_HTTPHelper::getStationUrl().'embeddableplayer/embed-code?stream=auto"></iframe>');
         $embedSrc->removeDecorator('label');
         $this->addElement($embedSrc);
 
diff --git a/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml b/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml
index adab3876e..47e713e42 100644
--- a/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml
+++ b/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml
@@ -2,7 +2,9 @@
 <html xmlns="http://www.w3.org/1999/xhtml">
 
 <head>
+    <link rel="stylesheet" href="<?php echo $this->css?>" type="text/css">
     <script src="<?php echo $this->mrp_js?>" type="text/javascript"></script>
+    <script src="<?php echo $this->jquery?>" type="text/javascript"></script>
     <script type="text/javascript">
 
         var MusesPlayer = function() {
@@ -19,27 +21,38 @@
                 'width':180,
                 'height':60
             });
+            $("p.station_name").html("<?php echo $this->station_name?>");
 
             this.flashDetect = FlashDetect.versionAtLeast(10, 1) ? true : false;
+
+            getMetadata();
         };
 
         MusesPlayer.prototype.play = function() {
             this.flashDetect ? MRP.play() : musesHTMLPlayClick();
+            togglePlayStopButton();
         };
 
         MusesPlayer.prototype.stop = function() {
             this.flashDetect ? MRP.stop() : musesHTMLStopClick();
+            togglePlayStopButton();
         };
 
         MusesPlayer.prototype.setVolume = function(value) {
             //this.flashDetect ? MRP.setVolume(value) : null;
-            //TODO - maybe
         };
 
         MusesPlayer.prototype.setURL = function() {
             //TODO
         };
 
+        /*function musesCallback(event,value){
+         console.log('event: "'+event+'", value: "'+value+'"');
+         }*/
+
+        /**
+         * This is a hack to trigger the play button in HTML5 mode
+         */
         function musesHTMLPlayClick() {
             //child nodes
             var cn = document.getElementById("MusesRadioPlayer-HTML5-player-1").childNodes;
@@ -47,6 +60,9 @@
             playDiv.onclick();
         }
 
+        /**
+         * This is a hack to trigger the stop button in HTML5 mode
+         */
         function musesHTMLStopClick() {
             //child nodes
             var cn = document.getElementById("MusesRadioPlayer-HTML5-player-1").childNodes;
@@ -54,7 +70,39 @@
             stopDiv.onclick();
         }
 
+        function togglePlayStopButton() {
+            document.getElementById("play_button").classList.toggle("hide_button");
+            document.getElementById("stop_button").classList.toggle("hide_button");
+        }
+
+        // default how often to fetch metadata to 20 seconds
+        var time_to_next_track_starts = 20000;
+
+        function getMetadata(){
+            $.ajax({url: "<?php echo $this->metadata_api_url?>",
+                data: {type:"interval",limit:"5"},
+                dataType: "jsonp",
+                success: function(data) {
+                    console.log("fetching metadata");
+                    var current_track_end_time = new Date(data.current.ends);
+                    var current_time = new Date();
+                    current_time = new Date(current_time.getTime() + current_time.getTimezoneOffset()*60*1000);
+                    time_to_next_track_starts = current_track_end_time - current_time;
+                    // maybe we should set time_to_next_track_starts to
+                    // (10 || 20 || etc.) minutes if its greater than that
+                    // in case of on-the-fly schedule changes
+
+                    var artist = data.current.name.split(" - ")[0];
+                    var track = data.current.name.split(" - ")[1];
+                    $("p.now_playing").html(artist+"<span>"+track+"</span>");
+                    $("ul.schedule_list").find("li").html(data.next.name);
+                }
+            });
+            setTimeout(getMetadata, time_to_next_track_starts);
+        }
+
     </script>
+
     <style type="text/css">
         #muses_skin{width:1px; height:1px; overflow-x: hidden; overflow-y: hidden;}
     </style>
@@ -62,18 +110,58 @@
 
 <body>
 
+<div class="airtime_player">
+
+    <div class="airtime_header">
+        <p class="station_name">fff</p>
+        <a class="airtime_pro" href="#"><span>airtime.pro</span><img src="http://localhost/css/embed-player-images/airtime_logo.png"></a>
+    </div>
+
+    <div class="airtime_box">
+
+        <div class="airtime_button">
+            <span id="play_button" class="play_button" onclick="musesPlayer.play()"></span>
+            <span id="stop_button" class="stop_button hide_button" onclick="musesPlayer.stop()"></span>
+        </div>
+        <p class="now_playing"></p>
+
+    </div>
+
+    <div class="airtime_volume">
+
+        <div class="volume_control">
+            <span class="mute"></span>
+        </div>
+
+        <div class="airtime_volume_bar">
+            <div class="airtime_volume_bar_value" style="width: 80%;"></div>
+        </div>
+
+    </div>
+
+    <div class="airtime_schedule">
+        <p class="airtime_next">Next</p>
+        <ul class="schedule_list">
+            <li>John Legend - Ordinary People</li>
+        </ul>
+    </div>
+
+</div>
+
 <div id="muses_skin">
     <script type="text/javascript">
         var musesPlayer = new MusesPlayer();
     </script>
 </div>
 
+<!--
 <div id="custom_muses_play" onclick="musesPlayer.play()">
     <a href="#">play</a>
 </div>
 <div id="custom_muses_stop" onclick="musesPlayer.stop()">
     <a href="#">stop</a>
 </div>
+-->
 
 </body>
 </html>
\ No newline at end of file
diff --git a/airtime_mvc/application/views/scripts/form/embeddableplayer.phtml b/airtime_mvc/application/views/scripts/form/embeddableplayer.phtml
index 7ab6cb227..18305c20b 100644
--- a/airtime_mvc/application/views/scripts/form/embeddableplayer.phtml
+++ b/airtime_mvc/application/views/scripts/form/embeddableplayer.phtml
@@ -3,12 +3,12 @@
 
         <?php echo $this->element->getElement('player_embed_src'); ?>
 
-        <?php echo $this->element->getElement('player_display_track_metadata'); ?>
-
         <?php echo $this->element->getElement('player_stream_mode'); ?>
 
         <?php echo $this->element->getElement('player_stream_url'); ?>
 
+        <?php //echo $this->element->getElement('player_display_track_metadata'); ?>
+
         <?php echo $this->element->getElement('player_preview_label')->renderLabel(); ?>
 
         <div style="clear:both"></div>
diff --git a/airtime_mvc/public/css/colorpicker/embeddable-player.css b/airtime_mvc/public/css/colorpicker/embeddable-player.css
new file mode 100644
index 000000000..e69de29bb
diff --git a/airtime_mvc/public/css/embed-player-images/airtime_logo.png b/airtime_mvc/public/css/embed-player-images/airtime_logo.png
new file mode 100644
index 0000000000000000000000000000000000000000..db8e5fb816358773294e4bb922cc58ca07cf69a3
GIT binary patch
literal 1162
zcmaJ>TWs4@7<ST;(r!_WCaue;;NWuUF0p;w#3iO#?rkHHu1g~=;sMpMPa2cj$JnQf
z+ab|S6Le?~Lr4hiX<{#X+Q^=eiWs1*Du@S$5JEg6ctmL8fg#4_xNABd2$t=0(f57-
z|DXS}FU-wOhX)T0G7J+g&g9E<Wa%^XXo$Xlc25X&h>${+%;P#~sSaW?I<6s5G}T2^
zMykH@>gQ;ZVfr|uQYF>Wi;9L#UiC4&XWEp_Fq0|IR<$M~poSI=E6M$`af<_np5#u&
zOJd2+p@uQD>Y(}6*^0K>)Dk+EIu0g1g$kI6sK7IqELZW8+_tVl=l-_9fo%wBCb<Vm
zRZDXqhaCjs{CHFoAq29_!&qFF;V~eIP!dFX%TX9p;<6%5fSrq@(Hy<5l=D+NvFIwv
zH3+d4L1?vFd~2M?&Y}PliG;5qNl}W3x+@k@y{P4mb`|o-)f~en2DX5&sMhc@NpdvP
z2PK&HuB_$m91}e-!BcGk@}gf-7g#F&Kh!jL(Jm>Yhxz`euv=NNkx)i1UUoFvxcaCc
z%2sj?QVDh{7%z2Cajt<0b{p6Rxp^6koiZ#Px7@?q_)<wJS}sv74HffAjw<kmp(|2u
z>Uk(;VXh!a5Ef!tQOspyFazU-oD4G)U2Yz0%O<i&m#aVIN<F#06-=8(&LhV-jr1u8
zn_#<S#psz!W~!&&4p;A;i`bJZ&}0O^vHxmxcZ<5mpYGb0E_RKNEb4ZL+WIFkVbM?G
zuVOw^@xHI!Po2CF2+uI>=h!y`?Ew4ao*!<fKN?!Ub@gcd{2{QXb2>dT*x}R1HrEEO
z2kssLFAsDkE`>h`ef?*8>5KHpy-?@OS#MxH6!~PIzSY+rW~T$~XZr3g92kA+pcrh&
zzq!JIcRN>qPi<{ntOg$ob<Tb_{K~<x*WSDHV=LJ1Ki;>Hj;!AZ!WS-o*uTX-%iWK>
zRrvLABQ3GgTIBK*UuA~azn|J<H1O^8{*7Sg@r99W=)87vJiPw;evRpm9eMlH)yB;_
z*ksOtHwt%_uQkuD-P?PUJ1`m2)9;wW>~HTkpVrsL*wiDnz2M`E!X+lSk2zX}hWy8u
QpZR}>VqrFaJ-cx3A7~43IsgCw

literal 0
HcmV?d00001

diff --git a/airtime_mvc/public/css/embed-player-images/mute.png b/airtime_mvc/public/css/embed-player-images/mute.png
new file mode 100644
index 0000000000000000000000000000000000000000..0276df62e7bae7cbe95915c4a590d5d0c0cd1e62
GIT binary patch
literal 1338
zcmeAS@N?(olHy`uVBq!ia0vp@Ak4uAB#T}@sR2@wC9V-A!TD(=<%vb942~)JNvR5+
zxryniL8*x;m4zo$Z5SAsl`=yjN+NuHtdjF{^%6m9^eS=-fVvqNZ0suv5|gu2OB9k)
z(=+pImEP~(ucVNfVyhHx>TBRz;GCL~=}}db8eHWUl3bOYY?-2DZ>L~WVFffGH?<^D
zp&~aYuh^=>Rtapb6_5=Q)>l#hD=EpgRf0Gw!Z$#{Ilm}X!Bo#!H`&0@P{GVh&(Orw
z%*;?n!N|bSNZ$a6%ybP+tW3?UjLa3FKnZADQA(Oskc%7CE+EfVDWjyMz)D}gyu4hm
z+*mKaC|%#s($W%ShLMpjP=#)BWnM{Qg>GK4GRy>*)Z*l#%z~24{5%DaiHS-1r6smX
zK$k+ikXryZHm?{OOuzusuShJ=H`Fr#c?qV_*B8Ii++4Wo;*y|LgnO|XTpUtakg6Y)
zTAW{6lnjixG-Z%g1y;^Qsfi`|MIrh5Ij~R+$jC3rFV4s>P;d@5Q_u*{%uC5HFV+OB
z_w}{%%quQQ%u7!7bg@+enxL1NnPO#PV&G!rWZ~lMYUF5W=xSo=X5`}P>||tO>|$hK
zY2ggh>yn>bnwy$e0@Is<(Cdm*FDNPG765H_NiE7OOHFYr%Fk5*d)X=zw_BWWng`XJ
zg4-?5IQ8lS9itD5Sfq%C2?0|NhzU=&Kn^_Nr{)1udl4{MmrBOJWnf@j=jq}YQgJIM
zXumg8qQt*<S6-j{;&N0cyRaxXk5fkFJ4dG&>+}r=PbvoZwI6Yel3`VjI<&M+rg_oQ
ze~m2~;_U`T6Z%5>URT=hJFrPy?#Dg(^Pm4cn0#Z8W`p>KMneO}Wt&+q*)Lh@qqbSJ
z*UjH;@x`*WVY{7t*mNAX&8cT`YH(v&fBm%6!T{-gn?tl@Z*4n!>ggxJi5`yZhYm#P
zh;fH&O`Ui9ZQ8DN#`Di#ciUKOBNy**L_qm;%w2<?bd~p}zTMhghd5nIcE+$De)wVW
z{rBHfBFldL{r5UXPyKXFvFpc#DHR41DUA*d!ZLj9v;CI8zM1olCpNG9=%cw2&Z?7q
zSzjEok>d{zohp3dLak`Qg!r{#rk;<=AJ6?^so5Yn!=u3Yqqb)7ngETObCZ0SILu2F
z5A`d4yO6cDOz?J&*=%X0<sMh$_{}$5cv;faeDJ}<K1b!qX{GbLmR|Z=Rm&PX@6*pe
zM)sC6+!6;X{naMx-^~j*_npkKWEZoJlLGI;<c-H}ua|FJ*Wp>V_~MPjtp3UqPt++*
z+##YJ@K*fOvpeQOk5@hVf3dpZ(8-*$+ZmV{rv8~4yV-Z!6i{jA>FVdQ&MBb@0Lzx(
A<NyEw

literal 0
HcmV?d00001

diff --git a/airtime_mvc/public/css/embed-player-images/pause_button.png b/airtime_mvc/public/css/embed-player-images/pause_button.png
new file mode 100644
index 0000000000000000000000000000000000000000..8719664daa1948c4189455f7743002f6d1b948c6
GIT binary patch
literal 1077
zcmaJ=TWHfz7!LJ<PQ0PQymA(GDA=S)+swt)*)^>e%^Y2EohVzDoUWlJCnjgM8~C88
zsGuTVL2)P|_@Lk(L{XU{h&K>@P|-(WA}E^=;)HoQscrSa8j_p~-}n9h`Ty@6XlY(M
zwQ61!MNw1Z>!bu3tI0Qi(nRu4zuUNp40CZbg<DY?=M)=KVGVUb5I2-=n1G7byZsSt
zpr~=Qo=oACyg^iv!6+_<$r~17Q&dA^-cr;o#Gngy>t=`^zBNb#T?^4|LD?r;5tz}}
z_1UnsuQ{pqWz~9(Zd?r-@*)v1AXY%$*k(FnK13IEMKX7{SsD}|I2)pWCzX<0Km^$k
z1R1|q^>G{!1cnO)1%X=ucpt~JKJp4)E+7U4k*@>AhbGZ%EiERbSTPn^h3E{%mdLWX
zT#m{48Dw{}Tz!4LtHJYLg77-MCRXxZ(^*_nkf5X5x`lOQ0#{M#LOnP{lT3df!LZ7*
zrc*2vDHxkqES6(@?vYABS^huNFv@5LC*Yra|0(Pwdo9Q&po4mBl{7BB*bQZg5gRHP
z*-3=9m8#g1K^Qq1WPwPl0G74sriOCP@&aC##klEU#Z+Nj3eiM?(REF%3&c2{Z}LT=
zQ9s8;15JD^x^iVWCisGNejy-~xDrx(3~1sKSNp@|Dso*b7#4{vL0jJewU~_zP&l%v
zSIi|Gt*BSzY87({$0~AJk__uM_OC{lwupP&Y1y`9Q8qp_iQ8>r>-5>vCb<%q<5D=8
zfAjI=wW|AI#=bi#?&4lNdGyD#p_Yd)YP<`V3=J-Qom_u(50e|IS@84Q&EDB+a_vj~
zEx0h{us;(Xmmcv<_bq+iHSNf`gPv)t-kY1VC$GrEJ3Ed&ne3U~o}JUL57wTV^>mD0
z#6P(GC2JoNZ%Dv1bN`z0^ynEdd*FQS*P6SJpATKS{=LIF-hO+cHDT+(aKpWY{bQ%M
jB%kj3e5Ui&=JD0krx}eWKCD;(+>0EKHcMBVI(Pp9Z|`BS

literal 0
HcmV?d00001

diff --git a/airtime_mvc/public/css/embed-player-images/play_button.png b/airtime_mvc/public/css/embed-player-images/play_button.png
new file mode 100644
index 0000000000000000000000000000000000000000..bff38adbc4fb4fb1da43231742f93568d8827ae2
GIT binary patch
literal 1590
zcmeAS@N?(olHy`uVBq!ia0vp^5<o1?!3HGL9{Yy@DajJoh?3y^w370~qErUQl>DSr
z1<%~X^wgl##FWaylc_cg49rTIArU1JzCKpT`MG+DAT@dwxdlMo3=B5*6$OdO*{LN8
zNvY|XdA3ULckfqH$V{<S3ODsN@GWpo&B*kqDoPEm@(W3>%1*XSQL?vFu&J;D8jzb>
zlBiITo0C^;Rbi_HHrEQs1_|pcDS(xfWZNo192Makpx~Tel&WB=XRMoSU}&gdW~OIo
zVrph)sH0$HU}&Uo07PcGh9*{~W>!Y#3Q(W~w5=#5%__*n4QdyVXRDM^Qc_^0uU}qX
zu2*iXmtT~wZ)j<02{OaTNEfI=x41H|B(Xv_uUHvof=g;~a#3bMNoIbY0?5R~r2Ntn
zTP2`NAzsKWfE$}v3=Jk=fazBx7U&!58GyV5Q|Rl9UukYGTy=3tP%6T`SPd=?sVqp<
z4@xc0FD*(2MqHXQ$f^P>=c3falKi5O{QMkPC<bKYm*f{`<QFJ72b(EqglFcZ<d+v~
zg4O%_T6yLbmn7yTr+T{BDgjN<%gju%GIVrxG;%hwbapi|H#BrLv2=7bbF(xwFn4q|
zb9J?Fg6Vb1PcF?(%`1WFO+n~&#HkmQ6mkoIHoK%2WtOF;xE1B+DuBIgm5JLe<~YrR
z>P^Az77Ltu^?{Dj2SqGWM8kxDsRzV_CtDx~p72xifT_I*n5?_z_V+U|Fs<@*aSW-r
zwPvb+hftx&@#pjZ|DUi>&Zp4%ri~7Z?k08S#d|7FIy=5|Ji0q}PsIlj7g@0-O#+TK
zE$w`=RxEQDCC4`35>wMyxioisQf%p+nR8$Mj;`B$ByFAbxdX}1{yuyD`^UZSfA4+Z
zIsCzZ+q7t9Pp3Gi-jAAn+<wcA4W)X^G&An|FuX6@t$!<L+jO~p^;N50Sw~JYT_ZgC
zEW-x9>DpOaqqrM%9#&p`SYYt@V+FIpr+*Ez3K@(#qI9M)De$~AyOBEOja5TDd-Fjx
z-Pt~yjiwxIQs7{fIQ-e>aG}i3`HULvn{*G~pP-WI@csRHR)vF+)2=EW5u0#Q>)V`A
zk*Bs_5;N4g5*zAXDoC(jP@VF2+TFbA7jqXa%VcU@(Z+b(vB6@)b1swJY<sH?KP;HN
z<)=w)8q<pj`yCu#6f-YS{qg#OyHd2;)~{z8IByDcJI}Ydb&ECk+Co8Z?`0BfJ{Q>S
zg~J3Mt0mM<@m*5L|MlTB+m$R%|0J5&FJ8)?=<%ddK_KFwwl-s7+8JqE=@*9<#GH;>
zzg?2A{rp7E12Zix87Dd|ys$WLd-c}quis7x6Z7d>o2ay3W2#s7)1sf;HJA47KH)Q4
zx}o{I;#9A@xh7Ki556VZ3;f8ikYZclx?Q-_W%1>gHitRo6JJU*{Wo6D!rXM~V8RE_
zy>az({Faw*_#&I#{Qs@JC`0ZKt@-EguMW|g|KMNCU$+k{H)p6ZRK@tHP5wUn?6d40
z)f;qK=4H;}QopiOzWb=$mZ-Js?!Q+rz2}nf(j@XV!`q0t`~_0;!&YByznN3keXa7m
zhcQR{=cdPfmyY^W&OZJ0-Ic7Z{RQ<CqvnS^f2r<r`OQopHR=B2_Tt?~Z+{R^6#V6A
z_>d!O*5<o;`dy1=9Qa(xWKvwSfy3jOpnGY+$&Y5jAKV)l8Oo~ed#YJn(*l*`p00i_
I>zopr01<p)kpKVy

literal 0
HcmV?d00001

diff --git a/airtime_mvc/public/css/embed-player-images/unmute.png b/airtime_mvc/public/css/embed-player-images/unmute.png
new file mode 100644
index 0000000000000000000000000000000000000000..83959783518ac07d6c764d8dbef9895e4f2280f1
GIT binary patch
literal 1378
zcmeAS@N?(olHy`uVBq!ia0vp@Ak4uAB#T}@sR2@wC9V-A!TD(=<%vb942~)JNvR5+
zxryniL8*x;m4zo$Z5SAsl`=yjN+NuHtdjF{^%6m9^eS=-fVvqNZ0suv5|gu2OB9k)
z(=+pImEP~(ucVNfVyhHx>TBRz;GCL~=}}db8eHWUl3bOYY?-2DZ>L~WVFffGH?<^D
zp&~aYuh^=>Rtapb6_5=Q)>l#hD=EpgRf0Gw!Z$#{Ilm}X!Bo#!H`&0@P{GVh&(Orw
z%*;?n!N|bSNZ$a6%ybP+tW3?UjLa3FKnZADQA(Oskc%7CE+EfVDWjyMz)D}gyu4hm
z+*mKaC|%#s($W%ShLMpjP=#)BWnM{Qg>GK4GRy>*)Z*l#%z~24{5%DaiHS-1r6smX
zK$k+ikXryZHm?{OOuzusuShJ=H`Fr#c?qV_*B8Ii++4Wo;*y|LgnO|XTpUtakg6Y)
zTAW{6lnjixG-Z%g1y;^Qsfi`|MIrh5Ij~R+$jC3rFV4s>P;d@5Q_u*{%uC5HFV+OB
z_w}{%%quQQ%u7!7bg@+enxL1NnPTN)Wa8vxXyM}Q>S}6e=xXBVYVK%h;cDUN>|)~T
z?BWE|>yn>bnwy$e0@Is<(Cdm*FDNPG765H_NiE7OOHFYr%Fk5*d)X=zw_BWWng`XJ
zg4-?5IQ8lS9itD5Sfq%C2?0|NhzU=&Kn^_Nr{)1udl4{MH(XTjWnf^u=IP=XQgJI~
z(p~SULW$$`^Mcjm`zCb-+^bY|mRPek_J~49$G-*>4)&*KSLAwyo0TbE>fPBZ))P44
z$&ITe)33${2x)t;-M+exwXl5B8RI8kDvvn4IMDw5`=^@u+dmhFXo;HsQ5E83e#|Pp
zE8*ei`WxvkcmE#?UU?-+Md;_HyzSGwjy`&+5Fq|B_|55w3wii_IAWAORPEIg;i{c}
zU}wxbPaU!916A^TM=q-OCAciU_%X%k=jFF$+WYUXkI}n6ZQbklJ8w5$|IqcIeNv{*
z{PX`e=Kf~)D{f2Fn15cq$(Duvj{M=|8Tn?jgMVoHdL6#FWXjG2gB47T4N8}zS?2HD
z)!;cp?XcxHWeeAo#|jgtX3m;+`K8b1{Zbrt2RFMd{<thaV+LP)$zl`1ug6awoVqOY
zb%dpLqyGkx{^Qki_MS-FY+kPPawW67Tz|T(wyN%7E}sWmqV%S_zf9g1qIK58{!*_V
z_oeGM<{T2y`BJslJ>~AvvYF4y)`o4?J-y3s`DNitePL_E<Tve*`Lph2)!u)*FTdR5
zeBpoXgN4UU+f<zce*B;M>D&Y9oPhnR6QkB%D>ka-Z9gm><fk_Ir$X-G{dNCsdVSx#
tyL;MU#pww4_x{&(7eya_|0b+~k>RkyOxZ90<}3r1dY-O+F6*2UngH(63Mc>o

literal 0
HcmV?d00001

diff --git a/airtime_mvc/public/css/embeddableplayer.css b/airtime_mvc/public/css/embeddable-player-form.css
similarity index 99%
rename from airtime_mvc/public/css/embeddableplayer.css
rename to airtime_mvc/public/css/embeddable-player-form.css
index a1e12cbc0..9a6fe20d8 100644
--- a/airtime_mvc/public/css/embeddableplayer.css
+++ b/airtime_mvc/public/css/embeddable-player-form.css
@@ -12,3 +12,5 @@
     padding: 4px 0px 4px 0px;
 }
 
+
+
diff --git a/airtime_mvc/public/css/embeddable-player.css b/airtime_mvc/public/css/embeddable-player.css
new file mode 100644
index 000000000..6c770c693
--- /dev/null
+++ b/airtime_mvc/public/css/embeddable-player.css
@@ -0,0 +1,190 @@
+.airtime_player {
+    max-width: 270px;
+    position: relative;
+    font-family: Arial, Helvetica, sans-serif;
+    color: #fff;
+    background: rgba(53, 53, 53, 0.9);
+    -webkit-border-radius: 4px;
+    -moz-border-radius: 4px;
+    border-radius: 4px;
+    -webkit-box-shadow: 0 3px 5px rgba(0,0,0,0.1) inset,0 1px 0 rgba(255,255,255,0.1),0 0 1px #000 inset;
+    -moz-box-shadow: 0 3px 5px rgba(0,0,0,0.1) inset,0 1px 0 rgba(255,255,255,0.1),0 0 1px #000 inset;
+    box-shadow: 0 3px 5px rgba(0,0,0,0.1) inset,0 1px 0 rgba(255,255,255,0.1),0 0 1px #000 inset;
+}
+
+.airtime_header {
+    background: rgba(53, 53, 53, 0.9);
+    -webkit-box-shadow: 0 3px 5px rgba(0,0,0,0.1) inset,0 1px 0 rgba(255,255,255,0.1),0 0 1px #000 inset;
+    -moz-box-shadow: 0 3px 5px rgba(0,0,0,0.1) inset,0 1px 0 rgba(255,255,255,0.1),0 0 1px #000 inset;
+    box-shadow: 0 3px 5px rgba(0,0,0,0.1) inset,0 1px 0 rgba(255,255,255,0.1),0 0 1px #000 inset;
+    height: 37px;
+    -webkit-border-radius: 4px;
+    -moz-border-radius: 4px;
+    border-radius: 4px;
+}
+.airtime_box {
+    margin-top: 15px;
+    float: left;
+    width: 100%;
+}
+.station_name {
+    font-size: 14px;
+    padding-top: 10px;
+    padding-left: 20px;
+    white-space: nowrap;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    padding-right: 30px;
+}
+.airtime_pro {
+    position: absolute;
+    right: 15px;
+    top: 10px;
+    color: #fff;
+    font-size: 12px;
+    text-decoration: none;
+}
+.airtime_pro span {
+    display: inline-block;
+    vertical-align: 2px;
+    margin-right: 5px;
+}
+.airtime_pro:hover span {
+    display: inline-block;
+    vertical-align: 2px;
+    margin-right: 5px;
+}
+.airtime_box .airtime_button {
+    text-indent: -9999px;
+    -webkit-border-radius: 2px;
+    -moz-border-radius: 2px;
+    border-radius: 2px;
+    background: rgb(100,100,100);
+    background: -moz-linear-gradient(top, rgba(107, 107, 107, 1) 0%, rgba(88,88,88,1) 100%);
+    background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(100,100,100,1)), color-stop(100%,rgba(88,88,88,1)));
+    background: -webkit-linear-gradient(top, rgba(107, 107, 107, 1) 0%,rgba(88,88,88,1) 100%);
+    background: -o-linear-gradient(top, rgba(107, 107, 107, 1) 0%,rgba(88,88,88,1) 100%);
+    background: -ms-linear-gradient(top, rgba(107, 107, 107, 1) 0%,rgba(88,88,88,1) 100%);
+    background: linear-gradient(to bottom, rgba(107, 107, 107, 1) 0%,rgba(88,88,88,1) 100%);
+    filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#646464', endColorstr='#585858',GradientType=0 );
+    -webkit-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.2) inset;
+    -moz-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.2) inset;
+    box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.2) inset;
+    width: 47px;
+    height: 47px;
+    display: inline-block;
+    float: left;
+    cursor: pointer;
+    margin-left: 20px;
+    margin-right: 15px;
+}
+
+.airtime_box .airtime_button:hover {
+    background: rgb(147,147,147);
+    background: -moz-linear-gradient(top, rgba(147,147,147,1) 0%, rgba(117,117,117,1) 100%);
+    background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(147,147,147,1)), color-stop(100%,rgba(117,117,117,1)));
+    background: -webkit-linear-gradient(top, rgba(147,147,147,1) 0%,rgba(117,117,117,1) 100%);
+    background: -o-linear-gradient(top, rgba(147,147,147,1) 0%,rgba(117,117,117,1) 100%);
+    background: -ms-linear-gradient(top, rgba(147,147,147,1) 0%,rgba(117,117,117,1) 100%);
+    background: linear-gradient(to bottom, rgba(147,147,147,1) 0%,rgba(117,117,117,1) 100%);
+    filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#939393', endColorstr='#757575',GradientType=0 );
+}
+
+.airtime_box .airtime_button .play_button {
+    display: block;
+    background: url("embed-player-images/play_button.png") center no-repeat;
+    width: 47px;
+    height: 47px;
+}
+
+.airtime_box .airtime_button .stop_button {
+    display: block;
+    background: url("embed-player-images/pause_button.png") center no-repeat;
+    width: 47px;
+    height: 47px;
+}
+
+.hide_button {
+    display:none !important;
+}
+
+.now_playing {
+    margin-top: 8px;
+    margin-left: 15px;
+    margin-right: 15px;
+    display: block;
+    font-size: 14px;
+    color: #fff;
+    width: auto;
+}
+
+.now_playing span {
+    display: block;
+    color: #aaaaaa;
+}
+
+.airtime_volume {
+    padding: 10px 0px 15px 0px;
+    clear: both;
+}
+
+.airtime_volume .volume_control {
+    margin-left: 55px;
+    float: left;
+    display: inline-block;
+}
+
+.airtime_volume .mute {
+    background: url("embed-player-images/mute.png") center no-repeat;
+    display: block;
+    margin-top: -4px;
+    width: 15px;
+    height: 15px;
+    cursor: pointer;
+}
+
+.airtime_volume_bar {
+    border-color: #262526 #262526 #5E5E5E;
+    border-style: solid;
+    border-width: 1px;
+    background-color: #393939;
+    width: auto;
+    height: 5px;
+    cursor: pointer;
+    margin-left: 80px;
+    margin-right: 40px;
+}
+
+.airtime_volume_bar_value {
+    background-color: #ff9122;
+    width: 0px;
+    height: 5px;
+}
+
+.airtime_schedule {
+    margin: 0px 20px 10px 20px;
+    padding-top: 10px;
+    font-size: 14px;
+    color: #aaaaaa;
+    border-top: 1px solid rgba(255, 255, 255, 0.1);
+}
+
+.airtime_next {
+    float: left;
+    margin: 0px;
+}
+
+.schedule_list {
+    list-style: none;
+    padding-left: 0px;
+    padding-bottom: 10px;
+    margin-top: 0px;
+    margin-left: 60px;
+    line-height: 130%;
+}
+
+.schedule_list li {
+    white-space: nowrap;
+    overflow: hidden;
+    text-overflow: ellipsis;
+}
\ No newline at end of file
diff --git a/airtime_mvc/public/js/airtime/embeddableplayer/embeddableplayer.js b/airtime_mvc/public/js/airtime/embeddableplayer/embeddableplayer.js
index 376c64e57..be4bbc7c3 100644
--- a/airtime_mvc/public/js/airtime/embeddableplayer/embeddableplayer.js
+++ b/airtime_mvc/public/js/airtime/embeddableplayer/embeddableplayer.js
@@ -2,17 +2,25 @@ function updateEmbedSrcParams()
 {
     var $embedCodeParams = "?";
     var $streamMode = getStreamMode();
-    if ($streamMode == "b") {
+    if ($streamMode == "manual") {
         var $stream = $("input[name=player_stream_url]:radio:checked").val();
-        $embedCodeParams += "stream-mode=b&stream="+$stream;
-    } else if ($streamMode == "a") {
-        $embedCodeParams += "stream-mode=a";
+        $embedCodeParams += "stream="+$stream;
+    } else if ($streamMode == "auto") {
+        $embedCodeParams += "stream=auto";
     }
     $embedCodeParams += "\"";
 
     $("input[name=player_embed_src]").val(function(index, value) {
         return value.replace(/\?.*?"/, $embedCodeParams);
     });
+
+    updatePlayerIframeSrc($("input[name=player_embed_src]").val());
+}
+
+function updatePlayerIframeSrc(iframe_text) {
+    var $player_iframe = $("#player_form iframe");
+    var player_iframe_src = iframe_text.match(/http.*?"/)[0].slice(0, -1);
+    $player_iframe.attr('src', player_iframe_src);
 }
 
 function getStreamMode() {
@@ -23,9 +31,9 @@ $(document).ready(function() {
 
     $("#player_stream_mode-element").change(function() {
         var $streamMode = getStreamMode();
-        if ($streamMode == "a") {
+        if ($streamMode == "auto") {
             $("#player_stream_url-element input[type='radio']").attr("disabled", "disabled");
-        } else if ($streamMode == "b") {
+        } else if ($streamMode == "manual") {
             $("#player_stream_url-element input[type='radio']").removeAttr("disabled");
 
             $("input[name=player_stream_url]").each(function(i, obj) {

From 3d2b189dbadfe28a651716d9f8c703edc6cd39be Mon Sep 17 00:00:00 2001
From: drigato <denise.rigato@sourcefabric.org>
Date: Wed, 25 Mar 2015 11:47:23 -0400
Subject: [PATCH 29/60] removed logging statement

---
 .../application/views/scripts/embeddableplayer/embed-code.phtml  | 1 -
 1 file changed, 1 deletion(-)

diff --git a/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml b/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml
index 47e713e42..f650ed509 100644
--- a/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml
+++ b/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml
@@ -83,7 +83,6 @@
                 data: {type:"interval",limit:"5"},
                 dataType: "jsonp",
                 success: function(data) {
-                    console.log("fetching metadata");
                     var current_track_end_time = new Date(data.current.ends);
                     var current_time = new Date();
                     current_time = new Date(current_time.getTime() + current_time.getTimezoneOffset()*60*1000);

From d0f7f820a78516c096acaa61b2b9c077eea4389b Mon Sep 17 00:00:00 2001
From: drigato <denise.rigato@sourcefabric.org>
Date: Fri, 27 Mar 2015 16:34:04 -0400
Subject: [PATCH 30/60] SAAS-675: Implement "auto" mode

---
 .../EmbeddableplayerController.php            |  25 ++-
 .../scripts/embeddableplayer/embed-code.phtml | 150 ++++++++++++++----
 2 files changed, 143 insertions(+), 32 deletions(-)

diff --git a/airtime_mvc/application/controllers/EmbeddableplayerController.php b/airtime_mvc/application/controllers/EmbeddableplayerController.php
index 2a66d0b7e..2d70c08a2 100644
--- a/airtime_mvc/application/controllers/EmbeddableplayerController.php
+++ b/airtime_mvc/application/controllers/EmbeddableplayerController.php
@@ -39,9 +39,26 @@ class EmbeddablePlayerController extends Zend_Controller_Action
         $this->view->station_name = Application_Model_Preference::GetStationName();
         $stream = $request->getParam('stream');
         $streamData = Application_Model_StreamSetting::getEnabledStreamData();
-        $selectedStreamData = $streamData[$stream];
-        $this->view->streamURL = $selectedStreamData["url"];
-        $this->view->codec = $selectedStreamData["codec"];
-        $this->view->displayMetadata = $request->getParam('display_metadata');
+
+        if ($stream == "auto") {
+            $this->view->playerMode = "auto";
+            $availableMobileStreams = array();
+            $availableDesktopStreams = array();
+            foreach ($streamData as $s) {
+                if ($s["mobile"]) {
+                    array_push($availableMobileStreams, $s);
+                } else if (!$s["mobile"]) {
+                    array_push($availableDesktopStreams, $s);
+                }
+            }
+            $this->view->availableMobileStreams = json_encode($availableMobileStreams);
+            $this->view->availableDesktopStreams = json_encode($availableDesktopStreams);
+        } else {
+            $this->view->playerMode = "manual";
+            $selectedStreamData = $streamData[$stream];
+            $this->view->streamURL = $selectedStreamData["url"];
+            $this->view->codec = $selectedStreamData["codec"];
+        }
+        //$this->view->displayMetadata = $request->getParam('display_metadata');
     }
 }
\ No newline at end of file
diff --git a/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml b/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml
index f650ed509..940850be9 100644
--- a/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml
+++ b/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml
@@ -8,19 +8,42 @@
     <script type="text/javascript">
 
         var MusesPlayer = function() {
-            MRP.insert({
-                'url':"<?php echo $this->streamURL ?>",
-                'codec':"<?php echo $this->codec ?>",
-                'volume':100,
-                'jsevents':true,
-                'autoplay':false,
-                'buffering':5,
-                'title':'test',
-                'bgcolor':'#FFFFFF',
-                'skin':'mcclean',
-                'width':180,
-                'height':60
-            });
+            this.mobileDetect = this.mobileDetect();
+            this.availableMobileStreamQueue = <?php echo $this->availableMobileStreams?>;
+            this.availableDesktopStreamQueue = <?php echo $this->availableDesktopStreams?>;
+            this.playerMode = "<?php echo $this->playerMode ?>";
+
+            if (this.playerMode == "manual") {
+                MRP.insert({
+                    'url': "<?php echo $this->streamURL ?>",
+                    'codec': "<?php echo $this->codec ?>",
+                    'volume': 100,
+                    'jsevents': true,
+                    'autoplay': false,
+                    'buffering': 5,
+                    'title': 'test',
+                    'bgcolor': '#FFFFFF',
+                    'skin': 'mcclean',
+                    'width': 180,
+                    'height': 60
+                });
+            } else if (this.playerMode == "auto") {
+                var stream = this.getNextAvailableStream();
+                MRP.insert({
+                    'url': stream["url"],
+                    'codec': stream["codec"],
+                    'volume': 100,
+                    'jsevents': true,
+                    'autoplay': false,
+                    'buffering': 5,
+                    'title': 'test',
+                    'bgcolor': '#FFFFFF',
+                    'skin': 'mcclean',
+                    'width': 180,
+                    'height': 60
+                });
+            }
+
             $("p.station_name").html("<?php echo $this->station_name?>");
 
             this.flashDetect = FlashDetect.versionAtLeast(10, 1) ? true : false;
@@ -28,6 +51,49 @@
             getMetadata();
         };
 
+        MusesPlayer.prototype.mobileDetect = function() {
+            if ( screen.width <= 760) {
+                return true;
+            } else {
+                return false;
+            }
+        }
+
+        MusesPlayer.prototype.getNextAvailableStream = function() {
+            if (this.mobileDetect && this.availableMobileStreamQueue.length > 0) {
+                return this.getNextAvailableMobileStream();
+            }
+
+            if (!this.mobileDetect && this.availableDesktopStreamQueue.length > 0) {
+                return this.getNextAvailableDesktopStream();
+            }
+
+            //if we get to this point there are no available streams for the
+            //type of device the client has connected with so just return
+            //the next available stream - first we'll try the desktop streams
+            var desktopStream = this.getNextAvailableDesktopStream();
+            if (desktopStream) {
+                return desktopStream;
+            } else {
+                return this.getNextAvailableMobileStream();
+            }
+
+        }
+
+        MusesPlayer.prototype.getNextAvailableMobileStream = function() {
+            var stream = this.availableMobileStreamQueue.shift();
+            //add to end of queue
+            this.availableMobileStreamQueue.push(stream);
+            return stream;
+        }
+
+        MusesPlayer.prototype.getNextAvailableDesktopStream = function() {
+            var stream = this.availableDesktopStreamQueue.shift();
+            //add to end of queue
+            this.availableDesktopStreamQueue.push(stream);
+            return stream;
+        }
+
         MusesPlayer.prototype.play = function() {
             this.flashDetect ? MRP.play() : musesHTMLPlayClick();
             togglePlayStopButton();
@@ -46,9 +112,20 @@
             //TODO
         };
 
-        /*function musesCallback(event,value){
-         console.log('event: "'+event+'", value: "'+value+'"');
-         }*/
+        function musesCallback(event,value){
+            switch (event) {
+                case "loadComplete":
+                    // no source URL is set
+                    if (value === "0") {
+                        console.log("loadComplete failed");
+                    }
+                case "ioError":
+                    // connection limit reached or problem connecting to stream
+                    if (value === "0") {
+                        console.log("ioError");
+                    }
+            }
+        }
 
         /**
          * This is a hack to trigger the play button in HTML5 mode
@@ -83,18 +160,35 @@
                 data: {type:"interval",limit:"5"},
                 dataType: "jsonp",
                 success: function(data) {
-                    var current_track_end_time = new Date(data.current.ends);
-                    var current_time = new Date();
-                    current_time = new Date(current_time.getTime() + current_time.getTimezoneOffset()*60*1000);
-                    time_to_next_track_starts = current_track_end_time - current_time;
-                    // maybe we should set time_to_next_track_starts to
-                    // (10 || 20 || etc.) minutes if its greater than that
-                    // in case of on-the-fly schedule changes
+                    //console.log("hello");
+
+                    if (data.current === null) {
+                        $("p.now_playing").html("Offline");
+                    } else {
+                        var artist = data.current.name.split(" - ")[0];
+                        var track = data.current.name.split(" - ")[1];
+                        $("p.now_playing").html(artist + "<span>" + track + "</span>");
+
+                        var current_track_end_time = new Date(data.current.ends);
+                        var current_time = new Date();
+                        //convert current_time to UTC to match the timezone of time_to_next_track_starts
+                        current_time = new Date(current_time.getTime() + current_time.getTimezoneOffset() * 60 * 1000);
+                        //TODO stop the first settimeout from executing!!
+                        time_to_next_track_starts = current_track_end_time - current_time;
+                        //console.log((time_to_next_track_starts/1000)/60);
+                        // maybe we should set time_to_next_track_starts to
+                        // (10 || 20 || etc.) minutes if its greater than that
+                        // in case of on-the-fly schedule changes
+
+
+                    }
+
+                    if (data.next === null) {
+                        $("ul.schedule_list").find("li").html("Nothing scheduled");
+                    } else {
+                        $("ul.schedule_list").find("li").html(data.next.name);
+                    }
 
-                    var artist = data.current.name.split(" - ")[0];
-                    var track = data.current.name.split(" - ")[1];
-                    $("p.now_playing").html(artist+"<span>"+track+"</span>");
-                    $("ul.schedule_list").find("li").html(data.next.name);
                 }
             });
             setTimeout(getMetadata, time_to_next_track_starts);
@@ -141,7 +235,7 @@
     <div class="airtime_schedule">
         <p class="airtime_next">Next</p>
         <ul class="schedule_list">
-            <li>John Legend - Ordinary People</li>
+            <li></li>
         </ul>
     </div>
 

From 778df97d3cb13c39e4ee1d14ecc2a07c6068741c Mon Sep 17 00:00:00 2001
From: drigato <denise.rigato@sourcefabric.org>
Date: Tue, 31 Mar 2015 16:51:14 -0400
Subject: [PATCH 31/60] SAAS-662: Make player auto-connect if there is a
 problem with the stream

Kind of working in HTML5 mode
---
 .../EmbeddableplayerController.php            |   8 +-
 .../scripts/embeddableplayer/embed-code.phtml | 101 +++++++-----------
 .../public/js/airtime/embeddableplayer/mrp.js |   1 +
 3 files changed, 44 insertions(+), 66 deletions(-)

diff --git a/airtime_mvc/application/controllers/EmbeddableplayerController.php b/airtime_mvc/application/controllers/EmbeddableplayerController.php
index 2d70c08a2..6a00df36b 100644
--- a/airtime_mvc/application/controllers/EmbeddableplayerController.php
+++ b/airtime_mvc/application/controllers/EmbeddableplayerController.php
@@ -39,11 +39,11 @@ class EmbeddablePlayerController extends Zend_Controller_Action
         $this->view->station_name = Application_Model_Preference::GetStationName();
         $stream = $request->getParam('stream');
         $streamData = Application_Model_StreamSetting::getEnabledStreamData();
+        $availableMobileStreams = array();
+        $availableDesktopStreams = array();
 
         if ($stream == "auto") {
             $this->view->playerMode = "auto";
-            $availableMobileStreams = array();
-            $availableDesktopStreams = array();
             foreach ($streamData as $s) {
                 if ($s["mobile"]) {
                     array_push($availableMobileStreams, $s);
@@ -51,14 +51,14 @@ class EmbeddablePlayerController extends Zend_Controller_Action
                     array_push($availableDesktopStreams, $s);
                 }
             }
-            $this->view->availableMobileStreams = json_encode($availableMobileStreams);
-            $this->view->availableDesktopStreams = json_encode($availableDesktopStreams);
         } else {
             $this->view->playerMode = "manual";
             $selectedStreamData = $streamData[$stream];
             $this->view->streamURL = $selectedStreamData["url"];
             $this->view->codec = $selectedStreamData["codec"];
         }
+        $this->view->availableMobileStreams = json_encode($availableMobileStreams);
+        $this->view->availableDesktopStreams = json_encode($availableDesktopStreams);
         //$this->view->displayMetadata = $request->getParam('display_metadata');
     }
 }
\ No newline at end of file
diff --git a/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml b/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml
index 940850be9..5c1a57b74 100644
--- a/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml
+++ b/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml
@@ -9,45 +9,35 @@
 
         var MusesPlayer = function() {
             this.mobileDetect = this.mobileDetect();
-            this.availableMobileStreamQueue = <?php echo $this->availableMobileStreams?>;
-            this.availableDesktopStreamQueue = <?php echo $this->availableDesktopStreams?>;
             this.playerMode = "<?php echo $this->playerMode ?>";
+            this.flashDetect = FlashDetect.versionAtLeast(10, 1) ? true : false;
+            this.settings = {
+                'volume': 100,
+                'jsevents': true,
+                'autoplay': false,
+                'buffering': 5,
+                'title': 'test',
+                'bgcolor': '#FFFFFF',
+                'skin': 'mcclean',
+                'width': 180,
+                'height': 60
+            };
 
             if (this.playerMode == "manual") {
-                MRP.insert({
-                    'url': "<?php echo $this->streamURL ?>",
-                    'codec': "<?php echo $this->codec ?>",
-                    'volume': 100,
-                    'jsevents': true,
-                    'autoplay': false,
-                    'buffering': 5,
-                    'title': 'test',
-                    'bgcolor': '#FFFFFF',
-                    'skin': 'mcclean',
-                    'width': 180,
-                    'height': 60
-                });
+                this.settings.url = "<?php echo $this->streamURL ?>";
+                this.settings.codec = "<?php echo $this->codec ?>";
+                MRP.insert(this.settings);
             } else if (this.playerMode == "auto") {
+                this.availableMobileStreamQueue = <?php echo $this->availableMobileStreams?>;
+                this.availableDesktopStreamQueue = <?php echo $this->availableDesktopStreams?>;
                 var stream = this.getNextAvailableStream();
-                MRP.insert({
-                    'url': stream["url"],
-                    'codec': stream["codec"],
-                    'volume': 100,
-                    'jsevents': true,
-                    'autoplay': false,
-                    'buffering': 5,
-                    'title': 'test',
-                    'bgcolor': '#FFFFFF',
-                    'skin': 'mcclean',
-                    'width': 180,
-                    'height': 60
-                });
+                this.settings.url = stream["url"];
+                this.settings.codec = stream["codec"];
+                MRP.insert(this.settings);
             }
 
             $("p.station_name").html("<?php echo $this->station_name?>");
 
-            this.flashDetect = FlashDetect.versionAtLeast(10, 1) ? true : false;
-
             getMetadata();
         };
 
@@ -95,7 +85,7 @@
         }
 
         MusesPlayer.prototype.play = function() {
-            this.flashDetect ? MRP.play() : musesHTMLPlayClick();
+            this.flashDetect ? MRP.play() : musesHTMLPlayClick();;
             togglePlayStopButton();
         };
 
@@ -108,43 +98,39 @@
             //this.flashDetect ? MRP.setVolume(value) : null;
         };
 
-        MusesPlayer.prototype.setURL = function() {
-            //TODO
+        MusesPlayer.prototype.setURL = function(url) {
+            MRP.setUrl(url);
         };
 
-        function musesCallback(event,value){
+        // detects errors in FLASH mode
+        function musesCallback(event,value) {
             switch (event) {
-                case "loadComplete":
-                    // no source URL is set
-                    if (value === "0") {
-                        console.log("loadComplete failed");
-                    }
                 case "ioError":
                     // connection limit reached or problem connecting to stream
                     if (value === "0") {
                         console.log("ioError");
+                        var stream = musesPlayer.getNextAvailableStream();
+                        musesPlayer.setURL(stream["url"]);
+                        musesPlayer.play();
                     }
             }
         }
 
-        /**
-         * This is a hack to trigger the play button in HTML5 mode
-         */
         function musesHTMLPlayClick() {
-            //child nodes
-            var cn = document.getElementById("MusesRadioPlayer-HTML5-player-1").childNodes;
-            var playDiv = cn[4];
-            playDiv.onclick();
+            MRP.html.audio.src = MRP.html.src;
+
+            MRP.html.audio.play();
+
+            // detects errors in HTML5 mode
+            MRP.html.audio.addEventListener('error', function failed(e) {
+                var stream = musesPlayer.getNextAvailableStream();
+                MRP.html.audio.src = stream["url"];
+                MRP.html.audio.play();
+            }, true);
         }
 
-        /**
-         * This is a hack to trigger the stop button in HTML5 mode
-         */
         function musesHTMLStopClick() {
-            //child nodes
-            var cn = document.getElementById("MusesRadioPlayer-HTML5-player-1").childNodes;
-            var stopDiv = cn[5];
-            stopDiv.onclick();
+            MRP.html.audio.pause();
         }
 
         function togglePlayStopButton() {
@@ -247,14 +233,5 @@
     </script>
 </div>
 
-<!--
-<div id="custom_muses_play" onclick="musesPlayer.play()">
-    <a href="#">play</a>
-</div>
-<div id="custom_muses_stop" onclick="musesPlayer.stop()">
-    <a href="#">stop</a>
-</div>
--->
-
 </body>
 </html>
\ No newline at end of file
diff --git a/airtime_mvc/public/js/airtime/embeddableplayer/mrp.js b/airtime_mvc/public/js/airtime/embeddableplayer/mrp.js
index 4377dddd5..ca7140dc1 100644
--- a/airtime_mvc/public/js/airtime/embeddableplayer/mrp.js
+++ b/airtime_mvc/public/js/airtime/embeddableplayer/mrp.js
@@ -2298,6 +2298,7 @@
         this.ui = new d.UI(this, a);
         a.autoplay && (a = window.navigator.userAgent.toLowerCase(), -1 == a.indexOf("iphone") && -1 == a.indexOf("ipad") && -1 == a.indexOf("ipod") &&
         this.playAudio())
+        n.MRP.html = this;
     };
     d.Muses.__name__ = !0;
     d.Muses.initTimer = function(a) {

From 15a8e3fa1f5e8fb2accfa58d63e6cfd814ced198 Mon Sep 17 00:00:00 2001
From: drigato <denise.rigato@sourcefabric.org>
Date: Tue, 31 Mar 2015 17:20:42 -0400
Subject: [PATCH 32/60] Moved html5 error listener to MusesPlayer constructor

---
 .../scripts/embeddableplayer/embed-code.phtml   | 17 ++++++++++-------
 1 file changed, 10 insertions(+), 7 deletions(-)

diff --git a/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml b/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml
index 5c1a57b74..076b6c38f 100644
--- a/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml
+++ b/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml
@@ -39,6 +39,16 @@
             $("p.station_name").html("<?php echo $this->station_name?>");
 
             getMetadata();
+
+            // detects errors in HTML5 mode
+            if (!this.flashDetect) {
+                MRP.html.audio.addEventListener('error', function failed(e) {
+                    var stream = musesPlayer.getNextAvailableStream();
+                    console.log(stream);
+                    MRP.html.audio.src = stream["url"];
+                    MRP.html.audio.play();
+                }, true);
+            }
         };
 
         MusesPlayer.prototype.mobileDetect = function() {
@@ -120,13 +130,6 @@
             MRP.html.audio.src = MRP.html.src;
 
             MRP.html.audio.play();
-
-            // detects errors in HTML5 mode
-            MRP.html.audio.addEventListener('error', function failed(e) {
-                var stream = musesPlayer.getNextAvailableStream();
-                MRP.html.audio.src = stream["url"];
-                MRP.html.audio.play();
-            }, true);
         }
 
         function musesHTMLStopClick() {

From 57cd2eda13dd00aa98c587859cb1d7ab20218c48 Mon Sep 17 00:00:00 2001
From: drigato <denise.rigato@sourcefabric.org>
Date: Tue, 31 Mar 2015 18:21:25 -0400
Subject: [PATCH 33/60] bad merge

---
 airtime_mvc/application/configs/ACL.php | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/airtime_mvc/application/configs/ACL.php b/airtime_mvc/application/configs/ACL.php
index fe6e4d3d6..1386d1dee 100644
--- a/airtime_mvc/application/configs/ACL.php
+++ b/airtime_mvc/application/configs/ACL.php
@@ -71,11 +71,8 @@ $ccAcl->allow('G', 'index')
       ->allow('A', 'user')
       ->allow('A', 'systemstatus')
       ->allow('A', 'preference')
-<<<<<<< HEAD
       ->allow('A', 'embeddableplayer')
-=======
       ->allow('S', 'thank-you')
->>>>>>> saas
       ->allow('S', 'billing');
       
 

From c1038cd92fe0b28ead6b39afa476e7f53b5e1531 Mon Sep 17 00:00:00 2001
From: drigato <denise.rigato@sourcefabric.org>
Date: Wed, 1 Apr 2015 11:25:58 -0400
Subject: [PATCH 34/60] SAAS-706: Remove volume bar from player

---
 .../views/scripts/embeddableplayer/embed-code.phtml          | 5 +++--
 airtime_mvc/public/css/embeddable-player.css                 | 2 +-
 2 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml b/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml
index 076b6c38f..0af07296e 100644
--- a/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml
+++ b/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml
@@ -209,7 +209,7 @@
 
     </div>
 
-    <div class="airtime_volume">
+    <!--<div class="airtime_volume">
 
         <div class="volume_control">
             <span class="mute"></span>
@@ -219,7 +219,8 @@
             <div class="airtime_volume_bar_value" style="width: 80%;"></div>
         </div>
 
-    </div>
+    </div>-->
+    <div style="clear:both"></div>
 
     <div class="airtime_schedule">
         <p class="airtime_next">Next</p>
diff --git a/airtime_mvc/public/css/embeddable-player.css b/airtime_mvc/public/css/embeddable-player.css
index 6c770c693..be1a06d9d 100644
--- a/airtime_mvc/public/css/embeddable-player.css
+++ b/airtime_mvc/public/css/embeddable-player.css
@@ -162,7 +162,7 @@
 }
 
 .airtime_schedule {
-    margin: 0px 20px 10px 20px;
+    margin: 10px 20px 10px 20px;
     padding-top: 10px;
     font-size: 14px;
     color: #aaaaaa;

From eaeed9be77a04b3f95164b479f1ce7de091d7794 Mon Sep 17 00:00:00 2001
From: drigato <denise.rigato@sourcefabric.org>
Date: Wed, 1 Apr 2015 12:50:49 -0400
Subject: [PATCH 35/60] SAAS-669: Long station names overlap with link to
 airtime.pro

---
 .../views/scripts/embeddableplayer/embed-code.phtml  |  3 ++-
 airtime_mvc/public/css/embeddable-player.css         | 12 ++++++++----
 2 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml b/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml
index 0af07296e..d2aa129db 100644
--- a/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml
+++ b/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml
@@ -196,7 +196,6 @@
 
     <div class="airtime_header">
         <p class="station_name">fff</p>
-        <a class="airtime_pro" href="#"><span>airtime.pro</span><img src="http://localhost/css/embed-player-images/airtime_logo.png"></a>
     </div>
 
     <div class="airtime_box">
@@ -227,8 +226,10 @@
         <ul class="schedule_list">
             <li></li>
         </ul>
+        <a class="airtime_pro" href="https://www.airtime.pro/">Powered by Airtime Pro<span class="airtime_pro_logo"></span></a>
     </div>
 
+
 </div>
 
 <div id="muses_skin">
diff --git a/airtime_mvc/public/css/embeddable-player.css b/airtime_mvc/public/css/embeddable-player.css
index be1a06d9d..88f3ee187 100644
--- a/airtime_mvc/public/css/embeddable-player.css
+++ b/airtime_mvc/public/css/embeddable-player.css
@@ -37,13 +37,15 @@
     padding-right: 30px;
 }
 .airtime_pro {
-    position: absolute;
-    right: 15px;
-    top: 10px;
     color: #fff;
-    font-size: 12px;
+    font-size: 10px;
     text-decoration: none;
 }
+.airtime_pro_logo {
+    background: url("embed-player-images/airtime_logo.png") center no-repeat;
+    width: 16px;
+    height: 16px;
+}
 .airtime_pro span {
     display: inline-block;
     vertical-align: 2px;
@@ -167,6 +169,7 @@
     font-size: 14px;
     color: #aaaaaa;
     border-top: 1px solid rgba(255, 255, 255, 0.1);
+    padding-bottom: 5px;
 }
 
 .airtime_next {
@@ -180,6 +183,7 @@
     padding-bottom: 10px;
     margin-top: 0px;
     margin-left: 60px;
+    margin-bottom: 0px;
     line-height: 130%;
 }
 

From 0bffa07ed9129995b3420d184432733e267e22e7 Mon Sep 17 00:00:00 2001
From: drigato <denise.rigato@sourcefabric.org>
Date: Wed, 1 Apr 2015 12:59:31 -0400
Subject: [PATCH 36/60] SAAS-669: Long station names overlap with link to
 airtime.pro

---
 airtime_mvc/public/css/embeddable-player.css | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/airtime_mvc/public/css/embeddable-player.css b/airtime_mvc/public/css/embeddable-player.css
index 88f3ee187..30ce8beac 100644
--- a/airtime_mvc/public/css/embeddable-player.css
+++ b/airtime_mvc/public/css/embeddable-player.css
@@ -45,8 +45,9 @@
     background: url("embed-player-images/airtime_logo.png") center no-repeat;
     width: 16px;
     height: 16px;
+    display:inline-block;
 }
-.airtime_pro span {
+/*.airtime_pro span {
     display: inline-block;
     vertical-align: 2px;
     margin-right: 5px;
@@ -55,7 +56,7 @@
     display: inline-block;
     vertical-align: 2px;
     margin-right: 5px;
-}
+}*/
 .airtime_box .airtime_button {
     text-indent: -9999px;
     -webkit-border-radius: 2px;

From 353bfe86a5f9c7ac915503dff569d1530a83438d Mon Sep 17 00:00:00 2001
From: drigato <denise.rigato@sourcefabric.org>
Date: Wed, 1 Apr 2015 13:05:08 -0400
Subject: [PATCH 37/60] Addded default for mobile stream setting

---
 airtime_mvc/application/models/StreamSetting.php | 1 +
 1 file changed, 1 insertion(+)

diff --git a/airtime_mvc/application/models/StreamSetting.php b/airtime_mvc/application/models/StreamSetting.php
index 19a147798..c51995d6d 100644
--- a/airtime_mvc/application/models/StreamSetting.php
+++ b/airtime_mvc/application/models/StreamSetting.php
@@ -177,6 +177,7 @@ class Application_Model_StreamSetting
         self::ensureKeyExists($keyPrefix . 'type', $data);
         self::ensureKeyExists($keyPrefix . 'url', $data);
         self::ensureKeyExists($keyPrefix . 'user', $data);
+        self::ensureKeyExists($keyPrefix . 'mobile', $data);
 
         return $data;
     }

From 06f43ef2d7c3420d57831f8fdd0366790a39e17d Mon Sep 17 00:00:00 2001
From: drigato <denise.rigato@sourcefabric.org>
Date: Thu, 2 Apr 2015 12:45:05 -0400
Subject: [PATCH 38/60] CSS modifications

Added fixed width and height to player.
Floated Airtime badge to the right
---
 airtime_mvc/public/css/embeddable-player.css | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/airtime_mvc/public/css/embeddable-player.css b/airtime_mvc/public/css/embeddable-player.css
index 30ce8beac..420d12ede 100644
--- a/airtime_mvc/public/css/embeddable-player.css
+++ b/airtime_mvc/public/css/embeddable-player.css
@@ -1,5 +1,6 @@
 .airtime_player {
-    max-width: 270px;
+    width: 270px;
+    height: 172px;
     position: relative;
     font-family: Arial, Helvetica, sans-serif;
     color: #fff;
@@ -40,6 +41,8 @@
     color: #fff;
     font-size: 10px;
     text-decoration: none;
+    display:inline-block;
+    float:right;
 }
 .airtime_pro_logo {
     background: url("embed-player-images/airtime_logo.png") center no-repeat;
@@ -47,6 +50,7 @@
     height: 16px;
     display:inline-block;
 }
+
 /*.airtime_pro span {
     display: inline-block;
     vertical-align: 2px;

From fdd8cdfaeaf5ff9ffc77fe43877461d5fd52a100 Mon Sep 17 00:00:00 2001
From: drigato <denise.rigato@sourcefabric.org>
Date: Thu, 2 Apr 2015 14:35:13 -0400
Subject: [PATCH 39/60] Fixed Airtime badge spacing

---
 .../views/scripts/embeddableplayer/embed-code.phtml       | 2 +-
 airtime_mvc/public/css/embeddable-player.css              | 8 +++++---
 2 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml b/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml
index d2aa129db..d1047885c 100644
--- a/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml
+++ b/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml
@@ -226,8 +226,8 @@
         <ul class="schedule_list">
             <li></li>
         </ul>
-        <a class="airtime_pro" href="https://www.airtime.pro/">Powered by Airtime Pro<span class="airtime_pro_logo"></span></a>
     </div>
+    <a class="airtime_pro" href="https://www.airtime.pro/">Powered by Airtime Pro<span class="airtime_pro_logo"></span></a>
 
 
 </div>
diff --git a/airtime_mvc/public/css/embeddable-player.css b/airtime_mvc/public/css/embeddable-player.css
index 420d12ede..261a6496f 100644
--- a/airtime_mvc/public/css/embeddable-player.css
+++ b/airtime_mvc/public/css/embeddable-player.css
@@ -1,6 +1,6 @@
 .airtime_player {
     width: 270px;
-    height: 172px;
+    height: 180px;
     position: relative;
     font-family: Arial, Helvetica, sans-serif;
     color: #fff;
@@ -38,6 +38,7 @@
     padding-right: 30px;
 }
 .airtime_pro {
+    margin: 0px 20px;
     color: #fff;
     font-size: 10px;
     text-decoration: none;
@@ -169,12 +170,13 @@
 }
 
 .airtime_schedule {
-    margin: 10px 20px 10px 20px;
+    margin: 10px 20px 5px 20px;
     padding-top: 10px;
     font-size: 14px;
     color: #aaaaaa;
     border-top: 1px solid rgba(255, 255, 255, 0.1);
-    padding-bottom: 5px;
+    border-bottom: 1px solid rgba(255, 255, 255, 0.1);
+    padding-bottom: 0px;
 }
 
 .airtime_next {

From 4ab4fe5cb9886dc0e24e8104091d96cba22e7e15 Mon Sep 17 00:00:00 2001
From: drigato <denise.rigato@sourcefabric.org>
Date: Thu, 2 Apr 2015 15:00:46 -0400
Subject: [PATCH 40/60] Fixed player css so long artist and track names don't
 overflow

---
 airtime_mvc/public/css/embeddable-player.css | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/airtime_mvc/public/css/embeddable-player.css b/airtime_mvc/public/css/embeddable-player.css
index 261a6496f..3c9ef0f08 100644
--- a/airtime_mvc/public/css/embeddable-player.css
+++ b/airtime_mvc/public/css/embeddable-player.css
@@ -1,6 +1,6 @@
 .airtime_player {
     width: 270px;
-    height: 180px;
+    height: 185px;
     position: relative;
     font-family: Arial, Helvetica, sans-serif;
     color: #fff;
@@ -123,12 +123,19 @@
     display: block;
     font-size: 14px;
     color: #fff;
-    width: auto;
+    width: 170px;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+    overflow: hidden;
 }
 
 .now_playing span {
     display: block;
     color: #aaaaaa;
+    width: 170px;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+    overflow: hidden;
 }
 
 .airtime_volume {

From 369a59c564ad1212360acfc85053eeaedf6f0bbf Mon Sep 17 00:00:00 2001
From: drigato <denise.rigato@sourcefabric.org>
Date: Thu, 2 Apr 2015 15:13:34 -0400
Subject: [PATCH 41/60] Changed mobile option text on streams page

---
 airtime_mvc/application/forms/StreamSettingSubForm.php | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/airtime_mvc/application/forms/StreamSettingSubForm.php b/airtime_mvc/application/forms/StreamSettingSubForm.php
index b84adf63d..8d1f96f43 100644
--- a/airtime_mvc/application/forms/StreamSettingSubForm.php
+++ b/airtime_mvc/application/forms/StreamSettingSubForm.php
@@ -54,7 +54,7 @@ class Application_Form_StreamSettingSubForm extends Zend_Form_SubForm
         $this->addElement($enable);
 
         $mobile = new Zend_Form_Element_Checkbox('mobile');
-        $mobile->setLabel(_('Good for mobile?'));
+        $mobile->setLabel(_('Mobile:'));
         $mobile->setValue($setting[$prefix.'_mobile']);
         $mobile->setDecorators(array('ViewHelper'));
         $this->addElement($mobile);

From e8c8fde8bde50325d7c1c81b5a64146ec02b7752 Mon Sep 17 00:00:00 2001
From: drigato <denise.rigato@sourcefabric.org>
Date: Thu, 2 Apr 2015 15:27:01 -0400
Subject: [PATCH 42/60] Fix airtime.pro link on player

---
 .../application/views/scripts/embeddableplayer/embed-code.phtml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml b/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml
index d1047885c..4ab35b768 100644
--- a/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml
+++ b/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml
@@ -227,7 +227,7 @@
             <li></li>
         </ul>
     </div>
-    <a class="airtime_pro" href="https://www.airtime.pro/">Powered by Airtime Pro<span class="airtime_pro_logo"></span></a>
+    <a class="airtime_pro" target="_blank" href="https://www.airtime.pro/">Powered by Airtime Pro<span class="airtime_pro_logo"></span></a>
 
 
 </div>

From faee0fba98123587b5ae9646cca4b93ef902c1c9 Mon Sep 17 00:00:00 2001
From: drigato <denise.rigato@sourcefabric.org>
Date: Thu, 2 Apr 2015 16:54:57 -0400
Subject: [PATCH 43/60] SAAS-673: Warn if public api is not enabled under
 Preferences

---
 .../controllers/EmbeddableplayerController.php           | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/airtime_mvc/application/controllers/EmbeddableplayerController.php b/airtime_mvc/application/controllers/EmbeddableplayerController.php
index 6a00df36b..3552ee47e 100644
--- a/airtime_mvc/application/controllers/EmbeddableplayerController.php
+++ b/airtime_mvc/application/controllers/EmbeddableplayerController.php
@@ -17,10 +17,15 @@ class EmbeddablePlayerController extends Zend_Controller_Action
 
         $form = new Application_Form_EmbeddablePlayer();
 
-        if ($form->getElement('player_stream_url')->getAttrib('numberOfEnabledStreams') > 0) {
+        $apiEnabled = Application_Model_Preference::GetAllow3rdPartyApi();
+        $numEnabledStreams = $form->getElement('player_stream_url')->getAttrib('numberOfEnabledStreams');
+
+        if ($numEnabledStreams > 0 && $apiEnabled) {
             $this->view->form = $form;
         } else {
-            $this->view->errorMsg = "You need to enable at least one MP3, AAC, or OGG stream to use this feature.";
+            $this->view->errorMsg = "To configure and use the embeddable player you must:<br><br>
+            1. Enable at least one MP3, AAC, or OGG stream under System -> Streams<br>
+            2. Enable the Public Airtime API under System -> Preferences";
         }
 
     }

From 481d21ff70a6bfd77dde5d4835d7d0ab01c01850 Mon Sep 17 00:00:00 2001
From: drigato <denise.rigato@sourcefabric.org>
Date: Tue, 7 Apr 2015 11:34:21 -0400
Subject: [PATCH 44/60] SAAS-662: Make player auto-connect if there is a
 problem with the stream

HTML5 error handling
---
 .../scripts/embeddableplayer/embed-code.phtml | 25 +++++++++++++------
 1 file changed, 18 insertions(+), 7 deletions(-)

diff --git a/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml b/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml
index 4ab35b768..66117609a 100644
--- a/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml
+++ b/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml
@@ -15,7 +15,7 @@
                 'volume': 100,
                 'jsevents': true,
                 'autoplay': false,
-                'buffering': 5,
+                'buffering': 0,
                 'title': 'test',
                 'bgcolor': '#FFFFFF',
                 'skin': 'mcclean',
@@ -26,27 +26,37 @@
             if (this.playerMode == "manual") {
                 this.settings.url = "<?php echo $this->streamURL ?>";
                 this.settings.codec = "<?php echo $this->codec ?>";
-                MRP.insert(this.settings);
             } else if (this.playerMode == "auto") {
                 this.availableMobileStreamQueue = <?php echo $this->availableMobileStreams?>;
                 this.availableDesktopStreamQueue = <?php echo $this->availableDesktopStreams?>;
                 var stream = this.getNextAvailableStream();
                 this.settings.url = stream["url"];
                 this.settings.codec = stream["codec"];
-                MRP.insert(this.settings);
             }
 
+            MRP.insert(this.settings);
+
             $("p.station_name").html("<?php echo $this->station_name?>");
 
             getMetadata();
 
-            // detects errors in HTML5 mode
+            // detects events in HTML5 mode
             if (!this.flashDetect) {
+
                 MRP.html.audio.addEventListener('error', function failed(e) {
+                    console.log("HTML error");
                     var stream = musesPlayer.getNextAvailableStream();
-                    console.log(stream);
-                    MRP.html.audio.src = stream["url"];
-                    MRP.html.audio.play();
+                    var audio = $(MRP.html.audio);
+                    audio.src = stream["url"];
+                    audio[0].load();
+                    audio[0].play();
+                }, true);
+
+                MRP.html.audio.addEventListener('pause', function paused(e) {
+                    //this is when pause happens
+                    console.log("HTML paused");
+                    //src = MRP.html.audio.src;
+                    //MRP.html.audio.src = "";
                 }, true);
             }
         };
@@ -109,6 +119,7 @@
         };
 
         MusesPlayer.prototype.setURL = function(url) {
+            console.log("setURL");
             MRP.setUrl(url);
         };
 

From f6d5b34cca21493931e8243476a5dbecd0685221 Mon Sep 17 00:00:00 2001
From: drigato <denise.rigato@sourcefabric.org>
Date: Tue, 7 Apr 2015 17:49:21 -0400
Subject: [PATCH 45/60] Embed player - code review fixes

---
 .../application/controllers/ApiController.php |  2 +-
 .../EmbeddableplayerController.php            | 17 +++-
 .../application/forms/EmbeddablePlayer.php    | 19 +++--
 .../application/models/StreamSetting.php      | 16 ----
 .../scripts/embeddableplayer/embed-code.phtml | 83 ++++++++++++++-----
 5 files changed, 89 insertions(+), 48 deletions(-)

diff --git a/airtime_mvc/application/controllers/ApiController.php b/airtime_mvc/application/controllers/ApiController.php
index 80429db08..5ecd5f1da 100644
--- a/airtime_mvc/application/controllers/ApiController.php
+++ b/airtime_mvc/application/controllers/ApiController.php
@@ -523,7 +523,7 @@ class ApiController extends Zend_Controller_Action
             $result["description"] = Application_Model_Preference::GetStationDescription();
             $result["timezone"] = Application_Model_Preference::GetDefaultTimezone();
             $result["locale"] = Application_Model_Preference::GetDefaultLocale();
-            $result["enabled_stream_urls"] = Application_Model_StreamSetting::getEnabledStreamUrls();
+            $result["stream_data"] = Application_Model_StreamSetting::getEnabledStreamData();
             
             // used by caller to determine if the airtime they are running or widgets in use is out of date.
             $result['AIRTIME_API_VERSION'] = AIRTIME_API_VERSION;
diff --git a/airtime_mvc/application/controllers/EmbeddableplayerController.php b/airtime_mvc/application/controllers/EmbeddableplayerController.php
index 3552ee47e..43e8be2d5 100644
--- a/airtime_mvc/application/controllers/EmbeddableplayerController.php
+++ b/airtime_mvc/application/controllers/EmbeddableplayerController.php
@@ -30,18 +30,29 @@ class EmbeddablePlayerController extends Zend_Controller_Action
 
     }
 
+    /**
+     * This is the action that is called to insert the player onto a web page.
+     * It passes all the js and css files to the view, as well as all the
+     * stream customization information.
+     *
+     * The view for this action contains all the inline javascript needed to
+     * create the player.
+     */
     public function embedCodeAction()
     {
         $this->view->layout()->disableLayout();
 
+        $CC_CONFIG = Config::getConfig();
+
         $request = $this->getRequest();
 
-        $this->view->css = Application_Common_HTTPHelper::getStationUrl() . "css/embeddable-player.css";
-        $this->view->mrp_js = Application_Common_HTTPHelper::getStationUrl() . "js/airtime/embeddableplayer/mrp.js";
+        $this->view->css = Application_Common_HTTPHelper::getStationUrl() . "css/embeddable-player.css?".$CC_CONFIG['airtime_version'];
+        $this->view->mrp_js = Application_Common_HTTPHelper::getStationUrl() . "js/airtime/embeddableplayer/mrp.js?".$CC_CONFIG['airtime_version'];
         $this->view->jquery = Application_Common_HTTPHelper::getStationUrl() . "js/libs/jquery-1.10.2.js";
         $this->view->muses_swf = Application_Common_HTTPHelper::getStationUrl() . "js/airtime/embeddableplayer/muses.swf";
         $this->view->metadata_api_url = Application_Common_HTTPHelper::getStationUrl() . "api/live-info";
-        $this->view->station_name = Application_Model_Preference::GetStationName();
+        $this->view->station_name = addslashes(Application_Model_Preference::GetStationName());
+
         $stream = $request->getParam('stream');
         $streamData = Application_Model_StreamSetting::getEnabledStreamData();
         $availableMobileStreams = array();
diff --git a/airtime_mvc/application/forms/EmbeddablePlayer.php b/airtime_mvc/application/forms/EmbeddablePlayer.php
index e5086716a..ca8ca45c9 100644
--- a/airtime_mvc/application/forms/EmbeddablePlayer.php
+++ b/airtime_mvc/application/forms/EmbeddablePlayer.php
@@ -1,5 +1,7 @@
 <?php
 
+define("OPUS", "opus");
+
 class Application_Form_EmbeddablePlayer extends Zend_Form_SubForm
 {
     public function init()
@@ -8,17 +10,19 @@ class Application_Form_EmbeddablePlayer extends Zend_Form_SubForm
             array('ViewScript', array('viewScript' => 'form/embeddableplayer.phtml'))
         ));
 
+        /* We will use this option in the future
         $displayTrackMetadata = new Zend_Form_Element_Checkbox('player_display_track_metadata');
         $displayTrackMetadata->setValue(true);
         $displayTrackMetadata->setLabel(_('Display track metadata?'));
         $this->addElement($displayTrackMetadata);
+        */
 
         $streamMode = new Zend_Form_Element_Radio('player_stream_mode');
         $streamMode->setLabel(_('Select Stream:'));
         $streamMode->setMultiOptions(
             array(
-                "auto" => "Auto detect the most appropriate stream to use.",
-                "manual" => "Select a stream:"
+                "auto" => _("Auto detect the most appropriate stream to use."),
+                "manual" => _("Select a stream:")
             )
         );
         $streamMode->setValue("auto");
@@ -30,19 +34,20 @@ class Application_Form_EmbeddablePlayer extends Zend_Form_SubForm
         foreach(Application_Model_StreamSetting::getEnabledStreamData() as $stream => $data) {
             $urlOptions[$stream] = strtoupper($data["codec"])." - ".$data["bitrate"]."kbps";
             if ($data["mobile"]) {
-                $urlOptions[$stream] .= " - Mobile friendly";
+                $urlOptions[$stream] .= _(" - Mobile friendly");
             }
-            if ($data["codec"] == "opus") {
+            if ($data["codec"] == OPUS) {
                 $opusStreamCount += 1;
-                $urlOptions[$stream] .=" - The player does not support Opus streams.";
+                $urlOptions[$stream] .= _(" - The player does not support Opus streams.");
             }
         }
         $streamURL->setMultiOptions(
             $urlOptions
         );
 
+        // Set default value to the first non-opus stream we find
         foreach ($urlOptions as $o => $v) {
-            if (strpos(strtolower($v), "opus") !== false) {
+            if (strpos(strtolower($v), OPUS) !== false) {
                 continue;
             } else {
                 $streamURL->setValue($o);
@@ -62,7 +67,7 @@ class Application_Form_EmbeddablePlayer extends Zend_Form_SubForm
         $this->addElement($embedSrc);
 
         $previewLabel = new Zend_Form_Element_Text('player_preview_label');
-        $previewLabel->setLabel("Preview:");
+        $previewLabel->setLabel(_("Preview:"));
         $this->addElement($previewLabel);
 
     }
diff --git a/airtime_mvc/application/models/StreamSetting.php b/airtime_mvc/application/models/StreamSetting.php
index c51995d6d..688ddc397 100644
--- a/airtime_mvc/application/models/StreamSetting.php
+++ b/airtime_mvc/application/models/StreamSetting.php
@@ -65,22 +65,6 @@ class Application_Model_StreamSetting
         return $result ? $result : $default;
     }
 
-    public static function getEnabledStreamUrls()
-    {
-        $urls = Array();
-        $streamIds = Application_Model_StreamSetting::getEnabledStreamIds();
-        foreach ($streamIds as $id) {
-            $prefix = $id."_";
-            $streamData = Application_Model_StreamSetting::getStreamData($id);
-            $host = $streamData[$prefix."host"];
-            $port = $streamData[$prefix."port"];
-            $mount = $streamData[$prefix."mount"];
-            $type = $streamData[$prefix."type"];
-            $urls[$type] = "http://$host:$port/$mount";
-        }
-        return $urls;
-    }
-
     public static function getEnabledStreamData()
     {
         $streams = Array();
diff --git a/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml b/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml
index 66117609a..f079a4564 100644
--- a/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml
+++ b/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml
@@ -7,6 +7,17 @@
     <script src="<?php echo $this->jquery?>" type="text/javascript"></script>
     <script type="text/javascript">
 
+        var MAX_MOBILE_SCREEN_WIDTH = 760;
+
+        // We are creating a custom player object that acts as a wrapper
+        // around the player object we get from Muses. We are doing this
+        // for a couple reasons:
+        //
+        // 1. It will be easier to swap out Muses for a different player engine
+        //    in the future - if we ever decide to do that.
+        // 2. We had to add in some custom behaviour depending on the player
+        //    customizations and whether or not the player is in Flash or HTML5
+        //    mode.
         var MusesPlayer = function() {
             this.mobileDetect = this.mobileDetect();
             this.playerMode = "<?php echo $this->playerMode ?>";
@@ -34,11 +45,12 @@
                 this.settings.codec = stream["codec"];
             }
 
+            // Create the Muses player object
             MRP.insert(this.settings);
 
-            $("p.station_name").html("<?php echo $this->station_name?>");
+            $("p.station_name").html(htmlEscape("<?php echo $this->station_name?>"));
 
-            getMetadata();
+            attachStreamMetadataToPlayer();
 
             // detects events in HTML5 mode
             if (!this.flashDetect) {
@@ -62,13 +74,14 @@
         };
 
         MusesPlayer.prototype.mobileDetect = function() {
-            if ( screen.width <= 760) {
-                return true;
-            } else {
-                return false;
-            }
+            return (screen.width <= MAX_MOBILE_SCREEN_WIDTH);
         }
 
+        // This function is called if an error occurs while a client is
+        // attempting to connect to a stream (An error would occur if
+        // the streams listener count has been maxed out or if the stream is down).
+        // It checks if the client is a mobile device or not and returns the next
+        // best available stream.
         MusesPlayer.prototype.getNextAvailableStream = function() {
             if (this.mobileDetect && this.availableMobileStreamQueue.length > 0) {
                 return this.getNextAvailableMobileStream();
@@ -78,9 +91,9 @@
                 return this.getNextAvailableDesktopStream();
             }
 
-            //if we get to this point there are no available streams for the
-            //type of device the client has connected with so just return
-            //the next available stream - first we'll try the desktop streams
+            // If we get to this point there are no available streams for the
+            // type of device the client has connected with so just return
+            // the next available stream - first we'll try the desktop streams
             var desktopStream = this.getNextAvailableDesktopStream();
             if (desktopStream) {
                 return desktopStream;
@@ -90,6 +103,8 @@
 
         }
 
+        // Gets and returns the next available mobile stream from the queue,
+        // but adds it back to the end of the queue to be recycled.
         MusesPlayer.prototype.getNextAvailableMobileStream = function() {
             var stream = this.availableMobileStreamQueue.shift();
             //add to end of queue
@@ -97,6 +112,8 @@
             return stream;
         }
 
+        // Gets and returns the next available desktop stream from the queue,
+        // but adds it back to the end of the queue to be recycled.
         MusesPlayer.prototype.getNextAvailableDesktopStream = function() {
             var stream = this.availableDesktopStreamQueue.shift();
             //add to end of queue
@@ -114,10 +131,6 @@
             togglePlayStopButton();
         };
 
-        MusesPlayer.prototype.setVolume = function(value) {
-            //this.flashDetect ? MRP.setVolume(value) : null;
-        };
-
         MusesPlayer.prototype.setURL = function(url) {
             console.log("setURL");
             MRP.setUrl(url);
@@ -129,7 +142,6 @@
                 case "ioError":
                     // connection limit reached or problem connecting to stream
                     if (value === "0") {
-                        console.log("ioError");
                         var stream = musesPlayer.getNextAvailableStream();
                         musesPlayer.setURL(stream["url"]);
                         musesPlayer.play();
@@ -137,14 +149,23 @@
             }
         }
 
+        // Triggers the play function on the Muses player object in HTML5 mode
         function musesHTMLPlayClick() {
+            /*if (MRP.html === undefined) {
+                console.log("inserting player");
+                MRP.insert(musesPlayer.settings);
+            }*/
             MRP.html.audio.src = MRP.html.src;
 
             MRP.html.audio.play();
         }
 
+        // Triggers the stop function on the Muses player object in HTML5 mode
+        // NOTE: The HTML5 audio element doesn't have stop functionality. It
+        // can only be paused.
         function musesHTMLStopClick() {
             MRP.html.audio.pause();
+            //delete MRP.html;
         }
 
         function togglePlayStopButton() {
@@ -155,12 +176,15 @@
         // default how often to fetch metadata to 20 seconds
         var time_to_next_track_starts = 20000;
 
-        function getMetadata(){
+        // Fetches the streams metadata from the Airtime live-info API
+        // and attaches it to the player UI.
+        //
+        // The metadata is fetched when the current track is about to end.
+        function attachStreamMetadataToPlayer(){
             $.ajax({url: "<?php echo $this->metadata_api_url?>",
                 data: {type:"interval",limit:"5"},
                 dataType: "jsonp",
                 success: function(data) {
-                    //console.log("hello");
 
                     if (data.current === null) {
                         $("p.now_playing").html("Offline");
@@ -191,14 +215,30 @@
 
                 }
             });
-            setTimeout(getMetadata, time_to_next_track_starts);
+            setTimeout(attachStreamMetadataToPlayer, time_to_next_track_starts);
+        }
+
+        function htmlEscape(str) {
+            return String(str)
+                .replace(/&/g, '&amp;')
+                .replace(/"/g, '&quot;')
+                .replace(/'/g, '&#39;')
+                .replace(/</g, '&lt;')
+                .replace(/>/g, '&gt;');
         }
 
     </script>
 
     <style type="text/css">
+        /*
+        We have to have the default Muses skin displayed on the page or else
+        the player will not work. Setting the display to none and hidden does
+        not work. It has to be "visible" on the page. As a hacky work around we
+        set the height and width to 1px so users will not see it.
+        */
         #muses_skin{width:1px; height:1px; overflow-x: hidden; overflow-y: hidden;}
     </style>
+
 </head>
 
 <body>
@@ -219,7 +259,8 @@
 
     </div>
 
-    <!--<div class="airtime_volume">
+    <!--
+    <div class="airtime_volume">
 
         <div class="volume_control">
             <span class="mute"></span>
@@ -229,7 +270,8 @@
             <div class="airtime_volume_bar_value" style="width: 80%;"></div>
         </div>
 
-    </div>-->
+    </div>
+    -->
     <div style="clear:both"></div>
 
     <div class="airtime_schedule">
@@ -240,7 +282,6 @@
     </div>
     <a class="airtime_pro" target="_blank" href="https://www.airtime.pro/">Powered by Airtime Pro<span class="airtime_pro_logo"></span></a>
 
-
 </div>
 
 <div id="muses_skin">

From 23bf866211187ac341eb6fbe2e44945b3614594f Mon Sep 17 00:00:00 2001
From: drigato <denise.rigato@sourcefabric.org>
Date: Wed, 8 Apr 2015 14:01:57 -0400
Subject: [PATCH 46/60] SAAS-712: UI Improvements

---
 airtime_mvc/application/configs/ACL.php       |   4 +-
 .../application/configs/navigation.php        |   7 ++--
 ...yerController.php => PlayerController.php} |  20 +++++-----
 .../{EmbeddablePlayer.php => Player.php}      |  10 ++---
 .../{embeddableplayer.phtml => player.phtml}  |  27 +++++++++-----
 .../index.phtml => player/customize.phtml}    |   4 +-
 .../embed-code.phtml => player/index.phtml}   |   0
 .../public/css/embeddable-player-form.css     |  16 --------
 airtime_mvc/public/css/player-form.css        |  35 ++++++++++++++++++
 .../css/{embeddable-player.css => player.css} |   0
 .../{embeddableplayer => player}/mrp.js       |   0
 .../{embeddableplayer => player}/muses.swf    | Bin
 .../embeddableplayer.js => player/player.js}  |   8 +++-
 13 files changed, 81 insertions(+), 50 deletions(-)
 rename airtime_mvc/application/controllers/{EmbeddableplayerController.php => PlayerController.php} (82%)
 rename airtime_mvc/application/forms/{EmbeddablePlayer.php => Player.php} (86%)
 rename airtime_mvc/application/views/scripts/form/{embeddableplayer.phtml => player.phtml} (55%)
 rename airtime_mvc/application/views/scripts/{embeddableplayer/index.phtml => player/customize.phtml} (84%)
 rename airtime_mvc/application/views/scripts/{embeddableplayer/embed-code.phtml => player/index.phtml} (100%)
 delete mode 100644 airtime_mvc/public/css/embeddable-player-form.css
 create mode 100644 airtime_mvc/public/css/player-form.css
 rename airtime_mvc/public/css/{embeddable-player.css => player.css} (100%)
 rename airtime_mvc/public/js/airtime/{embeddableplayer => player}/mrp.js (100%)
 rename airtime_mvc/public/js/airtime/{embeddableplayer => player}/muses.swf (100%)
 rename airtime_mvc/public/js/airtime/{embeddableplayer/embeddableplayer.js => player/player.js} (89%)

diff --git a/airtime_mvc/application/configs/ACL.php b/airtime_mvc/application/configs/ACL.php
index 1386d1dee..c58986f1e 100644
--- a/airtime_mvc/application/configs/ACL.php
+++ b/airtime_mvc/application/configs/ACL.php
@@ -38,7 +38,7 @@ $ccAcl->add(new Zend_Acl_Resource('library'))
       ->add(new Zend_Acl_Resource('billing'))
       ->add(new Zend_Acl_Resource('thank-you'))
       ->add(new Zend_Acl_Resource('provisioning'))
-      ->add(new Zend_Acl_Resource('embeddableplayer'));
+      ->add(new Zend_Acl_Resource('player'));
 
 /** Creating permissions */
 $ccAcl->allow('G', 'index')
@@ -71,7 +71,7 @@ $ccAcl->allow('G', 'index')
       ->allow('A', 'user')
       ->allow('A', 'systemstatus')
       ->allow('A', 'preference')
-      ->allow('A', 'embeddableplayer')
+      ->allow('A', 'player')
       ->allow('S', 'thank-you')
       ->allow('S', 'billing');
       
diff --git a/airtime_mvc/application/configs/navigation.php b/airtime_mvc/application/configs/navigation.php
index 01c8aa385..1aeab45d5 100644
--- a/airtime_mvc/application/configs/navigation.php
+++ b/airtime_mvc/application/configs/navigation.php
@@ -87,11 +87,10 @@ $pages = array(
                 'resource'   => 'listenerstat'
             ),
             array(
-                'label'      => _('Embeddable Player'),
+                'label'      => _('Player'),
                 'module'     => 'default',
-                'controller' => 'embeddableplayer',
-                'action'     => 'index',
-                'resource'   => 'embeddableplayer'
+                'controller' => 'player',
+                'action'     => 'customize'
             )
         )
     ),
diff --git a/airtime_mvc/application/controllers/EmbeddableplayerController.php b/airtime_mvc/application/controllers/PlayerController.php
similarity index 82%
rename from airtime_mvc/application/controllers/EmbeddableplayerController.php
rename to airtime_mvc/application/controllers/PlayerController.php
index 43e8be2d5..2775d1c55 100644
--- a/airtime_mvc/application/controllers/EmbeddableplayerController.php
+++ b/airtime_mvc/application/controllers/PlayerController.php
@@ -1,21 +1,20 @@
 <?php
 
-class EmbeddablePlayerController extends Zend_Controller_Action
+class PlayerController extends Zend_Controller_Action
 {
     public function init()
     {
 
     }
     
-    public function indexAction()
+    public function customizeAction()
     {
         $CC_CONFIG = Config::getConfig();
         $baseUrl = Application_Common_OsPath::getBaseDir();
-        $this->view->headLink()->appendStylesheet($baseUrl.'css/embeddable-player-form.css?'.$CC_CONFIG['airtime_version']);
-        $this->view->headScript()->appendFile($baseUrl.'js/airtime/embeddableplayer/mrp.js?'.$CC_CONFIG['airtime_version']);
-        $this->view->headScript()->appendFile($baseUrl.'js/airtime/embeddableplayer/embeddableplayer.js?'.$CC_CONFIG['airtime_version']);
+        $this->view->headLink()->appendStylesheet($baseUrl.'css/player-form.css?'.$CC_CONFIG['airtime_version']);
+        $this->view->headScript()->appendFile($baseUrl.'js/airtime/player/player.js?'.$CC_CONFIG['airtime_version']);
 
-        $form = new Application_Form_EmbeddablePlayer();
+        $form = new Application_Form_Player();
 
         $apiEnabled = Application_Model_Preference::GetAllow3rdPartyApi();
         $numEnabledStreams = $form->getElement('player_stream_url')->getAttrib('numberOfEnabledStreams');
@@ -38,18 +37,19 @@ class EmbeddablePlayerController extends Zend_Controller_Action
      * The view for this action contains all the inline javascript needed to
      * create the player.
      */
-    public function embedCodeAction()
+    public function indexAction()
     {
         $this->view->layout()->disableLayout();
 
         $CC_CONFIG = Config::getConfig();
 
+
         $request = $this->getRequest();
 
-        $this->view->css = Application_Common_HTTPHelper::getStationUrl() . "css/embeddable-player.css?".$CC_CONFIG['airtime_version'];
-        $this->view->mrp_js = Application_Common_HTTPHelper::getStationUrl() . "js/airtime/embeddableplayer/mrp.js?".$CC_CONFIG['airtime_version'];
+        $this->view->css = Application_Common_HTTPHelper::getStationUrl() . "css/player.css?".$CC_CONFIG['airtime_version'];
+        $this->view->mrp_js = Application_Common_HTTPHelper::getStationUrl() . "js/airtime/player/mrp.js?".$CC_CONFIG['airtime_version'];
         $this->view->jquery = Application_Common_HTTPHelper::getStationUrl() . "js/libs/jquery-1.10.2.js";
-        $this->view->muses_swf = Application_Common_HTTPHelper::getStationUrl() . "js/airtime/embeddableplayer/muses.swf";
+        $this->view->muses_swf = Application_Common_HTTPHelper::getStationUrl() . "js/airtime/player/muses.swf";
         $this->view->metadata_api_url = Application_Common_HTTPHelper::getStationUrl() . "api/live-info";
         $this->view->station_name = addslashes(Application_Model_Preference::GetStationName());
 
diff --git a/airtime_mvc/application/forms/EmbeddablePlayer.php b/airtime_mvc/application/forms/Player.php
similarity index 86%
rename from airtime_mvc/application/forms/EmbeddablePlayer.php
rename to airtime_mvc/application/forms/Player.php
index ca8ca45c9..4cad32e53 100644
--- a/airtime_mvc/application/forms/EmbeddablePlayer.php
+++ b/airtime_mvc/application/forms/Player.php
@@ -2,12 +2,12 @@
 
 define("OPUS", "opus");
 
-class Application_Form_EmbeddablePlayer extends Zend_Form_SubForm
+class Application_Form_Player extends Zend_Form_SubForm
 {
     public function init()
     {
         $this->setDecorators(array(
-            array('ViewScript', array('viewScript' => 'form/embeddableplayer.phtml'))
+            array('ViewScript', array('viewScript' => 'form/player.phtml'))
         ));
 
         /* We will use this option in the future
@@ -56,14 +56,14 @@ class Application_Form_EmbeddablePlayer extends Zend_Form_SubForm
         }
 
         $streamURL->setAttrib('numberOfEnabledStreams', sizeof($urlOptions)-$opusStreamCount);
-        $streamURL->setAttrib("disabled", "disabled");
+        $streamURL->removeDecorator('label');
         $this->addElement($streamURL);
 
         $embedSrc = new Zend_Form_Element_Text('player_embed_src');
         $embedSrc->setAttrib("readonly", "readonly");
         $embedSrc->setAttrib("class", "embed-player-text-box");
-        $embedSrc->setValue('<iframe frameborder="0" width="280" height="230" src="'.Application_Common_HTTPHelper::getStationUrl().'embeddableplayer/embed-code?stream=auto"></iframe>');
-        $embedSrc->removeDecorator('label');
+        $embedSrc->setLabel(_("Embeddable code:"));
+        $embedSrc->setValue('<iframe frameborder="0" width="280" height="210" src="'.Application_Common_HTTPHelper::getStationUrl().'player?stream=auto"></iframe>');
         $this->addElement($embedSrc);
 
         $previewLabel = new Zend_Form_Element_Text('player_preview_label');
diff --git a/airtime_mvc/application/views/scripts/form/embeddableplayer.phtml b/airtime_mvc/application/views/scripts/form/player.phtml
similarity index 55%
rename from airtime_mvc/application/views/scripts/form/embeddableplayer.phtml
rename to airtime_mvc/application/views/scripts/form/player.phtml
index 18305c20b..c47deaccf 100644
--- a/airtime_mvc/application/views/scripts/form/embeddableplayer.phtml
+++ b/airtime_mvc/application/views/scripts/form/player.phtml
@@ -1,18 +1,27 @@
 <fieldset class="padded">
     <dl class="zend_form">
 
-        <?php echo $this->element->getElement('player_embed_src'); ?>
-
-        <?php echo $this->element->getElement('player_stream_mode'); ?>
-
-        <?php echo $this->element->getElement('player_stream_url'); ?>
-
-        <?php //echo $this->element->getElement('player_display_track_metadata'); ?>
-
         <?php echo $this->element->getElement('player_preview_label')->renderLabel(); ?>
 
         <div style="clear:both"></div>
-        <?php echo $this->element->getElement('player_embed_src')->getValue(); ?>
+        <div class="player-preview">
+            <?php echo $this->element->getElement('player_embed_src')->getValue(); ?>
+        </div>
+
+        <div id="player_instructions">
+            Customize the player by configuring the options below. Once you are happy with the player
+            copy the embeddable code below into your websites HTML.
+        </div>
+
+        <?php echo $this->element->getElement('player_stream_mode')->render(); ?>
+
+        <?php echo $this->element->getElement('player_stream_url'); ?>
+
+        <?php echo $this->element->getElement('player_embed_src')->render(); ?>
+
+        <?php //echo $this->element->getElement('player_display_track_metadata'); ?>
+
+
 
     </dl>
 </fieldset>
\ No newline at end of file
diff --git a/airtime_mvc/application/views/scripts/embeddableplayer/index.phtml b/airtime_mvc/application/views/scripts/player/customize.phtml
similarity index 84%
rename from airtime_mvc/application/views/scripts/embeddableplayer/index.phtml
rename to airtime_mvc/application/views/scripts/player/customize.phtml
index e4c37849b..56c70f8a4 100644
--- a/airtime_mvc/application/views/scripts/embeddableplayer/index.phtml
+++ b/airtime_mvc/application/views/scripts/player/customize.phtml
@@ -1,9 +1,9 @@
 <div class="ui-widget ui-widget-content block-shadow simple-formblock embed-player-form clearfix padded-strong ">
-    <h2 style="float:left"><?php echo _("Embeddable Player") ?></h2>
+
     <?php $baseUrl = Application_Common_OsPath::getBaseDir(); ?>
 
     <form method="post" id="player_form" enctype="multipart/form-data">
-
+        <h2 style="float:left"><?php echo _("Embeddable Player") ?></h2>
         <div style="clear:both"></div>
         <?php echo $this->errorMsg; ?>
         <?php echo $this->form; ?>
diff --git a/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml b/airtime_mvc/application/views/scripts/player/index.phtml
similarity index 100%
rename from airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml
rename to airtime_mvc/application/views/scripts/player/index.phtml
diff --git a/airtime_mvc/public/css/embeddable-player-form.css b/airtime_mvc/public/css/embeddable-player-form.css
deleted file mode 100644
index 9a6fe20d8..000000000
--- a/airtime_mvc/public/css/embeddable-player-form.css
+++ /dev/null
@@ -1,16 +0,0 @@
-.embed-player-text-box {
-    padding-right: 0px !important;
-    width: 100% !important;
-}
-.embed-player-form {
-    width: 70%;
-}
-.embed-player-form dd {
-    width: 100% !important;
-    float: left;
-    margin: 0;
-    padding: 4px 0px 4px 0px;
-}
-
-
-
diff --git a/airtime_mvc/public/css/player-form.css b/airtime_mvc/public/css/player-form.css
new file mode 100644
index 000000000..663a304cf
--- /dev/null
+++ b/airtime_mvc/public/css/player-form.css
@@ -0,0 +1,35 @@
+.embed-player-text-box {
+    padding-right: 0px !important;
+    width: 100% !important;
+}
+.embed-player-form {
+    width: 98%;
+}
+.embed-player-form dd {
+    width: 100% !important;
+    float: left;
+    margin: 0;
+    padding: 4px 0px 4px 0px;
+}
+.player-preview {
+    width: 100%;
+}
+.player-preview iframe {
+    margin: 0 auto;
+    display: block;
+}
+#player_form {
+    width: 50%;
+    margin: 0 auto;
+}
+#player_instructions {
+    border-bottom: 1px solid;
+    padding-bottom: 10px;
+    font-size: 14px;
+    font-weight: bold;
+    color: #5b5b5b;
+    margin-bottom: 10px;
+}
+
+
+
diff --git a/airtime_mvc/public/css/embeddable-player.css b/airtime_mvc/public/css/player.css
similarity index 100%
rename from airtime_mvc/public/css/embeddable-player.css
rename to airtime_mvc/public/css/player.css
diff --git a/airtime_mvc/public/js/airtime/embeddableplayer/mrp.js b/airtime_mvc/public/js/airtime/player/mrp.js
similarity index 100%
rename from airtime_mvc/public/js/airtime/embeddableplayer/mrp.js
rename to airtime_mvc/public/js/airtime/player/mrp.js
diff --git a/airtime_mvc/public/js/airtime/embeddableplayer/muses.swf b/airtime_mvc/public/js/airtime/player/muses.swf
similarity index 100%
rename from airtime_mvc/public/js/airtime/embeddableplayer/muses.swf
rename to airtime_mvc/public/js/airtime/player/muses.swf
diff --git a/airtime_mvc/public/js/airtime/embeddableplayer/embeddableplayer.js b/airtime_mvc/public/js/airtime/player/player.js
similarity index 89%
rename from airtime_mvc/public/js/airtime/embeddableplayer/embeddableplayer.js
rename to airtime_mvc/public/js/airtime/player/player.js
index be4bbc7c3..ea5fb5588 100644
--- a/airtime_mvc/public/js/airtime/embeddableplayer/embeddableplayer.js
+++ b/airtime_mvc/public/js/airtime/player/player.js
@@ -29,12 +29,16 @@ function getStreamMode() {
 
 $(document).ready(function() {
 
+    $("#player_stream_url-element").hide();
+
     $("#player_stream_mode-element").change(function() {
         var $streamMode = getStreamMode();
+
         if ($streamMode == "auto") {
-            $("#player_stream_url-element input[type='radio']").attr("disabled", "disabled");
+            $("#player_stream_url-element").hide();
+
         } else if ($streamMode == "manual") {
-            $("#player_stream_url-element input[type='radio']").removeAttr("disabled");
+            $("#player_stream_url-element").show();
 
             $("input[name=player_stream_url]").each(function(i, obj) {
                 if ($(this).parent().text().toLowerCase().indexOf("opus") >= 0) {

From 94a7643ebc62082034abfd6d35e19b4cda140e0f Mon Sep 17 00:00:00 2001
From: drigato <denise.rigato@sourcefabric.org>
Date: Wed, 8 Apr 2015 15:00:02 -0400
Subject: [PATCH 47/60] Escape stream urls in the player js

---
 .../application/views/scripts/player/index.phtml       | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/airtime_mvc/application/views/scripts/player/index.phtml b/airtime_mvc/application/views/scripts/player/index.phtml
index f079a4564..3f198e642 100644
--- a/airtime_mvc/application/views/scripts/player/index.phtml
+++ b/airtime_mvc/application/views/scripts/player/index.phtml
@@ -35,20 +35,21 @@
             };
 
             if (this.playerMode == "manual") {
-                this.settings.url = "<?php echo $this->streamURL ?>";
+                this.settings.url = htmlEscape("<?php echo $this->streamURL ?>");
                 this.settings.codec = "<?php echo $this->codec ?>";
             } else if (this.playerMode == "auto") {
                 this.availableMobileStreamQueue = <?php echo $this->availableMobileStreams?>;
                 this.availableDesktopStreamQueue = <?php echo $this->availableDesktopStreams?>;
                 var stream = this.getNextAvailableStream();
-                this.settings.url = stream["url"];
+                this.settings.url = htmlEscape(stream["url"]);
                 this.settings.codec = stream["codec"];
             }
 
             // Create the Muses player object
             MRP.insert(this.settings);
 
-            $("p.station_name").html(htmlEscape("<?php echo $this->station_name?>"));
+            var station_name = htmlEscape("<?php echo $this->station_name?>");
+            $("p.station_name").html(station_name);
 
             attachStreamMetadataToPlayer();
 
@@ -132,7 +133,6 @@
         };
 
         MusesPlayer.prototype.setURL = function(url) {
-            console.log("setURL");
             MRP.setUrl(url);
         };
 
@@ -143,7 +143,7 @@
                     // connection limit reached or problem connecting to stream
                     if (value === "0") {
                         var stream = musesPlayer.getNextAvailableStream();
-                        musesPlayer.setURL(stream["url"]);
+                        musesPlayer.setURL(htmlEscape(stream["url"]));
                         musesPlayer.play();
                     }
             }

From 78b2631980a7c6569cb41a38db6cad6e1a33ebce Mon Sep 17 00:00:00 2001
From: drigato <denise.rigato@sourcefabric.org>
Date: Wed, 8 Apr 2015 15:19:22 -0400
Subject: [PATCH 48/60] Remove stream url js escaping and do it on server side
 instead

---
 .../controllers/PlayerController.php           |  4 ++--
 .../views/scripts/player/index.phtml           | 18 ++++--------------
 2 files changed, 6 insertions(+), 16 deletions(-)

diff --git a/airtime_mvc/application/controllers/PlayerController.php b/airtime_mvc/application/controllers/PlayerController.php
index 2775d1c55..92501bbd4 100644
--- a/airtime_mvc/application/controllers/PlayerController.php
+++ b/airtime_mvc/application/controllers/PlayerController.php
@@ -51,7 +51,7 @@ class PlayerController extends Zend_Controller_Action
         $this->view->jquery = Application_Common_HTTPHelper::getStationUrl() . "js/libs/jquery-1.10.2.js";
         $this->view->muses_swf = Application_Common_HTTPHelper::getStationUrl() . "js/airtime/player/muses.swf";
         $this->view->metadata_api_url = Application_Common_HTTPHelper::getStationUrl() . "api/live-info";
-        $this->view->station_name = addslashes(Application_Model_Preference::GetStationName());
+        $this->view->station_name = json_encode(Application_Model_Preference::GetStationName());
 
         $stream = $request->getParam('stream');
         $streamData = Application_Model_StreamSetting::getEnabledStreamData();
@@ -70,7 +70,7 @@ class PlayerController extends Zend_Controller_Action
         } else {
             $this->view->playerMode = "manual";
             $selectedStreamData = $streamData[$stream];
-            $this->view->streamURL = $selectedStreamData["url"];
+            $this->view->streamURL = json_encode($selectedStreamData["url"]);
             $this->view->codec = $selectedStreamData["codec"];
         }
         $this->view->availableMobileStreams = json_encode($availableMobileStreams);
diff --git a/airtime_mvc/application/views/scripts/player/index.phtml b/airtime_mvc/application/views/scripts/player/index.phtml
index 3f198e642..ee19b337c 100644
--- a/airtime_mvc/application/views/scripts/player/index.phtml
+++ b/airtime_mvc/application/views/scripts/player/index.phtml
@@ -35,21 +35,20 @@
             };
 
             if (this.playerMode == "manual") {
-                this.settings.url = htmlEscape("<?php echo $this->streamURL ?>");
+                this.settings.url = "<?php echo $this->streamURL ?>";
                 this.settings.codec = "<?php echo $this->codec ?>";
             } else if (this.playerMode == "auto") {
                 this.availableMobileStreamQueue = <?php echo $this->availableMobileStreams?>;
                 this.availableDesktopStreamQueue = <?php echo $this->availableDesktopStreams?>;
                 var stream = this.getNextAvailableStream();
-                this.settings.url = htmlEscape(stream["url"]);
+                this.settings.url = stream["url"];
                 this.settings.codec = stream["codec"];
             }
 
             // Create the Muses player object
             MRP.insert(this.settings);
 
-            var station_name = htmlEscape("<?php echo $this->station_name?>");
-            $("p.station_name").html(station_name);
+            $("p.station_name").html("<?php echo $this->station_name?>");
 
             attachStreamMetadataToPlayer();
 
@@ -143,7 +142,7 @@
                     // connection limit reached or problem connecting to stream
                     if (value === "0") {
                         var stream = musesPlayer.getNextAvailableStream();
-                        musesPlayer.setURL(htmlEscape(stream["url"]));
+                        musesPlayer.setURL(stream["url"]);
                         musesPlayer.play();
                     }
             }
@@ -218,15 +217,6 @@
             setTimeout(attachStreamMetadataToPlayer, time_to_next_track_starts);
         }
 
-        function htmlEscape(str) {
-            return String(str)
-                .replace(/&/g, '&amp;')
-                .replace(/"/g, '&quot;')
-                .replace(/'/g, '&#39;')
-                .replace(/</g, '&lt;')
-                .replace(/>/g, '&gt;');
-        }
-
     </script>
 
     <style type="text/css">

From 4429117f6a9d2ba30a1e858bc63cc115ec9813a8 Mon Sep 17 00:00:00 2001
From: drigato <denise.rigato@sourcefabric.org>
Date: Thu, 9 Apr 2015 09:43:15 -0400
Subject: [PATCH 49/60] SAAS-712: UI Improvements

---
 .../controllers/PlayerController.php          |  2 +-
 airtime_mvc/application/forms/Player.php      | 29 +++++++----
 .../views/scripts/form/player.phtml           |  6 ++-
 .../views/scripts/player/index.phtml          | 11 ++++-
 airtime_mvc/public/css/player-form.css        | 16 ++++++-
 .../public/js/airtime/player/player.js        | 48 ++++++++++++++++++-
 6 files changed, 97 insertions(+), 15 deletions(-)

diff --git a/airtime_mvc/application/controllers/PlayerController.php b/airtime_mvc/application/controllers/PlayerController.php
index 92501bbd4..8d51219fe 100644
--- a/airtime_mvc/application/controllers/PlayerController.php
+++ b/airtime_mvc/application/controllers/PlayerController.php
@@ -51,7 +51,7 @@ class PlayerController extends Zend_Controller_Action
         $this->view->jquery = Application_Common_HTTPHelper::getStationUrl() . "js/libs/jquery-1.10.2.js";
         $this->view->muses_swf = Application_Common_HTTPHelper::getStationUrl() . "js/airtime/player/muses.swf";
         $this->view->metadata_api_url = Application_Common_HTTPHelper::getStationUrl() . "api/live-info";
-        $this->view->station_name = json_encode(Application_Model_Preference::GetStationName());
+        $this->view->player_title = json_encode($request->getParam('title'));
 
         $stream = $request->getParam('stream');
         $streamData = Application_Model_StreamSetting::getEnabledStreamData();
diff --git a/airtime_mvc/application/forms/Player.php b/airtime_mvc/application/forms/Player.php
index 4cad32e53..01fc62d75 100644
--- a/airtime_mvc/application/forms/Player.php
+++ b/airtime_mvc/application/forms/Player.php
@@ -10,12 +10,23 @@ class Application_Form_Player extends Zend_Form_SubForm
             array('ViewScript', array('viewScript' => 'form/player.phtml'))
         ));
 
-        /* We will use this option in the future
-        $displayTrackMetadata = new Zend_Form_Element_Checkbox('player_display_track_metadata');
-        $displayTrackMetadata->setValue(true);
-        $displayTrackMetadata->setLabel(_('Display track metadata?'));
-        $this->addElement($displayTrackMetadata);
-        */
+        $displayTitle = new Zend_Form_Element_Checkbox('player_display_title');
+        $displayTitle->setValue(true);
+        $displayTitle->setLabel(_('Display title?'));
+        //$displayTitle->addDecorator('Label', array('placement' => 'APPEND'));
+        $displayTitle->setDecorators(array(
+            'ViewHelper',
+            'Errors',
+            'Label'
+        ));
+        $displayTitle->addDecorator('Label', array('class' => 'player-checkbox', 'placement' => 'APPEND'));
+        $this->addElement($displayTitle);
+
+        $title = new Zend_Form_Element_Text('player_title');
+        $title->setValue(_('Now Playing'));
+        $title->setLabel(_('Title:'));
+        $title->removeDecorator('DtDdWrapper');
+        $this->addElement($title);
 
         $streamMode = new Zend_Form_Element_Radio('player_stream_mode');
         $streamMode->setLabel(_('Select Stream:'));
@@ -59,11 +70,13 @@ class Application_Form_Player extends Zend_Form_SubForm
         $streamURL->removeDecorator('label');
         $this->addElement($streamURL);
 
-        $embedSrc = new Zend_Form_Element_Text('player_embed_src');
+        $embedSrc = new Zend_Form_Element_Textarea('player_embed_src');
         $embedSrc->setAttrib("readonly", "readonly");
         $embedSrc->setAttrib("class", "embed-player-text-box");
+        $embedSrc->setAttrib('cols', '40')
+            ->setAttrib('rows', '4');
         $embedSrc->setLabel(_("Embeddable code:"));
-        $embedSrc->setValue('<iframe frameborder="0" width="280" height="210" src="'.Application_Common_HTTPHelper::getStationUrl().'player?stream=auto"></iframe>');
+        $embedSrc->setValue('<iframe frameborder="0" width="280" height="210" src="'.Application_Common_HTTPHelper::getStationUrl().'player?stream=auto&title=Now Playing"></iframe>');
         $this->addElement($embedSrc);
 
         $previewLabel = new Zend_Form_Element_Text('player_preview_label');
diff --git a/airtime_mvc/application/views/scripts/form/player.phtml b/airtime_mvc/application/views/scripts/form/player.phtml
index c47deaccf..e9bb8f3ed 100644
--- a/airtime_mvc/application/views/scripts/form/player.phtml
+++ b/airtime_mvc/application/views/scripts/form/player.phtml
@@ -9,10 +9,14 @@
         </div>
 
         <div id="player_instructions">
-            Customize the player by configuring the options below. Once you are happy with the player
+            Customize the player by configuring the options below. When you are done
             copy the embeddable code below into your websites HTML.
         </div>
 
+        <?php echo $this->element->getElement('player_display_title'); ?>
+
+        <?php echo $this->element->getElement('player_title')->render(); ?>
+
         <?php echo $this->element->getElement('player_stream_mode')->render(); ?>
 
         <?php echo $this->element->getElement('player_stream_url'); ?>
diff --git a/airtime_mvc/application/views/scripts/player/index.phtml b/airtime_mvc/application/views/scripts/player/index.phtml
index ee19b337c..a2732b3c4 100644
--- a/airtime_mvc/application/views/scripts/player/index.phtml
+++ b/airtime_mvc/application/views/scripts/player/index.phtml
@@ -35,7 +35,7 @@
             };
 
             if (this.playerMode == "manual") {
-                this.settings.url = "<?php echo $this->streamURL ?>";
+                this.settings.url = '<?php echo $this->streamURL ?>';
                 this.settings.codec = "<?php echo $this->codec ?>";
             } else if (this.playerMode == "auto") {
                 this.availableMobileStreamQueue = <?php echo $this->availableMobileStreams?>;
@@ -48,7 +48,14 @@
             // Create the Muses player object
             MRP.insert(this.settings);
 
-            $("p.station_name").html("<?php echo $this->station_name?>");
+            // Configure player title
+            var player_title = <?php echo $this->player_title?>;
+            if (player_title === null) {
+                $(".airtime_header").hide();
+                $(".airtime_player").css('height', '150px');
+            } else {
+                $("p.station_name").html(player_title);
+            }
 
             attachStreamMetadataToPlayer();
 
diff --git a/airtime_mvc/public/css/player-form.css b/airtime_mvc/public/css/player-form.css
index 663a304cf..0ab842bb6 100644
--- a/airtime_mvc/public/css/player-form.css
+++ b/airtime_mvc/public/css/player-form.css
@@ -19,9 +19,12 @@
     display: block;
 }
 #player_form {
-    width: 50%;
+    width: 40%;
     margin: 0 auto;
 }
+#player_form dd {
+    margin-bottom: 10px;
+}
 #player_instructions {
     border-bottom: 1px solid;
     padding-bottom: 10px;
@@ -30,6 +33,17 @@
     color: #5b5b5b;
     margin-bottom: 10px;
 }
+.player-checkbox {
+    clear: left;
+    color: #5b5b5b;
+    float: left;
+    font-size: 13px;
+    font-weight: bold;
+    margin: 0;
+    min-width: 90px;
+    padding: 4px 0;
+    text-align: left;
+}
 
 
 
diff --git a/airtime_mvc/public/js/airtime/player/player.js b/airtime_mvc/public/js/airtime/player/player.js
index ea5fb5588..a2bb17808 100644
--- a/airtime_mvc/public/js/airtime/player/player.js
+++ b/airtime_mvc/public/js/airtime/player/player.js
@@ -8,13 +8,19 @@ function updateEmbedSrcParams()
     } else if ($streamMode == "auto") {
         $embedCodeParams += "stream=auto";
     }
+
+    var playerTitle = getPlayerTitle();
+    if (playerTitle !== null) {
+        $embedCodeParams += "&title="+playerTitle;
+    }
+
     $embedCodeParams += "\"";
 
-    $("input[name=player_embed_src]").val(function(index, value) {
+    $("textarea[name=player_embed_src]").val(function(index, value) {
         return value.replace(/\?.*?"/, $embedCodeParams);
     });
 
-    updatePlayerIframeSrc($("input[name=player_embed_src]").val());
+    updatePlayerIframeSrc($("textarea[name=player_embed_src]").val());
 }
 
 function updatePlayerIframeSrc(iframe_text) {
@@ -27,10 +33,19 @@ function getStreamMode() {
     return $("input[name=player_stream_mode]:radio:checked").val();
 }
 
+function getPlayerTitle() {
+    if ($("#player_display_title").prop("checked")) {
+        return $("input[name=player_title]").val();
+    } else {
+        return null;
+    }
+}
+
 $(document).ready(function() {
 
     $("#player_stream_url-element").hide();
 
+    // stream mode change event
     $("#player_stream_mode-element").change(function() {
         var $streamMode = getStreamMode();
 
@@ -50,8 +65,37 @@ $(document).ready(function() {
         updateEmbedSrcParams();
     });
 
+    // stream url change event
     $("#player_stream_url-element").change(function() {
         updateEmbedSrcParams();
     });
+
+    // display title checkbox change event
+    $("#player_display_title").change(function() {
+        if ($(this).prop("checked")) {
+            $("#player_title-label").show();
+            $("#player_title-element").show();
+        } else {
+            $("#player_title-label").hide();
+            $("#player_title-element").hide();
+        }
+        updateEmbedSrcParams();
+    });
+
+    // title textbox change event
+    // setup before functions
+    var typingTimer;
+    var doneTypingInterval = 3000;
+
+    // on keyup, start the countdown
+    $("input[name=player_title]").keyup(function(){
+        clearTimeout(typingTimer);
+        typingTimer = setTimeout(updateEmbedSrcParams, doneTypingInterval);
+    });
+
+    // on keydown, clear the countdown
+    $("input[name=player_title]").keydown(function(){
+        clearTimeout(typingTimer);
+    });
 });
 

From 84231f811a61b27bb5e62c7fbd09f3b99afe744a Mon Sep 17 00:00:00 2001
From: drigato <denise.rigato@sourcefabric.org>
Date: Thu, 9 Apr 2015 12:25:27 -0400
Subject: [PATCH 50/60] SAAS-720: Player can't be accessed unless a user has a
 valid session

---
 .../controllers/EmbedController.php           | 56 +++++++++++++++++++
 .../controllers/PlayerController.php          | 51 +----------------
 .../controllers/plugins/Acl_plugin.php        |  3 +-
 airtime_mvc/application/forms/Player.php      |  4 +-
 .../index.phtml => embed/player.phtml}        |  0
 5 files changed, 61 insertions(+), 53 deletions(-)
 create mode 100644 airtime_mvc/application/controllers/EmbedController.php
 rename airtime_mvc/application/views/scripts/{player/index.phtml => embed/player.phtml} (100%)

diff --git a/airtime_mvc/application/controllers/EmbedController.php b/airtime_mvc/application/controllers/EmbedController.php
new file mode 100644
index 000000000..11f2cc68e
--- /dev/null
+++ b/airtime_mvc/application/controllers/EmbedController.php
@@ -0,0 +1,56 @@
+<?php
+
+class EmbedController extends Zend_Controller_Action
+{
+    public function init()
+    {
+
+    }
+
+    /**
+     * This is the action that is called to insert the player onto a web page.
+     * It passes all the js and css files to the view, as well as all the
+     * stream customization information.
+     *
+     * The view for this action contains all the inline javascript needed to
+     * create the player.
+     */
+    public function playerAction()
+    {
+        $this->view->layout()->disableLayout();
+
+        $CC_CONFIG = Config::getConfig();
+
+        $request = $this->getRequest();
+
+        $this->view->css = Application_Common_HTTPHelper::getStationUrl() . "css/player.css?".$CC_CONFIG['airtime_version'];
+        $this->view->mrp_js = Application_Common_HTTPHelper::getStationUrl() . "js/airtime/player/mrp.js?".$CC_CONFIG['airtime_version'];
+        $this->view->jquery = Application_Common_HTTPHelper::getStationUrl() . "js/libs/jquery-1.10.2.js";
+        $this->view->muses_swf = Application_Common_HTTPHelper::getStationUrl() . "js/airtime/player/muses.swf";
+        $this->view->metadata_api_url = Application_Common_HTTPHelper::getStationUrl() . "api/live-info";
+        $this->view->player_title = json_encode($request->getParam('title'));
+
+        $stream = $request->getParam('stream');
+        $streamData = Application_Model_StreamSetting::getEnabledStreamData();
+        $availableMobileStreams = array();
+        $availableDesktopStreams = array();
+
+        if ($stream == "auto") {
+            $this->view->playerMode = "auto";
+            foreach ($streamData as $s) {
+                if ($s["mobile"]) {
+                    array_push($availableMobileStreams, $s);
+                } else if (!$s["mobile"]) {
+                    array_push($availableDesktopStreams, $s);
+                }
+            }
+        } else {
+            $this->view->playerMode = "manual";
+            $selectedStreamData = $streamData[$stream];
+            $this->view->streamURL = json_encode($selectedStreamData["url"]);
+            $this->view->codec = $selectedStreamData["codec"];
+        }
+        $this->view->availableMobileStreams = json_encode($availableMobileStreams);
+        $this->view->availableDesktopStreams = json_encode($availableDesktopStreams);
+    }
+}
diff --git a/airtime_mvc/application/controllers/PlayerController.php b/airtime_mvc/application/controllers/PlayerController.php
index 8d51219fe..bb3fbc2d3 100644
--- a/airtime_mvc/application/controllers/PlayerController.php
+++ b/airtime_mvc/application/controllers/PlayerController.php
@@ -28,53 +28,4 @@ class PlayerController extends Zend_Controller_Action
         }
 
     }
-
-    /**
-     * This is the action that is called to insert the player onto a web page.
-     * It passes all the js and css files to the view, as well as all the
-     * stream customization information.
-     *
-     * The view for this action contains all the inline javascript needed to
-     * create the player.
-     */
-    public function indexAction()
-    {
-        $this->view->layout()->disableLayout();
-
-        $CC_CONFIG = Config::getConfig();
-
-
-        $request = $this->getRequest();
-
-        $this->view->css = Application_Common_HTTPHelper::getStationUrl() . "css/player.css?".$CC_CONFIG['airtime_version'];
-        $this->view->mrp_js = Application_Common_HTTPHelper::getStationUrl() . "js/airtime/player/mrp.js?".$CC_CONFIG['airtime_version'];
-        $this->view->jquery = Application_Common_HTTPHelper::getStationUrl() . "js/libs/jquery-1.10.2.js";
-        $this->view->muses_swf = Application_Common_HTTPHelper::getStationUrl() . "js/airtime/player/muses.swf";
-        $this->view->metadata_api_url = Application_Common_HTTPHelper::getStationUrl() . "api/live-info";
-        $this->view->player_title = json_encode($request->getParam('title'));
-
-        $stream = $request->getParam('stream');
-        $streamData = Application_Model_StreamSetting::getEnabledStreamData();
-        $availableMobileStreams = array();
-        $availableDesktopStreams = array();
-
-        if ($stream == "auto") {
-            $this->view->playerMode = "auto";
-            foreach ($streamData as $s) {
-                if ($s["mobile"]) {
-                    array_push($availableMobileStreams, $s);
-                } else if (!$s["mobile"]) {
-                    array_push($availableDesktopStreams, $s);
-                }
-            }
-        } else {
-            $this->view->playerMode = "manual";
-            $selectedStreamData = $streamData[$stream];
-            $this->view->streamURL = json_encode($selectedStreamData["url"]);
-            $this->view->codec = $selectedStreamData["codec"];
-        }
-        $this->view->availableMobileStreams = json_encode($availableMobileStreams);
-        $this->view->availableDesktopStreams = json_encode($availableDesktopStreams);
-        //$this->view->displayMetadata = $request->getParam('display_metadata');
-    }
-}
\ No newline at end of file
+}
diff --git a/airtime_mvc/application/controllers/plugins/Acl_plugin.php b/airtime_mvc/application/controllers/plugins/Acl_plugin.php
index 7ea1336d0..9eef38fdb 100644
--- a/airtime_mvc/application/controllers/plugins/Acl_plugin.php
+++ b/airtime_mvc/application/controllers/plugins/Acl_plugin.php
@@ -118,7 +118,8 @@ class Zend_Controller_Plugin_Acl extends Zend_Controller_Plugin_Abstract
                 "locale",
                 "upgrade",
                 'whmcs-login',
-                "provisioning"
+                "provisioning",
+                "embed"
             )))
         {
             $this->setRoleName("G");
diff --git a/airtime_mvc/application/forms/Player.php b/airtime_mvc/application/forms/Player.php
index 01fc62d75..5e1ac4009 100644
--- a/airtime_mvc/application/forms/Player.php
+++ b/airtime_mvc/application/forms/Player.php
@@ -76,7 +76,7 @@ class Application_Form_Player extends Zend_Form_SubForm
         $embedSrc->setAttrib('cols', '40')
             ->setAttrib('rows', '4');
         $embedSrc->setLabel(_("Embeddable code:"));
-        $embedSrc->setValue('<iframe frameborder="0" width="280" height="210" src="'.Application_Common_HTTPHelper::getStationUrl().'player?stream=auto&title=Now Playing"></iframe>');
+        $embedSrc->setValue('<iframe frameborder="0" width="280" height="210" src="'.Application_Common_HTTPHelper::getStationUrl().'embed/player?stream=auto&title=Now Playing"></iframe>');
         $this->addElement($embedSrc);
 
         $previewLabel = new Zend_Form_Element_Text('player_preview_label');
@@ -84,4 +84,4 @@ class Application_Form_Player extends Zend_Form_SubForm
         $this->addElement($previewLabel);
 
     }
-}
\ No newline at end of file
+}
diff --git a/airtime_mvc/application/views/scripts/player/index.phtml b/airtime_mvc/application/views/scripts/embed/player.phtml
similarity index 100%
rename from airtime_mvc/application/views/scripts/player/index.phtml
rename to airtime_mvc/application/views/scripts/embed/player.phtml

From f238faa9374122bee7e9b556707ee0ac82963e85 Mon Sep 17 00:00:00 2001
From: drigato <denise.rigato@sourcefabric.org>
Date: Thu, 9 Apr 2015 14:22:50 -0400
Subject: [PATCH 51/60] SAAS-712: UI Improvements

---
 airtime_mvc/application/forms/Player.php      | 18 +++++--------
 .../views/scripts/embed/player.phtml          |  2 +-
 .../views/scripts/form/player.phtml           |  6 ++---
 airtime_mvc/public/css/player-form.css        | 27 ++++++++++++++-----
 airtime_mvc/public/css/player.css             | 10 +++++--
 .../public/js/airtime/player/player.js        | 11 ++------
 6 files changed, 39 insertions(+), 35 deletions(-)

diff --git a/airtime_mvc/application/forms/Player.php b/airtime_mvc/application/forms/Player.php
index 5e1ac4009..a1dbff341 100644
--- a/airtime_mvc/application/forms/Player.php
+++ b/airtime_mvc/application/forms/Player.php
@@ -10,22 +10,15 @@ class Application_Form_Player extends Zend_Form_SubForm
             array('ViewScript', array('viewScript' => 'form/player.phtml'))
         ));
 
-        $displayTitle = new Zend_Form_Element_Checkbox('player_display_title');
-        $displayTitle->setValue(true);
-        $displayTitle->setLabel(_('Display title?'));
-        //$displayTitle->addDecorator('Label', array('placement' => 'APPEND'));
-        $displayTitle->setDecorators(array(
+        $title = new Zend_Form_Element_Text('player_title');
+        $title->setValue(_('Now Playing'));
+        $title->setLabel(_('Title:'));
+        $title->setDecorators(array(
             'ViewHelper',
             'Errors',
             'Label'
         ));
-        $displayTitle->addDecorator('Label', array('class' => 'player-checkbox', 'placement' => 'APPEND'));
-        $this->addElement($displayTitle);
-
-        $title = new Zend_Form_Element_Text('player_title');
-        $title->setValue(_('Now Playing'));
-        $title->setLabel(_('Title:'));
-        $title->removeDecorator('DtDdWrapper');
+        $title->addDecorator('Label', array('class' => 'player-title'));
         $this->addElement($title);
 
         $streamMode = new Zend_Form_Element_Radio('player_stream_mode');
@@ -76,6 +69,7 @@ class Application_Form_Player extends Zend_Form_SubForm
         $embedSrc->setAttrib('cols', '40')
             ->setAttrib('rows', '4');
         $embedSrc->setLabel(_("Embeddable code:"));
+        $embedSrc->setDescription(_("Copy this code and paste it into your website's HTML to embed the player in your site."));
         $embedSrc->setValue('<iframe frameborder="0" width="280" height="210" src="'.Application_Common_HTTPHelper::getStationUrl().'embed/player?stream=auto&title=Now Playing"></iframe>');
         $this->addElement($embedSrc);
 
diff --git a/airtime_mvc/application/views/scripts/embed/player.phtml b/airtime_mvc/application/views/scripts/embed/player.phtml
index a2732b3c4..0695ba202 100644
--- a/airtime_mvc/application/views/scripts/embed/player.phtml
+++ b/airtime_mvc/application/views/scripts/embed/player.phtml
@@ -277,7 +277,7 @@
             <li></li>
         </ul>
     </div>
-    <a class="airtime_pro" target="_blank" href="https://www.airtime.pro/">Powered by Airtime Pro<span class="airtime_pro_logo"></span></a>
+    <a class="airtime_pro" target="_blank" href="https://www.airtime.pro/">Powered by <span class="airtime-pro-orange">Airtime Pro</span></a>
 
 </div>
 
diff --git a/airtime_mvc/application/views/scripts/form/player.phtml b/airtime_mvc/application/views/scripts/form/player.phtml
index e9bb8f3ed..bedd3f099 100644
--- a/airtime_mvc/application/views/scripts/form/player.phtml
+++ b/airtime_mvc/application/views/scripts/form/player.phtml
@@ -9,12 +9,10 @@
         </div>
 
         <div id="player_instructions">
-            Customize the player by configuring the options below. When you are done
-            copy the embeddable code below into your websites HTML.
+            Customize the player by configuring the options below. When you are done,
+            copy the embeddable code below and paste it into your website's HTML.
         </div>
 
-        <?php echo $this->element->getElement('player_display_title'); ?>
-
         <?php echo $this->element->getElement('player_title')->render(); ?>
 
         <?php echo $this->element->getElement('player_stream_mode')->render(); ?>
diff --git a/airtime_mvc/public/css/player-form.css b/airtime_mvc/public/css/player-form.css
index 0ab842bb6..69654c9f1 100644
--- a/airtime_mvc/public/css/player-form.css
+++ b/airtime_mvc/public/css/player-form.css
@@ -3,7 +3,8 @@
     width: 100% !important;
 }
 .embed-player-form {
-    width: 98%;
+    width: 40%;
+    margin: 0 auto;
 }
 .embed-player-form dd {
     width: 100% !important;
@@ -19,7 +20,7 @@
     display: block;
 }
 #player_form {
-    width: 40%;
+    width: 100%;
     margin: 0 auto;
 }
 #player_form dd {
@@ -29,20 +30,32 @@
     border-bottom: 1px solid;
     padding-bottom: 10px;
     font-size: 14px;
-    font-weight: bold;
-    color: #5b5b5b;
+    /*font-weight: bold;*/
+    color: #333;
     margin-bottom: 10px;
 }
-.player-checkbox {
+.player-title {
     clear: left;
     color: #5b5b5b;
     float: left;
     font-size: 13px;
     font-weight: bold;
-    margin: 0;
-    min-width: 90px;
+    width: 40px;
     padding: 4px 0;
     text-align: left;
+    margin-top: 5px;
+    margin-bottom: 17px;
+}
+#player_title {
+    clear: left;
+}
+#player_stream_url-element {
+    margin-left:30px;
+}
+#player_embed_src-element p {
+    margin: 0px;
+    font-size: 13px;
+    color: #333;
 }
 
 
diff --git a/airtime_mvc/public/css/player.css b/airtime_mvc/public/css/player.css
index 3c9ef0f08..cdb76e01f 100644
--- a/airtime_mvc/public/css/player.css
+++ b/airtime_mvc/public/css/player.css
@@ -38,9 +38,9 @@
     padding-right: 30px;
 }
 .airtime_pro {
-    margin: 0px 20px;
+    margin: 6px 20px;
     color: #fff;
-    font-size: 10px;
+    font-size: 11px;
     text-decoration: none;
     display:inline-block;
     float:right;
@@ -189,6 +189,7 @@
 .airtime_next {
     float: left;
     margin: 0px;
+    margin-top: 1px;
 }
 
 .schedule_list {
@@ -199,10 +200,15 @@
     margin-left: 60px;
     margin-bottom: 0px;
     line-height: 130%;
+    height: 20px;
 }
 
 .schedule_list li {
     white-space: nowrap;
     overflow: hidden;
     text-overflow: ellipsis;
+}
+
+.airtime-pro-orange {
+    color: #ff5d1a;
 }
\ No newline at end of file
diff --git a/airtime_mvc/public/js/airtime/player/player.js b/airtime_mvc/public/js/airtime/player/player.js
index a2bb17808..db2fbb8bb 100644
--- a/airtime_mvc/public/js/airtime/player/player.js
+++ b/airtime_mvc/public/js/airtime/player/player.js
@@ -9,10 +9,7 @@ function updateEmbedSrcParams()
         $embedCodeParams += "stream=auto";
     }
 
-    var playerTitle = getPlayerTitle();
-    if (playerTitle !== null) {
-        $embedCodeParams += "&title="+playerTitle;
-    }
+    $embedCodeParams += "&title="+getPlayerTitle();
 
     $embedCodeParams += "\"";
 
@@ -34,11 +31,7 @@ function getStreamMode() {
 }
 
 function getPlayerTitle() {
-    if ($("#player_display_title").prop("checked")) {
-        return $("input[name=player_title]").val();
-    } else {
-        return null;
-    }
+    return $("input[name=player_title]").val();
 }
 
 $(document).ready(function() {

From 9e62c71690678a1965a7453a84650ba6d3590314 Mon Sep 17 00:00:00 2001
From: drigato <denise.rigato@sourcefabric.org>
Date: Fri, 10 Apr 2015 10:52:40 -0400
Subject: [PATCH 52/60] Fix player's manual mode

---
 .../controllers/EmbedController.php            |  3 ++-
 .../views/scripts/embed/player.phtml           | 18 +-----------------
 2 files changed, 3 insertions(+), 18 deletions(-)

diff --git a/airtime_mvc/application/controllers/EmbedController.php b/airtime_mvc/application/controllers/EmbedController.php
index 11f2cc68e..3212c8e5d 100644
--- a/airtime_mvc/application/controllers/EmbedController.php
+++ b/airtime_mvc/application/controllers/EmbedController.php
@@ -37,6 +37,7 @@ class EmbedController extends Zend_Controller_Action
 
         if ($stream == "auto") {
             $this->view->playerMode = "auto";
+            $this->view->streamURL = json_encode("");
             foreach ($streamData as $s) {
                 if ($s["mobile"]) {
                     array_push($availableMobileStreams, $s);
@@ -44,7 +45,7 @@ class EmbedController extends Zend_Controller_Action
                     array_push($availableDesktopStreams, $s);
                 }
             }
-        } else {
+        } elseif (!empty($stream)) {
             $this->view->playerMode = "manual";
             $selectedStreamData = $streamData[$stream];
             $this->view->streamURL = json_encode($selectedStreamData["url"]);
diff --git a/airtime_mvc/application/views/scripts/embed/player.phtml b/airtime_mvc/application/views/scripts/embed/player.phtml
index 0695ba202..c7c5560b1 100644
--- a/airtime_mvc/application/views/scripts/embed/player.phtml
+++ b/airtime_mvc/application/views/scripts/embed/player.phtml
@@ -35,7 +35,7 @@
             };
 
             if (this.playerMode == "manual") {
-                this.settings.url = '<?php echo $this->streamURL ?>';
+                this.settings.url = <?php echo $this->streamURL ?>;
                 this.settings.codec = "<?php echo $this->codec ?>";
             } else if (this.playerMode == "auto") {
                 this.availableMobileStreamQueue = <?php echo $this->availableMobileStreams?>;
@@ -63,7 +63,6 @@
             if (!this.flashDetect) {
 
                 MRP.html.audio.addEventListener('error', function failed(e) {
-                    console.log("HTML error");
                     var stream = musesPlayer.getNextAvailableStream();
                     var audio = $(MRP.html.audio);
                     audio.src = stream["url"];
@@ -72,8 +71,6 @@
                 }, true);
 
                 MRP.html.audio.addEventListener('pause', function paused(e) {
-                    //this is when pause happens
-                    console.log("HTML paused");
                     //src = MRP.html.audio.src;
                     //MRP.html.audio.src = "";
                 }, true);
@@ -256,19 +253,6 @@
 
     </div>
 
-    <!--
-    <div class="airtime_volume">
-
-        <div class="volume_control">
-            <span class="mute"></span>
-        </div>
-
-        <div class="airtime_volume_bar">
-            <div class="airtime_volume_bar_value" style="width: 80%;"></div>
-        </div>
-
-    </div>
-    -->
     <div style="clear:both"></div>
 
     <div class="airtime_schedule">

From 4d7d48d6fbb06a8e83a58770cc0eb5cb0b3bcd71 Mon Sep 17 00:00:00 2001
From: drigato <denise.rigato@sourcefabric.org>
Date: Fri, 10 Apr 2015 10:55:39 -0400
Subject: [PATCH 53/60] Player - fix height

---
 airtime_mvc/application/forms/Player.php | 2 +-
 airtime_mvc/public/css/player.css        | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/airtime_mvc/application/forms/Player.php b/airtime_mvc/application/forms/Player.php
index a1dbff341..5a24397d7 100644
--- a/airtime_mvc/application/forms/Player.php
+++ b/airtime_mvc/application/forms/Player.php
@@ -70,7 +70,7 @@ class Application_Form_Player extends Zend_Form_SubForm
             ->setAttrib('rows', '4');
         $embedSrc->setLabel(_("Embeddable code:"));
         $embedSrc->setDescription(_("Copy this code and paste it into your website's HTML to embed the player in your site."));
-        $embedSrc->setValue('<iframe frameborder="0" width="280" height="210" src="'.Application_Common_HTTPHelper::getStationUrl().'embed/player?stream=auto&title=Now Playing"></iframe>');
+        $embedSrc->setValue('<iframe frameborder="0" width="280" height="216" src="'.Application_Common_HTTPHelper::getStationUrl().'embed/player?stream=auto&title=Now Playing"></iframe>');
         $this->addElement($embedSrc);
 
         $previewLabel = new Zend_Form_Element_Text('player_preview_label');
diff --git a/airtime_mvc/public/css/player.css b/airtime_mvc/public/css/player.css
index cdb76e01f..47cdd0994 100644
--- a/airtime_mvc/public/css/player.css
+++ b/airtime_mvc/public/css/player.css
@@ -1,6 +1,6 @@
 .airtime_player {
     width: 270px;
-    height: 185px;
+    height: 191px;
     position: relative;
     font-family: Arial, Helvetica, sans-serif;
     color: #fff;

From caa591bd5ec9ca9e95046ba15ade1e1a2908e87e Mon Sep 17 00:00:00 2001
From: drigato <denise.rigato@sourcefabric.org>
Date: Fri, 10 Apr 2015 11:07:42 -0400
Subject: [PATCH 54/60] Player - set fixed height for metadata area

---
 airtime_mvc/public/css/player.css | 1 +
 1 file changed, 1 insertion(+)

diff --git a/airtime_mvc/public/css/player.css b/airtime_mvc/public/css/player.css
index 47cdd0994..f8a3102c7 100644
--- a/airtime_mvc/public/css/player.css
+++ b/airtime_mvc/public/css/player.css
@@ -27,6 +27,7 @@
     margin-top: 15px;
     float: left;
     width: 100%;
+    height: 52px;
 }
 .station_name {
     font-size: 14px;

From c80d4376011709d05a2d0089b1599d5a3aaeb8c7 Mon Sep 17 00:00:00 2001
From: drigato <denise.rigato@sourcefabric.org>
Date: Fri, 10 Apr 2015 15:25:49 -0400
Subject: [PATCH 55/60] Fixed player HTML5 error handling

---
 .../views/scripts/embed/player.phtml          | 56 +++++++++++++++++--
 1 file changed, 50 insertions(+), 6 deletions(-)

diff --git a/airtime_mvc/application/views/scripts/embed/player.phtml b/airtime_mvc/application/views/scripts/embed/player.phtml
index c7c5560b1..b964c75bc 100644
--- a/airtime_mvc/application/views/scripts/embed/player.phtml
+++ b/airtime_mvc/application/views/scripts/embed/player.phtml
@@ -63,11 +63,55 @@
             if (!this.flashDetect) {
 
                 MRP.html.audio.addEventListener('error', function failed(e) {
-                    var stream = musesPlayer.getNextAvailableStream();
-                    var audio = $(MRP.html.audio);
-                    audio.src = stream["url"];
-                    audio[0].load();
-                    audio[0].play();
+                    switch (e.target.error.code) {
+                        case e.target.error.MEDIA_ERR_NETWORK:
+                            // If there is a network error keep retrying to connect
+                            // to a stream.
+                            var stream;
+                            if (musesPlayer.playerMode == "auto") {
+                                var nextAvailableStream = musesPlayer.getNextAvailableStream();
+                                stream = nextAvailableStream["url"];
+                            } else {
+                                stream = musesPlayer.settings.url;
+                            }
+                            var audio = $(MRP.html.audio);
+                            audio.src = stream;
+                            audio[0].load();
+                            audio[0].play();
+                            break;
+                        case e.target.error.MEDIA_ERR_DECODE:
+                            // If there was a corruption error or a problem with the browser
+                            // display an error and stop playback.
+                            togglePlayStopButton();
+                            clearTimeout(metadataTimer);
+                            $("p.now_playing").html("Error - Try again later");
+                            break;
+                        case e.target.error.MEDIA_ERR_SRC_NOT_SUPPORTED:
+                            // If in auto mode and the current stream format is not supported
+                            // or the max number of listeners has been reached
+                            // retry connection with the next available stream.
+                            if (musesPlayer.playerMode == "auto") {
+                                var nextAvailableStream = musesPlayer.getNextAvailableStream();
+                                var audio = $(MRP.html.audio);
+                                audio.src = nextAvailableStream["url"];;
+                                audio[0].load();
+                                audio[0].play();
+                            } else {
+                                // If in manual mode and the current stream format is not supported
+                                // or the max number of listeners has been reached
+                                // display an error and stop play back.
+                                togglePlayStopButton();
+                                clearTimeout(metadataTimer);
+                                $("p.now_playing").html("Error - Try again later");
+                            }
+                            break;
+                        default:
+                            togglePlayStopButton();
+                            clearTimeout(metadataTimer);
+                            $("p.now_playing").html("Error - Try again later");
+                            break;
+                    }
+
                 }, true);
 
                 MRP.html.audio.addEventListener('pause', function paused(e) {
@@ -218,8 +262,8 @@
 
                 }
             });
-            setTimeout(attachStreamMetadataToPlayer, time_to_next_track_starts);
         }
+        var metadataTimer = setTimeout(attachStreamMetadataToPlayer, time_to_next_track_starts);
 
     </script>
 

From 1d79f13716dd4151fd530586c8075d0fb7aa42af Mon Sep 17 00:00:00 2001
From: drigato <denise.rigato@sourcefabric.org>
Date: Fri, 10 Apr 2015 16:06:19 -0400
Subject: [PATCH 56/60] Player HTML5 error handling fix

---
 airtime_mvc/application/views/scripts/embed/player.phtml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/airtime_mvc/application/views/scripts/embed/player.phtml b/airtime_mvc/application/views/scripts/embed/player.phtml
index b964c75bc..da64ab0e5 100644
--- a/airtime_mvc/application/views/scripts/embed/player.phtml
+++ b/airtime_mvc/application/views/scripts/embed/player.phtml
@@ -93,7 +93,7 @@
                             if (musesPlayer.playerMode == "auto") {
                                 var nextAvailableStream = musesPlayer.getNextAvailableStream();
                                 var audio = $(MRP.html.audio);
-                                audio.src = nextAvailableStream["url"];;
+                                audio[0].src = nextAvailableStream["url"];;
                                 audio[0].load();
                                 audio[0].play();
                             } else {

From b8e8a1a983764ec738fdf6b5d8b1dfb8ba2a568c Mon Sep 17 00:00:00 2001
From: drigato <denise.rigato@sourcefabric.org>
Date: Fri, 10 Apr 2015 16:44:51 -0400
Subject: [PATCH 57/60] Player HTML5 error handling fix

---
 airtime_mvc/application/views/scripts/embed/player.phtml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/airtime_mvc/application/views/scripts/embed/player.phtml b/airtime_mvc/application/views/scripts/embed/player.phtml
index da64ab0e5..34e39803a 100644
--- a/airtime_mvc/application/views/scripts/embed/player.phtml
+++ b/airtime_mvc/application/views/scripts/embed/player.phtml
@@ -75,7 +75,7 @@
                                 stream = musesPlayer.settings.url;
                             }
                             var audio = $(MRP.html.audio);
-                            audio.src = stream;
+                            audio[0].src = stream;
                             audio[0].load();
                             audio[0].play();
                             break;

From 63c3236e7ab7b741bf293ba34d15e1b8085b08b6 Mon Sep 17 00:00:00 2001
From: drigato <denise.rigato@sourcefabric.org>
Date: Fri, 10 Apr 2015 17:38:39 -0400
Subject: [PATCH 58/60] Player metadata fix

---
 .../views/scripts/embed/player.phtml          | 19 +++++++++----------
 1 file changed, 9 insertions(+), 10 deletions(-)

diff --git a/airtime_mvc/application/views/scripts/embed/player.phtml b/airtime_mvc/application/views/scripts/embed/player.phtml
index 34e39803a..0531b702b 100644
--- a/airtime_mvc/application/views/scripts/embed/player.phtml
+++ b/airtime_mvc/application/views/scripts/embed/player.phtml
@@ -220,8 +220,9 @@
             document.getElementById("stop_button").classList.toggle("hide_button");
         }
 
-        // default how often to fetch metadata to 20 seconds
-        var time_to_next_track_starts = 20000;
+        // variables for updating the player's metadata
+        var time_to_next_track_starts;
+        var metadataTimer;
 
         // Fetches the streams metadata from the Airtime live-info API
         // and attaches it to the player UI.
@@ -235,23 +236,19 @@
 
                     if (data.current === null) {
                         $("p.now_playing").html("Offline");
+                        time_to_next_track_starts = 20000;
                     } else {
                         var artist = data.current.name.split(" - ")[0];
                         var track = data.current.name.split(" - ")[1];
+                        console.log(artist);
+                        console.log(track);
                         $("p.now_playing").html(artist + "<span>" + track + "</span>");
 
                         var current_track_end_time = new Date(data.current.ends);
                         var current_time = new Date();
                         //convert current_time to UTC to match the timezone of time_to_next_track_starts
                         current_time = new Date(current_time.getTime() + current_time.getTimezoneOffset() * 60 * 1000);
-                        //TODO stop the first settimeout from executing!!
                         time_to_next_track_starts = current_track_end_time - current_time;
-                        //console.log((time_to_next_track_starts/1000)/60);
-                        // maybe we should set time_to_next_track_starts to
-                        // (10 || 20 || etc.) minutes if its greater than that
-                        // in case of on-the-fly schedule changes
-
-
                     }
 
                     if (data.next === null) {
@@ -262,8 +259,10 @@
 
                 }
             });
+            console.log(time_to_next_track_starts);
+            // Add 3 seconds to the timeout so Airtime has time to update the metadata before we fetch it
+            metadataTimer = setTimeout(attachStreamMetadataToPlayer, time_to_next_track_starts+3000);
         }
-        var metadataTimer = setTimeout(attachStreamMetadataToPlayer, time_to_next_track_starts);
 
     </script>
 

From 988fcae9899edd8fc4bccf95560d23ea507ea91a Mon Sep 17 00:00:00 2001
From: drigato <denise.rigato@sourcefabric.org>
Date: Fri, 10 Apr 2015 18:17:22 -0400
Subject: [PATCH 59/60] Remove console.log

---
 airtime_mvc/application/views/scripts/embed/player.phtml | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/airtime_mvc/application/views/scripts/embed/player.phtml b/airtime_mvc/application/views/scripts/embed/player.phtml
index 0531b702b..37a3221f2 100644
--- a/airtime_mvc/application/views/scripts/embed/player.phtml
+++ b/airtime_mvc/application/views/scripts/embed/player.phtml
@@ -240,8 +240,6 @@
                     } else {
                         var artist = data.current.name.split(" - ")[0];
                         var track = data.current.name.split(" - ")[1];
-                        console.log(artist);
-                        console.log(track);
                         $("p.now_playing").html(artist + "<span>" + track + "</span>");
 
                         var current_track_end_time = new Date(data.current.ends);
@@ -259,7 +257,6 @@
 
                 }
             });
-            console.log(time_to_next_track_starts);
             // Add 3 seconds to the timeout so Airtime has time to update the metadata before we fetch it
             metadataTimer = setTimeout(attachStreamMetadataToPlayer, time_to_next_track_starts+3000);
         }

From 24b6751eebc2bd77d45f4b84a14760569d909265 Mon Sep 17 00:00:00 2001
From: drigato <denise.rigato@sourcefabric.org>
Date: Mon, 13 Apr 2015 09:18:36 -0400
Subject: [PATCH 60/60] Remove unused code from player

---
 airtime_mvc/application/views/scripts/embed/player.phtml | 5 -----
 1 file changed, 5 deletions(-)

diff --git a/airtime_mvc/application/views/scripts/embed/player.phtml b/airtime_mvc/application/views/scripts/embed/player.phtml
index 37a3221f2..3d7d312e1 100644
--- a/airtime_mvc/application/views/scripts/embed/player.phtml
+++ b/airtime_mvc/application/views/scripts/embed/player.phtml
@@ -113,11 +113,6 @@
                     }
 
                 }, true);
-
-                MRP.html.audio.addEventListener('pause', function paused(e) {
-                    //src = MRP.html.audio.src;
-                    //MRP.html.audio.src = "";
-                }, true);
             }
         };