Bug 1032469 Update Loop to OpenTok library v2.2.6. r=abr
☠☠ backed out by 6999f481c942 ☠ ☠
authorMark Banner <standard8@mozilla.com>
Tue, 08 Jul 2014 09:50:45 +0100
changeset 192835 7e27f2f4793c08f1147470a9196f7107131e9f51
parent 192834 416d7931e3490c416b8544344eb32b8213bdd2b1
child 192836 fb2a8327a8bbcb7c7e93c99d997e11e94a50cc5b
push id7663
push userkwierso@gmail.com
push dateWed, 09 Jul 2014 03:08:08 +0000
treeherderfx-team@48de6f4f82af [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersabr
bugs1032469
milestone33.0a1
Bug 1032469 Update Loop to OpenTok library v2.2.6. r=abr
browser/components/loop/content/conversation.html
browser/components/loop/content/libs/otcdn/webrtc/v2.2.5/css/ot.min.css
browser/components/loop/content/libs/otcdn/webrtc/v2.2.5/images/rtc/access-denied-chrome.png
browser/components/loop/content/libs/otcdn/webrtc/v2.2.5/images/rtc/access-denied-copy-firefox.png
browser/components/loop/content/libs/otcdn/webrtc/v2.2.5/images/rtc/access-denied-firefox.png
browser/components/loop/content/libs/otcdn/webrtc/v2.2.5/images/rtc/access-predenied-chrome.png
browser/components/loop/content/libs/otcdn/webrtc/v2.2.5/images/rtc/access-prompt-chrome.png
browser/components/loop/content/libs/otcdn/webrtc/v2.2.5/images/rtc/audioonly-publisher.png
browser/components/loop/content/libs/otcdn/webrtc/v2.2.5/images/rtc/audioonly-subscriber.png
browser/components/loop/content/libs/otcdn/webrtc/v2.2.5/images/rtc/buttons.png
browser/components/loop/content/libs/otcdn/webrtc/v2.2.5/images/rtc/loader.gif
browser/components/loop/content/libs/otcdn/webrtc/v2.2.5/images/rtc/mic-off.png
browser/components/loop/content/libs/otcdn/webrtc/v2.2.5/images/rtc/mic-on.png
browser/components/loop/content/libs/otcdn/webrtc/v2.2.5/images/rtc/speaker-off.png
browser/components/loop/content/libs/otcdn/webrtc/v2.2.5/images/rtc/speaker-on.png
browser/components/loop/content/libs/otcdn/webrtc/v2.2.5/js/dynamic_config.min.js
browser/components/loop/content/libs/sdk-content/css/ot.css
browser/components/loop/content/libs/sdk-content/images/rtc/access-denied-chrome.png
browser/components/loop/content/libs/sdk-content/images/rtc/access-denied-copy-firefox.png
browser/components/loop/content/libs/sdk-content/images/rtc/access-denied-firefox.png
browser/components/loop/content/libs/sdk-content/images/rtc/access-predenied-chrome.png
browser/components/loop/content/libs/sdk-content/images/rtc/access-prompt-chrome.png
browser/components/loop/content/libs/sdk-content/images/rtc/audioonly-publisher.png
browser/components/loop/content/libs/sdk-content/images/rtc/audioonly-subscriber.png
browser/components/loop/content/libs/sdk-content/images/rtc/buttons.png
browser/components/loop/content/libs/sdk-content/images/rtc/loader.gif
browser/components/loop/content/libs/sdk-content/images/rtc/mic-off.png
browser/components/loop/content/libs/sdk-content/images/rtc/mic-on.png
browser/components/loop/content/libs/sdk-content/images/rtc/speaker-off.png
browser/components/loop/content/libs/sdk-content/images/rtc/speaker-on.png
browser/components/loop/content/libs/sdk-content/js/dynamic_config.min.js
browser/components/loop/content/libs/sdk.js
browser/components/loop/jar.mn
--- a/browser/components/loop/content/conversation.html
+++ b/browser/components/loop/content/conversation.html
@@ -12,16 +12,24 @@
  </head>
   <body onload="loop.conversation.init();">
 
     <div id="messages"></div>
 
     <div id="main"></div>
 
     <script type="text/javascript" src="loop/libs/l10n.js"></script>
+    <script>
+      window.OTProperties = {
+        cdnURL: 'loop/',
+      };
+      window.OTProperties.assetURL = window.OTProperties.cdnURL + 'sdk-content/';
+      window.OTProperties.configURL = window.OTProperties.assetURL + 'js/dynamic_config.min.js';
+      window.OTProperties.cssURL = window.OTProperties.assetURL + 'css/ot.css';
+    </script>
     <script type="text/javascript" src="loop/libs/sdk.js"></script>
     <script type="text/javascript" src="loop/shared/libs/jquery-2.1.0.js"></script>
     <script type="text/javascript" src="loop/shared/libs/lodash-2.4.1.js"></script>
     <script type="text/javascript" src="loop/shared/libs/backbone-1.1.2.js"></script>
 
     <script type="text/javascript" src="loop/shared/js/models.js"></script>
     <script type="text/javascript" src="loop/shared/js/router.js"></script>
     <script type="text/javascript" src="loop/shared/js/views.js"></script>
rename from browser/components/loop/content/libs/otcdn/webrtc/v2.2.5/css/ot.min.css
rename to browser/components/loop/content/libs/sdk-content/css/ot.css
--- a/browser/components/loop/content/libs/otcdn/webrtc/v2.2.5/css/ot.min.css
+++ b/browser/components/loop/content/libs/sdk-content/css/ot.css
@@ -1,12 +1,973 @@
-/**
- * @license  OpenTok JavaScript Library v2.2.5
- * http://www.tokbox.com/
- *
+/*!
  * Copyright (c) 2014 TokBox, Inc.
  * Released under the MIT license
  * http://opensource.org/licenses/MIT
- *
- * Date: May 22 07:14:18 2014
+ */
+
+/**
+ * OT Base styles
+ */
+
+/* Root OT object, this is where our CSS reset happens */
+.OT_root,
+.OT_root * {
+    color: #ffffff;
+    margin: 0;
+    padding: 0;
+    border: 0;
+    font-size: 100%;
+    font-family: Arial, Helvetica, sans-serif;
+    vertical-align: baseline;
+}
+
+
+/**
+ * Specific Element Reset
  */
 
-.OT_root,.OT_root *{color:#fff;margin:0;padding:0;border:0;font-size:100%;font-family:Arial,Helvetica,sans-serif;vertical-align:baseline}.OT_root h1,.OT_root h2,.OT_root h3,.OT_root h4,.OT_root h5,.OT_root h6{color:#fff;font-family:Arial,Helvetica,sans-serif;font-size:100%;font-weight:bold}.OT_root strong{font-weight:bold}.OT_root em{font-style:italic}.OT_root a,.OT_root a:link,.OT_root a:visited,.OT_root a:hover,.OT_root a:active{font-family:Arial,Helvetica,sans-serif}.OT_root ul,.OT_root ol{margin:1em 1em 1em 2em}.OT_root ol{list-style:decimal outside}.OT_root ul{list-style:disc outside}.OT_root dl{margin:4px}.OT_root dl dt,.OT_root dl dd{float:left;margin:0;padding:0}.OT_root dl dt{clear:left;text-align:right;width:50px}.OT_root dl dd{margin-left:10px}.OT_root img{border:0 none}.OT_dialog{border:0;border-radius:0;top:50%;left:50%;position:absolute;position:fixed;padding:0;background-color:#363636;color:#fff;z-index:9999;box-shadow:2px 4px 6px #999;font-family:'Didact Gothic',sans-serif}.OT_dialog-blackout{position:absolute;position:fixed;top:0;right:0;bottom:0;left:0;background-color:#363636}.OT_dialog-blackout .OT_dialog{box-shadow:0 0 0 transparent}.OT_dialog *{font-family:'Didact Gothic',sans-serif}.OT_dialog-plugin-prompt{margin-left:-350px;margin-top:-141px;width:650px;height:282px}.OT_dialog-plugin-reinstall{margin-left:-271px;margin-top:-117px;width:542px;height:234px}.OT_dialog-plugin-upgrading{margin-left:-267px;margin-top:-94px;width:514px;height:188px}.OT_dialog-allow-deny-chrome-first{margin-left:-227px;margin-top:-122px;width:453px;height:244px}.OT_dialog-allow-deny-chrome-pre-denied{margin-left:-263px;margin-top:-135px;width:526px;height:270px}.OT_dialog-allow-deny-chrome-now-denied{margin-left:-120px;margin-top:-85px;width:256px;height:170px}.OT_dialog-allow-deny-firefox-denied{margin-left:-160px;margin-top:-105px;width:320px;height:190px}.OT_dialog-allow-deny-firefox-maybe-denied{margin-left:-281px;margin-top:-126px;width:562px;height:252px}.OT_dialog-allow-highlight-chrome{display:inline-block;margin-top:20px;width:227px;height:94px;background-image:url(../images/rtc/access-prompt-chrome.png)}.OT_closeButton{top:15px;right:15px;position:absolute;font-size:18px;cursor:pointer}.OT_dialog-messages{position:absolute;top:32px;left:32px;right:32px;text-align:center}.OT_dialog-allow-deny-firefox-maybe-denied .OT_dialog-messages{top:45px}.OT_dialog-messages-main{font-weight:300;font-size:18pt;line-height:24px}.OT_dialog-messages-minor{font-weight:300;margin-top:12px;font-size:13px;line-height:18px;color:#a4a4a4}.OT_dialog-allow-deny-firefox-maybe-denied .OT_dialog-messages-minor{margin-top:4px}.OT_dialog-messages-minor strong{font-weight:300;color:#fff}.OT_dialog-single-button{position:absolute;bottom:41px;left:50%;margin-left:-97px;height:47px;width:193px}.OT_dialog-button-pair{position:absolute;bottom:45px;left:5px;right:0;height:94px}.OT_dialog-button-with-title{padding-left:30px;padding-right:30px;width:260px;float:left}.OT_dialog-button-pair-seperator{border-right:1px solid #555;height:112px;width:1px;float:left}.OT_dialog-button-title{font-weight:300;text-align:center;margin-bottom:15px;font-size:12px;line-height:150%;color:#a4a4a4}.OT_dialog-button-title strong{color:#fff;font-weight:100;display:block}.OT_dialog-button{font-weight:100;display:block;line-height:50px;height:47px;background-color:#29a4da;text-align:center;font-size:16pt;cursor:pointer}.OT_dialog-button.OT_dialog-button-large{line-height:60px;height:58px}.OT_dialog-progress-bar{border:1px solid #4e4e4e;height:8px}.OT_dialog-progress-bar-fill{background-color:#29a4da;height:10px;margin-top:-1px;margin-left:-1px;margin-right:-1px}.OT_dialog-plugin-upgrading .OT_dialog-plugin-upgrade-percentage{font-size:36pt;font-weight:100}.OT_dialog-plugin-upgrading .OT_dialog-progress-bar{margin-top:25px;margin-bottom:25px}.OT_dialog-3steps{margin-top:24px}.OT_dialog-allow-deny-firefox-maybe-denied .OT_dialog-3steps{margin-top:21px}.OT_dialog-3steps-step{float:left;-moz-box-sizing:border-box;box-sizing:border-box;width:33%;height:140px;padding:0 10px;color:#a4a4a4}.OT_dialog-3steps-seperator{float:left;-moz-box-sizing:border-box;box-sizing:border-box;margin-top:10px;width:1px;height:68px;background-color:#555}.OT_dialog-allow-deny-chrome-pre-denied .OT_dialog-3steps-seperator{margin-top:16px}.OT_dialog-3steps-step-num{font-size:20px;background-color:#2aa3d8;border-radius:20px;line-height:33px;height:33px;width:33px;margin:0 auto 17px}.OT_dialog-allow-deny-chrome-pre-denied .OT_dialog-3steps-step-num{margin-bottom:10px}.OT_dialog-allow-camera-icon{background-color:#000;width:113px;height:48px;margin:10px auto 0;background-image:url(../images/rtc/access-predenied-chrome.png)}.OT_publisher-denied-firefox{background-color:#fff}.OT_publisher-denied-firefox p{width:232px;height:103px;top:50%;left:50%;display:block;position:absolute;margin-top:-52px;margin-left:-116px;background-image:url(../images/rtc/access-denied-firefox.png);background-position:50% 0;background-repeat:no-repeat}.OT_publisher-denied-firefox span{display:block;position:absolute;bottom:0;right:0;left:0;margin:0 auto;width:232px;height:31px;background-image:url(../images/rtc/access-denied-copy-firefox.png);text-indent:100%;white-space:nowrap;overflow:hidden}.OT_centered{position:fixed;left:50%;top:50%;margin:0}.OT_publisher,.OT_subscriber{position:relative;min-width:48px;min-height:48px}.OT_publisher video,.OT_subscriber video{width:100%;height:100%}.OT_publisher.OT_mirrored video{-webkit-transform:scale(-1,1);-moz-transform:scale(-1,1)}.OT_subscriber_error{background-color:#000;color:#fff;text-align:center}.OT_subscriber_error>p{padding:20px}.OT_publisher .OT_bar,.OT_subscriber .OT_bar,.OT_publisher .OT_name,.OT_subscriber .OT_name,.OT_publisher .OT_archiving,.OT_subscriber .OT_archiving,.OT_publisher .OT_archiving-status,.OT_subscriber .OT_archiving-status,.OT_publihser .OT_archiving-light-box,.OT_subscriber .OT_archiving-light-box{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box;top:0;left:0;right:0;display:block;height:34px;position:absolute}.OT_publisher .OT_bar,.OT_subscriber .OT_bar{background:rgba(0,0,0,0.4)}.OT_publisher .OT_name,.OT_subscriber .OT_name{background-color:transparent;color:#fff;font-size:15px;line-height:34px;font-weight:normal;padding:0 4px 0 36px}.OT_publisher .OT_archiving-status,.OT_subscriber .OT_archiving-status{background:rgba(0,0,0,0.4);top:auto;bottom:0;left:34px;padding:0 4px;color:rgba(255,255,255,0.8);font-size:15px;line-height:34px;font-weight:normal}.OT_micro .OT_archiving-status,.OT_micro:hover .OT_archiving-status,.OT_mini .OT_archiving-status,.OT_mini:hover .OT_archiving-status{display:none}.OT_publisher .OT_archiving-light-box,.OT_subscriber .OT_archiving-light-box{background:rgba(0,0,0,0.4);top:auto;bottom:0;right:auto;width:34px;height:34px}.OT_archiving-light{width:7px;height:7px;-webkit-border-radius:30px;-moz-border-radius:30px;border-radius:30px;position:absolute;top:14px;left:14px;background-color:#575757;-webkit-box-shadow:0 0 5px 1px #575757;-moz-box-shadow:0 0 5px 1px #575757;box-shadow:0 0 5px 1px #575757}.OT_archiving-light.OT_active{background-color:#970d13;-webkit-animation:OT_pulse 1.3s ease-in;-moz-animation:OT_pulse 1.3s ease-in;-webkit-animation:OT_pulse 1.3s ease-in;-webkit-animation-iteration-count:infinite;-moz-animation-iteration-count:infinite;-webkit-animation-iteration-count:infinite}@-moz-keyframes OT_pulse{0%{-webkit-box-shadow:0 0 0 0 #c70019;-moz-box-shadow:0 0 0 0 #c70019;box-shadow:0 0 0 0 #c70019}30%{-webkit-box-shadow:0 0 5px 1px #c70019;-moz-box-shadow:0 0 5px 1px #c70019;box-shadow:0 0 5px 1px #c70019}50%{-webkit-box-shadow:0 0 5px 1px #c70019;-moz-box-shadow:0 0 5px 1px #c70019;box-shadow:0 0 5px 1px #c70019}80%{-webkit-box-shadow:0 0 0 0 #c70019;-moz-box-shadow:0 0 0 0 #c70019;box-shadow:0 0 0 0 #c70019}100%{-webkit-box-shadow:0 0 0 0 #c70019;-moz-box-shadow:0 0 0 0 #c70019;box-shadow:0 0 0 0 #c70019}}@-webkit-keyframes OT_pulse{0%{-webkit-box-shadow:0 0 0 0 #c70019;-moz-box-shadow:0 0 0 0 #c70019;box-shadow:0 0 0 0 #c70019}30%{-webkit-box-shadow:0 0 5px 1px #c70019;-moz-box-shadow:0 0 5px 1px #c70019;box-shadow:0 0 5px 1px #c70019}50%{-webkit-box-shadow:0 0 5px 1px #c70019;-moz-box-shadow:0 0 5px 1px #c70019;box-shadow:0 0 5px 1px #c70019}80%{-webkit-box-shadow:0 0 0 0 #c70019;-moz-box-shadow:0 0 0 0 #c70019;box-shadow:0 0 0 0 #c70019}100%{-webkit-box-shadow:0 0 0 0 #c70019;-moz-box-shadow:0 0 0 0 #c70019;box-shadow:0 0 0 0 #c70019}}@-o-keyframes OT_pulse{0%{-webkit-box-shadow:0 0 0 0 #c70019;-moz-box-shadow:0 0 0 0 #c70019;box-shadow:0 0 0 0 #c70019}30%{-webkit-box-shadow:0 0 5px 1px #c70019;-moz-box-shadow:0 0 5px 1px #c70019;box-shadow:0 0 5px 1px #c70019}50%{-webkit-box-shadow:0 0 5px 1px #c70019;-moz-box-shadow:0 0 5px 1px #c70019;box-shadow:0 0 5px 1px #c70019}80%{-webkit-box-shadow:0 0 0 0 #c70019;-moz-box-shadow:0 0 0 0 #c70019;box-shadow:0 0 0 0 #c70019}100%{-webkit-box-shadow:0 0 0 0 #c70019;-moz-box-shadow:0 0 0 0 #c70019;box-shadow:0 0 0 0 #c70019}}@-ms-keyframes OT_pulse{0%{-webkit-box-shadow:0 0 0 0 #c70019;-moz-box-shadow:0 0 0 0 #c70019;box-shadow:0 0 0 0 #c70019}30%{-webkit-box-shadow:0 0 5px 1px #c70019;-moz-box-shadow:0 0 5px 1px #c70019;box-shadow:0 0 5px 1px #c70019}50%{-webkit-box-shadow:0 0 5px 1px #c70019;-moz-box-shadow:0 0 5px 1px #c70019;box-shadow:0 0 5px 1px #c70019}80%{-webkit-box-shadow:0 0 0 0 #c70019;-moz-box-shadow:0 0 0 0 #c70019;box-shadow:0 0 0 0 #c70019}100%{-webkit-box-shadow:0 0 0 0 #c70019;-moz-box-shadow:0 0 0 0 #c70019;box-shadow:0 0 0 0 #c70019}}@-webkit-keyframes OT_pulse{0%{-webkit-box-shadow:0 0 0 0 #c70019;-moz-box-shadow:0 0 0 0 #c70019;box-shadow:0 0 0 0 #c70019}30%{-webkit-box-shadow:0 0 5px 1px #c70019;-moz-box-shadow:0 0 5px 1px #c70019;box-shadow:0 0 5px 1px #c70019}50%{-webkit-box-shadow:0 0 5px 1px #c70019;-moz-box-shadow:0 0 5px 1px #c70019;box-shadow:0 0 5px 1px #c70019}80%{-webkit-box-shadow:0 0 0 0 #c70019;-moz-box-shadow:0 0 0 0 #c70019;box-shadow:0 0 0 0 #c70019}100%{-webkit-box-shadow:0 0 0 0 #c70019;-moz-box-shadow:0 0 0 0 #c70019;box-shadow:0 0 0 0 #c70019}}.OT_mini .OT_bar,.OT_bar.OT_mode-mini,.OT_bar.OT_mode-mini-auto{bottom:0;height:auto}.OT_mini .OT_name.OT_mode-off,.OT_mini .OT_name.OT_mode-on,.OT_mini .OT_name.OT_mode-auto,.OT_mini:hover .OT_name.OT_mode-auto{display:none}.OT_publisher .OT_name,.OT_subscriber .OT_name{left:24px;right:37px;height:34px}.OT_publisher .OT_name-no-bug,.OT_subscriber .OT_name-no-bug{left:10px;padding-left:0}.OT_publisher .OT_mute,.OT_subscriber .OT_mute,.OT_publisher .OT_opentok,.OT_subscriber .OT_opentok{border:0;cursor:pointer;display:block;position:absolute;text-align:center;text-indent:-9999em;background-color:transparent;background-repeat:no-repeat}.OT_publisher .OT_opentok,.OT_subscriber .OT_opentok{background:url(../images/rtc/buttons.png) 0 -32px no-repeat;cursor:default;height:18px;left:8px;line-height:18px;top:8px;width:16px}.OT_micro .OT_opentok{display:none!important}.OT_publisher .OT_mute,.OT_subscriber .OT_mute{right:0;top:0;border-left:1px solid rgba(255,255,255,0.2);height:36px;width:37px}.OT_mini .OT_mute,.OT_mute.OT_mode-mini,.OT_mute.OT_mode-mini-auto{top:50%;left:50%;right:auto;margin-top:-18px;margin-left:-18.5px;border-left:none}.OT_publisher .OT_mute{background-image:url(../images/rtc/mic-on.png);background-position:9px 5px}.OT_publisher .OT_mute.OT_active{background-image:url(../images/rtc/mic-off.png);background-position:9px 4px}.OT_subscriber .OT_mute{background-image:url(../images/rtc/speaker-on.png);background-position:8px 7px}.OT_subscriber .OT_mute.OT_active{background-image:url(../images/rtc/speaker-off.png);background-position:7px 7px}.OT_publisher .OT_edge-bar-item,.OT_subscriber .OT_edge-bar-item{-ms-transition-property:top,bottom,opacity;-ms-transition-duration:.5s;-moz-transition-property:top,bottom,opacity;-moz-transition-duration:.5s;-webkit-transition-property:top,bottom,opacity;-webkit-transition-duration:.5s;-o-transition-property:top,bottom,opacity;-o-transition-duration:.5s;transition-property:top,bottom,opacity;transition-duration:.5s;transition-timing-function:ease-in}.OT_publisher .OT_edge-bar-item.OT_mode-off,.OT_subscriber .OT_edge-bar-item.OT_mode-off,.OT_publisher .OT_edge-bar-item.OT_mode-auto,.OT_subscriber .OT_edge-bar-item.OT_mode-auto,.OT_publisher .OT_edge-bar-item.OT_mode-mini-auto,.OT_subscriber .OT_edge-bar-item.OT_mode-mini-auto{top:-25px;opacity:0}.OT_mini .OT_mute.OT_mode-auto,.OT_publisher .OT_mute.OT_mode-mini-auto,.OT_subscriber .OT_mute.OT_mode-mini-auto{top:50%}.OT_publisher .OT_edge-bar-item.OT_edge-bottom.OT_mode-off,.OT_subscriber .OT_edge-bar-item.OT_edge-bottom.OT_mode-off,.OT_publisher .OT_edge-bar-item.OT_edge-bottom.OT_mode-auto,.OT_subscriber .OT_edge-bar-item.OT_edge-bottom.OT_mode-auto,.OT_publisher .OT_edge-bar-item.OT_edge-bottom.OT_mode-mini-auto,.OT_subscriber .OT_edge-bar-item.OT_edge-bottom.OT_mode-mini-auto{top:auto;bottom:-25px}.OT_publisher .OT_edge-bar-item.OT_mode-on,.OT_subscriber .OT_edge-bar-item.OT_mode-on,.OT_publisher:hover .OT_edge-bar-item.OT_mode-auto,.OT_subscriber:hover .OT_edge-bar-item.OT_mode-auto,.OT_publisher:hover .OT_edge-bar-item.OT_mode-mini-auto,.OT_subscriber:hover .OT_edge-bar-item.OT_mode-mini-auto{top:0;opacity:1}.OT_mini .OT_mute.OT_mode-on,.OT_mini:hover .OT_mute.OT_mode-auto,.OT_mute.OT_mode-mini,.OT_root:hover .OT_mute.OT_mode-mini-auto{top:50%}.OT_publisher .OT_edge-bar-item.OT_edge-bottom.OT_mode-on,.OT_subscriber .OT_edge-bar-item.OT_edge-bottom.OT_mode-on,.OT_publisher:hover .OT_edge-bar-item.OT_edge-bottom.OT_mode-auto,.OT_subscriber:hover .OT_edge-bar-item.OT_edge-bottom.OT_mode-auto{top:auto;bottom:0;opacity:1}.OT_publisher .OT_opentok.OT_mode-off,.OT_publisher .OT_opentok.OT_mode-auto,.OT_subscriber .OT_opentok.OT_mode-off,.OT_subscriber .OT_opentok.OT_mode-auto{top:-17px}.OT_publisher .OT_opentok.OT_mode-on,.OT_publisher:hover .OT_opentok.OT_mode-auto,.OT_subscriber .OT_opentok.OT_mode-on,.OT_subscriber:hover .OT_opentok.OT_mode-auto{top:8px}.OT_video-container{position:absolute;background-color:#000;overflow:hidden}.OT_hidden-audio{position:absolute!important;height:1px!important;width:1px!important}.OT_root .OT_video-loading{background:url('../images/rtc/loader.gif') no-repeat;display:none;position:absolute;width:32px;height:32px;left:50%;top:50%;margin-left:-16px;margin-top:-16px}.OT_publisher.OT_loading .OT_video-loading,.OT_subscriber.OT_loading .OT_video-loading{display:block}.OT_publisher.OT_loading video,.OT_subscriber.OT_loading video{display:none}.OT_video-poster{width:100%;height:100%;background-position:50% 50%;background-repeat:no-repeat;display:none}.OT_publisher .OT_video-poster{background-image:url(../images/rtc/audioonly-publisher.png)}.OT_subscriber .OT_video-poster{background-image:url(../images/rtc/audioonly-subscriber.png)}
+.OT_root h1,
+.OT_root h2,
+.OT_root h3,
+.OT_root h4,
+.OT_root h5,
+.OT_root h6 {
+    color: #ffffff;
+    font-family: Arial, Helvetica, sans-serif;
+    font-size: 100%;
+    font-weight: bold;
+}
+
+.OT_root header {
+
+}
+
+.OT_root footer {
+
+}
+
+.OT_root div {
+
+}
+
+.OT_root section {
+
+}
+
+.OT_root video {
+
+}
+
+.OT_root button {
+
+}
+
+.OT_root strong {
+    font-weight: bold;
+}
+
+.OT_root em {
+    font-style: italic;
+}
+
+.OT_root a,
+.OT_root a:link,
+.OT_root a:visited,
+.OT_root a:hover,
+.OT_root a:active {
+    font-family: Arial, Helvetica, sans-serif;
+}
+
+
+.OT_root ul, .OT_root ol {
+    margin: 1em 1em 1em 2em;
+}
+
+.OT_root ol {
+    list-style: decimal outside;
+}
+
+.OT_root ul {
+    list-style: disc outside;
+}
+
+.OT_root dl {
+    margin: 4px;
+}
+    .OT_root dl dt,
+    .OT_root dl dd {
+        float: left;
+        margin: 0;
+        padding: 0;
+    }
+
+    .OT_root dl dt {
+        clear: left;
+        text-align: right;
+        width: 50px;
+    }
+    .OT_root dl dd {
+        margin-left: 10px;
+    }
+
+.OT_root img {
+    border: 0 none;
+}
+
+
+/* Modal dialog styles */
+
+/* Modal dialog styles */
+
+.OT_dialog {
+  border: none;
+  border-radius: 0;
+  top: 50%;
+  left: 50%;
+  position: absolute;
+  position: fixed;
+  padding: 0;
+  background-color: #363636;
+  color: #fff;
+  z-index: 9999;
+  box-shadow: 2px 4px 6px #999;
+  font-family: 'Didact Gothic', sans-serif;
+}
+
+.OT_dialog-blackout {
+  position: absolute;
+  position: fixed;
+  top: 0;
+  right: 0;
+  bottom: 0;
+  left: 0;
+  background-color: #363636;
+}
+
+.OT_dialog-blackout .OT_dialog {
+  box-shadow: 0 0 0 transparent;
+}
+
+.OT_dialog * {
+  font-family: 'Didact Gothic', sans-serif;
+}
+
+.OT_dialog-plugin-prompt {
+  margin-left: -350px;
+  margin-top: -141px;
+  width: 650px;
+  height: 282px;
+}
+
+.OT_dialog-plugin-reinstall {
+  margin-left: -271px;
+  margin-top: -117px;
+  width: 542px;
+  height: 234px;
+}
+
+.OT_dialog-plugin-upgrading {
+  margin-left: -267px;
+  margin-top: -94px;
+  width: 514px;
+  height: 188px;
+}
+
+.OT_dialog-allow-deny-chrome-first {
+  margin-left: -227px;
+  margin-top: -122px;
+  width: 453px;
+  height: 244px;
+}
+
+.OT_dialog-allow-deny-chrome-pre-denied {
+  margin-left: -263px;
+  margin-top: -135px;
+  width: 526px;
+  height: 270px;
+}
+
+.OT_dialog-allow-deny-chrome-now-denied {
+  margin-left: -120px;
+  margin-top: -85px;
+  width: 256px;
+  height: 170px;
+}
+
+.OT_dialog-allow-deny-firefox-denied {
+  margin-left: -160px;
+  margin-top: -105px;
+  width: 320px;
+  height: 190px;
+}
+
+.OT_dialog-allow-deny-firefox-maybe-denied {
+  margin-left: -281px;
+  margin-top: -126px;
+  width: 562px;
+  height: 252px;
+}
+
+.OT_dialog-allow-highlight-chrome {
+  display: inline-block;
+  margin-top: 20px;
+  width: 227px;
+  height: 94px;
+  background-image: url(../images/rtc/access-prompt-chrome.png);
+}
+
+.OT_closeButton {
+  top: 15px;
+right: 15px;
+position: absolute;
+  font-size: 18px;
+  cursor: pointer;
+}
+
+.OT_dialog-messages {
+  position: absolute;
+  top: 32px;
+  left: 32px;
+  right: 32px;
+  text-align: center;
+}
+
+.OT_dialog-allow-deny-firefox-maybe-denied .OT_dialog-messages {
+  top: 45px;
+}
+
+.OT_dialog-messages-main {
+  font-weight: 300;
+  font-size: 18pt;
+  line-height: 24px;
+}
+
+.OT_dialog-messages-minor {
+  font-weight: 300;
+  margin-top: 12px;
+  font-size: 13px;
+  line-height: 18px;
+  color: #A4A4A4;
+}
+
+.OT_dialog-allow-deny-firefox-maybe-denied .OT_dialog-messages-minor {
+  margin-top: 4px;
+}
+
+.OT_dialog-messages-minor strong {
+  font-weight: 300;
+  color: #ffffff;
+}
+
+.OT_dialog-single-button {
+  position: absolute;
+  bottom: 41px;
+  left: 50%;
+  margin-left: -97px;
+  height: 47px;
+  width: 193px;
+}
+
+.OT_dialog-button-pair {
+  position: absolute;
+  bottom: 45px;
+  left: 5px;
+  right: 0;
+  height: 94px;
+}
+
+.OT_dialog-button-with-title {
+  padding-left: 30px;
+  padding-right: 30px;
+  width: 260px;
+  float: left;
+}
+
+.OT_dialog-button-pair-seperator {
+  border-right: 1px solid #555555;
+  height: 112px;
+  width: 1px;
+  float: left;
+}
+
+.OT_dialog-button-title {
+  font-weight: 300;
+  text-align: center;
+  margin-bottom: 15px;
+  font-size: 12px;
+  line-height: 150%;
+  color: #A4A4A4;
+}
+
+
+.OT_dialog-button-title strong {
+  color: #ffffff;
+  font-weight: 100;
+  display: block;
+}
+
+.OT_dialog-button {
+  font-weight: 100;
+  display: block;
+  line-height: 50px;
+  height: 47px;
+  background-color: #29A4DA;
+  text-align: center;
+  font-size: 16pt;
+  cursor: pointer;
+}
+
+.OT_dialog-button.OT_dialog-button-large {
+  line-height: 60px;
+  height: 58px;
+}
+
+.OT_dialog-progress-bar {
+  border: 1px solid #4E4E4E;
+  height: 8px;
+}
+
+.OT_dialog-progress-bar-fill {
+  background-color: #29A4DA;
+  height: 10px;
+  margin-top: -1px;
+  margin-left: -1px;
+  margin-right: -1px;
+}
+
+.OT_dialog-plugin-upgrading .OT_dialog-plugin-upgrade-percentage {
+  font-size: 36pt;
+  font-weight: 100;
+}
+
+.OT_dialog-plugin-upgrading .OT_dialog-progress-bar {
+  margin-top: 25px;
+  margin-bottom: 25px;
+}
+
+.OT_dialog-3steps {
+  margin-top: 24px;
+}
+
+.OT_dialog-allow-deny-firefox-maybe-denied .OT_dialog-3steps {
+  margin-top: 21px;
+}
+
+.OT_dialog-3steps-step {
+  float: left;
+  -moz-box-sizing: border-box;
+       box-sizing: border-box;
+  width: 33%;
+  height: 140px;
+  padding: 0 10px;
+  color: #A4A4A4;
+}
+
+.OT_dialog-3steps-seperator {
+  float: left;
+  -moz-box-sizing: border-box;
+       box-sizing: border-box;
+  margin-top: 10px;
+  width: 1px;
+  height: 68px;
+  background-color: #555555;
+}
+
+.OT_dialog-allow-deny-chrome-pre-denied .OT_dialog-3steps-seperator {
+  margin-top: 16px;
+}
+
+.OT_dialog-3steps-step-num {
+  font-size: 20px;
+  background-color: #2AA3D8;
+  border-radius: 20px;
+  line-height: 33px;
+  height: 33px;
+  width: 33px;
+  margin: 0 auto 17px;
+}
+
+.OT_dialog-allow-deny-chrome-pre-denied .OT_dialog-3steps-step-num {
+  margin-bottom: 10px;
+}
+
+.OT_dialog-allow-camera-icon {
+  background-color: #000;
+  width: 113px;
+  height: 48px;
+  margin: 10px auto 0;
+  background-image: url(../images/rtc/access-predenied-chrome.png);
+}
+
+/* Publisher Deny Helpers */
+
+.OT_publisher-denied-firefox {
+  background-color: #fff;
+}
+
+.OT_publisher-denied-firefox p {
+  width: 232px;
+  height: 103px;
+  top: 50%;
+  left: 50%;
+  display: block;
+  position: absolute;
+  margin-top: -52px;
+  margin-left: -116px;
+  background-image: url(../images/rtc/access-denied-firefox.png);
+  background-position: 50% 0;
+  background-repeat: no-repeat;
+}
+
+.OT_publisher-denied-firefox span {
+  display: block;
+  position: absolute;
+  bottom: 0;
+  right: 0;
+  left: 0;
+  margin: 0 auto;
+  width: 232px;
+  height: 31px;
+  background-image: url(../images/rtc/access-denied-copy-firefox.png);
+  text-indent: 100%;
+  white-space: nowrap;
+  overflow: hidden;
+}
+
+.OT_centered {
+	position: fixed;
+	left: 50%;
+	top: 50%;
+	margin: 0;
+}
+
+/* Publisher and Subscriber styles */
+
+.OT_publisher, .OT_subscriber {
+    position: relative;
+    min-width: 48px;
+    min-height: 48px;
+}
+
+.OT_publisher video,
+.OT_subscriber video {
+    width: 100%;
+    height: 100%;
+}
+
+/* Styles that are applied when the video element should be mirrored */
+.OT_publisher.OT_mirrored video{
+    -webkit-transform: scale(-1, 1);
+    -moz-transform:scale(-1,1);
+}
+
+.OT_subscriber_error {
+		background-color: #000;
+		color: #fff;
+		text-align: center;
+}
+
+.OT_subscriber_error > p {
+		padding: 20px;
+}
+
+/* The publisher/subscriber name/mute background */
+.OT_publisher .OT_bar,
+.OT_subscriber .OT_bar,
+.OT_publisher .OT_name,
+.OT_subscriber .OT_name,
+.OT_publisher .OT_archiving,
+.OT_subscriber .OT_archiving,
+.OT_publisher .OT_archiving-status,
+.OT_subscriber .OT_archiving-status,
+.OT_publihser .OT_archiving-light-box,
+.OT_subscriber .OT_archiving-light-box {
+   -moz-box-sizing: border-box;
+   -webkit-box-sizing: border-box;
+   -ms-box-sizing: border-box;
+    box-sizing: border-box;
+    top: 0;
+    left: 0;
+    right: 0;
+    display: block;
+    height: 34px;
+    position: absolute;
+}
+
+.OT_publisher .OT_bar,
+.OT_subscriber .OT_bar {
+    background: rgba(0, 0, 0, 0.4);
+}
+
+/* The publisher/subscriber name panel/archiving status bar */
+.OT_publisher .OT_name,
+.OT_subscriber .OT_name {
+    background-color: transparent;
+    color: #ffffff;
+    font-size: 15px;
+    line-height: 34px;
+    font-weight: normal;
+    padding: 0 4px 0 36px;
+}
+
+.OT_publisher .OT_archiving-status,
+.OT_subscriber .OT_archiving-status {
+    background: rgba(0, 0, 0, 0.4);
+    top: auto;
+    bottom: 0;
+    left: 34px;
+    padding: 0 4px;
+    color: rgba(255,255,255,0.8);
+    font-size: 15px;
+    line-height: 34px;
+    font-weight: normal;
+}
+
+.OT_micro .OT_archiving-status,
+.OT_micro:hover .OT_archiving-status,
+.OT_mini .OT_archiving-status,
+.OT_mini:hover .OT_archiving-status {
+    display: none;
+}
+
+.OT_publisher .OT_archiving-light-box,
+.OT_subscriber .OT_archiving-light-box {
+    background: rgba(0, 0, 0, 0.4);
+    top: auto;
+    bottom: 0;
+    right: auto;
+    width: 34px;
+    height: 34px;    
+}
+
+.OT_archiving-light {
+  width: 7px;
+  height: 7px;
+  -webkit-border-radius: 30px;
+  -moz-border-radius: 30px;
+  border-radius: 30px;
+  position: absolute;
+  top: 14px;
+  left: 14px;
+  background-color: #575757;
+  -webkit-box-shadow: 0 0 5px 1px #575757;
+  -moz-box-shadow: 0 0 5px 1px #575757;
+  box-shadow: 0 0 5px 1px #575757;
+}
+.OT_archiving-light.OT_active {
+  background-color: #970d13;
+  -webkit-animation: OT_pulse 1.3s ease-in;
+  -moz-animation: OT_pulse 1.3s ease-in;
+  -webkit-animation: OT_pulse 1.3s ease-in;
+  -webkit-animation-iteration-count: infinite;
+  -moz-animation-iteration-count: infinite;
+  -webkit-animation-iteration-count: infinite;
+}
+@-moz-keyframes OT_pulse {
+  0% {
+    -webkit-box-shadow: 0 0 0px 0px #c70019;
+    -moz-box-shadow: 0 0 0px 0px #c70019;
+    box-shadow: 0 0 0px 0px #c70019;
+  }
+
+  30% {
+    -webkit-box-shadow: 0 0 5px 1px #c70019;
+    -moz-box-shadow: 0 0 5px 1px #c70019;
+    box-shadow: 0 0 5px 1px #c70019;
+  }
+
+  50% {
+    -webkit-box-shadow: 0 0 5px 1px #c70019;
+    -moz-box-shadow: 0 0 5px 1px #c70019;
+    box-shadow: 0 0 5px 1px #c70019;
+  }
+
+  80% {
+    -webkit-box-shadow: 0 0 0px 0px #c70019;
+    -moz-box-shadow: 0 0 0px 0px #c70019;
+    box-shadow: 0 0 0px 0px #c70019;
+  }
+
+  100% {
+    -webkit-box-shadow: 0 0 0px 0px #c70019;
+    -moz-box-shadow: 0 0 0px 0px #c70019;
+    box-shadow: 0 0 0px 0px #c70019;
+  }
+}
+@-webkit-keyframes OT_pulse {
+  0% {
+    -webkit-box-shadow: 0 0 0px 0px #c70019;
+    -moz-box-shadow: 0 0 0px 0px #c70019;
+    box-shadow: 0 0 0px 0px #c70019;
+  }
+
+  30% {
+    -webkit-box-shadow: 0 0 5px 1px #c70019;
+    -moz-box-shadow: 0 0 5px 1px #c70019;
+    box-shadow: 0 0 5px 1px #c70019;
+  }
+
+  50% {
+    -webkit-box-shadow: 0 0 5px 1px #c70019;
+    -moz-box-shadow: 0 0 5px 1px #c70019;
+    box-shadow: 0 0 5px 1px #c70019;
+  }
+
+  80% {
+    -webkit-box-shadow: 0 0 0px 0px #c70019;
+    -moz-box-shadow: 0 0 0px 0px #c70019;
+    box-shadow: 0 0 0px 0px #c70019;
+  }
+
+  100% {
+    -webkit-box-shadow: 0 0 0px 0px #c70019;
+    -moz-box-shadow: 0 0 0px 0px #c70019;
+    box-shadow: 0 0 0px 0px #c70019;
+  }
+}
+@-o-keyframes OT_pulse {
+  0% {
+    -webkit-box-shadow: 0 0 0px 0px #c70019;
+    -moz-box-shadow: 0 0 0px 0px #c70019;
+    box-shadow: 0 0 0px 0px #c70019;
+  }
+
+  30% {
+    -webkit-box-shadow: 0 0 5px 1px #c70019;
+    -moz-box-shadow: 0 0 5px 1px #c70019;
+    box-shadow: 0 0 5px 1px #c70019;
+  }
+
+  50% {
+    -webkit-box-shadow: 0 0 5px 1px #c70019;
+    -moz-box-shadow: 0 0 5px 1px #c70019;
+    box-shadow: 0 0 5px 1px #c70019;
+  }
+
+  80% {
+    -webkit-box-shadow: 0 0 0px 0px #c70019;
+    -moz-box-shadow: 0 0 0px 0px #c70019;
+    box-shadow: 0 0 0px 0px #c70019;
+  }
+
+  100% {
+    -webkit-box-shadow: 0 0 0px 0px #c70019;
+    -moz-box-shadow: 0 0 0px 0px #c70019;
+    box-shadow: 0 0 0px 0px #c70019;
+  }
+}
+@-ms-keyframes OT_pulse {
+  0% {
+    -webkit-box-shadow: 0 0 0px 0px #c70019;
+    -moz-box-shadow: 0 0 0px 0px #c70019;
+    box-shadow: 0 0 0px 0px #c70019;
+  }
+
+  30% {
+    -webkit-box-shadow: 0 0 5px 1px #c70019;
+    -moz-box-shadow: 0 0 5px 1px #c70019;
+    box-shadow: 0 0 5px 1px #c70019;
+  }
+
+  50% {
+    -webkit-box-shadow: 0 0 5px 1px #c70019;
+    -moz-box-shadow: 0 0 5px 1px #c70019;
+    box-shadow: 0 0 5px 1px #c70019;
+  }
+
+  80% {
+    -webkit-box-shadow: 0 0 0px 0px #c70019;
+    -moz-box-shadow: 0 0 0px 0px #c70019;
+    box-shadow: 0 0 0px 0px #c70019;
+  }
+
+  100% {
+    -webkit-box-shadow: 0 0 0px 0px #c70019;
+    -moz-box-shadow: 0 0 0px 0px #c70019;
+    box-shadow: 0 0 0px 0px #c70019;
+  }
+}
+@-webkit-keyframes OT_pulse {
+  0% {
+    -webkit-box-shadow: 0 0 0px 0px #c70019;
+    -moz-box-shadow: 0 0 0px 0px #c70019;
+    box-shadow: 0 0 0px 0px #c70019;
+  }
+
+  30% {
+    -webkit-box-shadow: 0 0 5px 1px #c70019;
+    -moz-box-shadow: 0 0 5px 1px #c70019;
+    box-shadow: 0 0 5px 1px #c70019;
+  }
+
+  50% {
+    -webkit-box-shadow: 0 0 5px 1px #c70019;
+    -moz-box-shadow: 0 0 5px 1px #c70019;
+    box-shadow: 0 0 5px 1px #c70019;
+  }
+
+  80% {
+    -webkit-box-shadow: 0 0 0px 0px #c70019;
+    -moz-box-shadow: 0 0 0px 0px #c70019;
+    box-shadow: 0 0 0px 0px #c70019;
+  }
+
+  100% {
+    -webkit-box-shadow: 0 0 0px 0px #c70019;
+    -moz-box-shadow: 0 0 0px 0px #c70019;
+    box-shadow: 0 0 0px 0px #c70019;
+  }
+}
+
+.OT_mini .OT_bar,
+.OT_bar.OT_mode-mini,
+.OT_bar.OT_mode-mini-auto {
+    bottom: 0;
+    height: auto;    
+}
+
+.OT_mini .OT_name.OT_mode-off,
+.OT_mini .OT_name.OT_mode-on,
+.OT_mini .OT_name.OT_mode-auto,
+.OT_mini:hover .OT_name.OT_mode-auto {
+    display: none;
+}
+
+.OT_publisher .OT_name,
+.OT_subscriber .OT_name {
+    left: 24px;
+    right: 37px;
+    height: 34px;
+}
+
+.OT_publisher .OT_name-no-bug,
+.OT_subscriber .OT_name-no-bug {
+    left: 10px;
+    padding-left: 0;
+}
+
+.OT_publisher .OT_mute,
+.OT_subscriber .OT_mute,
+.OT_publisher .OT_opentok,
+.OT_subscriber .OT_opentok {
+    border: none;
+    cursor: pointer;
+    display: block;
+    position: absolute;
+    text-align: center;
+    text-indent: -9999em;
+    background-color: transparent;
+    background-repeat: no-repeat;
+}
+
+.OT_publisher .OT_opentok,
+.OT_subscriber .OT_opentok {
+    background: url(../images/rtc/buttons.png) 0 -32px no-repeat;    
+    cursor: default;
+    height: 18px;
+    left: 8px;
+    line-height: 18px;
+    top: 8px;
+    width: 16px;
+}
+
+.OT_micro .OT_opentok {
+    display: none !important;
+}
+
+.OT_publisher .OT_mute,
+.OT_subscriber .OT_mute {
+    right: 0;
+    top: 0;
+    border-left: 1px solid rgba(255, 255, 255, 0.2);
+    height: 36px;
+    width: 37px;
+}
+
+.OT_mini .OT_mute,
+.OT_mute.OT_mode-mini,
+.OT_mute.OT_mode-mini-auto {
+    top: 50%;
+    left: 50%;
+    right: auto;
+    margin-top: -18px;
+    margin-left: -18.5px;
+    border-left: none;
+}
+
+.OT_publisher .OT_mute {
+    background-image: url(../images/rtc/mic-on.png);
+    background-position: 9px 5px;
+}
+
+.OT_publisher .OT_mute.OT_active {
+    background-image: url(../images/rtc/mic-off.png);
+    background-position: 9px 4px;
+}
+
+.OT_subscriber .OT_mute {
+    background-image: url(../images/rtc/speaker-on.png);
+    background-position: 8px 7px;
+}
+
+.OT_subscriber .OT_mute.OT_active {
+    background-image: url(../images/rtc/speaker-off.png);
+    background-position: 7px 7px;
+}
+
+/* Disabling this for now - see https://jira.tokbox.com/browse/OPENTOK-8870
+.OT_publisher .OT_opentok:hover:after,
+.OT_subscriber .OT_opentok:hover:after {
+    content: 'tokbox';
+    color: #fff;
+    font-weight: bold;
+    font-size: 14px;
+    letter-spacing: -1px;
+    top: 20px;
+    opacity: 0.5;
+    position: absolute;
+    text-indent: 0;
+    top: 0;
+}*/
+
+/**
+ * Styles for display modes
+ *
+ * Note: It's important that these completely control the display and opacity
+ * attributes, no other selectors should atempt to change them.
+ */
+
+/* Default display mode transitions for various chrome elements */
+.OT_publisher .OT_edge-bar-item,
+.OT_subscriber .OT_edge-bar-item {
+    -ms-transition-property: top, bottom, opacity;
+    -ms-transition-duration: 0.5s;
+    -moz-transition-property: top, bottom, opacity;
+    -moz-transition-duration: 0.5s;
+    -webkit-transition-property: top, bottom, opacity;
+    -webkit-transition-duration: 0.5s;
+    -o-transition-property: top, bottom, opacity;
+    -o-transition-duration: 0.5s;
+    transition-property: top, bottom, opacity;
+    transition-duration: 0.5s;
+    transition-timing-function: ease-in;
+}
+
+.OT_publisher .OT_edge-bar-item.OT_mode-off,
+.OT_subscriber .OT_edge-bar-item.OT_mode-off,
+.OT_publisher .OT_edge-bar-item.OT_mode-auto,
+.OT_subscriber .OT_edge-bar-item.OT_mode-auto,
+.OT_publisher .OT_edge-bar-item.OT_mode-mini-auto,
+.OT_subscriber .OT_edge-bar-item.OT_mode-mini-auto {
+    top: -25px;
+    opacity: 0;
+}
+
+.OT_mini .OT_mute.OT_mode-auto,
+.OT_publisher .OT_mute.OT_mode-mini-auto,
+.OT_subscriber .OT_mute.OT_mode-mini-auto {
+    top: 50%;
+}
+
+.OT_publisher .OT_edge-bar-item.OT_edge-bottom.OT_mode-off,
+.OT_subscriber .OT_edge-bar-item.OT_edge-bottom.OT_mode-off,
+.OT_publisher .OT_edge-bar-item.OT_edge-bottom.OT_mode-auto,
+.OT_subscriber .OT_edge-bar-item.OT_edge-bottom.OT_mode-auto,
+.OT_publisher .OT_edge-bar-item.OT_edge-bottom.OT_mode-mini-auto,
+.OT_subscriber .OT_edge-bar-item.OT_edge-bottom.OT_mode-mini-auto {
+    top: auto;
+    bottom: -25px;
+}
+
+.OT_publisher .OT_edge-bar-item.OT_mode-on,
+.OT_subscriber .OT_edge-bar-item.OT_mode-on,
+.OT_publisher:hover .OT_edge-bar-item.OT_mode-auto,
+.OT_subscriber:hover .OT_edge-bar-item.OT_mode-auto,
+.OT_publisher:hover .OT_edge-bar-item.OT_mode-mini-auto,
+.OT_subscriber:hover .OT_edge-bar-item.OT_mode-mini-auto {
+    top: 0;
+    opacity: 1;
+}
+
+.OT_mini .OT_mute.OT_mode-on,
+.OT_mini:hover .OT_mute.OT_mode-auto,
+.OT_mute.OT_mode-mini,
+.OT_root:hover .OT_mute.OT_mode-mini-auto  {
+    top: 50%;
+}
+
+.OT_publisher .OT_edge-bar-item.OT_edge-bottom.OT_mode-on,
+.OT_subscriber .OT_edge-bar-item.OT_edge-bottom.OT_mode-on,
+.OT_publisher:hover .OT_edge-bar-item.OT_edge-bottom.OT_mode-auto,
+.OT_subscriber:hover .OT_edge-bar-item.OT_edge-bottom.OT_mode-auto {
+    top: auto;
+    bottom: 0;
+    opacity: 1;
+}
+
+.OT_publisher .OT_opentok.OT_mode-off,
+.OT_publisher .OT_opentok.OT_mode-auto,
+.OT_subscriber .OT_opentok.OT_mode-off,
+.OT_subscriber .OT_opentok.OT_mode-auto  {
+    top: -17px;
+}
+
+.OT_publisher .OT_opentok.OT_mode-on,
+.OT_publisher:hover .OT_opentok.OT_mode-auto,
+.OT_subscriber .OT_opentok.OT_mode-on,
+.OT_subscriber:hover .OT_opentok.OT_mode-auto {
+    top: 8px;
+}
+
+
+/* Contains the video element, used to fix video letter-boxing */
+.OT_video-container {
+    position: absolute;
+    background-color: #000000;
+    overflow: hidden;
+}
+
+.OT_hidden-audio {
+    position: absolute !important;
+    height: 1px !important;
+    width: 1px !important;
+}
+
+/* Load animation */
+.OT_root .OT_video-loading {
+    background: url('../images/rtc/loader.gif') no-repeat;
+    display:none;
+    position: absolute;
+    width: 32px;
+    height: 32px;
+    left: 50%;
+    top: 50%;
+    margin-left: -16px;
+    margin-top: -16px;
+}
+
+.OT_publisher.OT_loading .OT_video-loading,
+.OT_subscriber.OT_loading .OT_video-loading {
+    display: block;
+}
+
+.OT_publisher.OT_loading video,
+.OT_subscriber.OT_loading video {
+    display: none;
+}
+
+
+.OT_video-poster {
+    width: 100%;
+    height: 100%;
+    background-position: 50% 50%;
+    background-repeat: no-repeat;
+    display: none;
+}
+
+.OT_publisher .OT_video-poster {
+    background-image: url(../images/rtc/audioonly-publisher.png);    
+}
+
+.OT_subscriber .OT_video-poster  {
+    background-image: url(../images/rtc/audioonly-subscriber.png);
+}
rename from browser/components/loop/content/libs/otcdn/webrtc/v2.2.5/images/rtc/access-denied-chrome.png
rename to browser/components/loop/content/libs/sdk-content/images/rtc/access-denied-chrome.png
rename from browser/components/loop/content/libs/otcdn/webrtc/v2.2.5/images/rtc/access-denied-copy-firefox.png
rename to browser/components/loop/content/libs/sdk-content/images/rtc/access-denied-copy-firefox.png
rename from browser/components/loop/content/libs/otcdn/webrtc/v2.2.5/images/rtc/access-denied-firefox.png
rename to browser/components/loop/content/libs/sdk-content/images/rtc/access-denied-firefox.png
rename from browser/components/loop/content/libs/otcdn/webrtc/v2.2.5/images/rtc/access-predenied-chrome.png
rename to browser/components/loop/content/libs/sdk-content/images/rtc/access-predenied-chrome.png
rename from browser/components/loop/content/libs/otcdn/webrtc/v2.2.5/images/rtc/access-prompt-chrome.png
rename to browser/components/loop/content/libs/sdk-content/images/rtc/access-prompt-chrome.png
rename from browser/components/loop/content/libs/otcdn/webrtc/v2.2.5/images/rtc/audioonly-publisher.png
rename to browser/components/loop/content/libs/sdk-content/images/rtc/audioonly-publisher.png
rename from browser/components/loop/content/libs/otcdn/webrtc/v2.2.5/images/rtc/audioonly-subscriber.png
rename to browser/components/loop/content/libs/sdk-content/images/rtc/audioonly-subscriber.png
rename from browser/components/loop/content/libs/otcdn/webrtc/v2.2.5/images/rtc/buttons.png
rename to browser/components/loop/content/libs/sdk-content/images/rtc/buttons.png
rename from browser/components/loop/content/libs/otcdn/webrtc/v2.2.5/images/rtc/loader.gif
rename to browser/components/loop/content/libs/sdk-content/images/rtc/loader.gif
rename from browser/components/loop/content/libs/otcdn/webrtc/v2.2.5/images/rtc/mic-off.png
rename to browser/components/loop/content/libs/sdk-content/images/rtc/mic-off.png
rename from browser/components/loop/content/libs/otcdn/webrtc/v2.2.5/images/rtc/mic-on.png
rename to browser/components/loop/content/libs/sdk-content/images/rtc/mic-on.png
rename from browser/components/loop/content/libs/otcdn/webrtc/v2.2.5/images/rtc/speaker-off.png
rename to browser/components/loop/content/libs/sdk-content/images/rtc/speaker-off.png
rename from browser/components/loop/content/libs/otcdn/webrtc/v2.2.5/images/rtc/speaker-on.png
rename to browser/components/loop/content/libs/sdk-content/images/rtc/speaker-on.png
rename from browser/components/loop/content/libs/otcdn/webrtc/v2.2.5/js/dynamic_config.min.js
rename to browser/components/loop/content/libs/sdk-content/js/dynamic_config.min.js
--- a/browser/components/loop/content/libs/otcdn/webrtc/v2.2.5/js/dynamic_config.min.js
+++ b/browser/components/loop/content/libs/sdk-content/js/dynamic_config.min.js
@@ -1,28 +1,7 @@
-/**
- * @license  OpenTok JavaScript Library v2.2.5
- * http://www.tokbox.com/
- *
- * Copyright (c) 2014 TokBox, Inc.
- * Released under the MIT license
- * http://opensource.org/licenses/MIT
- *
- * Date: May 22 07:14:18 2014
- */
+/*
 
-!(function() {
-  TB.Config.replaceWith({
-    global: {
-      exceptionLogging: {
-        enabled: true,
-        messageLimitPerPartner: 100
-      },
-
-      iceServers: {
-        enabled: false
-      },
-    },
-
-    partners: {
-    }
-  });
-})(TB);
+ Copyright (c) 2014 TokBox, Inc.
+ Released under the MIT license
+ http://opensource.org/licenses/MIT
+*/
+!function(){TB.Config.replaceWith({global:{exceptionLogging:{enabled:!0,messageLimitPerPartner:100},iceServers:{enabled:!1},instrumentation:{enabled:!1,debugging:!1},tokshow:{textchat:!0}},partners:{change878:{instrumentation:{enabled:!0,debugging:!0}}}})}(TB);
\ No newline at end of file
--- a/browser/components/loop/content/libs/sdk.js
+++ b/browser/components/loop/content/libs/sdk.js
@@ -1,51 +1,47 @@
 /**
- * @license  OpenTok JavaScript Library v2.2.5
+ * @license  OpenTok JavaScript Library v2.2.6
  * http://www.tokbox.com/
  *
  * Copyright (c) 2014 TokBox, Inc.
  * Released under the MIT license
  * http://opensource.org/licenses/MIT
  *
- * Date: May 22 07:14:18 2014
+ * Date: June 24 11:09:07 2014
  */
 
 (function(window) {
   if (!window.OT) window.OT = {};
 
   OT.properties = {
-    version: 'v2.2.5',         // The current version (eg. v2.0.4) (This is replaced by gradle)
-    build: '12d9384',    // The current build hash (This is replaced by gradle)
+    version: 'v2.2.6',         // The current version (eg. v2.0.4) (This is replaced by gradle)
+    build: 'd326ad1',    // The current build hash (This is replaced by gradle)
 
     // Whether or not to turn on debug logging by default
     debug: 'false',
     // The URL of the tokbox website
     websiteURL: 'http://www.tokbox.com',
 
     // The URL of the CDN
-    // XXX: patched for loop so we use local files
-    cdnURL: 'loop/otcdn',
+    cdnURL: 'http://static.opentok.com',
     // The URL to use for logging
     loggingURL: 'https://hlg.tokbox.com/prod',
     // The anvil API URL
-    apiURL: 'https://anvil.opentok.com',
+    apiURL: 'http://anvil.opentok.com',
 
     // What protocol to use when connecting to the rumor web socket
     messagingProtocol: 'wss',
     // What port to use when connection to the rumor web socket
     messagingPort: 443,
 
     // If this environment supports SSL
     supportSSL: 'true',
     // The CDN to use if we're using SSL
-    // XXX: patched for loop so we use local files
-    cdnURLSSL: 'loop/otcdn',
-    // The loggging URL to use if we're using SSL
-    loggingURLSSL: 'https://hlg.tokbox.com/prod',
+    cdnURLSSL: 'https://static.opentok.com',
     // The anvil API URL to use if we're using SSL
     apiURLSSL: 'https://anvil.opentok.com',
 
     minimumVersion: {
       firefox: parseFloat('26'),
       chrome: parseFloat('32')
     }
   };
@@ -2881,16 +2877,19 @@ OTHelpers.centerElement = function(eleme
   // REMOVE THIS POST IE MERGE
 
   OT.$.defineGetters = function(self, getters, enumerable) {
     var propsDefinition = {};
 
     if (enumerable === void 0) enumerable = false;
 
     for (var key in getters) {
+      if(!getters.hasOwnProperty(key)) {
+        continue;
+      }
       propsDefinition[key] = {
         get: getters[key],
         enumerable: enumerable
       };
     }
 
     Object.defineProperties(self, propsDefinition);
   };
@@ -3013,23 +3012,30 @@ OTHelpers.centerElement = function(eleme
     var props = OT.$.clone(properties);
 
     props.debug = properties.debug === 'true' || properties.debug === true;
     props.supportSSL = properties.supportSSL === 'true' || properties.supportSSL === true;
 
     if (props.supportSSL && (window.location.protocol.indexOf('https') >= 0 ||
       window.location.protocol.indexOf('chrome-extension') >= 0)) {
       props.assetURL = props.cdnURLSSL + '/webrtc/' + props.version;
-      props.loggingURL = props.loggingURLSSL;
     } else {
       props.assetURL = props.cdnURL + '/webrtc/' + props.version;
     }
 
     props.configURL = props.assetURL + '/js/dynamic_config.min.js';
     props.cssURL = props.assetURL + '/css/ot.min.css';
+    
+    if (window.OTProperties) {
+      // Allow window.OTProperties to override cdnURL, configURL, assetURL and cssURL
+      if (window.OTProperties.cdnURL) props.cdnURL = window.OTProperties.cdnURL;
+      if (window.OTProperties.configURL) props.configURL = window.OTProperties.configURL;
+      if (window.OTProperties.assetURL) props.assetURL = window.OTProperties.assetURL;
+      if (window.OTProperties.cssURL) props.cssURL = window.OTProperties.cssURL;
+    }
 
     return props;
   }(OT.properties);
 
 })(window);
 !(function() {
 
 //--------------------------------------
@@ -3514,18 +3520,17 @@ OTHelpers.centerElement = function(eleme
 
 })(window);
 // Web OT Helpers
 !(function(window) {
 
   /* global mozRTCPeerConnection */
 
   var nativeGetUserMedia,
-      mozToW3CErrors,
-      chromeToW3CErrors,
+      vendorToW3CErrors,
       gumNamesToMessages,
       mapVendorErrorName,
       parseErrorEvent,
       areInvalidConstraints;
 
   // Handy cross-browser getUserMedia shim. Inspired by some code from Adam Barth
   nativeGetUserMedia = (function() {
     if (navigator.getUserMedia) {
@@ -3596,97 +3601,91 @@ OTHelpers.centerElement = function(eleme
     //         return this.remoteStreams;
     //     };
     // }
   }
 
 
   // Mozilla error strings and the equivalent W3C names. NOT_SUPPORTED_ERROR does not
   // exist in the spec right now, so we'll include Mozilla's error description.
-  mozToW3CErrors = {
+  // Chrome TrackStartError is triggered when the camera is already used by another app (Windows)
+  vendorToW3CErrors = {
     PERMISSION_DENIED: 'PermissionDeniedError',
     NOT_SUPPORTED_ERROR: 'NotSupportedError',
     MANDATORY_UNSATISFIED_ERROR: ' ConstraintNotSatisfiedError',
     NO_DEVICES_FOUND: 'NoDevicesFoundError',
-    HARDWARE_UNAVAILABLE: 'HardwareUnavailableError'
-  };
-
-  // Chrome only seems to expose a single error with a code of 1 right now.
-  chromeToW3CErrors = {
-    1: 'PermissionDeniedError'
+    HARDWARE_UNAVAILABLE: 'HardwareUnavailableError',
+    TrackStartError: 'HardwareUnavailableError'
   };
 
   gumNamesToMessages = {
     PermissionDeniedError: 'End-user denied permission to hardware devices',
+    PermissionDismissedError: 'End-user dismissed permission to hardware devices',
     NotSupportedError: 'A constraint specified is not supported by the browser.',
     ConstraintNotSatisfiedError: 'It\'s not possible to satisfy one or more constraints ' +
       'passed into the getUserMedia function',
     OverconstrainedError: 'Due to changes in the environment, one or more mandatory ' +
       'constraints can no longer be satisfied.',
     NoDevicesFoundError: 'No voice or video input devices are available on this machine.',
     HardwareUnavailableError: 'The selected voice or video devices are unavailable. Verify ' +
       'that the chosen devices are not in use by another application.'
   };
 
-// Map vendor error strings to names and messages
-  mapVendorErrorName = function mapVendorErrorName (vendorErrorName, vendorErrors) {
-    var errorName = vendorErrors[vendorErrorName],
-        errorMessage = gumNamesToMessages[errorName];
-
-    if (!errorMessage) {
+  // Map vendor error strings to names and messages if possible
+  mapVendorErrorName = function mapVendorErrorName(vendorErrorName, vendorErrors) {
+    var errorName, errorMessage;
+
+    if(vendorErrors.hasOwnProperty(vendorErrorName)) {
+      errorName = vendorErrors[vendorErrorName];
+    } else {
       // This doesn't map to a known error from the Media Capture spec, it's
       // probably a custom vendor error message.
-      errorMessage = null; // This is undefined?
       errorName = vendorErrorName;
     }
 
+    if(gumNamesToMessages.hasOwnProperty(errorName)) {
+      errorMessage = gumNamesToMessages[errorName];
+    } else {
+      errorMessage = 'Unknown Error while getting user media';
+    }
+
     return {
       name: errorName,
       message: errorMessage
     };
   };
 
   // Parse and normalise a getUserMedia error event from Chrome or Mozilla
   // @ref http://dev.w3.org/2011/webrtc/editor/getusermedia.html#idl-def-NavigatorUserMediaError
-  parseErrorEvent = function parseErrorObject (event) {
+  parseErrorEvent = function parseErrorObject(event) {
     var error;
 
     if (OT.$.isObject(event) && event.name) {
-      error = {
-        name: event.name,
-        message: event.message || gumNamesToMessages[event.name],
-        constraintName: event.constraintName
-      };
-
-    } else if (OT.$.isObject(event)) {
-      error = mapVendorErrorName(event.code, chromeToW3CErrors);
-
-      // message and constraintName are probably missing if the
-      // property is also omitted, but just in case they aren't.
-      if (event.message) error.message = event.message;
-      if (event.constraintName) error.constraintName = event.constraintName;
-
-    } else if (event && mozToW3CErrors.hasOwnProperty(event)) {
-      error = mapVendorErrorName(event, mozToW3CErrors);
-
+      error = mapVendorErrorName(event.name, vendorToW3CErrors);
+      error.constraintName = event.constraintName;
+    } else if (typeof event === 'string') {
+      error = mapVendorErrorName(event, vendorToW3CErrors);
     } else {
       error = {
-        message: 'Unknown Error while getting user media'
+        message: 'Unknown Error type while getting media'
       };
     }
 
     return error;
   };
 
   // Validates a Hash of getUserMedia constraints. Currently we only
   // check to see if there is at least one non-false constraint.
   areInvalidConstraints = function(constraints) {
     if (!constraints || !OT.$.isObject(constraints)) return true;
 
     for (var key in constraints) {
+      if(!constraints.hasOwnProperty(key)) {
+        continue;
+      }
       if (constraints[key]) return false;
     }
 
     return true;
   };
 
   // Returns true if the client supports Web RTC, false otherwise.
   //
@@ -3764,16 +3763,39 @@ OTHelpers.centerElement = function(eleme
   // * Older versions of Firefox (<= 25) don't support rtcp mux
   // * Older versions of Firefox (>= 26) support rtcp mux (not tested yet)
   // * Chrome support bundle
   //
   OT.$.supportsRtcpMux = function() {
     return OT.$.supportsWebRTC() && OT.$.browser() === 'Chrome';
   };
 
+  OT.$.shouldAskForDevices = function(callback) {
+    var memoiseReply = function(audio, video) {
+      OT.$.shouldAskForDevices = function(callback) {
+        setTimeout(callback.bind(null, { video: video, audio: audio }));
+      };
+      OT.$.shouldAskForDevices(callback);
+    };
+    var MST = window.MediaStreamTrack;
+    if(MST != null && OT.$.isFunction(MST.getSources)) {
+      window.MediaStreamTrack.getSources(function(sources) {
+        var hasAudio = sources.some(function(src) {
+          return src.kind === 'audio';
+        });
+        var hasVideo = sources.some(function(src) {
+          return src.kind === 'video';
+        });
+        memoiseReply(hasAudio, hasVideo);
+      });
+    } else {
+      memoiseReply(true, true);
+    }
+  };
+
   // A wrapper for the builtin navigator.getUserMedia. In addition to the usual
   // getUserMedia behaviour, this helper method also accepts a accessDialogOpened
   // and accessDialogClosed callback.
   //
   // @memberof OT.$
   // @private
   //
   // @param {Object} constraints
@@ -3845,33 +3867,18 @@ OTHelpers.centerElement = function(eleme
           success.call(null, stream);
         },
 
         onError = function(event) {
           finaliseAccessDialog();
           var error = parseErrorEvent(event);
 
           // The error name 'PERMISSION_DENIED' is from an earlier version of the spec
-          if (error.name === 'PermissionDeniedError') {
-            var MST = window.MediaStreamTrack;
-            if(MST != null && OT.$.isFunction(MST.getSources)) {
-              window.MediaStreamTrack.getSources(function(sources) {
-                if(sources.length > 0) {
-                  accessDenied.call(null, error);
-                } else {
-                  failure.call(null, {
-                    name: 'NoDevicesFoundError',
-                    message: gumNamesToMessages.NoDevicesFoundError
-                  });
-                }
-              });
-            } else {
-              accessDenied.call(null, error);
-            }
-
+          if (error.name === 'PermissionDeniedError' || error.name === 'PermissionDismissedError') {
+            accessDenied.call(null, error);
           } else {
             failure.call(null, error);
           }
         };
 
     try {
       getUserMedia(constraints, onStream, onError);
     } catch (e) {
@@ -4198,16 +4205,34 @@ OTHelpers.centerElement = function(eleme
 
             default:
               // The standard version, just Firefox, Opera, and IE > 9
               this.domElement.style.transform = transform;
           }
 
           this.trigger('orientationChanged');
         }
+      },
+
+      // see https://wiki.mozilla.org/WebAPI/AudioChannels
+      // The audioChannelType is currently only available in Firefox. This property returns
+      // "unknown" in other browser. The related HTML tag attribute is "mozaudiochannel"
+      audioChannelType: {
+        get: function() {
+          if ('mozAudioChannelType' in this.domElement) {
+            return this.domElement.mozAudioChannelType;
+          } else {
+            return 'unknown';
+          }
+        },
+        set: function(type) {
+          if ('mozAudioChannelType' in this.domElement) {
+            this.domElement.mozAudioChannelType = type;
+          }
+        }
       }
     });
   }
 
 /// Private Helper functions
 
   function createVideoElement(fallbackText, attributes) {
     var videoElement = document.createElement('video');
@@ -4216,16 +4241,19 @@ OTHelpers.centerElement = function(eleme
 
     if (attributes) {
       if (attributes.muted === true) {
         delete attributes.muted;
         videoElement.muted = 'true';
       }
 
       for (var key in attributes) {
+        if(!attributes.hasOwnProperty(key)) {
+          continue;
+        }
         videoElement.setAttribute(key, attributes[key]);
       }
     }
 
     return videoElement;
   }
 
 
@@ -5323,16 +5351,19 @@ OTHelpers.centerElement = function(eleme
     //     return publisher.stream.id === 4;
     //   }, self);
     //
     this.where = function(attrsOrFilterFn, context) {
       if (OT.$.isFunction(attrsOrFilterFn)) return _models.filter(attrsOrFilterFn, context);
 
       return _models.filter(function(model) {
         for (var key in attrsOrFilterFn) {
+          if(!attrsOrFilterFn.hasOwnProperty(key)) {
+            continue;
+          }
           if (model[key] !== attrsOrFilterFn[key]) return false;
         }
 
         return true;
       });
     };
 
     // Similar to where in behaviour, except that it only returns
@@ -5341,16 +5372,19 @@ OTHelpers.centerElement = function(eleme
       var filterFn;
 
       if (OT.$.isFunction(attrsOrFilterFn)) {
         filterFn = attrsOrFilterFn;
       }
       else {
         filterFn = function(model) {
           for (var key in attrsOrFilterFn) {
+            if(!attrsOrFilterFn.hasOwnProperty(key)) {
+              continue;
+            }
             if (model[key] !== attrsOrFilterFn[key]) return false;
           }
 
           return true;
         };
       }
 
       filterFn = filterFn.bind(context);
@@ -6189,16 +6223,29 @@ OTHelpers.centerElement = function(eleme
     OT.Event.call(this, type, false);
     this.type = type;
     this.stream = stream;
     this.changedProperty = changedProperty;
     this.oldValue = oldValue;
     this.newValue = newValue;
   };
 
+/**
+ * Defines event objects for the <code>archiveStarted</code> and <code>archiveStopped</code> events.
+ * The Session object dispatches these events when an archive recording of the session starts and
+ * stops.
+ *
+ * @property {String} id The archive ID.
+ * @property {String} name The name of the archive. You can assign an archive a name when you create
+ * it, using the <a href="http://www.tokbox.com/opentok/api">OpenTok REST API</a> or one of the
+ * <a href="http://www.tokbox.com/opentok/libraries/server">OpenTok server SDKs</a>.
+ *
+ * @class ArchiveEvent
+ * @augments Event
+ */
   OT.ArchiveEvent = function (type, archive) {
     OT.Event.call(this, type, false);
     this.type = type;
     this.id = archive.id;
     this.name = archive.name;
     this.status = archive.status;
     this.archive = archive;
   };
@@ -9177,16 +9224,19 @@ OTHelpers.centerElement = function(eleme
 
     // The number of parameters
     cBuf++;
 
     // Write out the params
     i = 0;
 
     for (var key in this.headers) {
+      if(!this.headers.hasOwnProperty(key)) {
+        continue;
+      }
       headerKey.push(new TextEncoder('utf-8').encode(key));
       headerVal.push(new TextEncoder('utf-8').encode(this.headers[key]));
       cBuf += 4;
       cBuf += headerKey[i].length;
       cBuf += headerVal[i].length;
 
       i++;
     }
@@ -11356,16 +11406,19 @@ OTHelpers.centerElement = function(eleme
     OT.$.eventing(this, true);
 
     // Returns true if a property was updated.
     this.update = function(attributes) {
       var videoDimensions = {},
           oldVideoDimensions = {};
 
       for (var key in attributes) {
+        if(!attributes.hasOwnProperty(key)) {
+          continue;
+        }
         // we shouldn't really read this before we know the key is valid
         var oldValue = this[key];
 
         switch(key) {
           case 'active':
             this.active = OT.$.castToBoolean(attributes[key]);
             break;
 
@@ -11435,17 +11488,19 @@ OTHelpers.centerElement = function(eleme
  * <code>connection</code> property of the Session object to see if the stream is being published
  * by the local web page.
  *
  * @property {Number} creationTime The timestamp for the creation
  * of the stream. This value is calculated in milliseconds. You can convert this value to a
  * Date object by calling <code>new Date(creationTime)</code>, where <code>creationTime</code> is
  * the <code>creationTime</code> property of the Stream object.
  *
- * @property {Number} fps The frame rate of the video stream.
+ * @property {Number} frameRate The frame rate of the video stream. This property is only set if the
+ * publisher of the stream specifies a frame rate when calling the <code>OT.initPublisher()</code>
+ * method; otherwise, this property is undefined.
  *
  * @property {Boolean} hasAudio Whether the stream has audio. This property can change if the
  * publisher turns on or off audio (by calling
  * <a href="Publisher.html#publishAudio">Publisher.publishAudio()</a>). When this occurs, the
  * {@link Session} object dispatches a <code>streamPropertyChanged</code> event (see
  * {@link StreamPropertyChangedEvent}.)
  *
  * @property {Boolean} hasVideo Whether the stream has video. This property can change if the
@@ -11666,16 +11721,19 @@ OTHelpers.centerElement = function(eleme
 
       var event = new OT.StreamUpdatedEvent(this, key, oldValue, newValue);
       this.dispatchEvent(event);
     }.bind(this);
 
     // Mass update, called by Raptor.Dispatcher
     this._.update = function (attributes) {
       for (var key in attributes) {
+        if(!attributes.hasOwnProperty(key)) {
+          continue;
+        }
         this._.updateProperty(key, attributes[key]);
       }
     }.bind(this);
 
     this._.updateChannel = function (channelId, attributes) {
       this.getChannel(channelId).update(attributes);
     }.bind(this);
   };
@@ -11692,16 +11750,19 @@ OTHelpers.centerElement = function(eleme
     
     this._ = {};
 
     OT.$.eventing(this);
     
     // Mass update, called by Raptor.Dispatcher
     this._.update = function (attributes) {
       for (var key in attributes) {
+        if(!attributes.hasOwnProperty(key)) {
+          continue;
+        }
         var oldValue = this[key];
         this[key] = attributes[key];
         
         var event = new OT.ArchiveUpdatedEvent(this, key, oldValue, this[key]);
         this.dispatchEvent(event);
         
       }
     }.bind(this);
@@ -13604,20 +13665,23 @@ OTHelpers.centerElement = function(eleme
           return value;
       }
     };
 
     // Returns a shallow copy of the styles.
     this.getAll = function() {
       var style = OT.$.clone(_style);
 
-      for (var i in style) {
-        if (_COMPONENT_STYLES.indexOf(i) < 0) {
+      for (var key in style) {
+        if(!style.hasOwnProperty(key)) {
+          continue;
+        }
+        if (_COMPONENT_STYLES.indexOf(key) < 0) {
           // Strip unnecessary properties out, should this happen on Set?
-          delete style[i];
+          delete style[key];
         }
       }
 
       return style;
     };
 
     this.get = function(key) {
       if (key) {
@@ -13628,16 +13692,19 @@ OTHelpers.centerElement = function(eleme
       return this.getAll();
     };
 
     // *note:* this will not trigger onStyleChange if +silent+ is truthy
     this.setAll = function(newStyles, silent) {
       var oldValue, newValue;
 
       for (var key in newStyles) {
+        if(!newStyles.hasOwnProperty(key)) {
+          continue;
+        }
         newValue = castValue(newStyles[key]);
 
         if (isValidStyle(key, newValue)) {
           oldValue = _style[key];
 
           if (newValue !== oldValue) {
             _style[key] = newValue;
             if (!silent) onStyleChange(key, newValue, oldValue);
@@ -14102,16 +14169,18 @@ OTHelpers.centerElement = function(eleme
         recordQOS = function(connectionId) {
           var QoSBlob = {
             'widget_type': 'Publisher',
             'stream_type': 'WebRTC',
             sessionId: _session ? _session.sessionId : null,
             connectionId: _session && _session.connected ? _session.connection.connectionId : null,
             partnerId: _session ? _session.apiKey : OT.APIKEY,
             streamId: _stream ? _stream.id : null,
+            width: _container ? OT.$.width(_container.domElement)  : undefined,
+            height: _container ? OT.$.height(_container.domElement)  : undefined,
             widgetId: _guid,
             version: OT.properties.version,
             'media_server_name': _session ? _session.sessionInfo.messagingServer : null,
             p2pFlag: _session ? _session.sessionInfo.p2pEnabled : false,
             duration: _publishStartTime ? new Date().getTime() - _publishStartTime.getTime() : 0,
             'remote_connection_id': connectionId
           };
 
@@ -14133,17 +14202,19 @@ OTHelpers.centerElement = function(eleme
           OT.error('Publisher State Change Failed: ', changeFailed.message);
           OT.debug(changeFailed);
         },
 
         onLoaded = function() {
           OT.debug('OT.Publisher.onLoaded');
 
           _state.set('MediaBound');
-          _container.loading = false;
+          // If we have a session and we haven't created the stream yet then
+          // wait until that is complete before hiding the loading spinner
+          _container.loading = this.session ? !_stream : false;
           _loaded = true;
 
           _createChrome.call(this);
 
           this.trigger('initSuccess');
           this.trigger('loaded', this);
         },
 
@@ -14251,46 +14322,54 @@ OTHelpers.centerElement = function(eleme
                 }
               }
             };
 
           this.dispatchEvent(event, defaultAction);
         },
 
         accessDialogPrompt,
+        accessDialogChromeTimeout,
         accessDialogFirefoxTimeout,
         accessDialogWasOpened = false,
 
         onAccessDialogOpened = function() {
 
           accessDialogWasOpened = true;
 
           logAnalyticsEvent('accessDialog', 'Opened', '', '');
 
           var browser = OT.$.browserVersion();
 
           this.dispatchEvent(
             new OT.Event(OT.Event.names.ACCESS_DIALOG_OPENED, true),
             function(event) {
               if(!event.isDefaultPrevented()) {
                 if(browser.browser === 'Chrome') {
-                  accessDialogPrompt = OT.Dialogs.AllowDeny.Chrome.initialPrompt();
+                  accessDialogChromeTimeout = setTimeout(function() {
+                    accessDialogPrompt = OT.Dialogs.AllowDeny.Chrome.initialPrompt();
+                  }, 5000);
                 } else if(browser.browser === 'Firefox') {
                   accessDialogFirefoxTimeout = setTimeout(function() {
                     accessDialogPrompt = OT.Dialogs.AllowDeny.Firefox.maybeDenied();
                   }, 7000);
                 }
               }
             }
           );
         },
 
         onAccessDialogClosed = function() {
           logAnalyticsEvent('accessDialog', 'Closed', '', '');
 
+          if(accessDialogChromeTimeout) {
+            clearTimeout(accessDialogChromeTimeout);
+            accessDialogChromeTimeout = null;
+          }
+
           if(accessDialogFirefoxTimeout) {
             clearTimeout(accessDialogFirefoxTimeout);
             accessDialogFirefoxTimeout = null;
           }
 
           if(accessDialogPrompt) {
             accessDialogPrompt.close();
             accessDialogPrompt = null;
@@ -14359,16 +14438,17 @@ OTHelpers.centerElement = function(eleme
         // Assigns +stream+ to this publisher. The publisher listens
         // for a bunch of events on the stream so it can respond to
         // changes.
         assignStream = function(stream) {
           _stream = stream;
           _stream.on('destroyed', this.disconnect, this);
 
           _state.set('Publishing');
+          _container.loading = !_loaded;
           _publishStartTime = new Date();
 
           this.trigger('publishComplete', null, this);
       
           this.dispatchEvent(new OT.StreamEvent('streamCreated', stream, null, false));
           
           logAnalyticsEvent('publish', 'Success', 'streamType:streamId', 'WebRTC:' + _streamId);
         }.bind(this),
@@ -14554,17 +14634,17 @@ OTHelpers.centerElement = function(eleme
       if ( _state.attemptingToPublish || _state.publishing ) reset();
       _state.set('GetUserMedia');
 
       _publishProperties = OT.$.defaults(properties || {}, {
         publishAudio : true,
         publishVideo : true,
         mirror: true
       });
-        
+
       if (!_publishProperties.constraints) {
         _publishProperties.constraints = OT.$.clone(defaultConstraints);
         if (_publishProperties.resolution) {
           if (_publishProperties.resolution !== void 0 &&
             !_validResolutions.hasOwnProperty(_publishProperties.resolution)) {
             OT.warn('Invalid resolution passed to the Publisher. Got: ' +
               _publishProperties.resolution + ' expecting one of "' +
               Object.keys(_validResolutions).join('","') + '"');
@@ -14616,24 +14696,34 @@ OTHelpers.centerElement = function(eleme
       _publishProperties.classNames = 'OT_root OT_publisher';
 
       // Defer actually creating the publisher DOM nodes until we know
       // the DOM is actually loaded.
       OT.onLoad(function() {
         _container = new OT.WidgetView(targetElement, _publishProperties);
         _domId = _container.domId;
 
-        OT.$.getUserMedia(
-          _publishProperties.constraints,
-          onStreamAvailable.bind(this),
-          onStreamAvailableError.bind(this),
-          onAccessDialogOpened.bind(this),
-          onAccessDialogClosed.bind(this),
-          onAccessDenied.bind(this)
-        );
+        OT.$.shouldAskForDevices(function(devices) {
+          if(!devices.video) {
+            OT.warn('Setting video constraint to false, there are no video sources');
+            _publishProperties.constraints.video = false;
+          }
+          if(!devices.audio) {
+            OT.warn('Setting audio constraint to false, there are no audio sources');
+            _publishProperties.constraints.audio = false;
+          }
+          OT.$.getUserMedia(
+            _publishProperties.constraints,
+            onStreamAvailable.bind(this),
+            onStreamAvailableError.bind(this),
+            onAccessDialogOpened.bind(this),
+            onAccessDialogClosed.bind(this),
+            onAccessDenied.bind(this)
+          );
+        }.bind(this));
       }, this);
 
       return this;
     };
 
  /**
   * Starts publishing audio (if it is currently not being published)
   * when the <code>value</code> is <code>true</code>; stops publishing audio
@@ -15192,16 +15282,18 @@ OTHelpers.centerElement = function(eleme
         },
 
         recordQOS = function() {
           if(_state.subscribing && _session && _session.connected) {
             /*jshint camelcase:false */
             var QoSBlob = {
               widget_type: 'Subscriber',
               stream_type : 'WebRTC',
+              width: _container ? OT.$.width(_container.domElement) : undefined,
+              height: _container ? OT.$.height(_container.domElement) : undefined,
               session_id: _session ? _session.sessionId : null,
               connectionId: _session ? _session.connection.connectionId : null,
               media_server_name: _session ? _session.sessionInfo.messagingServer : null,
               p2pFlag: _session ? _session.sessionInfo.p2pEnabled : false,
               partner_id: _session ? _session.apiKey : null,
               stream_id: _stream.id,
               widget_id: _widgetId,
               version: OT.properties.version,
@@ -15315,16 +15407,18 @@ OTHelpers.centerElement = function(eleme
           // Disable the audio/video, if needed
           this.subscribeToAudio(_properties.subscribeToAudio);
 
           var preserver = _subscribeAudioFalseWorkaround;
           this.subscribeToVideo(_properties.subscribeToVideo);
           _subscribeAudioFalseWorkaround = preserver;
 
           var streamElement = new OT.VideoElement();
+          // makes the incoming audio streams takes priority (will impact only FF OS for now)
+          streamElement.audioChannelType = 'telephony';
 
           // Initialize the audio volume
           streamElement.setAudioVolume(_audioVolume);
           streamElement.on({
             streamBound: onLoaded,
             loadError: onPeerConnectionFailure,
             error: onPeerConnectionFailure
           }, this);
@@ -17917,16 +18011,36 @@ OTHelpers.centerElement = function(eleme
       capabilities: function() {
         var connection =  this.connection;
         return connection ? connection.permissions : new OT.Capabilities([]);
       }.bind(this)
     }, true);
 
 
   /**
+   * Dispatched when an archive recording of the session starts.
+   *
+   * @name archiveStarted
+   * @event
+   * @memberof Session
+   * @see ArchiveEvent
+   * @see <a href="http://www.tokbox.com/opentok/tutorials/archiving">Archiving overview</a>.
+   */
+
+  /**
+   * Dispatched when an archive recording of the session stops.
+   *
+   * @name archiveStopped
+   * @event
+   * @memberof Session
+   * @see ArchiveEvent
+   * @see <a href="http://www.tokbox.com/opentok/tutorials/archiving">Archiving overview</a>.
+   */
+
+  /**
    * A new client, other than your own, has connected to the session.
    * @name connectionCreated
    * @event
    * @memberof Session
    * @see ConnectionEvent
    * @see <a href="OT.html#initSession">OT.initSession()</a>
    */
 
--- a/browser/components/loop/jar.mn
+++ b/browser/components/loop/jar.mn
@@ -50,24 +50,24 @@ browser.jar:
   content/browser/loop/shared/libs/lodash-2.4.1.js    (content/shared/libs/lodash-2.4.1.js)
   content/browser/loop/shared/libs/jquery-2.1.0.js    (content/shared/libs/jquery-2.1.0.js)
   content/browser/loop/shared/libs/backbone-1.1.2.js  (content/shared/libs/backbone-1.1.2.js)
 
   # Shared sounds
   content/browser/loop/shared/sounds/Firefox-Long.ogg (content/shared/sounds/Firefox-Long.ogg)
 
   # Partner SDK assets
-  content/browser/loop/libs/sdk.js                                                    (content/libs/sdk.js)
-  content/browser/loop/otcdn/webrtc/v2.2.5/css/ot.min.css                             (content/libs/otcdn/webrtc/v2.2.5/css/ot.min.css)
-  content/browser/loop/otcdn/webrtc/v2.2.5/js/dynamic_config.min.js                   (content/libs/otcdn/webrtc/v2.2.5/js/dynamic_config.min.js)
-  content/browser/loop/otcdn/webrtc/v2.2.5/images/rtc/access-denied-chrome.png        (content/libs/otcdn/webrtc/v2.2.5/images/rtc/access-denied-chrome.png)
-  content/browser/loop/otcdn/webrtc/v2.2.5/images/rtc/access-denied-copy-firefox.png  (content/libs/otcdn/webrtc/v2.2.5/images/rtc/access-denied-copy-firefox.png)
-  content/browser/loop/otcdn/webrtc/v2.2.5/images/rtc/access-denied-firefox.png       (content/libs/otcdn/webrtc/v2.2.5/images/rtc/access-denied-firefox.png)
-  content/browser/loop/otcdn/webrtc/v2.2.5/images/rtc/access-predenied-chrome.png     (content/libs/otcdn/webrtc/v2.2.5/images/rtc/access-predenied-chrome.png)
-  content/browser/loop/otcdn/webrtc/v2.2.5/images/rtc/access-prompt-chrome.png        (content/libs/otcdn/webrtc/v2.2.5/images/rtc/access-prompt-chrome.png)
-  content/browser/loop/otcdn/webrtc/v2.2.5/images/rtc/audioonly-publisher.png         (content/libs/otcdn/webrtc/v2.2.5/images/rtc/audioonly-publisher.png)
-  content/browser/loop/otcdn/webrtc/v2.2.5/images/rtc/audioonly-subscriber.png        (content/libs/otcdn/webrtc/v2.2.5/images/rtc/audioonly-subscriber.png)
-  content/browser/loop/otcdn/webrtc/v2.2.5/images/rtc/buttons.png                     (content/libs/otcdn/webrtc/v2.2.5/images/rtc/buttons.png)
-  content/browser/loop/otcdn/webrtc/v2.2.5/images/rtc/loader.gif                      (content/libs/otcdn/webrtc/v2.2.5/images/rtc/loader.gif)
-  content/browser/loop/otcdn/webrtc/v2.2.5/images/rtc/mic-off.png                     (content/libs/otcdn/webrtc/v2.2.5/images/rtc/mic-off.png)
-  content/browser/loop/otcdn/webrtc/v2.2.5/images/rtc/mic-on.png                      (content/libs/otcdn/webrtc/v2.2.5/images/rtc/mic-on.png)
-  content/browser/loop/otcdn/webrtc/v2.2.5/images/rtc/speaker-off.png                 (content/libs/otcdn/webrtc/v2.2.5/images/rtc/speaker-off.png)
-  content/browser/loop/otcdn/webrtc/v2.2.5/images/rtc/speaker-on.png                  (content/libs/otcdn/webrtc/v2.2.5/images/rtc/speaker-on.png)
+  content/browser/loop/libs/sdk.js                                            (content/libs/sdk.js)
+  content/browser/loop/sdk-content/css/ot.css                                 (content/libs/sdk-content/css/ot.css)
+  content/browser/loop/sdk-content/js/dynamic_config.min.js                   (content/libs/sdk-content/js/dynamic_config.min.js)
+  content/browser/loop/sdk-content/images/rtc/access-denied-chrome.png        (content/libs/sdk-content/images/rtc/access-denied-chrome.png)
+  content/browser/loop/sdk-content/images/rtc/access-denied-copy-firefox.png  (content/libs/sdk-content/images/rtc/access-denied-copy-firefox.png)
+  content/browser/loop/sdk-content/images/rtc/access-denied-firefox.png       (content/libs/sdk-content/images/rtc/access-denied-firefox.png)
+  content/browser/loop/sdk-content/images/rtc/access-predenied-chrome.png     (content/libs/sdk-content/images/rtc/access-predenied-chrome.png)
+  content/browser/loop/sdk-content/images/rtc/access-prompt-chrome.png        (content/libs/sdk-content/images/rtc/access-prompt-chrome.png)
+  content/browser/loop/sdk-content/images/rtc/audioonly-publisher.png         (content/libs/sdk-content/images/rtc/audioonly-publisher.png)
+  content/browser/loop/sdk-content/images/rtc/audioonly-subscriber.png        (content/libs/sdk-content/images/rtc/audioonly-subscriber.png)
+  content/browser/loop/sdk-content/images/rtc/buttons.png                     (content/libs/sdk-content/images/rtc/buttons.png)
+  content/browser/loop/sdk-content/images/rtc/loader.gif                      (content/libs/sdk-content/images/rtc/loader.gif)
+  content/browser/loop/sdk-content/images/rtc/mic-off.png                     (content/libs/sdk-content/images/rtc/mic-off.png)
+  content/browser/loop/sdk-content/images/rtc/mic-on.png                      (content/libs/sdk-content/images/rtc/mic-on.png)
+  content/browser/loop/sdk-content/images/rtc/speaker-off.png                 (content/libs/sdk-content/images/rtc/speaker-off.png)
+  content/browser/loop/sdk-content/images/rtc/speaker-on.png                  (content/libs/sdk-content/images/rtc/speaker-on.png)